git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1829453 13f79535-47bb-0310-9956-ffa450edef68tags/REL_4_0_0_FINAL
import org.apache.poi.sl.usermodel.TextRun.FieldType; | import org.apache.poi.sl.usermodel.TextRun.FieldType; | ||||
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; | ||||
import org.apache.poi.util.Internal; | |||||
import org.apache.poi.util.LocaleUtil; | 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; | ||||
return getRenderableText(tr); | return getRenderableText(tr); | ||||
} | } | ||||
private String getRenderableText(final TextRun tr) { | |||||
@Internal | |||||
public String getRenderableText(final TextRun tr) { | |||||
final String txtSpace = tr.getRawText().replace("\t", tab2space(tr)).replace('\u000b', '\n'); | final String txtSpace = tr.getRawText().replace("\t", tab2space(tr)).replace('\u000b', '\n'); | ||||
final Locale loc = LocaleUtil.getUserLocale(); | final Locale loc = LocaleUtil.getUserLocale(); | ||||
package org.apache.poi.sl.extractor; | |||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
import org.apache.poi.POITextExtractor; | |||||
import org.apache.poi.sl.usermodel.Comment; | |||||
import org.apache.poi.sl.usermodel.MasterSheet; | |||||
import org.apache.poi.sl.usermodel.Notes; | |||||
import org.apache.poi.sl.usermodel.ObjectShape; | |||||
import org.apache.poi.sl.usermodel.Placeholder; | |||||
import org.apache.poi.sl.usermodel.PlaceholderDetails; | |||||
import org.apache.poi.sl.usermodel.Shape; | |||||
import org.apache.poi.sl.usermodel.ShapeContainer; | |||||
import org.apache.poi.sl.usermodel.Sheet; | |||||
import org.apache.poi.sl.usermodel.Slide; | |||||
import org.apache.poi.sl.usermodel.SlideShow; | |||||
import org.apache.poi.sl.usermodel.TableCell; | |||||
import org.apache.poi.sl.usermodel.TableShape; | |||||
import org.apache.poi.sl.usermodel.TextParagraph; | |||||
import org.apache.poi.sl.usermodel.TextRun; | |||||
import org.apache.poi.sl.usermodel.TextShape; | |||||
import org.apache.poi.util.LocaleUtil; | |||||
import org.apache.poi.util.POILogFactory; | |||||
import org.apache.poi.util.POILogger; | |||||
/** | |||||
* Common SlideShow extractor | |||||
* | |||||
* @since POI 4.0.0 | |||||
*/ | |||||
public class SlideShowExtractor< | |||||
S extends Shape<S,P>, | |||||
P extends TextParagraph<S,P,? extends TextRun> | |||||
> extends POITextExtractor { | |||||
private static final POILogger LOG = POILogFactory.getLogger(SlideShowExtractor.class); | |||||
private SlideShow<S,P> slideshow; | |||||
private boolean slidesByDefault = true; | |||||
private boolean notesByDefault; | |||||
private boolean commentsByDefault; | |||||
private boolean masterByDefault; | |||||
public SlideShowExtractor(final SlideShow<S,P> slideshow) { | |||||
setFilesystem(slideshow); | |||||
this.slideshow = slideshow; | |||||
} | |||||
/** | |||||
* Should a call to getText() return slide text? Default is yes | |||||
*/ | |||||
public void setSlidesByDefault(final boolean slidesByDefault) { | |||||
this.slidesByDefault = slidesByDefault; | |||||
} | |||||
/** | |||||
* Should a call to getText() return notes text? Default is no | |||||
*/ | |||||
public void setNotesByDefault(final boolean notesByDefault) { | |||||
this.notesByDefault = notesByDefault; | |||||
} | |||||
/** | |||||
* Should a call to getText() return comments text? Default is no | |||||
*/ | |||||
public void setCommentsByDefault(final boolean commentsByDefault) { | |||||
this.commentsByDefault = commentsByDefault; | |||||
} | |||||
/** | |||||
* Should a call to getText() return text from master? Default is no | |||||
*/ | |||||
public void setMasterByDefault(final boolean masterByDefault) { | |||||
this.masterByDefault = masterByDefault; | |||||
} | |||||
@Override | |||||
public POITextExtractor getMetadataTextExtractor() { | |||||
return slideshow.getMetadataTextExtractor(); | |||||
} | |||||
/** | |||||
* Fetches all the slide text from the slideshow, but not the notes, unless | |||||
* you've called setSlidesByDefault() and setNotesByDefault() to change this | |||||
*/ | |||||
@Override | |||||
public String getText() { | |||||
final StringBuilder sb = new StringBuilder(); | |||||
if (masterByDefault) { | |||||
for (final MasterSheet<S,P> master : slideshow.getSlideMasters()) { | |||||
for (final Shape<S,P> shape : master) { | |||||
if (shape instanceof TextShape) { | |||||
final TextShape<S,P> ts = (TextShape<S,P>)shape; | |||||
final String text = ts.getText(); | |||||
if (text == null || text.isEmpty() || "*".equals(text)) { | |||||
continue; | |||||
} | |||||
if (ts.isPlaceholder()) { | |||||
// don't bother about boiler plate text on master sheets | |||||
LOG.log(POILogger.INFO, "Ignoring boiler plate (placeholder) text on slide master:", text); | |||||
continue; | |||||
} | |||||
sb.append(text); | |||||
if (!text.endsWith("\n")) { | |||||
sb.append("\n"); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
for (final Slide<S, P> slide : slideshow.getSlides()) { | |||||
sb.append(getText(slide)); | |||||
} | |||||
return sb.toString(); | |||||
} | |||||
public String getText(final Slide<S,P> slide) { | |||||
final StringBuilder sb = new StringBuilder(); | |||||
if (slidesByDefault) { | |||||
printShapeText(slide, sb); | |||||
} | |||||
if (commentsByDefault) { | |||||
printComments(slide, sb); | |||||
} | |||||
if (notesByDefault) { | |||||
printNotes(slide, sb); | |||||
} | |||||
return sb.toString(); | |||||
} | |||||
private String printHeaderReturnFooter(final Sheet<S,P> sheet, final StringBuilder sb) { | |||||
final Sheet<S, P> m = (sheet instanceof Slide) ? sheet.getMasterSheet() : sheet; | |||||
final StringBuilder footer = new StringBuilder("\n"); | |||||
addSheetPlaceholderDatails(sheet, Placeholder.HEADER, sb); | |||||
addSheetPlaceholderDatails(sheet, Placeholder.FOOTER, footer); | |||||
if (masterByDefault) { | |||||
// write header texts and determine footer text | |||||
for (Shape<S, P> s : m) { | |||||
if (!(s instanceof TextShape)) { | |||||
continue; | |||||
} | |||||
final TextShape<S, P> ts = (TextShape<S, P>) s; | |||||
final PlaceholderDetails pd = ts.getPlaceholderDetails(); | |||||
if (pd == null || !pd.isVisible()) { | |||||
continue; | |||||
} | |||||
switch (pd.getPlaceholder()) { | |||||
case HEADER: | |||||
sb.append(ts.getText()); | |||||
sb.append('\n'); | |||||
break; | |||||
case SLIDE_NUMBER: | |||||
if (sheet instanceof Slide) { | |||||
footer.append(ts.getText().replace("‹#›", Integer.toString(((Slide<S, P>) sheet).getSlideNumber() + 1))); | |||||
footer.append('\n'); | |||||
} | |||||
break; | |||||
case FOOTER: | |||||
footer.append(ts.getText()); | |||||
footer.append('\n'); | |||||
break; | |||||
case DATETIME: | |||||
// currently not supported | |||||
default: | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
return (footer.length() > 1) ? footer.toString() : ""; | |||||
} | |||||
private void addSheetPlaceholderDatails(final Sheet<S,P> sheet, final Placeholder placeholder, final StringBuilder sb) { | |||||
final PlaceholderDetails headerPD = sheet.getPlaceholderDetails(placeholder); | |||||
if (headerPD == null) { | |||||
return; | |||||
} | |||||
final String headerStr = headerPD.getText(); | |||||
if (headerStr == null) { | |||||
return; | |||||
} | |||||
sb.append(headerStr); | |||||
} | |||||
private void printShapeText(final Sheet<S,P> sheet, final StringBuilder sb) { | |||||
final String footer = printHeaderReturnFooter(sheet, sb); | |||||
printShapeText((ShapeContainer<S,P>)sheet, sb); | |||||
sb.append(footer); | |||||
} | |||||
@SuppressWarnings("unchecked") | |||||
private void printShapeText(final ShapeContainer<S,P> container, final StringBuilder sb) { | |||||
for (Shape<S,P> shape : container) { | |||||
if (shape instanceof TextShape) { | |||||
printShapeText((TextShape<S,P>)shape, sb); | |||||
} else if (shape instanceof TableShape) { | |||||
printShapeText((TableShape<S,P>)shape, sb); | |||||
} else if (shape instanceof ShapeContainer) { | |||||
printShapeText((ShapeContainer<S,P>)shape, sb); | |||||
} | |||||
} | |||||
} | |||||
private void printShapeText(final TextShape<S,P> shape, final StringBuilder sb) { | |||||
final List<P> paraList = shape.getTextParagraphs(); | |||||
if (paraList.isEmpty()) { | |||||
sb.append('\n'); | |||||
return; | |||||
} | |||||
for (final P para : paraList) { | |||||
final int oldLen = sb.length(); | |||||
for (final TextRun tr : para) { | |||||
final String str = tr.getRawText().replace("\r", ""); | |||||
final String newStr; | |||||
switch (tr.getTextCap()) { | |||||
case ALL: | |||||
newStr = str.toUpperCase(LocaleUtil.getUserLocale()); | |||||
break; | |||||
case SMALL: | |||||
newStr = str.toLowerCase(LocaleUtil.getUserLocale()); | |||||
break; | |||||
default: | |||||
case NONE: | |||||
newStr = str; | |||||
break; | |||||
} | |||||
sb.append(newStr); | |||||
} | |||||
sb.append('\n'); | |||||
} | |||||
} | |||||
@SuppressWarnings("Duplicates") | |||||
private void printShapeText(final TableShape<S,P> shape, final StringBuilder sb) { | |||||
final int nrows = shape.getNumberOfRows(); | |||||
final int ncols = shape.getNumberOfColumns(); | |||||
for (int row = 0; row < nrows; row++){ | |||||
for (int col = 0; col < ncols; col++){ | |||||
TableCell<S, P> cell = shape.getCell(row, col); | |||||
//defensive null checks; don't know if they're necessary | |||||
if (cell != null){ | |||||
String txt = cell.getText(); | |||||
txt = (txt == null) ? "" : txt; | |||||
sb.append(txt); | |||||
if (col < ncols-1){ | |||||
sb.append('\t'); | |||||
} | |||||
} | |||||
} | |||||
sb.append('\n'); | |||||
} | |||||
} | |||||
private void printComments(final Slide<S,P> slide, final StringBuilder sb) { | |||||
for (final Comment comment : slide.getComments()) { | |||||
sb.append(comment.getAuthor()); | |||||
sb.append(" - "); | |||||
sb.append(comment.getText()); | |||||
sb.append("\n"); | |||||
} | |||||
} | |||||
private void printNotes(final Slide<S,P> slide, final StringBuilder sb) { | |||||
final Notes<S, P> notes = slide.getNotes(); | |||||
if (notes == null) { | |||||
return; | |||||
} | |||||
final String footer = printHeaderReturnFooter(notes, sb); | |||||
printShapeText(notes, sb); | |||||
sb.append(footer); | |||||
} | |||||
public List<? extends ObjectShape<S,P>> getOLEShapes() { | |||||
final List<ObjectShape<S,P>> oleShapes = new ArrayList<>(); | |||||
for (final Slide<S,P> slide : slideshow.getSlides()) { | |||||
addOLEShapes(oleShapes, slide); | |||||
} | |||||
return oleShapes; | |||||
} | |||||
@SuppressWarnings("unchecked") | |||||
private void addOLEShapes(final List<ObjectShape<S,P>> oleShapes, ShapeContainer<S,P> container) { | |||||
for (Shape<S,P> shape : container) { | |||||
if (shape instanceof ShapeContainer) { | |||||
addOLEShapes(oleShapes, (ShapeContainer<S,P>)shape); | |||||
} else if (shape instanceof ObjectShape) { | |||||
oleShapes.add((ObjectShape<S,P>)shape); | |||||
} | |||||
} | |||||
} | |||||
} |
/* ==================================================================== | |||||
Licensed to the Apache Software Foundation (ASF) under one or more | |||||
contributor license agreements. See the NOTICE file distributed with | |||||
this work for additional information regarding copyright ownership. | |||||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||||
(the "License"); you may not use this file except in compliance with | |||||
the License. You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
==================================================================== */ | |||||
package org.apache.poi.sl.usermodel; | |||||
import java.awt.geom.Point2D; | |||||
import java.util.Date; | |||||
/** | |||||
* Common interface for comments | |||||
* | |||||
* @since POI 4.0.0 | |||||
*/ | |||||
public interface Comment { | |||||
/** | |||||
* Get the Author of this comment | |||||
*/ | |||||
String getAuthor(); | |||||
/** | |||||
* Set the Author of this comment. | |||||
* if the author wasn't registered before, create a new entry | |||||
*/ | |||||
void setAuthor(String author); | |||||
/** | |||||
* Get the Author's Initials of this comment | |||||
*/ | |||||
String getAuthorInitials(); | |||||
/** | |||||
* Set the Author's Initials of this comment. | |||||
* if the author wasn't registered before via {@link #setAuthor(String)} | |||||
* this has no effect | |||||
*/ | |||||
void setAuthorInitials(String initials); | |||||
/** | |||||
* Get the text of this comment | |||||
*/ | |||||
String getText(); | |||||
/** | |||||
* Set the text of this comment | |||||
*/ | |||||
void setText(String text); | |||||
/** | |||||
* Gets the date the comment was made. | |||||
* @return the comment date. | |||||
*/ | |||||
Date getDate(); | |||||
/** | |||||
* Sets the date the comment was made. | |||||
* @param date the comment date. | |||||
*/ | |||||
void setDate(Date date); | |||||
/** | |||||
* Gets the offset of the comment on the page. | |||||
* @return the offset. | |||||
*/ | |||||
Point2D getOffset(); | |||||
/** | |||||
* Sets the offset of the comment on the page. | |||||
* @param offset the offset. | |||||
*/ | |||||
void setOffset(Point2D offset); | |||||
} |
/* ==================================================================== | |||||
Licensed to the Apache Software Foundation (ASF) under one or more | |||||
contributor license agreements. See the NOTICE file distributed with | |||||
this work for additional information regarding copyright ownership. | |||||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||||
(the "License"); you may not use this file except in compliance with | |||||
the License. You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
==================================================================== */ | |||||
package org.apache.poi.sl.usermodel; | |||||
/** | |||||
* Extended details about placholders | |||||
* | |||||
* @since POI 4.0.0 | |||||
*/ | |||||
public interface PlaceholderDetails { | |||||
enum PlaceholderSize { | |||||
quarter, half, full; | |||||
} | |||||
Placeholder getPlaceholder(); | |||||
/** | |||||
* Specifies that the corresponding shape should be represented by the generating application | |||||
* as a placeholder. When a shape is considered a placeholder by the generating application | |||||
* it can have special properties to alert the user that they may enter content into the shape. | |||||
* Different types of placeholders are allowed and can be specified by using the placeholder | |||||
* type attribute for this element | |||||
* | |||||
* @param placeholder The shape to use as placeholder or null if no placeholder should be set. | |||||
*/ | |||||
void setPlaceholder(Placeholder placeholder); | |||||
boolean isVisible(); | |||||
void setVisible(boolean isVisible); | |||||
PlaceholderSize getSize(); | |||||
void setSize(PlaceholderSize size); | |||||
/** | |||||
* If the placeholder shape or object stores text, this text is returned otherwise {@code null}. | |||||
* | |||||
* @return the text of the shape / placeholder | |||||
* | |||||
* @since POI 4.0.0 | |||||
*/ | |||||
String getText(); | |||||
/** | |||||
* If the placeholder shape or object stores text, the given text is stored otherwise this is a no-op. | |||||
* | |||||
* @param text the placeholder text | |||||
* | |||||
* @since POI 4.0.0 | |||||
*/ | |||||
void setText(String text); | |||||
} |
* @param graphics | * @param graphics | ||||
*/ | */ | ||||
void draw(Graphics2D graphics); | void draw(Graphics2D graphics); | ||||
/** | |||||
* Get the placeholder details for the given placeholder type. Not all placeholders are also shapes - | |||||
* this is especially true for old HSLF slideshows, which notes have header/footers elements which | |||||
* aren't shapes. | |||||
* | |||||
* @param placeholder the placeholder type | |||||
* @return the placeholder details or {@code null}, if the placeholder isn't contained in the sheet | |||||
* | |||||
* @since POI 4.0.0 | |||||
*/ | |||||
PlaceholderDetails getPlaceholderDetails(Placeholder placeholder); | |||||
} | } |
*/ | */ | ||||
void setPlaceholder(Placeholder placeholder); | void setPlaceholder(Placeholder placeholder); | ||||
/** | |||||
* @return an accessor for placeholder details | |||||
* | |||||
* @since POI 4.0.0 | |||||
*/ | |||||
PlaceholderDetails getPlaceholderDetails(); | |||||
/** | |||||
* Checks if the shape is a placeholder. | |||||
* (placeholders aren't normal shapes, they are visible only in the Edit Master mode) | |||||
* | |||||
* @return {@code true} if the shape is a placeholder | |||||
* | |||||
* @since POI 4.0.0 | |||||
*/ | |||||
boolean isPlaceholder(); | |||||
Shadow<S,P> getShadow(); | Shadow<S,P> getShadow(); | ||||
/** | /** |
package org.apache.poi.sl.usermodel; | package org.apache.poi.sl.usermodel; | ||||
import java.util.List; | |||||
public interface Slide< | public interface Slide< | ||||
S extends Shape<S,P>, | S extends Shape<S,P>, | ||||
P extends TextParagraph<S,P,? extends TextRun> | P extends TextParagraph<S,P,? extends TextRun> | ||||
* whereas in HSLF they are activated via a HeadersFooter configuration. | * whereas in HSLF they are activated via a HeadersFooter configuration. | ||||
* This method is used to generalize that handling. | * This method is used to generalize that handling. | ||||
* | * | ||||
* @param placeholder | |||||
* @param placeholder the placeholder type | |||||
* @return {@code true} if the placeholder should be displayed/rendered | * @return {@code true} if the placeholder should be displayed/rendered | ||||
* @since POI 3.16-beta2 | * @since POI 3.16-beta2 | ||||
*/ | */ | ||||
* @since POI 4.0.0 | * @since POI 4.0.0 | ||||
*/ | */ | ||||
boolean isHidden(); | boolean isHidden(); | ||||
/** | |||||
* @return the comment(s) for this slide | |||||
*/ | |||||
List<? extends Comment> getComments(); | |||||
} | } |
import java.io.OutputStream; | import java.io.OutputStream; | ||||
import java.util.List; | import java.util.List; | ||||
import org.apache.poi.POITextExtractor; | |||||
import org.apache.poi.sl.usermodel.PictureData.PictureType; | import org.apache.poi.sl.usermodel.PictureData.PictureType; | ||||
public interface SlideShow< | public interface SlideShow< | ||||
* OutputStream | * OutputStream | ||||
*/ | */ | ||||
void write(OutputStream out) throws IOException; | void write(OutputStream out) throws IOException; | ||||
/** | |||||
* @return an extractor for the slideshow metadata | |||||
* | |||||
* @since POI 4.0.0 | |||||
*/ | |||||
POITextExtractor getMetadataTextExtractor(); | |||||
} | } |
import org.apache.poi.POIXMLTextExtractor; | import org.apache.poi.POIXMLTextExtractor; | ||||
import org.apache.poi.openxml4j.exceptions.OpenXML4JException; | import org.apache.poi.openxml4j.exceptions.OpenXML4JException; | ||||
import org.apache.poi.openxml4j.opc.OPCPackage; | import org.apache.poi.openxml4j.opc.OPCPackage; | ||||
import org.apache.poi.sl.extractor.SlideShowExtractor; | |||||
import org.apache.poi.util.Removal; | |||||
import org.apache.poi.xslf.usermodel.XMLSlideShow; | import org.apache.poi.xslf.usermodel.XMLSlideShow; | ||||
import org.apache.poi.xslf.usermodel.XSLFCommentAuthors; | |||||
import org.apache.poi.xslf.usermodel.XSLFComments; | |||||
import org.apache.poi.xslf.usermodel.XSLFNotes; | |||||
import org.apache.poi.xslf.usermodel.XSLFRelation; | import org.apache.poi.xslf.usermodel.XSLFRelation; | ||||
import org.apache.poi.xslf.usermodel.XSLFShape; | import org.apache.poi.xslf.usermodel.XSLFShape; | ||||
import org.apache.poi.xslf.usermodel.XSLFShapeContainer; | |||||
import org.apache.poi.xslf.usermodel.XSLFSlide; | import org.apache.poi.xslf.usermodel.XSLFSlide; | ||||
import org.apache.poi.xslf.usermodel.XSLFSlideLayout; | |||||
import org.apache.poi.xslf.usermodel.XSLFSlideMaster; | |||||
import org.apache.poi.xslf.usermodel.XSLFSlideShow; | import org.apache.poi.xslf.usermodel.XSLFSlideShow; | ||||
import org.apache.poi.xslf.usermodel.XSLFTable; | |||||
import org.apache.poi.xslf.usermodel.XSLFTableCell; | |||||
import org.apache.poi.xslf.usermodel.XSLFTableRow; | |||||
import org.apache.poi.xslf.usermodel.XSLFTextShape; | |||||
import org.apache.poi.xslf.usermodel.XSLFTextParagraph; | |||||
import org.apache.xmlbeans.XmlException; | import org.apache.xmlbeans.XmlException; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTComment; | |||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTCommentAuthor; | |||||
/** | |||||
* Extractor for XSLF SlideShows | |||||
* | |||||
* @deprecated use {@link SlideShowExtractor} | |||||
*/ | |||||
@Deprecated | |||||
@Removal(version="4.2.0") | |||||
public class XSLFPowerPointExtractor extends POIXMLTextExtractor { | public class XSLFPowerPointExtractor extends POIXMLTextExtractor { | ||||
public static final XSLFRelation[] SUPPORTED_TYPES = new XSLFRelation[] { | |||||
XSLFRelation.MAIN, XSLFRelation.MACRO, XSLFRelation.MACRO_TEMPLATE, | |||||
XSLFRelation.PRESENTATIONML, XSLFRelation.PRESENTATIONML_TEMPLATE, | |||||
XSLFRelation.PRESENTATION_MACRO | |||||
}; | |||||
private XMLSlideShow slideshow; | |||||
private boolean slidesByDefault = true; | |||||
private boolean notesByDefault; | |||||
private boolean masterByDefault; | |||||
public XSLFPowerPointExtractor(XMLSlideShow slideshow) { | |||||
super(slideshow); | |||||
this.slideshow = slideshow; | |||||
} | |||||
public XSLFPowerPointExtractor(XSLFSlideShow slideshow) throws XmlException, IOException { | |||||
this(new XMLSlideShow(slideshow.getPackage())); | |||||
} | |||||
public XSLFPowerPointExtractor(OPCPackage container) throws XmlException, OpenXML4JException, IOException { | |||||
this(new XSLFSlideShow(container)); | |||||
} | |||||
public static void main(String[] args) throws Exception { | |||||
if(args.length < 1) { | |||||
System.err.println("Use:"); | |||||
System.err.println(" XSLFPowerPointExtractor <filename.pptx>"); | |||||
System.exit(1); | |||||
} | |||||
POIXMLTextExtractor extractor = | |||||
new XSLFPowerPointExtractor( | |||||
new XSLFSlideShow(args[0])); | |||||
System.out.println(extractor.getText()); | |||||
extractor.close(); | |||||
} | |||||
/** | |||||
* Should a call to getText() return slide text? | |||||
* Default is yes | |||||
*/ | |||||
public void setSlidesByDefault(boolean slidesByDefault) { | |||||
this.slidesByDefault = slidesByDefault; | |||||
} | |||||
/** | |||||
* Should a call to getText() return notes text? | |||||
* Default is no | |||||
*/ | |||||
public void setNotesByDefault(boolean notesByDefault) { | |||||
this.notesByDefault = notesByDefault; | |||||
} | |||||
/** | |||||
* Should a call to getText() return text from master? Default is no | |||||
*/ | |||||
public void setMasterByDefault(boolean masterByDefault) { | |||||
this.masterByDefault = masterByDefault; | |||||
} | |||||
/** | |||||
* Gets the slide text, but not the notes text | |||||
*/ | |||||
@Override | |||||
public static final XSLFRelation[] SUPPORTED_TYPES = new XSLFRelation[]{ | |||||
XSLFRelation.MAIN, XSLFRelation.MACRO, XSLFRelation.MACRO_TEMPLATE, | |||||
XSLFRelation.PRESENTATIONML, XSLFRelation.PRESENTATIONML_TEMPLATE, | |||||
XSLFRelation.PRESENTATION_MACRO | |||||
}; | |||||
private final SlideShowExtractor<XSLFShape, XSLFTextParagraph> delegate; | |||||
private boolean slidesByDefault = true; | |||||
private boolean notesByDefault; | |||||
private boolean commentsByDefault; | |||||
private boolean masterByDefault; | |||||
@SuppressWarnings("WeakerAccess") | |||||
public XSLFPowerPointExtractor(XMLSlideShow slideShow) { | |||||
super(slideShow); | |||||
delegate = new SlideShowExtractor<>(slideShow); | |||||
} | |||||
public XSLFPowerPointExtractor(XSLFSlideShow slideShow) { | |||||
this(new XMLSlideShow(slideShow.getPackage())); | |||||
} | |||||
public XSLFPowerPointExtractor(OPCPackage container) throws XmlException, OpenXML4JException, IOException { | |||||
this(new XSLFSlideShow(container)); | |||||
} | |||||
public static void main(String[] args) throws Exception { | |||||
if (args.length < 1) { | |||||
System.err.println("Use:"); | |||||
System.err.println(" XSLFPowerPointExtractor <filename.pptx>"); | |||||
System.exit(1); | |||||
} | |||||
POIXMLTextExtractor extractor = | |||||
new XSLFPowerPointExtractor( | |||||
new XSLFSlideShow(args[0])); | |||||
System.out.println(extractor.getText()); | |||||
extractor.close(); | |||||
} | |||||
/** | |||||
* Should a call to getText() return slide text? | |||||
* Default is yes | |||||
*/ | |||||
@SuppressWarnings("WeakerAccess") | |||||
public void setSlidesByDefault(final boolean slidesByDefault) { | |||||
this.slidesByDefault = slidesByDefault; | |||||
delegate.setSlidesByDefault(slidesByDefault); | |||||
} | |||||
/** | |||||
* Should a call to getText() return notes text? | |||||
* Default is no | |||||
*/ | |||||
@SuppressWarnings("WeakerAccess") | |||||
public void setNotesByDefault(final boolean notesByDefault) { | |||||
this.notesByDefault = notesByDefault; | |||||
delegate.setNotesByDefault(notesByDefault); | |||||
} | |||||
/** | |||||
* Should a call to getText() return comments text? Default is no | |||||
*/ | |||||
@SuppressWarnings({"WeakerAccess", "unused"}) | |||||
public void setCommentsByDefault(final boolean commentsByDefault) { | |||||
this.commentsByDefault = commentsByDefault; | |||||
delegate.setCommentsByDefault(commentsByDefault); | |||||
} | |||||
/** | |||||
* Should a call to getText() return text from master? Default is no | |||||
*/ | |||||
@SuppressWarnings("WeakerAccess") | |||||
public void setMasterByDefault(final boolean masterByDefault) { | |||||
this.masterByDefault = masterByDefault; | |||||
delegate.setMasterByDefault(masterByDefault); | |||||
} | |||||
/** | |||||
* Gets the slide text, but not the notes text | |||||
*/ | |||||
@Override | |||||
public String getText() { | public String getText() { | ||||
return getText(slidesByDefault, notesByDefault); | |||||
} | |||||
/** | |||||
* Gets the requested text from the file | |||||
* @param slideText Should we retrieve text from slides? | |||||
* @param notesText Should we retrieve text from notes? | |||||
*/ | |||||
public String getText(boolean slideText, boolean notesText) { | |||||
return getText(slideText, notesText, masterByDefault); | |||||
} | |||||
/** | |||||
* Gets the requested text from the file | |||||
* | |||||
* @param slideText Should we retrieve text from slides? | |||||
* @param notesText Should we retrieve text from notes? | |||||
* @param masterText Should we retrieve text from master slides? | |||||
* | |||||
* @return the extracted text | |||||
*/ | |||||
public String getText(boolean slideText, boolean notesText, boolean masterText) { | |||||
StringBuilder text = new StringBuilder(); | |||||
for (XSLFSlide slide : slideshow.getSlides()) { | |||||
text.append(getText(slide, slideText, notesText, masterText)); | |||||
} | |||||
return text.toString(); | |||||
} | |||||
/** | |||||
* Gets the requested text from the slide | |||||
* | |||||
* @param slide the slide to retrieve the text from | |||||
* @param slideText Should we retrieve text from slides? | |||||
* @param notesText Should we retrieve text from notes? | |||||
* @param masterText Should we retrieve text from master slides? | |||||
* | |||||
* @return the extracted text | |||||
*/ | |||||
public static String getText(XSLFSlide slide, boolean slideText, boolean notesText, boolean masterText) { | |||||
StringBuilder text = new StringBuilder(); | |||||
XSLFCommentAuthors commentAuthors = slide.getSlideShow().getCommentAuthors(); | |||||
XSLFNotes notes = slide.getNotes(); | |||||
XSLFComments comments = slide.getComments(); | |||||
XSLFSlideLayout layout = slide.getSlideLayout(); | |||||
XSLFSlideMaster master = layout.getSlideMaster(); | |||||
// TODO Do the slide's name | |||||
// (Stored in docProps/app.xml) | |||||
// Do the slide's text if requested | |||||
if (slideText) { | |||||
extractText(slide, false, text); | |||||
// If requested, get text from the master and it's layout | |||||
if(masterText) { | |||||
assert (layout != null); | |||||
extractText(layout, true, text); | |||||
assert (master != null); | |||||
extractText(master, true, text); | |||||
} | |||||
// If the slide has comments, do those too | |||||
if (comments != null) { | |||||
for (CTComment comment : comments.getCTCommentsList().getCmArray()) { | |||||
// Do the author if we can | |||||
if (commentAuthors != null) { | |||||
CTCommentAuthor author = commentAuthors.getAuthorById(comment.getAuthorId()); | |||||
if(author != null) { | |||||
text.append(author.getName() + ": "); | |||||
} | |||||
} | |||||
// Then the comment text, with a new line afterwards | |||||
text.append(comment.getText()); | |||||
text.append("\n"); | |||||
} | |||||
} | |||||
} | |||||
// Do the notes if requested | |||||
if (notesText && notes != null) { | |||||
extractText(notes, false, text); | |||||
} | |||||
return text.toString(); | |||||
} | |||||
private static void extractText(XSLFShapeContainer data, boolean skipPlaceholders, StringBuilder text) { | |||||
for (XSLFShape s : data) { | |||||
if (s instanceof XSLFShapeContainer) { | |||||
extractText((XSLFShapeContainer)s, skipPlaceholders, text); | |||||
} else if (s instanceof XSLFTextShape) { | |||||
XSLFTextShape ts = (XSLFTextShape)s; | |||||
// Skip non-customised placeholder text | |||||
if (!(skipPlaceholders && ts.isPlaceholder())) { | |||||
text.append(ts.getText()); | |||||
text.append("\n"); | |||||
} | |||||
} else if (s instanceof XSLFTable) { | |||||
XSLFTable ts = (XSLFTable)s; | |||||
// Skip non-customised placeholder text | |||||
for (XSLFTableRow r : ts) { | |||||
for (XSLFTableCell c : r) { | |||||
text.append(c.getText()); | |||||
text.append("\t"); | |||||
} | |||||
text.append("\n"); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
return delegate.getText(); | |||||
} | |||||
/** | |||||
* Gets the requested text from the file | |||||
* | |||||
* @param slideText Should we retrieve text from slides? | |||||
* @param notesText Should we retrieve text from notes? | |||||
*/ | |||||
public String getText(final boolean slideText, final boolean notesText) { | |||||
return getText(slideText, notesText, commentsByDefault, masterByDefault); | |||||
} | |||||
/** | |||||
* Gets the requested text from the file | |||||
* | |||||
* @param slideText Should we retrieve text from slides? | |||||
* @param notesText Should we retrieve text from notes? | |||||
* @param masterText Should we retrieve text from master slides? | |||||
* @return the extracted text | |||||
*/ | |||||
public String getText(boolean slideText, boolean notesText, boolean masterText) { | |||||
return getText(slideText, notesText, commentsByDefault, masterText); | |||||
} | |||||
/** | |||||
* Gets the requested text from the file | |||||
* | |||||
* @param slideText Should we retrieve text from slides? | |||||
* @param notesText Should we retrieve text from notes? | |||||
* @param commentText Should we retrieve text from comments? | |||||
* @param masterText Should we retrieve text from master slides? | |||||
* @return the extracted text | |||||
*/ | |||||
@SuppressWarnings("Duplicates") | |||||
public String getText(boolean slideText, boolean notesText, boolean commentText, boolean masterText) { | |||||
delegate.setSlidesByDefault(slideText); | |||||
delegate.setNotesByDefault(notesText); | |||||
delegate.setCommentsByDefault(commentText); | |||||
delegate.setMasterByDefault(masterText); | |||||
try { | |||||
return delegate.getText(); | |||||
} finally { | |||||
delegate.setSlidesByDefault(slidesByDefault); | |||||
delegate.setNotesByDefault(notesByDefault); | |||||
delegate.setCommentsByDefault(commentsByDefault); | |||||
delegate.setMasterByDefault(masterByDefault); | |||||
} | |||||
} | |||||
/** | |||||
* Gets the requested text from the slide | |||||
* | |||||
* @param slide the slide to retrieve the text from | |||||
* @param slideText Should we retrieve text from slides? | |||||
* @param notesText Should we retrieve text from notes? | |||||
* @param masterText Should we retrieve text from master slides? | |||||
* @return the extracted text | |||||
*/ | |||||
public static String getText(XSLFSlide slide, boolean slideText, boolean notesText, boolean masterText) { | |||||
return getText(slide, slideText, notesText, false, masterText); | |||||
} | |||||
/** | |||||
* Gets the requested text from the slide | |||||
* | |||||
* @param slide the slide to retrieve the text from | |||||
* @param slideText Should we retrieve text from slides? | |||||
* @param notesText Should we retrieve text from notes? | |||||
* @param commentText Should we retrieve text from comments? | |||||
* @param masterText Should we retrieve text from master slides? | |||||
* @return the extracted text | |||||
*/ | |||||
public static String getText(XSLFSlide slide, boolean slideText, boolean notesText, boolean commentText, boolean masterText) { | |||||
final SlideShowExtractor<XSLFShape, XSLFTextParagraph> ex = new SlideShowExtractor<>(slide.getSlideShow()); | |||||
ex.setSlidesByDefault(slideText); | |||||
ex.setNotesByDefault(notesText); | |||||
ex.setCommentsByDefault(commentText); | |||||
ex.setMasterByDefault(masterText); | |||||
return ex.getText(slide); | |||||
} | |||||
} | } |
import org.apache.poi.POIXMLDocument; | import org.apache.poi.POIXMLDocument; | ||||
import org.apache.poi.POIXMLDocumentPart; | import org.apache.poi.POIXMLDocumentPart; | ||||
import org.apache.poi.POIXMLException; | import org.apache.poi.POIXMLException; | ||||
import org.apache.poi.POIXMLPropertiesTextExtractor; | |||||
import org.apache.poi.openxml4j.exceptions.OpenXML4JException; | import org.apache.poi.openxml4j.exceptions.OpenXML4JException; | ||||
import org.apache.poi.openxml4j.opc.OPCPackage; | import org.apache.poi.openxml4j.opc.OPCPackage; | ||||
import org.apache.poi.openxml4j.opc.PackagePart; | import org.apache.poi.openxml4j.opc.PackagePart; | ||||
import org.apache.poi.openxml4j.opc.PackageRelationship; | |||||
import org.apache.poi.sl.usermodel.MasterSheet; | import org.apache.poi.sl.usermodel.MasterSheet; | ||||
import org.apache.poi.sl.usermodel.PictureData.PictureType; | import org.apache.poi.sl.usermodel.PictureData.PictureType; | ||||
import org.apache.poi.sl.usermodel.Resources; | import org.apache.poi.sl.usermodel.Resources; | ||||
// TODO: implement! | // TODO: implement! | ||||
throw new UnsupportedOperationException(); | throw new UnsupportedOperationException(); | ||||
} | } | ||||
@Override | |||||
public POIXMLPropertiesTextExtractor getMetadataTextExtractor() { | |||||
return new POIXMLPropertiesTextExtractor(this); | |||||
} | |||||
} | } |
/* ==================================================================== | |||||
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.xslf.usermodel; | |||||
import java.awt.geom.Point2D; | |||||
import java.util.Calendar; | |||||
import java.util.Date; | |||||
import org.apache.poi.sl.usermodel.Comment; | |||||
import org.apache.poi.util.LocaleUtil; | |||||
import org.apache.poi.util.Units; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D; | |||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTComment; | |||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTCommentAuthor; | |||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTCommentAuthorList; | |||||
/** | |||||
* XSLF Comment | |||||
* | |||||
* @since POI 4.0.0 | |||||
*/ | |||||
public class XSLFComment implements Comment { | |||||
final CTComment comment; | |||||
final XSLFCommentAuthors authors; | |||||
XSLFComment(final CTComment comment, final XSLFCommentAuthors authors) { | |||||
this.comment = comment; | |||||
this.authors = authors; | |||||
} | |||||
@Override | |||||
public String getAuthor() { | |||||
return authors.getAuthorById(comment.getAuthorId()).getName(); | |||||
} | |||||
@Override | |||||
public void setAuthor(final String author) { | |||||
if (author == null) { | |||||
throw new IllegalArgumentException("author must not be null"); | |||||
} | |||||
final CTCommentAuthorList list = authors.getCTCommentAuthorsList(); | |||||
long maxId = -1; | |||||
for (final CTCommentAuthor aut : list.getCmAuthorArray()) { | |||||
maxId = Math.max(aut.getId(), maxId); | |||||
if (author.equals(aut.getName())) { | |||||
comment.setAuthorId(aut.getId()); | |||||
return; | |||||
} | |||||
} | |||||
// author not found -> add new author | |||||
final CTCommentAuthor newAuthor = list.addNewCmAuthor(); | |||||
newAuthor.setName(author); | |||||
newAuthor.setId(maxId+1); | |||||
newAuthor.setInitials(author.replaceAll( "\\s*(\\w)\\S*", "$1").toUpperCase(LocaleUtil.getUserLocale())); | |||||
comment.setAuthorId(maxId+1); | |||||
} | |||||
@Override | |||||
public String getAuthorInitials() { | |||||
final CTCommentAuthor aut = authors.getAuthorById(comment.getAuthorId()); | |||||
return aut == null ? null : aut.getInitials(); | |||||
} | |||||
@Override | |||||
public void setAuthorInitials(final String initials) { | |||||
final CTCommentAuthor aut = authors.getAuthorById(comment.getAuthorId()); | |||||
if (aut != null) { | |||||
aut.setInitials(initials); | |||||
} | |||||
} | |||||
@Override | |||||
public String getText() { | |||||
return comment.getText(); | |||||
} | |||||
@Override | |||||
public void setText(final String text) { | |||||
comment.setText(text); | |||||
} | |||||
@Override | |||||
public Date getDate() { | |||||
final Calendar cal = comment.getDt(); | |||||
return (cal == null) ? null : cal.getTime(); | |||||
} | |||||
@Override | |||||
public void setDate(final Date date) { | |||||
final Calendar cal = LocaleUtil.getLocaleCalendar(); | |||||
cal.setTime(date); | |||||
comment.setDt(cal); | |||||
} | |||||
@Override | |||||
public Point2D getOffset() { | |||||
final CTPoint2D pos = comment.getPos(); | |||||
return new Point2D.Double(Units.toPoints(pos.getX()), Units.toPoints(pos.getY())); | |||||
} | |||||
@Override | |||||
public void setOffset(final Point2D offset) { | |||||
CTPoint2D pos = comment.getPos(); | |||||
if (pos == null) { | |||||
pos = comment.addNewPos(); | |||||
} | |||||
pos.setX(Units.toEMU(offset.getX())); | |||||
pos.setY(Units.toEMU(offset.getY())); | |||||
} | |||||
} |
@Beta | @Beta | ||||
public class XSLFComments extends POIXMLDocumentPart { | public class XSLFComments extends POIXMLDocumentPart { | ||||
private final CTCommentList _comments; | |||||
private final CmLstDocument doc; | |||||
/** | /** | ||||
* Create a new set of slide comments | * Create a new set of slide comments | ||||
*/ | */ | ||||
XSLFComments() { | XSLFComments() { | ||||
super(); | |||||
CmLstDocument doc = CmLstDocument.Factory.newInstance(); | |||||
_comments = doc.addNewCmLst(); | |||||
doc = CmLstDocument.Factory.newInstance(); | |||||
} | } | ||||
/** | /** | ||||
* Construct a SpreadsheetML slide comments from a package part | * Construct a SpreadsheetML slide comments from a package part | ||||
* | * | ||||
* @param part the package part holding the comments data, | * @param part the package part holding the comments data, | ||||
* the content type must be <code>application/vnd.openxmlformats-officedocument.comments+xml</code> | |||||
* | |||||
* the content type must be <code>application/vnd.openxmlformats-officedocument.comments+xml</code> | |||||
* @since POI 3.14-Beta1 | * @since POI 3.14-Beta1 | ||||
*/ | */ | ||||
XSLFComments(PackagePart part) throws IOException, XmlException { | XSLFComments(PackagePart part) throws IOException, XmlException { | ||||
super(part); | super(part); | ||||
CmLstDocument doc = | |||||
CmLstDocument.Factory.parse(getPackagePart().getInputStream(), DEFAULT_XML_OPTIONS); | |||||
_comments = doc.getCmLst(); | |||||
doc = CmLstDocument.Factory.parse(getPackagePart().getInputStream(), DEFAULT_XML_OPTIONS); | |||||
} | } | ||||
public CTCommentList getCTCommentsList() { | public CTCommentList getCTCommentsList() { | ||||
return _comments; | |||||
return doc.getCmLst(); | |||||
} | } | ||||
public int getNumberOfComments() { | public int getNumberOfComments() { | ||||
return _comments.sizeOfCmArray(); | |||||
return doc.getCmLst().sizeOfCmArray(); | |||||
} | } | ||||
public CTComment getCommentAt(int pos) { | public CTComment getCommentAt(int pos) { | ||||
return _comments.getCmArray(pos); | |||||
return doc.getCmLst().getCmArray(pos); | |||||
} | } | ||||
} | } |
public class XSLFNotesMaster extends XSLFSheet | public class XSLFNotesMaster extends XSLFSheet | ||||
implements MasterSheet<XSLFShape,XSLFTextParagraph> { | implements MasterSheet<XSLFShape,XSLFTextParagraph> { | ||||
private CTNotesMaster _slide; | private CTNotesMaster _slide; | ||||
private XSLFTheme _theme; | |||||
XSLFNotesMaster() { | XSLFNotesMaster() { | ||||
super(); | super(); | ||||
public MasterSheet<XSLFShape,XSLFTextParagraph> getMasterSheet() { | public MasterSheet<XSLFShape,XSLFTextParagraph> getMasterSheet() { | ||||
return null; | return null; | ||||
} | } | ||||
@Override | @Override | ||||
public XSLFTheme getTheme() { | |||||
if (_theme == null) { | |||||
for (POIXMLDocumentPart p : getRelations()) { | |||||
if (p instanceof XSLFTheme) { | |||||
_theme = (XSLFTheme) p; | |||||
CTColorMapping cmap = _slide.getClrMap(); | |||||
if (cmap != null) { | |||||
_theme.initColorMap(cmap); | |||||
} | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
return _theme; | |||||
} | |||||
boolean isSupportTheme() { | |||||
return true; | |||||
} | |||||
@Override | |||||
CTColorMapping getColorMapping() { | |||||
return _slide.getClrMap(); | |||||
} | |||||
} | } |
package org.apache.poi.xslf.usermodel; | |||||
import static org.apache.poi.xslf.usermodel.XSLFShape.PML_NS; | |||||
import java.util.function.Consumer; | |||||
import java.util.function.Function; | |||||
import org.apache.poi.sl.usermodel.MasterSheet; | |||||
import org.apache.poi.sl.usermodel.Placeholder; | |||||
import org.apache.poi.sl.usermodel.PlaceholderDetails; | |||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTApplicationNonVisualDrawingProps; | |||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTHeaderFooter; | |||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTNotesMaster; | |||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; | |||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMaster; | |||||
import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderSize; | |||||
import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType; | |||||
/** | |||||
* XSLF Placeholder Details | |||||
* | |||||
* @since POI 4.0.0 | |||||
*/ | |||||
public class XSLFPlaceholderDetails implements PlaceholderDetails { | |||||
private final XSLFShape shape; | |||||
private CTPlaceholder _ph; | |||||
XSLFPlaceholderDetails(final XSLFShape shape) { | |||||
this.shape = shape; | |||||
} | |||||
@Override | |||||
public Placeholder getPlaceholder() { | |||||
final CTPlaceholder ph = getCTPlaceholder(false); | |||||
if (ph == null || !(ph.isSetType() || ph.isSetIdx())) { | |||||
return null; | |||||
} | |||||
return Placeholder.lookupOoxml(ph.getType().intValue()); | |||||
} | |||||
@Override | |||||
public void setPlaceholder(final Placeholder placeholder) { | |||||
CTPlaceholder ph = getCTPlaceholder(placeholder != null); | |||||
if (ph != null) { | |||||
if (placeholder != null) { | |||||
ph.setType(STPlaceholderType.Enum.forInt(placeholder.ooxmlId)); | |||||
} else { | |||||
getNvProps().unsetPh(); | |||||
} | |||||
} | |||||
} | |||||
@Override | |||||
public boolean isVisible() { | |||||
final CTPlaceholder ph = getCTPlaceholder(false); | |||||
if (ph == null || !ph.isSetType()) { | |||||
return true; | |||||
} | |||||
final CTHeaderFooter hf = getHeaderFooter(false); | |||||
if (hf == null) { | |||||
return false; | |||||
} | |||||
final Placeholder pl = Placeholder.lookupOoxml(ph.getType().intValue()); | |||||
if (pl == null) { | |||||
return true; | |||||
} | |||||
switch (pl) { | |||||
case DATETIME: | |||||
return !hf.isSetDt() || hf.getDt(); | |||||
case FOOTER: | |||||
return !hf.isSetFtr() || hf.getFtr(); | |||||
case HEADER: | |||||
return !hf.isSetHdr() || hf.getHdr(); | |||||
case SLIDE_NUMBER: | |||||
return !hf.isSetSldNum() || hf.getSldNum(); | |||||
default: | |||||
return true; | |||||
} | |||||
} | |||||
@Override | |||||
public void setVisible(final boolean isVisible) { | |||||
final Placeholder ph = getPlaceholder(); | |||||
if (ph == null) { | |||||
return; | |||||
} | |||||
final Function<CTHeaderFooter,Consumer<Boolean>> fun; | |||||
switch (ph) { | |||||
case DATETIME: | |||||
fun = (hf) -> hf::setDt; | |||||
break; | |||||
case FOOTER: | |||||
fun = (hf) -> hf::setFtr; | |||||
break; | |||||
case HEADER: | |||||
fun = (hf) -> hf::setHdr; | |||||
break; | |||||
case SLIDE_NUMBER: | |||||
fun = (hf) -> hf::setSldNum; | |||||
break; | |||||
default: | |||||
return; | |||||
} | |||||
// only create a header, if we need to, i.e. the placeholder type is eligible | |||||
final CTHeaderFooter hf = getHeaderFooter(true); | |||||
if (hf == null) { | |||||
return; | |||||
} | |||||
fun.apply(hf).accept(isVisible); | |||||
} | |||||
@Override | |||||
public PlaceholderSize getSize() { | |||||
final CTPlaceholder ph = getCTPlaceholder(false); | |||||
if (ph == null || !ph.isSetSz()) { | |||||
return null; | |||||
} | |||||
switch (ph.getSz().intValue()) { | |||||
case STPlaceholderSize.INT_FULL: | |||||
return PlaceholderSize.full; | |||||
case STPlaceholderSize.INT_HALF: | |||||
return PlaceholderSize.half; | |||||
case STPlaceholderSize.INT_QUARTER: | |||||
return PlaceholderSize.quarter; | |||||
default: | |||||
return null; | |||||
} | |||||
} | |||||
@Override | |||||
public void setSize(final PlaceholderSize size) { | |||||
final CTPlaceholder ph = getCTPlaceholder(false); | |||||
if (ph == null) { | |||||
return; | |||||
} | |||||
if (size == null) { | |||||
ph.unsetSz(); | |||||
return; | |||||
} | |||||
switch (size) { | |||||
case full: | |||||
ph.setSz(STPlaceholderSize.FULL); | |||||
break; | |||||
case half: | |||||
ph.setSz(STPlaceholderSize.HALF); | |||||
break; | |||||
case quarter: | |||||
ph.setSz(STPlaceholderSize.QUARTER); | |||||
break; | |||||
} | |||||
} | |||||
/** | |||||
* Gets or creates a new placeholder element | |||||
* | |||||
* @param create if {@code true} creates the element if it hasn't existed before | |||||
* @return the placeholder or {@code null} if the shape doesn't support placeholders | |||||
*/ | |||||
CTPlaceholder getCTPlaceholder(final boolean create) { | |||||
if (_ph != null) { | |||||
return _ph; | |||||
} | |||||
final CTApplicationNonVisualDrawingProps nv = getNvProps(); | |||||
if (nv == null) { | |||||
// shape doesn't support CTApplicationNonVisualDrawingProps | |||||
return null; | |||||
} | |||||
_ph = (nv.isSetPh() || !create) ? nv.getPh() : nv.addNewPh(); | |||||
return _ph; | |||||
} | |||||
private CTApplicationNonVisualDrawingProps getNvProps() { | |||||
final String xquery = "declare namespace p='" + PML_NS + "' .//*/p:nvPr"; | |||||
return shape.selectProperty(CTApplicationNonVisualDrawingProps.class, xquery); | |||||
} | |||||
private CTHeaderFooter getHeaderFooter(final boolean create) { | |||||
final XSLFSheet sheet = shape.getSheet(); | |||||
final XSLFSheet master = (sheet instanceof MasterSheet && !(sheet instanceof XSLFSlideLayout)) ? sheet : (XSLFSheet)sheet.getMasterSheet(); | |||||
if (master instanceof XSLFSlideMaster) { | |||||
final CTSlideMaster ct = ((XSLFSlideMaster) master).getXmlObject(); | |||||
return (ct.isSetHf() || !create) ? ct.getHf() : ct.addNewHf(); | |||||
} else if (master instanceof XSLFNotesMaster) { | |||||
final CTNotesMaster ct = ((XSLFNotesMaster) master).getXmlObject(); | |||||
return (ct.isSetHf() || !create) ? ct.getHf() : ct.addNewHf(); | |||||
} else { | |||||
return null; | |||||
} | |||||
} | |||||
@Override | |||||
public String getText() { | |||||
return null; | |||||
} | |||||
@Override | |||||
public void setText(String text) { | |||||
} | |||||
} |
import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint; | import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint; | ||||
import org.apache.poi.sl.usermodel.PlaceableShape; | import org.apache.poi.sl.usermodel.PlaceableShape; | ||||
import org.apache.poi.sl.usermodel.Placeholder; | import org.apache.poi.sl.usermodel.Placeholder; | ||||
import org.apache.poi.sl.usermodel.PlaceholderDetails; | |||||
import org.apache.poi.sl.usermodel.Shape; | import org.apache.poi.sl.usermodel.Shape; | ||||
import org.apache.poi.sl.usermodel.SimpleShape; | |||||
import org.apache.poi.util.Beta; | import org.apache.poi.util.Beta; | ||||
import org.apache.poi.util.Internal; | import org.apache.poi.util.Internal; | ||||
import org.apache.poi.xslf.model.PropertyFetcher; | import org.apache.poi.xslf.model.PropertyFetcher; | ||||
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.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; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; | import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; | ||||
*/ | */ | ||||
@Beta | @Beta | ||||
public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> { | public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> { | ||||
protected static final String PML_NS = "http://schemas.openxmlformats.org/presentationml/2006/main"; | |||||
static final String PML_NS = "http://schemas.openxmlformats.org/presentationml/2006/main"; | |||||
private final XmlObject _shape; | private final XmlObject _shape; | ||||
private final XSLFSheet _sheet; | private final XSLFSheet _sheet; | ||||
private CTShapeStyle _spStyle; | private CTShapeStyle _spStyle; | ||||
private CTNonVisualDrawingProps _nvPr; | private CTNonVisualDrawingProps _nvPr; | ||||
private CTPlaceholder _ph; | |||||
protected XSLFShape(XmlObject shape, XSLFSheet sheet) { | protected XSLFShape(XmlObject shape, XSLFSheet sheet) { | ||||
_shape = shape; | _shape = shape; | ||||
cur.dispose(); | cur.dispose(); | ||||
return child; | return child; | ||||
} | } | ||||
protected CTPlaceholder getCTPlaceholder() { | |||||
if (_ph == null) { | |||||
String xquery = "declare namespace p='"+PML_NS+"' .//*/p:nvPr/p:ph"; | |||||
_ph = selectProperty(CTPlaceholder.class, xquery); | |||||
} | |||||
return _ph; | |||||
public boolean isPlaceholder() { | |||||
return getPlaceholderDetails().getCTPlaceholder(false) != null; | |||||
} | } | ||||
/** | |||||
* @see PlaceholderDetails#getPlaceholder() | |||||
*/ | |||||
public Placeholder getPlaceholder() { | public Placeholder getPlaceholder() { | ||||
CTPlaceholder ph = getCTPlaceholder(); | |||||
if (ph == null || !(ph.isSetType() || ph.isSetIdx())) { | |||||
return null; | |||||
} | |||||
return Placeholder.lookupOoxml(ph.getType().intValue()); | |||||
return getPlaceholderDetails().getPlaceholder(); | |||||
} | } | ||||
/** | /** | ||||
* Specifies that the corresponding shape should be represented by the generating application | |||||
* as a placeholder. When a shape is considered a placeholder by the generating application | |||||
* it can have special properties to alert the user that they may enter content into the shape. | |||||
* Different types of placeholders are allowed and can be specified by using the placeholder | |||||
* type attribute for this element | |||||
* | |||||
* @param placeholder The shape to use as placeholder or null if no placeholder should be set. | |||||
* @see PlaceholderDetails#setPlaceholder(Placeholder) | |||||
*/ | */ | ||||
protected void setPlaceholder(Placeholder placeholder) { | |||||
String xquery = "declare namespace p='"+PML_NS+"' .//*/p:nvPr"; | |||||
CTApplicationNonVisualDrawingProps nv = selectProperty(CTApplicationNonVisualDrawingProps.class, xquery); | |||||
if (nv == null) return; | |||||
if(placeholder == null) { | |||||
if (nv.isSetPh()) nv.unsetPh(); | |||||
_ph = null; | |||||
} else { | |||||
nv.addNewPh().setType(STPlaceholderType.Enum.forInt(placeholder.ooxmlId)); | |||||
} | |||||
public void setPlaceholder(final Placeholder placeholder) { | |||||
getPlaceholderDetails().setPlaceholder(placeholder); | |||||
} | } | ||||
/** | |||||
* @see SimpleShape#getPlaceholderDetails() | |||||
*/ | |||||
public XSLFPlaceholderDetails getPlaceholderDetails() { | |||||
return new XSLFPlaceholderDetails(this); | |||||
} | |||||
/** | /** | ||||
* As there's no xmlbeans hierarchy, but XSLF works with subclassing, not all | * As there's no xmlbeans hierarchy, but XSLF works with subclassing, not all | ||||
* child classes work with a {@link CTShape} object, but often contain the same | * child classes work with a {@link CTShape} object, but often contain the same | ||||
return true; | return true; | ||||
} | } | ||||
CTPlaceholder ph = getCTPlaceholder(); | |||||
final CTPlaceholder ph = getPlaceholderDetails().getCTPlaceholder(false); | |||||
if (ph == null) { | if (ph == null) { | ||||
return false; | return false; | ||||
} | } |
import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS; | import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS; | ||||
import javax.xml.namespace.QName; | |||||
import java.awt.Dimension; | import java.awt.Dimension; | ||||
import java.awt.Graphics2D; | import java.awt.Graphics2D; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.util.Iterator; | import java.util.Iterator; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
import javax.xml.namespace.QName; | |||||
import java.util.Optional; | |||||
import org.apache.poi.POIXMLDocumentPart; | import org.apache.poi.POIXMLDocumentPart; | ||||
import org.apache.poi.POIXMLException; | import org.apache.poi.POIXMLException; | ||||
import org.apache.xmlbeans.XmlObject; | import org.apache.xmlbeans.XmlObject; | ||||
import org.apache.xmlbeans.XmlOptions; | import org.apache.xmlbeans.XmlOptions; | ||||
import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl; | import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTColorMapping; | |||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTConnector; | import org.openxmlformats.schemas.presentationml.x2006.main.CTConnector; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame; | import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape; | import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape; | ||||
private XSLFDrawing _drawing; | private XSLFDrawing _drawing; | ||||
private List<XSLFShape> _shapes; | private List<XSLFShape> _shapes; | ||||
private CTGroupShape _spTree; | private CTGroupShape _spTree; | ||||
private XSLFTheme _theme; | |||||
private List<XSLFTextShape>_placeholders; | private List<XSLFTextShape>_placeholders; | ||||
private Map<Integer, XSLFSimpleShape> _placeholderByIdMap; | private Map<Integer, XSLFSimpleShape> _placeholderByIdMap; | ||||
* Sheets that support the notion of themes (slides, masters, layouts, etc.) should override this | * Sheets that support the notion of themes (slides, masters, layouts, etc.) should override this | ||||
* method and return the corresponding package part. | * method and return the corresponding package part. | ||||
*/ | */ | ||||
XSLFTheme getTheme(){ | |||||
public XSLFTheme getTheme() { | |||||
if (_theme != null || !isSupportTheme()) { | |||||
return _theme; | |||||
} | |||||
final Optional<XSLFTheme> t = | |||||
getRelations().stream().filter((p) -> p instanceof XSLFTheme).map((p) -> (XSLFTheme) p).findAny(); | |||||
if (t.isPresent()) { | |||||
_theme = t.get(); | |||||
final CTColorMapping cmap = getColorMapping(); | |||||
if (cmap != null) { | |||||
_theme.initColorMap(cmap); | |||||
} | |||||
} | |||||
return _theme; | |||||
} | |||||
/** | |||||
* @return {@code true} if this class supports themes | |||||
*/ | |||||
boolean isSupportTheme() { | |||||
return false; | |||||
} | |||||
/** | |||||
* @return the color mapping for this slide type | |||||
*/ | |||||
CTColorMapping getColorMapping() { | |||||
return null; | return null; | ||||
} | } | ||||
return shape; | return shape; | ||||
} | } | ||||
void initPlaceholders() { | |||||
private void initPlaceholders() { | |||||
if(_placeholders == null) { | if(_placeholders == null) { | ||||
_placeholders = new ArrayList<>(); | _placeholders = new ArrayList<>(); | ||||
_placeholderByIdMap = new HashMap<>(); | _placeholderByIdMap = new HashMap<>(); | ||||
_placeholderByTypeMap = new HashMap<>(); | _placeholderByTypeMap = new HashMap<>(); | ||||
for(XSLFShape sh : getShapes()){ | |||||
for(final XSLFShape sh : getShapes()){ | |||||
if(sh instanceof XSLFTextShape){ | if(sh instanceof XSLFTextShape){ | ||||
XSLFTextShape sShape = (XSLFTextShape)sh; | |||||
CTPlaceholder ph = sShape.getCTPlaceholder(); | |||||
final XSLFTextShape sShape = (XSLFTextShape)sh; | |||||
final CTPlaceholder ph = sShape.getPlaceholderDetails().getCTPlaceholder(false); | |||||
if(ph != null) { | if(ph != null) { | ||||
_placeholders.add(sShape); | _placeholders.add(sShape); | ||||
if(ph.isSetIdx()) { | if(ph.isSetIdx()) { | ||||
} | } | ||||
} | } | ||||
XSLFSimpleShape getPlaceholderById(int id) { | |||||
private XSLFSimpleShape getPlaceholderById(int id) { | |||||
initPlaceholders(); | initPlaceholders(); | ||||
return _placeholderByIdMap.get(id); | return _placeholderByIdMap.get(id); | ||||
} | } | ||||
/** | /** | ||||
* Render this sheet into the supplied graphics object | * Render this sheet into the supplied graphics object | ||||
* | * | ||||
* @param graphics | |||||
* @param graphics the graphics context to draw to | |||||
*/ | */ | ||||
@Override | @Override | ||||
public void draw(Graphics2D graphics){ | public void draw(Graphics2D graphics){ | ||||
void removePictureRelation(XSLFPictureShape pictureShape) { | void removePictureRelation(XSLFPictureShape pictureShape) { | ||||
removeRelation(pictureShape.getBlipId()); | removeRelation(pictureShape.getBlipId()); | ||||
} | } | ||||
@Override | |||||
public XSLFPlaceholderDetails getPlaceholderDetails(Placeholder placeholder) { | |||||
final XSLFSimpleShape ph = getPlaceholder(placeholder); | |||||
return (ph == null) ? null : new XSLFPlaceholderDetails(ph); | |||||
} | |||||
} | } |
import org.apache.poi.sl.usermodel.LineDecoration.DecorationSize; | import org.apache.poi.sl.usermodel.LineDecoration.DecorationSize; | ||||
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.ShapeType; | import org.apache.poi.sl.usermodel.ShapeType; | ||||
import org.apache.poi.sl.usermodel.SimpleShape; | import org.apache.poi.sl.usermodel.SimpleShape; | ||||
import org.apache.poi.sl.usermodel.StrokeStyle; | import org.apache.poi.sl.usermodel.StrokeStyle; | ||||
return ds; | return ds; | ||||
} | } | ||||
public boolean isPlaceholder() { | |||||
CTPlaceholder ph = getCTPlaceholder(); | |||||
return ph != null; | |||||
} | |||||
@Override | @Override | ||||
public Guide getAdjustValue(String name) { | public Guide getAdjustValue(String name) { | ||||
XSLFGeometryProperties gp = XSLFPropertiesDelegate.getGeometryDelegate(getShapeProperties()); | XSLFGeometryProperties gp = XSLFPropertiesDelegate.getGeometryDelegate(getShapeProperties()); | ||||
} | } | ||||
} | } | ||||
@Override | |||||
public void setPlaceholder(Placeholder placeholder) { | |||||
super.setPlaceholder(placeholder); | |||||
} | |||||
@Override | @Override | ||||
public XSLFHyperlink getHyperlink() { | public XSLFHyperlink getHyperlink() { | ||||
CTNonVisualDrawingProps cNvPr = getCNvPr(); | CTNonVisualDrawingProps cNvPr = getCNvPr(); |
import java.awt.Graphics2D; | import java.awt.Graphics2D; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
import org.apache.poi.POIXMLDocumentPart; | import org.apache.poi.POIXMLDocumentPart; | ||||
import org.apache.poi.openxml4j.opc.PackagePart; | import org.apache.poi.openxml4j.opc.PackagePart; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D; | import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D; | import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTBackground; | import org.openxmlformats.schemas.presentationml.x2006.main.CTBackground; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTComment; | |||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTCommonSlideData; | import org.openxmlformats.schemas.presentationml.x2006.main.CTCommonSlideData; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape; | import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShapeNonVisual; | import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShapeNonVisual; | ||||
private final CTSlide _slide; | private final CTSlide _slide; | ||||
private XSLFSlideLayout _layout; | private XSLFSlideLayout _layout; | ||||
private XSLFComments _comments; | private XSLFComments _comments; | ||||
private XSLFCommentAuthors _commentAuthors; | |||||
private XSLFNotes _notes; | private XSLFNotes _notes; | ||||
/** | /** | ||||
return getSlideLayout().getSlideMaster(); | return getSlideLayout().getSlideMaster(); | ||||
} | } | ||||
public XSLFComments getComments() { | |||||
/** | |||||
* @return the comments part or {@code null} if there weren't any comments | |||||
* @since POI 4.0.0 | |||||
*/ | |||||
public XSLFComments getCommentsPart() { | |||||
if(_comments == null) { | if(_comments == null) { | ||||
for (POIXMLDocumentPart p : getRelations()) { | for (POIXMLDocumentPart p : getRelations()) { | ||||
if (p instanceof XSLFComments) { | if (p instanceof XSLFComments) { | ||||
_comments = (XSLFComments)p; | _comments = (XSLFComments)p; | ||||
break; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
if(_comments == null) { | |||||
// This slide lacks comments | |||||
// Not all have them, sorry... | |||||
return null; | |||||
} | |||||
return _comments; | return _comments; | ||||
} | } | ||||
/** | |||||
* @return the comment authors part or {@code null} if there weren't any comments | |||||
* @since POI 4.0.0 | |||||
*/ | |||||
public XSLFCommentAuthors getCommentAuthorsPart() { | |||||
if(_commentAuthors == null) { | |||||
for (POIXMLDocumentPart p : getRelations()) { | |||||
if (p instanceof XSLFCommentAuthors) { | |||||
_commentAuthors = (XSLFCommentAuthors)p; | |||||
return _commentAuthors; | |||||
} | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
@Override | |||||
public List<XSLFComment> getComments() { | |||||
final List<XSLFComment> comments = new ArrayList<>(); | |||||
final XSLFComments xComments = getCommentsPart(); | |||||
final XSLFCommentAuthors xAuthors = getCommentAuthorsPart(); | |||||
if (xComments != null) { | |||||
for (final CTComment xc : xComments.getCTCommentsList().getCmArray()) { | |||||
comments.add(new XSLFComment(xc, xAuthors)); | |||||
} | |||||
} | |||||
return comments; | |||||
} | |||||
@Override | @Override | ||||
public XSLFNotes getNotes() { | public XSLFNotes getNotes() { | ||||
if(_notes == null) { | if(_notes == null) { |
import org.apache.poi.util.Internal; | import org.apache.poi.util.Internal; | ||||
import org.apache.xmlbeans.XmlException; | import org.apache.xmlbeans.XmlException; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTBackground; | import org.openxmlformats.schemas.presentationml.x2006.main.CTBackground; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; | |||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideLayout; | import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideLayout; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.SldLayoutDocument; | import org.openxmlformats.schemas.presentationml.x2006.main.SldLayoutDocument; | ||||
@Beta | @Beta | ||||
public class XSLFSlideLayout extends XSLFSheet | public class XSLFSlideLayout extends XSLFSheet | ||||
implements MasterSheet<XSLFShape,XSLFTextParagraph> { | implements MasterSheet<XSLFShape,XSLFTextParagraph> { | ||||
private CTSlideLayout _layout; | |||||
private final CTSlideLayout _layout; | |||||
private XSLFSlideMaster _master; | private XSLFSlideMaster _master; | ||||
XSLFSlideLayout() { | |||||
super(); | |||||
_layout = CTSlideLayout.Factory.newInstance(); | |||||
} | |||||
/** | /** | ||||
* @since POI 3.14-Beta1 | * @since POI 3.14-Beta1 | ||||
*/ | */ | ||||
*/ | */ | ||||
@Override | @Override | ||||
protected boolean canDraw(XSLFShape shape) { | protected boolean canDraw(XSLFShape shape) { | ||||
if (shape instanceof XSLFSimpleShape) { | |||||
XSLFSimpleShape txt = (XSLFSimpleShape) shape; | |||||
CTPlaceholder ph = txt.getCTPlaceholder(); | |||||
if (ph != null) { | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
return !(shape instanceof XSLFSimpleShape) || !shape.isPlaceholder(); | |||||
} | } | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTColorMapping; | import org.openxmlformats.schemas.drawingml.x2006.main.CTColorMapping; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextListStyle; | import org.openxmlformats.schemas.drawingml.x2006.main.CTTextListStyle; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTBackground; | import org.openxmlformats.schemas.presentationml.x2006.main.CTBackground; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; | |||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMaster; | import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMaster; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMasterTextStyles; | import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMasterTextStyles; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.SldMasterDocument; | import org.openxmlformats.schemas.presentationml.x2006.main.SldMasterDocument; | ||||
* Within a slide master slide are contained all elements | * Within a slide master slide are contained all elements | ||||
* that describe the objects and their corresponding formatting | * that describe the objects and their corresponding formatting | ||||
* for within a presentation slide. | * for within a presentation slide. | ||||
* </p> | |||||
* <p> | * <p> | ||||
* Within a slide master slide are two main elements. | * Within a slide master slide are two main elements. | ||||
* The cSld element specifies the common slide elements such as shapes and | * The cSld element specifies the common slide elements such as shapes and | ||||
* within a slide master slide specify other properties for within a presentation slide | * within a slide master slide specify other properties for within a presentation slide | ||||
* such as color information, headers and footers, as well as timing and | * such as color information, headers and footers, as well as timing and | ||||
* transition information for all corresponding presentation slides. | * transition information for all corresponding presentation slides. | ||||
* </p> | |||||
* | |||||
* @author Yegor Kozlov | |||||
*/ | */ | ||||
@Beta | @Beta | ||||
public class XSLFSlideMaster extends XSLFSheet | public class XSLFSlideMaster extends XSLFSheet | ||||
implements MasterSheet<XSLFShape,XSLFTextParagraph> { | implements MasterSheet<XSLFShape,XSLFTextParagraph> { | ||||
private CTSlideMaster _slide; | private CTSlideMaster _slide; | ||||
private Map<String, XSLFSlideLayout> _layouts; | private Map<String, XSLFSlideLayout> _layouts; | ||||
private XSLFTheme _theme; | |||||
XSLFSlideMaster() { | |||||
super(); | |||||
_slide = CTSlideMaster.Factory.newInstance(); | |||||
} | |||||
/** | /** | ||||
* @since POI 3.14-Beta1 | * @since POI 3.14-Beta1 | ||||
} | } | ||||
@Override | |||||
public XSLFTheme getTheme(){ | |||||
if(_theme == null){ | |||||
for (POIXMLDocumentPart p : getRelations()) { | |||||
if (p instanceof XSLFTheme){ | |||||
_theme = (XSLFTheme)p; | |||||
CTColorMapping cmap = _slide.getClrMap(); | |||||
if(cmap != null){ | |||||
_theme.initColorMap(cmap); | |||||
} | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
return _theme; | |||||
} | |||||
@SuppressWarnings(value = "unused") | |||||
protected CTTextListStyle getTextProperties(Placeholder textType) { | protected CTTextListStyle getTextProperties(Placeholder textType) { | ||||
CTTextListStyle props; | CTTextListStyle props; | ||||
CTSlideMasterTextStyles txStyles = getXmlObject().getTxStyles(); | CTSlideMasterTextStyles txStyles = getXmlObject().getTxStyles(); | ||||
* | * | ||||
*/ | */ | ||||
@Override | @Override | ||||
protected boolean canDraw(XSLFShape shape){ | |||||
if(shape instanceof XSLFSimpleShape){ | |||||
XSLFSimpleShape txt = (XSLFSimpleShape)shape; | |||||
CTPlaceholder ph = txt.getCTPlaceholder(); | |||||
if(ph != null) { | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
protected boolean canDraw(XSLFShape shape) { | |||||
return !(shape instanceof XSLFSimpleShape) || !shape.isPlaceholder(); | |||||
} | } | ||||
@Override | @Override | ||||
return null; | return null; | ||||
} | } | ||||
} | } | ||||
@Override | |||||
boolean isSupportTheme() { | |||||
return true; | |||||
} | |||||
@Override | |||||
CTColorMapping getColorMapping() { | |||||
return _slide.getClrMap(); | |||||
} | |||||
} | } |
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.Iterator; | import java.util.Iterator; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Objects; | |||||
import java.util.function.Function; | |||||
import java.util.function.Supplier; | |||||
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; | ||||
private final List<XSLFTextRun> _runs; | private final List<XSLFTextRun> _runs; | ||||
private final XSLFTextShape _shape; | private final XSLFTextShape _shape; | ||||
@FunctionalInterface | |||||
private interface Procedure { | |||||
void accept(); | |||||
} | |||||
XSLFTextParagraph(CTTextParagraph p, XSLFTextShape shape){ | XSLFTextParagraph(CTTextParagraph p, XSLFTextShape shape){ | ||||
_p = p; | _p = p; | ||||
_runs = new ArrayList<>(); | _runs = new ArrayList<>(); | ||||
return out.toString(); | return out.toString(); | ||||
} | } | ||||
String getRenderableText(){ | |||||
StringBuilder out = new StringBuilder(); | |||||
for (XSLFTextRun r : _runs) { | |||||
out.append(r.getRenderableText()); | |||||
} | |||||
return out.toString(); | |||||
} | |||||
@Internal | @Internal | ||||
public CTTextParagraph getXmlObject(){ | public CTTextParagraph getXmlObject(){ | ||||
return _p; | return _p; | ||||
* | * | ||||
* @return text run representing this line break ('\n') | * @return text run representing this line break ('\n') | ||||
*/ | */ | ||||
@SuppressWarnings("WeakerAccess") | |||||
public XSLFTextRun addLineBreak(){ | public XSLFTextRun addLineBreak(){ | ||||
XSLFLineBreak run = new XSLFLineBreak(_p.addNewBr(), this); | XSLFLineBreak run = new XSLFLineBreak(_p.addNewBr(), this); | ||||
CTTextCharacterProperties brProps = run.getRPr(true); | CTTextCharacterProperties brProps = run.getRPr(true); | ||||
/** | /** | ||||
* @return the font to be used on bullet characters within a given paragraph | * @return the font to be used on bullet characters within a given paragraph | ||||
*/ | */ | ||||
@SuppressWarnings("WeakerAccess") | |||||
public String getBulletFont(){ | public String getBulletFont(){ | ||||
ParagraphPropertyFetcher<String> fetcher = new ParagraphPropertyFetcher<String>(getIndentLevel()){ | ParagraphPropertyFetcher<String> fetcher = new ParagraphPropertyFetcher<String>(getIndentLevel()){ | ||||
public boolean fetch(CTTextParagraphProperties props){ | public boolean fetch(CTTextParagraphProperties props){ | ||||
return fetcher.getValue(); | return fetcher.getValue(); | ||||
} | } | ||||
@SuppressWarnings("WeakerAccess") | |||||
public void setBulletFont(String typeface){ | public void setBulletFont(String typeface){ | ||||
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); | CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); | ||||
CTTextFont font = pr.isSetBuFont() ? pr.getBuFont() : pr.addNewBuFont(); | CTTextFont font = pr.isSetBuFont() ? pr.getBuFont() : pr.addNewBuFont(); | ||||
/** | /** | ||||
* @return the character to be used in place of the standard bullet point | * @return the character to be used in place of the standard bullet point | ||||
*/ | */ | ||||
@SuppressWarnings("WeakerAccess") | |||||
public String getBulletCharacter(){ | public String getBulletCharacter(){ | ||||
ParagraphPropertyFetcher<String> fetcher = new ParagraphPropertyFetcher<String>(getIndentLevel()){ | ParagraphPropertyFetcher<String> fetcher = new ParagraphPropertyFetcher<String>(getIndentLevel()){ | ||||
public boolean fetch(CTTextParagraphProperties props){ | public boolean fetch(CTTextParagraphProperties props){ | ||||
return fetcher.getValue(); | return fetcher.getValue(); | ||||
} | } | ||||
@SuppressWarnings("WeakerAccess") | |||||
public void setBulletCharacter(String str){ | public void setBulletCharacter(String str){ | ||||
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); | CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); | ||||
CTTextCharBullet c = pr.isSetBuChar() ? pr.getBuChar() : pr.addNewBuChar(); | CTTextCharBullet c = pr.isSetBuChar() ? pr.getBuChar() : pr.addNewBuChar(); | ||||
* @return the color of bullet characters within a given paragraph. | * @return the color of bullet characters within a given paragraph. | ||||
* A <code>null</code> value means to use the text font color. | * A <code>null</code> value means to use the text font color. | ||||
*/ | */ | ||||
@SuppressWarnings("WeakerAccess") | |||||
public PaintStyle getBulletFontColor(){ | public PaintStyle getBulletFontColor(){ | ||||
final XSLFTheme theme = getParentShape().getSheet().getTheme(); | final XSLFTheme theme = getParentShape().getSheet().getTheme(); | ||||
ParagraphPropertyFetcher<Color> fetcher = new ParagraphPropertyFetcher<Color>(getIndentLevel()){ | ParagraphPropertyFetcher<Color> fetcher = new ParagraphPropertyFetcher<Color>(getIndentLevel()){ | ||||
return (col == null) ? null : DrawPaint.createSolidPaint(col); | return (col == null) ? null : DrawPaint.createSolidPaint(col); | ||||
} | } | ||||
@SuppressWarnings("WeakerAccess") | |||||
public void setBulletFontColor(Color color) { | public void setBulletFontColor(Color color) { | ||||
setBulletFontColor(DrawPaint.createSolidPaint(color)); | setBulletFontColor(DrawPaint.createSolidPaint(color)); | ||||
} | } | ||||
* | * | ||||
* @param color the bullet color | * @param color the bullet color | ||||
*/ | */ | ||||
@SuppressWarnings("WeakerAccess") | |||||
public void setBulletFontColor(PaintStyle color) { | public void setBulletFontColor(PaintStyle color) { | ||||
if (!(color instanceof SolidPaint)) { | if (!(color instanceof SolidPaint)) { | ||||
throw new IllegalArgumentException("Currently XSLF only supports SolidPaint"); | throw new IllegalArgumentException("Currently XSLF only supports SolidPaint"); | ||||
* | * | ||||
* @return the bullet size | * @return the bullet size | ||||
*/ | */ | ||||
@SuppressWarnings("WeakerAccess") | |||||
public Double getBulletFontSize(){ | public Double getBulletFontSize(){ | ||||
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){ | ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){ | ||||
public boolean fetch(CTTextParagraphProperties props){ | public boolean fetch(CTTextParagraphProperties props){ | ||||
* If bulletSize < 0, then it specifies the size in points | * If bulletSize < 0, then it specifies the size in points | ||||
* </p> | * </p> | ||||
*/ | */ | ||||
@SuppressWarnings("WeakerAccess") | |||||
public void setBulletFontSize(double bulletSize){ | public void setBulletFontSize(double bulletSize){ | ||||
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); | CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); | ||||
/** | /** | ||||
* @return the auto numbering scheme, or null if not defined | * @return the auto numbering scheme, or null if not defined | ||||
*/ | */ | ||||
@SuppressWarnings("WeakerAccess") | |||||
public AutoNumberingScheme getAutoNumberingScheme() { | public AutoNumberingScheme getAutoNumberingScheme() { | ||||
ParagraphPropertyFetcher<AutoNumberingScheme> fetcher = new ParagraphPropertyFetcher<AutoNumberingScheme>(getIndentLevel()) { | ParagraphPropertyFetcher<AutoNumberingScheme> fetcher = new ParagraphPropertyFetcher<AutoNumberingScheme>(getIndentLevel()) { | ||||
public boolean fetch(CTTextParagraphProperties props) { | public boolean fetch(CTTextParagraphProperties props) { | ||||
/** | /** | ||||
* @return the auto numbering starting number, or null if not defined | * @return the auto numbering starting number, or null if not defined | ||||
*/ | */ | ||||
@SuppressWarnings("WeakerAccess") | |||||
public Integer getAutoNumberingStartAt() { | public Integer getAutoNumberingStartAt() { | ||||
ParagraphPropertyFetcher<Integer> fetcher = new ParagraphPropertyFetcher<Integer>(getIndentLevel()) { | ParagraphPropertyFetcher<Integer> fetcher = new ParagraphPropertyFetcher<Integer>(getIndentLevel()) { | ||||
public boolean fetch(CTTextParagraphProperties props) { | public boolean fetch(CTTextParagraphProperties props) { | ||||
return fetcher.getValue(); | return fetcher.getValue(); | ||||
} | } | ||||
public double getTabStop(final int idx){ | |||||
@SuppressWarnings("WeakerAccess") | |||||
public double getTabStop(final int idx) { | |||||
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){ | ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){ | ||||
public boolean fetch(CTTextParagraphProperties props){ | public boolean fetch(CTTextParagraphProperties props){ | ||||
if(props.isSetTabLst()){ | |||||
if (props.isSetTabLst()) { | |||||
CTTextTabStopList tabStops = props.getTabLst(); | CTTextTabStopList tabStops = props.getTabLst(); | ||||
if(idx < tabStops.sizeOfTabArray() ) { | if(idx < tabStops.sizeOfTabArray() ) { | ||||
CTTextTabStop ts = tabStops.getTabArray(idx); | CTTextTabStop ts = tabStops.getTabArray(idx); | ||||
return fetcher.getValue() == null ? 0. : fetcher.getValue(); | return fetcher.getValue() == null ? 0. : fetcher.getValue(); | ||||
} | } | ||||
@SuppressWarnings("WeakerAccess") | |||||
public void addTabStop(double value){ | public void addTabStop(double value){ | ||||
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); | CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); | ||||
CTTextTabStopList tabStops = pr.isSetTabLst() ? pr.getTabLst() : pr.addNewTabLst(); | CTTextTabStopList tabStops = pr.isSetTabLst() ? pr.getTabLst() : pr.addNewTabLst(); | ||||
@Override | @Override | ||||
public void setLineSpacing(Double lineSpacing){ | public void setLineSpacing(Double lineSpacing){ | ||||
if (lineSpacing == null && !_p.isSetPPr()) return; | |||||
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); | |||||
if(lineSpacing == null) { | |||||
if (pr.isSetLnSpc()) pr.unsetLnSpc(); | |||||
} else { | |||||
CTTextSpacing spc = (pr.isSetLnSpc()) ? pr.getLnSpc() : pr.addNewLnSpc(); | |||||
if (lineSpacing >= 0) { | |||||
(spc.isSetSpcPct() ? spc.getSpcPct() : spc.addNewSpcPct()).setVal((int)(lineSpacing*1000)); | |||||
if (spc.isSetSpcPts()) spc.unsetSpcPts(); | |||||
} else { | |||||
(spc.isSetSpcPts() ? spc.getSpcPts() : spc.addNewSpcPts()).setVal((int)(-lineSpacing*100)); | |||||
if (spc.isSetSpcPct()) spc.unsetSpcPct(); | |||||
} | |||||
} | |||||
setSpacing(lineSpacing, props -> props::getLnSpc, props -> props::addNewLnSpc, props -> props::unsetLnSpc); | |||||
} | } | ||||
@Override | @Override | ||||
public Double getLineSpacing(){ | public Double getLineSpacing(){ | ||||
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){ | |||||
public boolean fetch(CTTextParagraphProperties props){ | |||||
if(props.isSetLnSpc()){ | |||||
CTTextSpacing spc = props.getLnSpc(); | |||||
if(spc.isSetSpcPct()) setValue( spc.getSpcPct().getVal()*0.001 ); | |||||
else if (spc.isSetSpcPts()) setValue( -spc.getSpcPts().getVal()*0.01 ); | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
}; | |||||
fetchParagraphProperty(fetcher); | |||||
Double lnSpc = fetcher.getValue(); | |||||
final Double lnSpc = getSpacing(props -> props::getLnSpc); | |||||
if (lnSpc != null && lnSpc > 0) { | if (lnSpc != null && lnSpc > 0) { | ||||
// check if the percentage value is scaled | // check if the percentage value is scaled | ||||
CTTextNormalAutofit normAutofit = getParentShape().getTextBodyPr().getNormAutofit(); | |||||
if(normAutofit != null) { | |||||
double scale = 1 - (double)normAutofit.getLnSpcReduction() / 100000; | |||||
lnSpc *= scale; | |||||
final CTTextNormalAutofit normAutofit = getParentShape().getTextBodyPr().getNormAutofit(); | |||||
if (normAutofit != null) { | |||||
final double scale = 1 - (double)normAutofit.getLnSpcReduction() / 100000; | |||||
return lnSpc * scale; | |||||
} | } | ||||
} | } | ||||
@Override | @Override | ||||
public void setSpaceBefore(Double spaceBefore){ | public void setSpaceBefore(Double spaceBefore){ | ||||
if (spaceBefore == null && !_p.isSetPPr()) { | |||||
return; | |||||
} | |||||
// unset the space before on null input | |||||
if (spaceBefore == null) { | |||||
if(_p.getPPr().isSetSpcBef()) { | |||||
_p.getPPr().unsetSpcBef(); | |||||
} | |||||
return; | |||||
} | |||||
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); | |||||
CTTextSpacing spc = CTTextSpacing.Factory.newInstance(); | |||||
if(spaceBefore >= 0) { | |||||
spc.addNewSpcPct().setVal((int)(spaceBefore*1000)); | |||||
} else { | |||||
spc.addNewSpcPts().setVal((int)(-spaceBefore*100)); | |||||
} | |||||
pr.setSpcBef(spc); | |||||
setSpacing(spaceBefore, props -> props::getSpcBef, props -> props::addNewSpcBef, props -> props::unsetSpcBef); | |||||
} | } | ||||
@Override | @Override | ||||
public Double getSpaceBefore(){ | public Double getSpaceBefore(){ | ||||
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){ | |||||
public boolean fetch(CTTextParagraphProperties props){ | |||||
if(props.isSetSpcBef()){ | |||||
CTTextSpacing spc = props.getSpcBef(); | |||||
if(spc.isSetSpcPct()) setValue( spc.getSpcPct().getVal()*0.001 ); | |||||
else if (spc.isSetSpcPts()) setValue( -spc.getSpcPts().getVal()*0.01 ); | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
}; | |||||
fetchParagraphProperty(fetcher); | |||||
return fetcher.getValue(); | |||||
return getSpacing(props -> props::getSpcBef); | |||||
} | } | ||||
@Override | @Override | ||||
public void setSpaceAfter(Double spaceAfter){ | public void setSpaceAfter(Double spaceAfter){ | ||||
if (spaceAfter == null && !_p.isSetPPr()) { | |||||
setSpacing(spaceAfter, props -> props::getSpcAft, props -> props::addNewSpcAft, props -> props::unsetSpcAft); | |||||
} | |||||
@Override | |||||
public Double getSpaceAfter() { | |||||
return getSpacing(props -> props::getSpcAft); | |||||
} | |||||
private void setSpacing(final Double space, | |||||
final Function<CTTextParagraphProperties,Supplier<CTTextSpacing>> getSpc, | |||||
final Function<CTTextParagraphProperties,Supplier<CTTextSpacing>> addSpc, | |||||
final Function<CTTextParagraphProperties,Procedure> unsetSpc | |||||
) { | |||||
final CTTextParagraphProperties pPr = (space == null || _p.isSetPPr()) ? _p.getPPr() : _p.addNewPPr(); | |||||
if (pPr == null) { | |||||
return; | return; | ||||
} | } | ||||
// unset the space before on null input | |||||
if (spaceAfter == null) { | |||||
if(_p.getPPr().isSetSpcAft()) { | |||||
_p.getPPr().unsetSpcAft(); | |||||
CTTextSpacing spc = getSpc.apply(pPr).get(); | |||||
if (space == null) { | |||||
if (spc != null) { | |||||
// unset the space before on null input | |||||
unsetSpc.apply(pPr).accept(); | |||||
} | } | ||||
return; | return; | ||||
} | } | ||||
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); | |||||
CTTextSpacing spc = CTTextSpacing.Factory.newInstance(); | |||||
if (spc == null) { | |||||
spc = addSpc.apply(pPr).get(); | |||||
} | |||||
if(spaceAfter >= 0) { | |||||
spc.addNewSpcPct().setVal((int)(spaceAfter*1000)); | |||||
if (space >= 0) { | |||||
if (spc.isSetSpcPts()) { | |||||
spc.unsetSpcPts(); | |||||
} | |||||
final CTTextSpacingPercent pct = spc.isSetSpcPct() ? spc.getSpcPct() : spc.addNewSpcPct(); | |||||
pct.setVal((int)(space*1000)); | |||||
} else { | } else { | ||||
spc.addNewSpcPts().setVal((int)(-spaceAfter*100)); | |||||
if (spc.isSetSpcPct()) { | |||||
spc.unsetSpcPct(); | |||||
} | |||||
final CTTextSpacingPoint pts = spc.isSetSpcPts() ? spc.getSpcPts() : spc.addNewSpcPts(); | |||||
pts.setVal((int)(-space*100)); | |||||
} | } | ||||
pr.setSpcAft(spc); | |||||
} | } | ||||
@Override | |||||
public Double getSpaceAfter(){ | |||||
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){ | |||||
public boolean fetch(CTTextParagraphProperties props){ | |||||
if(props.isSetSpcAft()){ | |||||
CTTextSpacing spc = props.getSpcAft(); | |||||
private Double getSpacing(final Function<CTTextParagraphProperties,Supplier<CTTextSpacing>> getSpc) { | |||||
final ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){ | |||||
public boolean fetch(final CTTextParagraphProperties props){ | |||||
final CTTextSpacing spc = getSpc.apply(props).get(); | |||||
if (spc == null) { | |||||
return false; | |||||
} | |||||
if (spc.isSetSpcPct()) { | |||||
setValue( spc.getSpcPct().getVal()*0.001 ); | |||||
return true; | |||||
} | |||||
if(spc.isSetSpcPct()) setValue( spc.getSpcPct().getVal()*0.001 ); | |||||
else if (spc.isSetSpcPts()) setValue( -spc.getSpcPts().getVal()*0.01 ); | |||||
if (spc.isSetSpcPts()) { | |||||
setValue( -spc.getSpcPts().getVal()*0.01 ); | |||||
return true; | return true; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
}; | }; | ||||
* @param startAt the number that will start number for a given sequence of automatically | * @param startAt the number that will start number for a given sequence of automatically | ||||
numbered bullets (1-based). | numbered bullets (1-based). | ||||
*/ | */ | ||||
@SuppressWarnings("WeakerAccess") | |||||
public void setBulletAutoNumber(AutoNumberingScheme scheme, int startAt) { | public void setBulletAutoNumber(AutoNumberingScheme scheme, int startAt) { | ||||
if(startAt < 1) throw new IllegalArgumentException("Start Number must be greater or equal that 1") ; | if(startAt < 1) throw new IllegalArgumentException("Start Number must be greater or equal that 1") ; | ||||
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); | CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); | ||||
* there are no master slides or the master slides do not contain a text paragraph | * there are no master slides or the master slides do not contain a text paragraph | ||||
*/ | */ | ||||
/* package */ CTTextParagraphProperties getDefaultMasterStyle(){ | /* package */ CTTextParagraphProperties getDefaultMasterStyle(){ | ||||
CTPlaceholder ph = _shape.getCTPlaceholder(); | |||||
CTPlaceholder ph = _shape.getPlaceholderDetails().getCTPlaceholder(false); | |||||
String defaultStyleSelector; | String defaultStyleSelector; | ||||
switch(ph == null ? -1 : ph.getType().intValue()) { | switch(ph == null ? -1 : ph.getType().intValue()) { | ||||
case STPlaceholderType.INT_TITLE: | case STPlaceholderType.INT_TITLE: | ||||
return null; | return null; | ||||
} | } | ||||
private <T> boolean fetchParagraphProperty(ParagraphPropertyFetcher<T> visitor){ | |||||
boolean ok = false; | |||||
private void fetchParagraphProperty(final ParagraphPropertyFetcher<?> visitor){ | |||||
final XSLFTextShape shape = getParentShape(); | final XSLFTextShape shape = getParentShape(); | ||||
final XSLFSheet sheet = shape.getSheet(); | final XSLFSheet sheet = shape.getSheet(); | ||||
if (!(sheet instanceof XSLFSlideMaster)) { | if (!(sheet instanceof XSLFSlideMaster)) { | ||||
if(_p.isSetPPr()) ok = visitor.fetch(_p.getPPr()); | |||||
if (ok) return true; | |||||
if (_p.isSetPPr() && visitor.fetch(_p.getPPr())) { | |||||
return; | |||||
} | |||||
ok = shape.fetchShapeProperty(visitor); | |||||
if (ok) return true; | |||||
CTPlaceholder ph = shape.getCTPlaceholder(); | |||||
if(ph == null){ | |||||
// if it is a plain text box then take defaults from presentation.xml | |||||
@SuppressWarnings("resource") | |||||
XMLSlideShow ppt = sheet.getSlideShow(); | |||||
CTTextParagraphProperties themeProps = ppt.getDefaultParagraphStyle(getIndentLevel()); | |||||
if (themeProps != null) ok = visitor.fetch(themeProps); | |||||
if (shape.fetchShapeProperty(visitor)) { | |||||
return; | |||||
} | |||||
if (fetchThemeProperty(visitor)) { | |||||
return; | |||||
} | } | ||||
if (ok) return true; | |||||
} | } | ||||
fetchMasterProperty(visitor); | |||||
} | |||||
boolean fetchMasterProperty(final ParagraphPropertyFetcher<?> visitor) { | |||||
// defaults for placeholders are defined in the slide master | // defaults for placeholders are defined in the slide master | ||||
CTTextParagraphProperties defaultProps = getDefaultMasterStyle(); | |||||
final CTTextParagraphProperties defaultProps = getDefaultMasterStyle(); | |||||
// TODO: determine master shape | // TODO: determine master shape | ||||
if(defaultProps != null) ok = visitor.fetch(defaultProps); | |||||
if (ok) return true; | |||||
return defaultProps != null && visitor.fetch(defaultProps); | |||||
} | |||||
boolean fetchThemeProperty(final ParagraphPropertyFetcher<?> visitor) { | |||||
final XSLFTextShape shape = getParentShape(); | |||||
if (shape.isPlaceholder()) { | |||||
return false; | |||||
} | |||||
return false; | |||||
// if it is a plain text box then take defaults from presentation.xml | |||||
@SuppressWarnings("resource") | |||||
final XMLSlideShow ppt = shape.getSheet().getSlideShow(); | |||||
final CTTextParagraphProperties themeProps = ppt.getDefaultParagraphStyle(getIndentLevel()); | |||||
return themeProps != null && visitor.fetch(themeProps); | |||||
} | } | ||||
void copy(XSLFTextParagraph other){ | void copy(XSLFTextParagraph other){ | ||||
setBulletFontColor(buColor); | setBulletFontColor(buColor); | ||||
} | } | ||||
Double buSize = other.getBulletFontSize(); | Double buSize = other.getBulletFontSize(); | ||||
if(!doubleEquals(buSize, getBulletFontSize())){ | |||||
if(doubleNotEquals(buSize, getBulletFontSize())){ | |||||
setBulletFontSize(buSize); | setBulletFontSize(buSize); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
Double leftMargin = other.getLeftMargin(); | Double leftMargin = other.getLeftMargin(); | ||||
if (!doubleEquals(leftMargin, getLeftMargin())){ | |||||
if (doubleNotEquals(leftMargin, getLeftMargin())){ | |||||
setLeftMargin(leftMargin); | setLeftMargin(leftMargin); | ||||
} | } | ||||
Double indent = other.getIndent(); | Double indent = other.getIndent(); | ||||
if (!doubleEquals(indent, getIndent())) { | |||||
if (doubleNotEquals(indent, getIndent())) { | |||||
setIndent(indent); | setIndent(indent); | ||||
} | } | ||||
Double spaceAfter = other.getSpaceAfter(); | Double spaceAfter = other.getSpaceAfter(); | ||||
if (!doubleEquals(spaceAfter, getSpaceAfter())) { | |||||
if (doubleNotEquals(spaceAfter, getSpaceAfter())) { | |||||
setSpaceAfter(spaceAfter); | setSpaceAfter(spaceAfter); | ||||
} | } | ||||
Double spaceBefore = other.getSpaceBefore(); | Double spaceBefore = other.getSpaceBefore(); | ||||
if (!doubleEquals(spaceBefore, getSpaceBefore())) { | |||||
if (doubleNotEquals(spaceBefore, getSpaceBefore())) { | |||||
setSpaceBefore(spaceBefore); | setSpaceBefore(spaceBefore); | ||||
} | } | ||||
Double lineSpacing = other.getLineSpacing(); | Double lineSpacing = other.getLineSpacing(); | ||||
if (!doubleEquals(lineSpacing, getLineSpacing())) { | |||||
if (doubleNotEquals(lineSpacing, getLineSpacing())) { | |||||
setLineSpacing(lineSpacing); | setLineSpacing(lineSpacing); | ||||
} | } | ||||
} | } | ||||
private static boolean doubleEquals(Double d1, Double d2) { | |||||
return (d1 == d2 || (d1 != null && d1.equals(d2))); | |||||
private static boolean doubleNotEquals(Double d1, Double d2) { | |||||
return !Objects.equals(d1, d2); | |||||
} | } | ||||
@Override | @Override | ||||
@Override | @Override | ||||
public boolean isHeaderOrFooter() { | public boolean isHeaderOrFooter() { | ||||
CTPlaceholder ph = _shape.getCTPlaceholder(); | |||||
CTPlaceholder ph = _shape.getPlaceholderDetails().getCTPlaceholder(false); | |||||
int phId = (ph == null ? -1 : ph.getType().intValue()); | int phId = (ph == null ? -1 : ph.getType().intValue()); | ||||
switch (phId) { | switch (phId) { | ||||
case STPlaceholderType.INT_SLD_NUM: | case STPlaceholderType.INT_SLD_NUM: |
package org.apache.poi.xslf.usermodel; | package org.apache.poi.xslf.usermodel; | ||||
import java.awt.Color; | import java.awt.Color; | ||||
import java.util.Locale; | |||||
import org.apache.poi.common.usermodel.fonts.FontCharset; | import org.apache.poi.common.usermodel.fonts.FontCharset; | ||||
import org.apache.poi.common.usermodel.fonts.FontFamily; | import org.apache.poi.common.usermodel.fonts.FontFamily; | ||||
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; | import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; | ||||
import org.apache.poi.sl.usermodel.TextRun; | import org.apache.poi.sl.usermodel.TextRun; | ||||
import org.apache.poi.util.Beta; | import org.apache.poi.util.Beta; | ||||
import org.apache.poi.util.LocaleUtil; | |||||
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.apache.xmlbeans.XmlObject; | ||||
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.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.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; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; | |||||
/** | /** | ||||
* Represents a run of text within the containing text body. The run element is the | * Represents a run of text within the containing text body. The run element is the | ||||
return ((CTRegularTextRun)_r).getT(); | return ((CTRegularTextRun)_r).getT(); | ||||
} | } | ||||
String getRenderableText(){ | |||||
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"; | |||||
} | |||||
return getRenderableText(((CTRegularTextRun)_r).getT()); | |||||
} | |||||
/* package */ String getRenderableText(final String txt){ | |||||
// TODO: finish support for tabs | |||||
final String txtSpace = txt.replace("\t", " "); | |||||
final Locale loc = LocaleUtil.getUserLocale(); | |||||
switch (getTextCap()) { | |||||
case ALL: | |||||
return txtSpace.toUpperCase(loc); | |||||
case SMALL: | |||||
return txtSpace.toLowerCase(loc); | |||||
default: | |||||
return txtSpace; | |||||
} | |||||
} | |||||
@Override | @Override | ||||
public void setText(String text){ | public void setText(String text){ | ||||
if (_r instanceof CTTextField) { | if (_r instanceof CTTextField) { | ||||
* @return the spacing between characters within a text run, | * @return the spacing between characters within a text run, | ||||
* If this attribute is omitted than a value of 0 or no adjustment is assumed. | * If this attribute is omitted than a value of 0 or no adjustment is assumed. | ||||
*/ | */ | ||||
@SuppressWarnings("WeakerAccess") | |||||
public double getCharacterSpacing(){ | public double getCharacterSpacing(){ | ||||
CharacterPropertyFetcher<Double> fetcher = new CharacterPropertyFetcher<Double>(_p.getIndentLevel()){ | CharacterPropertyFetcher<Double> fetcher = new CharacterPropertyFetcher<Double>(_p.getIndentLevel()){ | ||||
* | * | ||||
* @param spc character spacing in points. | * @param spc character spacing in points. | ||||
*/ | */ | ||||
@SuppressWarnings("WeakerAccess") | |||||
public void setCharacterSpacing(double spc){ | public void setCharacterSpacing(double spc){ | ||||
CTTextCharacterProperties rPr = getRPr(true); | CTTextCharacterProperties rPr = getRPr(true); | ||||
if(spc == 0.0) { | if(spc == 0.0) { | ||||
* The size is specified using a percentage. | * The size is specified using a percentage. | ||||
* Positive values indicate superscript, negative values indicate subscript. | * Positive values indicate superscript, negative values indicate subscript. | ||||
* </p> | * </p> | ||||
* | |||||
* @param baselineOffset | |||||
*/ | */ | ||||
@SuppressWarnings("WeakerAccess") | |||||
public void setBaselineOffset(double baselineOffset){ | public void setBaselineOffset(double baselineOffset){ | ||||
getRPr(true).setBaseline((int) baselineOffset * 1000); | getRPr(true).setBaseline((int) baselineOffset * 1000); | ||||
} | } | ||||
* | * | ||||
* @see #setBaselineOffset(double) | * @see #setBaselineOffset(double) | ||||
*/ | */ | ||||
@SuppressWarnings("WeakerAccess") | |||||
public void setSuperscript(boolean flag){ | public void setSuperscript(boolean flag){ | ||||
setBaselineOffset(flag ? 30. : 0.); | setBaselineOffset(flag ? 30. : 0.); | ||||
} | } | ||||
* | * | ||||
* @see #setBaselineOffset(double) | * @see #setBaselineOffset(double) | ||||
*/ | */ | ||||
@SuppressWarnings("WeakerAccess") | |||||
public void setSubscript(boolean flag){ | public void setSubscript(boolean flag){ | ||||
setBaselineOffset(flag ? -25.0 : 0.); | setBaselineOffset(flag ? -25.0 : 0.); | ||||
} | } | ||||
return new XSLFHyperlink(hl, _p.getParentShape().getSheet()); | return new XSLFHyperlink(hl, _p.getParentShape().getSheet()); | ||||
} | } | ||||
private boolean fetchCharacterProperty(CharacterPropertyFetcher<?> fetcher){ | |||||
private void fetchCharacterProperty(final CharacterPropertyFetcher<?> visitor){ | |||||
XSLFTextShape shape = _p.getParentShape(); | XSLFTextShape shape = _p.getParentShape(); | ||||
XSLFSheet sheet = shape.getSheet(); | |||||
CTTextCharacterProperties rPr = getRPr(false); | CTTextCharacterProperties rPr = getRPr(false); | ||||
if (rPr != null && fetcher.fetch(rPr)) { | |||||
return true; | |||||
} | |||||
if (shape.fetchShapeProperty(fetcher)) { | |||||
return true; | |||||
if (rPr != null && visitor.fetch(rPr)) { | |||||
return; | |||||
} | } | ||||
CTPlaceholder ph = shape.getCTPlaceholder(); | |||||
if (ph == null){ | |||||
// if it is a plain text box then take defaults from presentation.xml | |||||
@SuppressWarnings("resource") | |||||
XMLSlideShow ppt = sheet.getSlideShow(); | |||||
// TODO: determine master shape | |||||
CTTextParagraphProperties themeProps = ppt.getDefaultParagraphStyle(_p.getIndentLevel()); | |||||
if (themeProps != null && fetcher.fetch(themeProps)) { | |||||
return true; | |||||
} | |||||
if (shape.fetchShapeProperty(visitor)) { | |||||
return; | |||||
} | } | ||||
// TODO: determine master shape | |||||
CTTextParagraphProperties defaultProps = _p.getDefaultMasterStyle(); | |||||
if(defaultProps != null && fetcher.fetch(defaultProps)) { | |||||
return true; | |||||
if (_p.fetchThemeProperty(visitor)) { | |||||
return; | |||||
} | } | ||||
return false; | |||||
_p.fetchMasterProperty(visitor); | |||||
} | } | ||||
void copy(XSLFTextRun r){ | void copy(XSLFTextRun r){ | ||||
} | } | ||||
private class XSLFFontInfo implements FontInfo { | |||||
private final class XSLFFontInfo implements FontInfo { | |||||
private final FontGroup fontGroup; | private final FontGroup fontGroup; | ||||
private XSLFFontInfo(FontGroup fontGroup) { | private XSLFFontInfo(FontGroup fontGroup) { | ||||
this.fontGroup = (fontGroup != null) ? fontGroup : FontGroup.getFontGroupFirst(getRawText()); | this.fontGroup = (fontGroup != null) ? fontGroup : FontGroup.getFontGroupFirst(getRawText()); | ||||
} | } | ||||
public void copyFrom(FontInfo fontInfo) { | |||||
void copyFrom(FontInfo fontInfo) { | |||||
CTTextFont tf = getXmlObject(true); | CTTextFont tf = getXmlObject(true); | ||||
setTypeface(fontInfo.getTypeface()); | setTypeface(fontInfo.getTypeface()); | ||||
setCharset(fontInfo.getCharset()); | setCharset(fontInfo.getCharset()); |
} | } | ||||
public Placeholder getTextType(){ | public Placeholder getTextType(){ | ||||
CTPlaceholder ph = getCTPlaceholder(); | |||||
if (ph == null) { | |||||
return null; | |||||
} | |||||
int val = ph.getType().intValue(); | |||||
return Placeholder.lookupOoxml(val); | |||||
return getPlaceholder(); | |||||
} | } | ||||
@Override | @Override |
import static org.junit.Assert.assertEquals; | import static org.junit.Assert.assertEquals; | ||||
import static org.junit.Assert.assertFalse; | import static org.junit.Assert.assertFalse; | ||||
import static org.junit.Assert.assertNotNull; | import static org.junit.Assert.assertNotNull; | ||||
import static org.junit.Assert.assertNull; | |||||
import static org.junit.Assert.assertTrue; | import static org.junit.Assert.assertTrue; | ||||
import static org.junit.Assert.fail; | import static org.junit.Assert.fail; | ||||
} | } | ||||
@After | @After | ||||
public void tearDown() throws IOException { | |||||
public void tearDown() { | |||||
pack.revert(); | pack.revert(); | ||||
} | } | ||||
assertEquals(null, xml.getCommentAuthors()); | assertEquals(null, xml.getCommentAuthors()); | ||||
for (XSLFSlide slide : xml.getSlides()) { | for (XSLFSlide slide : xml.getSlides()) { | ||||
assertEquals(null, slide.getComments()); | |||||
assertTrue(slide.getComments().isEmpty()); | |||||
} | } | ||||
// Try another with comments | // Try another with comments | ||||
i++; | i++; | ||||
if(i == 0) { | if(i == 0) { | ||||
assertNotNull(slide.getComments()); | |||||
assertEquals(1, slide.getComments().getNumberOfComments()); | |||||
assertEquals("testdoc", slide.getComments().getCommentAt(0).getText()); | |||||
assertEquals(0, slide.getComments().getCommentAt(0).getAuthorId()); | |||||
assertNotNull(slide.getCommentsPart()); | |||||
assertEquals(1, slide.getCommentsPart().getNumberOfComments()); | |||||
assertEquals("testdoc", slide.getCommentsPart().getCommentAt(0).getText()); | |||||
assertEquals(0, slide.getCommentsPart().getCommentAt(0).getAuthorId()); | |||||
} else if (i == 1) { | } else if (i == 1) { | ||||
assertNotNull(slide.getComments()); | assertNotNull(slide.getComments()); | ||||
assertEquals(1, slide.getComments().getNumberOfComments()); | |||||
assertEquals("test phrase", slide.getComments().getCommentAt(0).getText()); | |||||
assertEquals(0, slide.getComments().getCommentAt(0).getAuthorId()); | |||||
assertEquals(1, slide.getCommentsPart().getNumberOfComments()); | |||||
assertEquals("test phrase", slide.getCommentsPart().getCommentAt(0).getText()); | |||||
assertEquals(0, slide.getCommentsPart().getCommentAt(0).getAuthorId()); | |||||
} else { | } else { | ||||
assertEquals(null, slide.getComments()); | |||||
assertNull(slide.getCommentsPart()); | |||||
assertTrue(slide.getComments().isEmpty()); | |||||
} | } | ||||
} | } | ||||
return reopen((XMLSlideShow)show); | return reopen((XMLSlideShow)show); | ||||
} | } | ||||
public static XMLSlideShow reopen(XMLSlideShow show) { | |||||
private static XMLSlideShow reopen(XMLSlideShow show) { | |||||
try { | try { | ||||
BufAccessBAOS bos = new BufAccessBAOS(); | BufAccessBAOS bos = new BufAccessBAOS(); | ||||
show.write(bos); | show.write(bos); | ||||
} | } | ||||
private static class BufAccessBAOS extends ByteArrayOutputStream { | private static class BufAccessBAOS extends ByteArrayOutputStream { | ||||
public byte[] getBuf() { | |||||
byte[] getBuf() { | |||||
return buf; | return buf; | ||||
} | } | ||||
} | } |
import java.awt.Color; | import java.awt.Color; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import org.apache.poi.sl.draw.DrawTextParagraph; | |||||
import org.junit.Test; | import org.junit.Test; | ||||
/** | /** | ||||
r.setFontSize(13.0); | r.setFontSize(13.0); | ||||
assertEquals(13.0, r.getFontSize(), 0); | assertEquals(13.0, r.getFontSize(), 0); | ||||
assertEquals(false, r.isSuperscript()); | |||||
assertFalse(r.isSuperscript()); | |||||
r.setSuperscript(true); | r.setSuperscript(true); | ||||
assertEquals(true, r.isSuperscript()); | |||||
assertTrue(r.isSuperscript()); | |||||
r.setSuperscript(false); | r.setSuperscript(false); | ||||
assertEquals(false, r.isSuperscript()); | |||||
assertFalse(r.isSuperscript()); | |||||
assertEquals(false, r.isSubscript()); | |||||
assertFalse(r.isSubscript()); | |||||
r.setSubscript(true); | r.setSubscript(true); | ||||
assertEquals(true, r.isSubscript()); | |||||
assertTrue(r.isSubscript()); | |||||
r.setSubscript(false); | r.setSubscript(false); | ||||
assertEquals(false, r.isSubscript()); | |||||
assertFalse(r.isSubscript()); | |||||
ppt.close(); | ppt.close(); | ||||
} | } | ||||
try (XMLSlideShow ppt = new XMLSlideShow()) { | try (XMLSlideShow ppt = new XMLSlideShow()) { | ||||
XSLFSlide slide = ppt.createSlide(); | XSLFSlide slide = ppt.createSlide(); | ||||
XSLFTextShape sh = slide.createAutoShape(); | XSLFTextShape sh = slide.createAutoShape(); | ||||
XSLFTextRun r = sh.addNewTextParagraph().addNewTextRun(); | |||||
assertEquals(unicodeSurrogates, r.getRenderableText(unicodeSurrogates)); | |||||
XSLFTextParagraph p = sh.addNewTextParagraph(); | |||||
XSLFTextRun r = p.addNewTextRun(); | |||||
r.setText(unicodeSurrogates); | |||||
assertEquals(unicodeSurrogates, new DrawTextParagraph(p).getRenderableText(r)); | |||||
} | } | ||||
} | } | ||||
assertEquals("Title Slide",layout.getName()); | assertEquals("Title Slide",layout.getName()); | ||||
XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0); | XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0); | ||||
CTPlaceholder ph1 = shape1.getCTPlaceholder(); | |||||
CTPlaceholder ph1 = shape1.getPlaceholderDetails().getCTPlaceholder(false); | |||||
assertEquals(STPlaceholderType.CTR_TITLE, ph1.getType()); | assertEquals(STPlaceholderType.CTR_TITLE, ph1.getType()); | ||||
// anchor is not defined in the shape | // anchor is not defined in the shape | ||||
assertNull(getSpPr(shape1).getXfrm()); | assertNull(getSpPr(shape1).getXfrm()); | ||||
assertTrue(sameColor(Color.black, r1.getFontColor())); | assertTrue(sameColor(Color.black, r1.getFontColor())); | ||||
XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1); | XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1); | ||||
CTPlaceholder ph2 = shape2.getCTPlaceholder(); | |||||
CTPlaceholder ph2 = shape2.getPlaceholderDetails().getCTPlaceholder(false); | |||||
assertEquals(STPlaceholderType.SUB_TITLE, ph2.getType()); | assertEquals(STPlaceholderType.SUB_TITLE, ph2.getType()); | ||||
// anchor is not defined in the shape | // anchor is not defined in the shape | ||||
assertNull(getSpPr(shape2).getXfrm()); | assertNull(getSpPr(shape2).getXfrm()); | ||||
assertEquals("Title and Content",layout.getName()); | assertEquals("Title and Content",layout.getName()); | ||||
XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0); | XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0); | ||||
CTPlaceholder ph1 = shape1.getCTPlaceholder(); | |||||
CTPlaceholder ph1 = shape1.getPlaceholderDetails().getCTPlaceholder(false); | |||||
assertEquals(STPlaceholderType.TITLE, ph1.getType()); | assertEquals(STPlaceholderType.TITLE, ph1.getType()); | ||||
// anchor is not defined in the shape | // anchor is not defined in the shape | ||||
assertNull(getSpPr(shape1).getXfrm()); | assertNull(getSpPr(shape1).getXfrm()); | ||||
assertTrue(sameColor(Color.black, r1.getFontColor())); | assertTrue(sameColor(Color.black, r1.getFontColor())); | ||||
XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1); | XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1); | ||||
CTPlaceholder ph2 = shape2.getCTPlaceholder(); | |||||
CTPlaceholder ph2 = shape2.getPlaceholderDetails().getCTPlaceholder(false); | |||||
assertFalse(ph2.isSetType()); // <p:ph idx="1"/> | assertFalse(ph2.isSetType()); // <p:ph idx="1"/> | ||||
assertTrue(ph2.isSetIdx()); | assertTrue(ph2.isSetIdx()); | ||||
assertEquals(1, ph2.getIdx()); | assertEquals(1, ph2.getIdx()); | ||||
assertEquals("Section Header",layout.getName()); | assertEquals("Section Header",layout.getName()); | ||||
XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0); | XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0); | ||||
CTPlaceholder ph1 = shape1.getCTPlaceholder(); | |||||
CTPlaceholder ph1 = shape1.getPlaceholderDetails().getCTPlaceholder(false); | |||||
assertEquals(STPlaceholderType.TITLE, ph1.getType()); | assertEquals(STPlaceholderType.TITLE, ph1.getType()); | ||||
// anchor is not defined in the shape | // anchor is not defined in the shape | ||||
assertNull(getSpPr(shape1).getXfrm()); | assertNull(getSpPr(shape1).getXfrm()); | ||||
assertFalse(r1.isUnderlined()); | assertFalse(r1.isUnderlined()); | ||||
XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1); | XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1); | ||||
CTPlaceholder ph2 = shape2.getCTPlaceholder(); | |||||
CTPlaceholder ph2 = shape2.getPlaceholderDetails().getCTPlaceholder(false); | |||||
assertEquals(STPlaceholderType.BODY, ph2.getType()); | assertEquals(STPlaceholderType.BODY, ph2.getType()); | ||||
// anchor is not defined in the shape | // anchor is not defined in the shape | ||||
assertNull(getSpPr(shape2).getXfrm()); | assertNull(getSpPr(shape2).getXfrm()); | ||||
assertEquals("Two Content",layout.getName()); | assertEquals("Two Content",layout.getName()); | ||||
XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0); | XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0); | ||||
CTPlaceholder ph1 = shape1.getCTPlaceholder(); | |||||
CTPlaceholder ph1 = shape1.getPlaceholderDetails().getCTPlaceholder(false); | |||||
assertEquals(STPlaceholderType.TITLE, ph1.getType()); | assertEquals(STPlaceholderType.TITLE, ph1.getType()); | ||||
// anchor is not defined in the shape | // anchor is not defined in the shape | ||||
assertNull(getSpPr(shape1).getXfrm()); | assertNull(getSpPr(shape1).getXfrm()); | ||||
assertTrue(sameColor(Color.black, r1.getFontColor())); | assertTrue(sameColor(Color.black, r1.getFontColor())); | ||||
XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1); | XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1); | ||||
CTPlaceholder ph2 = shape2.getCTPlaceholder(); | |||||
CTPlaceholder ph2 = shape2.getPlaceholderDetails().getCTPlaceholder(false); | |||||
assertFalse(ph2.isSetType()); | assertFalse(ph2.isSetType()); | ||||
assertTrue(ph2.isSetIdx()); | assertTrue(ph2.isSetIdx()); | ||||
assertEquals(1, ph2.getIdx()); //<p:ph sz="half" idx="1"/> | assertEquals(1, ph2.getIdx()); //<p:ph sz="half" idx="1"/> | ||||
assertEquals("Blank",layout.getName()); | assertEquals("Blank",layout.getName()); | ||||
XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0); | XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0); | ||||
CTPlaceholder ph1 = shape1.getCTPlaceholder(); | |||||
CTPlaceholder ph1 = shape1.getPlaceholderDetails().getCTPlaceholder(false); | |||||
assertEquals(STPlaceholderType.TITLE, ph1.getType()); | assertEquals(STPlaceholderType.TITLE, ph1.getType()); | ||||
// anchor is not defined in the shape | // anchor is not defined in the shape | ||||
assertNull(getSpPr(shape1).getXfrm()); | assertNull(getSpPr(shape1).getXfrm()); | ||||
assertEquals("Content with Caption",layout.getName()); | assertEquals("Content with Caption",layout.getName()); | ||||
XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0); | XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0); | ||||
CTPlaceholder ph1 = shape1.getCTPlaceholder(); | |||||
CTPlaceholder ph1 = shape1.getPlaceholderDetails().getCTPlaceholder(false); | |||||
assertEquals(STPlaceholderType.TITLE, ph1.getType()); | assertEquals(STPlaceholderType.TITLE, ph1.getType()); | ||||
// anchor is not defined in the shape | // anchor is not defined in the shape | ||||
assertNull(getSpPr(shape1).getXfrm()); | assertNull(getSpPr(shape1).getXfrm()); | ||||
assertTrue(r1.isBold()); | assertTrue(r1.isBold()); | ||||
XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1); | XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1); | ||||
CTPlaceholder ph2 = shape2.getCTPlaceholder(); | |||||
CTPlaceholder ph2 = shape2.getPlaceholderDetails().getCTPlaceholder(false); | |||||
assertFalse(ph2.isSetType()); | assertFalse(ph2.isSetType()); | ||||
assertTrue(ph2.isSetIdx()); | assertTrue(ph2.isSetIdx()); | ||||
assertEquals(1, ph2.getIdx()); | assertEquals(1, ph2.getIdx()); |
import java.io.File; | import java.io.File; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.InputStream; | import java.io.InputStream; | ||||
import java.util.ArrayList; | |||||
import java.util.HashSet; | |||||
import java.util.List; | import java.util.List; | ||||
import java.util.Set; | |||||
import org.apache.poi.POIOLE2TextExtractor; | import org.apache.poi.POIOLE2TextExtractor; | ||||
import org.apache.poi.hslf.model.Comment; | |||||
import org.apache.poi.hslf.model.HSLFMetroShape; | |||||
import org.apache.poi.hslf.model.HeadersFooters; | |||||
import org.apache.poi.hslf.usermodel.HSLFMasterSheet; | |||||
import org.apache.poi.hslf.usermodel.HSLFNotes; | |||||
import org.apache.poi.hslf.usermodel.HSLFObjectShape; | |||||
import org.apache.poi.hslf.usermodel.HSLFShape; | import org.apache.poi.hslf.usermodel.HSLFShape; | ||||
import org.apache.poi.hslf.usermodel.HSLFSlide; | |||||
import org.apache.poi.hslf.usermodel.HSLFSlideMaster; | |||||
import org.apache.poi.hslf.usermodel.HSLFSlideShow; | import org.apache.poi.hslf.usermodel.HSLFSlideShow; | ||||
import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; | import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; | ||||
import org.apache.poi.hslf.usermodel.HSLFTable; | |||||
import org.apache.poi.hslf.usermodel.HSLFTableCell; | |||||
import org.apache.poi.hslf.usermodel.HSLFTextParagraph; | import org.apache.poi.hslf.usermodel.HSLFTextParagraph; | ||||
import org.apache.poi.hslf.usermodel.HSLFTextShape; | |||||
import org.apache.poi.hslf.usermodel.HSLFObjectShape; | |||||
import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey; | |||||
import org.apache.poi.poifs.filesystem.DirectoryNode; | import org.apache.poi.poifs.filesystem.DirectoryNode; | ||||
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; | import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; | ||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem; | import org.apache.poi.poifs.filesystem.POIFSFileSystem; | ||||
import org.apache.poi.util.POILogFactory; | |||||
import org.apache.poi.util.POILogger; | |||||
import org.apache.poi.sl.extractor.SlideShowExtractor; | |||||
import org.apache.poi.sl.usermodel.SlideShowFactory; | |||||
/** | /** | ||||
* This class can be used to extract text from a PowerPoint file. Can optionally | * This class can be used to extract text from a PowerPoint file. Can optionally | ||||
* also get the notes from one. | * also get the notes from one. | ||||
* | |||||
* @deprecated in POI 4.0.0, use {@link SlideShowExtractor} instead | |||||
*/ | */ | ||||
@SuppressWarnings("WeakerAccess") | |||||
@Deprecated | |||||
public final class PowerPointExtractor extends POIOLE2TextExtractor { | public final class PowerPointExtractor extends POIOLE2TextExtractor { | ||||
private static final POILogger LOG = POILogFactory.getLogger(PowerPointExtractor.class); | |||||
private final HSLFSlideShow _show; | |||||
private final List<HSLFSlide> _slides; | |||||
private final SlideShowExtractor<HSLFShape,HSLFTextParagraph> delegate; | |||||
private boolean _slidesByDefault = true; | |||||
private boolean _notesByDefault; | |||||
private boolean _commentsByDefault; | |||||
private boolean _masterByDefault; | |||||
private boolean slidesByDefault = true; | |||||
private boolean notesByDefault; | |||||
private boolean commentsByDefault; | |||||
private boolean masterByDefault; | |||||
/** | /** | ||||
* Basic extractor. Returns all the text, and optionally all the notes | * Basic extractor. Returns all the text, and optionally all the notes | ||||
ppe.close(); | ppe.close(); | ||||
} | } | ||||
public PowerPointExtractor(final HSLFSlideShow slideShow) { | |||||
super(slideShow.getSlideShowImpl()); | |||||
setFilesystem(slideShow); | |||||
delegate = new SlideShowExtractor<>(slideShow); | |||||
} | |||||
/** | /** | ||||
* Creates a PowerPointExtractor, from a file | * Creates a PowerPointExtractor, from a file | ||||
* | * | ||||
* @param fileName The name of the file to extract from | * @param fileName The name of the file to extract from | ||||
*/ | */ | ||||
public PowerPointExtractor(String fileName) throws IOException { | public PowerPointExtractor(String fileName) throws IOException { | ||||
this(new NPOIFSFileSystem(new File(fileName))); | |||||
this((HSLFSlideShow)SlideShowFactory.create(new File(fileName), Biff8EncryptionKey.getCurrentUserPassword(), true)); | |||||
} | } | ||||
/** | /** | ||||
* @param iStream The input stream containing the PowerPoint document | * @param iStream The input stream containing the PowerPoint document | ||||
*/ | */ | ||||
public PowerPointExtractor(InputStream iStream) throws IOException { | public PowerPointExtractor(InputStream iStream) throws IOException { | ||||
this(new POIFSFileSystem(iStream)); | |||||
this((HSLFSlideShow)SlideShowFactory.create(iStream, Biff8EncryptionKey.getCurrentUserPassword())); | |||||
} | } | ||||
/** | /** | ||||
* @param fs the POIFSFileSystem containing the PowerPoint document | * @param fs the POIFSFileSystem containing the PowerPoint document | ||||
*/ | */ | ||||
public PowerPointExtractor(POIFSFileSystem fs) throws IOException { | public PowerPointExtractor(POIFSFileSystem fs) throws IOException { | ||||
this(fs.getRoot()); | |||||
this((HSLFSlideShow)SlideShowFactory.create(fs, Biff8EncryptionKey.getCurrentUserPassword())); | |||||
} | } | ||||
/** | /** | ||||
* @param fs the NPOIFSFileSystem containing the PowerPoint document | * @param fs the NPOIFSFileSystem containing the PowerPoint document | ||||
*/ | */ | ||||
public PowerPointExtractor(NPOIFSFileSystem fs) throws IOException { | public PowerPointExtractor(NPOIFSFileSystem fs) throws IOException { | ||||
this(fs.getRoot()); | |||||
setFilesystem(fs); | |||||
this((HSLFSlideShow)SlideShowFactory.create(fs, Biff8EncryptionKey.getCurrentUserPassword())); | |||||
} | } | ||||
/** | /** | ||||
* @param dir the POIFS Directory containing the PowerPoint document | * @param dir the POIFS Directory containing the PowerPoint document | ||||
*/ | */ | ||||
public PowerPointExtractor(DirectoryNode dir) throws IOException { | public PowerPointExtractor(DirectoryNode dir) throws IOException { | ||||
this(new HSLFSlideShowImpl(dir)); | |||||
this(new HSLFSlideShow(dir)); | |||||
} | } | ||||
/** | /** | ||||
* @param ss the HSLFSlideShow to extract text from | * @param ss the HSLFSlideShow to extract text from | ||||
*/ | */ | ||||
public PowerPointExtractor(HSLFSlideShowImpl ss) { | public PowerPointExtractor(HSLFSlideShowImpl ss) { | ||||
super(ss); | |||||
_show = new HSLFSlideShow(ss); | |||||
_slides = _show.getSlides(); | |||||
this(new HSLFSlideShow(ss)); | |||||
} | } | ||||
/** | /** | ||||
* Should a call to getText() return slide text? Default is yes | * Should a call to getText() return slide text? Default is yes | ||||
*/ | */ | ||||
public void setSlidesByDefault(boolean slidesByDefault) { | |||||
this._slidesByDefault = slidesByDefault; | |||||
public void setSlidesByDefault(final boolean slidesByDefault) { | |||||
this.slidesByDefault = slidesByDefault; | |||||
delegate.setSlidesByDefault(slidesByDefault); | |||||
} | } | ||||
/** | /** | ||||
* Should a call to getText() return notes text? Default is no | * Should a call to getText() return notes text? Default is no | ||||
*/ | */ | ||||
public void setNotesByDefault(boolean notesByDefault) { | |||||
this._notesByDefault = notesByDefault; | |||||
public void setNotesByDefault(final boolean notesByDefault) { | |||||
this.notesByDefault = notesByDefault; | |||||
delegate.setNotesByDefault(notesByDefault); | |||||
} | } | ||||
/** | /** | ||||
* Should a call to getText() return comments text? Default is no | * Should a call to getText() return comments text? Default is no | ||||
*/ | */ | ||||
public void setCommentsByDefault(boolean commentsByDefault) { | |||||
this._commentsByDefault = commentsByDefault; | |||||
public void setCommentsByDefault(final boolean commentsByDefault) { | |||||
this.commentsByDefault = commentsByDefault; | |||||
delegate.setCommentsByDefault(commentsByDefault); | |||||
} | } | ||||
/** | /** | ||||
* Should a call to getText() return text from master? Default is no | * Should a call to getText() return text from master? Default is no | ||||
*/ | */ | ||||
public void setMasterByDefault(boolean masterByDefault) { | |||||
this._masterByDefault = masterByDefault; | |||||
public void setMasterByDefault(final boolean masterByDefault) { | |||||
this.masterByDefault = masterByDefault; | |||||
delegate.setMasterByDefault(masterByDefault); | |||||
} | } | ||||
/** | /** | ||||
*/ | */ | ||||
@Override | @Override | ||||
public String getText() { | public String getText() { | ||||
return getText(_slidesByDefault, _notesByDefault, _commentsByDefault, _masterByDefault); | |||||
} | |||||
/** | |||||
* Fetches all the notes text from the slideshow, but not the slide text | |||||
*/ | |||||
public String getNotes() { | |||||
return getText(false, true); | |||||
} | |||||
public List<HSLFObjectShape> getOLEShapes() { | |||||
List<HSLFObjectShape> list = new ArrayList<>(); | |||||
for (HSLFSlide slide : _slides) { | |||||
for (HSLFShape shape : slide.getShapes()) { | |||||
if (shape instanceof HSLFObjectShape) { | |||||
list.add((HSLFObjectShape) shape); | |||||
} | |||||
} | |||||
} | |||||
return list; | |||||
return delegate.getText(); | |||||
} | } | ||||
/** | /** | ||||
* @param getNoteText fetch note text | * @param getNoteText fetch note text | ||||
*/ | */ | ||||
public String getText(boolean getSlideText, boolean getNoteText) { | public String getText(boolean getSlideText, boolean getNoteText) { | ||||
return getText(getSlideText, getNoteText, _commentsByDefault, _masterByDefault); | |||||
return getText(getSlideText,getNoteText,commentsByDefault,masterByDefault); | |||||
} | } | ||||
public String getText(boolean getSlideText, boolean getNoteText, boolean getCommentText, boolean getMasterText) { | public String getText(boolean getSlideText, boolean getNoteText, boolean getCommentText, boolean getMasterText) { | ||||
StringBuffer ret = new StringBuffer(); | |||||
if (getSlideText) { | |||||
if (getMasterText) { | |||||
for (HSLFSlideMaster master : _show.getSlideMasters()) { | |||||
for(HSLFShape sh : master.getShapes()){ | |||||
if(sh instanceof HSLFTextShape){ | |||||
HSLFTextShape hsh = (HSLFTextShape)sh; | |||||
final String text = hsh.getText(); | |||||
if (text == null || text.isEmpty() || "*".equals(text)) { | |||||
continue; | |||||
} | |||||
if (HSLFMasterSheet.isPlaceholder(sh)) { | |||||
// check for metro shape of complex placeholder | |||||
boolean isMetro = new HSLFMetroShape<HSLFShape>(sh).hasMetroBlob(); | |||||
if (!isMetro) { | |||||
// don't bother about boiler plate text on master sheets | |||||
LOG.log(POILogger.INFO, "Ignoring boiler plate (placeholder) text on slide master:", text); | |||||
continue; | |||||
} | |||||
} | |||||
ret.append(text); | |||||
if (!text.endsWith("\n")) { | |||||
ret.append("\n"); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
for (HSLFSlide slide : _slides) { | |||||
String headerText = ""; | |||||
String footerText = ""; | |||||
HeadersFooters hf = slide.getHeadersFooters(); | |||||
if (hf != null) { | |||||
if (hf.isHeaderVisible()) { | |||||
headerText = safeLine(hf.getHeaderText()); | |||||
} | |||||
if (hf.isFooterVisible()) { | |||||
footerText = safeLine(hf.getFooterText()); | |||||
} | |||||
} | |||||
// Slide header, if set | |||||
ret.append(headerText); | |||||
// Slide text | |||||
textRunsToText(ret, slide.getTextParagraphs()); | |||||
// Table text | |||||
for (HSLFShape shape : slide.getShapes()){ | |||||
if (shape instanceof HSLFTable){ | |||||
extractTableText(ret, (HSLFTable)shape); | |||||
} | |||||
} | |||||
// Slide footer, if set | |||||
ret.append(footerText); | |||||
// Comments, if requested and present | |||||
if (getCommentText) { | |||||
for (Comment comment : slide.getComments()) { | |||||
ret.append(comment.getAuthor() + " - " + comment.getText() + "\n"); | |||||
} | |||||
} | |||||
} | |||||
if (getNoteText) { | |||||
ret.append('\n'); | |||||
} | |||||
delegate.setSlidesByDefault(getSlideText); | |||||
delegate.setNotesByDefault(getNoteText); | |||||
delegate.setCommentsByDefault(getCommentText); | |||||
delegate.setMasterByDefault(getMasterText); | |||||
try { | |||||
return delegate.getText(); | |||||
} finally { | |||||
delegate.setSlidesByDefault(slidesByDefault); | |||||
delegate.setNotesByDefault(notesByDefault); | |||||
delegate.setCommentsByDefault(commentsByDefault); | |||||
delegate.setMasterByDefault(masterByDefault); | |||||
} | } | ||||
if (getNoteText) { | |||||
// Not currently using _notes, as that can have the notes of | |||||
// master sheets in. Grab Slide list, then work from there, | |||||
// but ensure no duplicates | |||||
Set<Integer> seenNotes = new HashSet<>(); | |||||
String headerText = ""; | |||||
String footerText = ""; | |||||
HeadersFooters hf = _show.getNotesHeadersFooters(); | |||||
if (hf != null) { | |||||
if (hf.isHeaderVisible()) { | |||||
headerText = safeLine(hf.getHeaderText()); | |||||
} | |||||
if (hf.isFooterVisible()) { | |||||
footerText = safeLine(hf.getFooterText()); | |||||
} | |||||
} | |||||
for (HSLFSlide slide : _slides) { | |||||
HSLFNotes notes = slide.getNotes(); | |||||
if (notes == null) { | |||||
continue; | |||||
} | |||||
Integer id = Integer.valueOf(notes._getSheetNumber()); | |||||
if (seenNotes.contains(id)) { | |||||
continue; | |||||
} | |||||
seenNotes.add(id); | |||||
// Repeat the Notes header, if set | |||||
ret.append(headerText); | |||||
// Notes text | |||||
textRunsToText(ret, notes.getTextParagraphs()); | |||||
// Repeat the notes footer, if set | |||||
ret.append(footerText); | |||||
} | |||||
} | |||||
return ret.toString(); | |||||
} | |||||
private static String safeLine(String text) { | |||||
return (text == null) ? "" : (text+'\n'); | |||||
} | } | ||||
private void extractTableText(StringBuffer ret, HSLFTable table) { | |||||
final int nrows = table.getNumberOfRows(); | |||||
final int ncols = table.getNumberOfColumns(); | |||||
for (int row = 0; row < nrows; row++){ | |||||
for (int col = 0; col < ncols; col++){ | |||||
HSLFTableCell cell = table.getCell(row, col); | |||||
//defensive null checks; don't know if they're necessary | |||||
if (cell != null){ | |||||
String txt = cell.getText(); | |||||
txt = (txt == null) ? "" : txt; | |||||
ret.append(txt); | |||||
if (col < ncols-1){ | |||||
ret.append('\t'); | |||||
} | |||||
} | |||||
} | |||||
ret.append('\n'); | |||||
} | |||||
} | |||||
private void textRunsToText(StringBuffer ret, List<List<HSLFTextParagraph>> paragraphs) { | |||||
if (paragraphs==null) { | |||||
return; | |||||
} | |||||
/** | |||||
* Fetches all the notes text from the slideshow, but not the slide text | |||||
*/ | |||||
public String getNotes() { | |||||
return getText(false, true, false, false); | |||||
} | |||||
for (List<HSLFTextParagraph> lp : paragraphs) { | |||||
ret.append(HSLFTextParagraph.getText(lp)); | |||||
if (ret.length() > 0 && ret.charAt(ret.length()-1) != '\n') { | |||||
ret.append('\n'); | |||||
} | |||||
} | |||||
} | |||||
@SuppressWarnings("unchecked") | |||||
public List<HSLFObjectShape> getOLEShapes() { | |||||
return (List<HSLFObjectShape>)delegate.getOLEShapes(); | |||||
} | |||||
} | } |
/* ==================================================================== | |||||
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.model; | |||||
import org.apache.poi.hslf.record.Comment2000; | |||||
/** | |||||
* | |||||
* @author Nick Burch | |||||
*/ | |||||
public final class Comment { | |||||
private Comment2000 _comment2000; | |||||
public Comment(Comment2000 comment2000) { | |||||
_comment2000 = comment2000; | |||||
} | |||||
protected Comment2000 getComment2000() { | |||||
return _comment2000; | |||||
} | |||||
/** | |||||
* Get the Author of this comment | |||||
*/ | |||||
public String getAuthor() { | |||||
return _comment2000.getAuthor(); | |||||
} | |||||
/** | |||||
* Set the Author of this comment | |||||
*/ | |||||
public void setAuthor(String author) { | |||||
_comment2000.setAuthor(author); | |||||
} | |||||
/** | |||||
* Get the Author's Initials of this comment | |||||
*/ | |||||
public String getAuthorInitials() { | |||||
return _comment2000.getAuthorInitials(); | |||||
} | |||||
/** | |||||
* Set the Author's Initials of this comment | |||||
*/ | |||||
public void setAuthorInitials(String initials) { | |||||
_comment2000.setAuthorInitials(initials); | |||||
} | |||||
/** | |||||
* Get the text of this comment | |||||
*/ | |||||
public String getText() { | |||||
return _comment2000.getText(); | |||||
} | |||||
/** | |||||
* Set the text of this comment | |||||
*/ | |||||
public void setText(String text) { | |||||
_comment2000.setText(text); | |||||
} | |||||
} |
private void setFlag(int type, boolean flag) { | private void setFlag(int type, boolean flag) { | ||||
_container.getHeadersFootersAtom().setFlag(type, flag); | _container.getHeadersFootersAtom().setFlag(type, flag); | ||||
} | } | ||||
/** | |||||
* @return true, if this is a ppt 2007 document and header/footer are stored as placeholder shapes | |||||
*/ | |||||
public boolean isPpt2007() { | |||||
return _ppt2007; | |||||
} | |||||
} | } |
import java.io.OutputStream; | import java.io.OutputStream; | ||||
import java.util.Map; | import java.util.Map; | ||||
import org.apache.poi.EncryptedDocumentException; | |||||
import org.apache.poi.poifs.crypt.CipherAlgorithm; | import org.apache.poi.poifs.crypt.CipherAlgorithm; | ||||
import org.apache.poi.poifs.crypt.EncryptionInfo; | import org.apache.poi.poifs.crypt.EncryptionInfo; | ||||
import org.apache.poi.poifs.crypt.EncryptionMode; | import org.apache.poi.poifs.crypt.EncryptionMode; | ||||
/** | /** | ||||
* For the Document Encryption Atom | * For the Document Encryption Atom | ||||
*/ | */ | ||||
protected DocumentEncryptionAtom(byte[] source, int start, int len) throws IOException { | |||||
protected DocumentEncryptionAtom(byte[] source, int start, int len) { | |||||
// Get the header | // Get the header | ||||
_header = new byte[8]; | _header = new byte[8]; | ||||
System.arraycopy(source,start,_header,0,8); | System.arraycopy(source,start,_header,0,8); | ||||
ByteArrayInputStream bis = new ByteArrayInputStream(source, start+8, len-8); | ByteArrayInputStream bis = new ByteArrayInputStream(source, start+8, len-8); | ||||
LittleEndianInputStream leis = new LittleEndianInputStream(bis); | |||||
ei = new EncryptionInfo(leis, EncryptionMode.cryptoAPI); | |||||
leis.close(); | |||||
try (LittleEndianInputStream leis = new LittleEndianInputStream(bis)) { | |||||
ei = new EncryptionInfo(leis, EncryptionMode.cryptoAPI); | |||||
} catch (IOException e) { | |||||
throw new EncryptedDocumentException(e); | |||||
} | |||||
} | } | ||||
public DocumentEncryptionAtom() { | public DocumentEncryptionAtom() { |
import java.io.ByteArrayOutputStream; | import java.io.ByteArrayOutputStream; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.Iterator; | |||||
import java.util.List; | import java.util.List; | ||||
import org.apache.poi.ddf.EscherClientDataRecord; | import org.apache.poi.ddf.EscherClientDataRecord; | ||||
} | } | ||||
public void removeChild(Class<? extends Record> childClass) { | public void removeChild(Class<? extends Record> childClass) { | ||||
Iterator<Record> iter = _childRecords.iterator(); | |||||
while (iter.hasNext()) { | |||||
if (childClass.isInstance(iter.next())) { | |||||
iter.remove(); | |||||
} | |||||
} | |||||
_childRecords.removeIf(childClass::isInstance); | |||||
} | } | ||||
public void addChild(Record childRecord) { | public void addChild(Record childRecord) { | ||||
_childRecords.clear(); | _childRecords.clear(); | ||||
int offset = 0; | int offset = 0; | ||||
while (offset < remainingData.length) { | while (offset < remainingData.length) { | ||||
Record r = Record.buildRecordAtOffset(remainingData, offset); | |||||
_childRecords.add(r); | |||||
final Record r = Record.buildRecordAtOffset(remainingData, offset); | |||||
if (r != null) { | |||||
_childRecords.add(r); | |||||
} | |||||
long rlen = LittleEndian.getUInt(remainingData,offset+4); | long rlen = LittleEndian.getUInt(remainingData,offset+4); | ||||
offset += 8 + rlen; | offset += 8 + rlen; | ||||
} | } |
import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException; | import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException; | ||||
import org.apache.poi.hslf.exceptions.HSLFException; | import org.apache.poi.hslf.exceptions.HSLFException; | ||||
import org.apache.poi.hslf.record.RecordTypes.RecordConstructor; | |||||
import org.apache.poi.util.LittleEndian; | import org.apache.poi.util.LittleEndian; | ||||
import org.apache.poi.util.POILogFactory; | import org.apache.poi.util.POILogFactory; | ||||
import org.apache.poi.util.POILogger; | import org.apache.poi.util.POILogger; | ||||
// Abort if first record is of type 0000 and length FFFF, | // Abort if first record is of type 0000 and length FFFF, | ||||
// as that's a sign of a screwed up record | // as that's a sign of a screwed up record | ||||
if(pos == 0 && type == 0l && rleni == 0xffff) { | |||||
if(pos == 0 && type == 0L && rleni == 0xffff) { | |||||
throw new CorruptPowerPointFileException("Corrupt document - starts with record of type 0000 and length 0xFFFF"); | throw new CorruptPowerPointFileException("Corrupt document - starts with record of type 0000 and length 0xFFFF"); | ||||
} | } | ||||
Record r = createRecordForType(type,b,pos,8+rleni); | Record r = createRecordForType(type,b,pos,8+rleni); | ||||
if(r != null) { | if(r != null) { | ||||
children.add(r); | children.add(r); | ||||
} else { | |||||
// Record was horribly corrupt | |||||
} | } | ||||
pos += 8; | pos += 8; | ||||
pos += rleni; | pos += rleni; | ||||
* passing in corrected lengths | * passing in corrected lengths | ||||
*/ | */ | ||||
public static Record createRecordForType(long type, byte[] b, int start, int len) { | public static Record createRecordForType(long type, byte[] b, int start, int len) { | ||||
Record toReturn = null; | |||||
// Handle case of a corrupt last record, whose claimed length | |||||
// would take us passed the end of the file | |||||
if(start + len > b.length) { | |||||
logger.log(POILogger.WARN, "Warning: Skipping record of type " + type + " at position " + start + " which claims to be longer than the file! (" + len + " vs " + (b.length-start) + ")"); | |||||
return null; | |||||
} | |||||
// We use the RecordTypes class to provide us with the right | // We use the RecordTypes class to provide us with the right | ||||
// class to use for a given type | // class to use for a given type | ||||
// A spot of reflection gets us the (byte[],int,int) constructor | // A spot of reflection gets us the (byte[],int,int) constructor | ||||
// From there, we instanciate the class | // From there, we instanciate the class | ||||
// Any special record handling occurs once we have the class | // Any special record handling occurs once we have the class | ||||
Class<? extends Record> c = null; | |||||
RecordConstructor c = RecordTypes.forTypeID((short)type).recordConstructor; | |||||
if (c == null) { | |||||
// How odd. RecordTypes normally substitutes in | |||||
// a default handler class if it has heard of the record | |||||
// type but there's no support for it. Explicitly request | |||||
// that now | |||||
c = RecordTypes.UnknownRecordPlaceholder.recordConstructor; | |||||
} | |||||
final Record toReturn; | |||||
try { | try { | ||||
c = RecordTypes.forTypeID((short)type).handlingClass; | |||||
if(c == null) { | |||||
// How odd. RecordTypes normally substitutes in | |||||
// a default handler class if it has heard of the record | |||||
// type but there's no support for it. Explicitly request | |||||
// that now | |||||
c = RecordTypes.UnknownRecordPlaceholder.handlingClass; | |||||
toReturn = c.apply(b, start, len); | |||||
} catch(RuntimeException e) { | |||||
// Handle case of a corrupt last record, whose claimed length | |||||
// would take us passed the end of the file | |||||
if(start + len > b.length ) { | |||||
logger.log(POILogger.WARN, "Warning: Skipping record of type " + type + " at position " + start + " which claims to be longer than the file! (" + len + " vs " + (b.length-start) + ")"); | |||||
return null; | |||||
} | } | ||||
// Grab the right constructor | |||||
java.lang.reflect.Constructor<? extends Record> con = c.getDeclaredConstructor(new Class[] { byte[].class, Integer.TYPE, Integer.TYPE }); | |||||
// Instantiate | |||||
toReturn = con.newInstance(new Object[] { b, start, len }); | |||||
} catch(InstantiationException ie) { | |||||
throw new HSLFException("Couldn't instantiate the class for type with id " + type + " on class " + c + " : " + ie, ie); | |||||
} catch(java.lang.reflect.InvocationTargetException ite) { | |||||
throw new HSLFException("Couldn't instantiate the class for type with id " + type + " on class " + c + " : " + ite + "\nCause was : " + ite.getCause(), ite); | |||||
} catch(IllegalAccessException iae) { | |||||
throw new HSLFException("Couldn't access the constructor for type with id " + type + " on class " + c + " : " + iae, iae); | |||||
} catch(NoSuchMethodException nsme) { | |||||
throw new HSLFException("Couldn't access the constructor for type with id " + type + " on class " + c + " : " + nsme, nsme); | |||||
throw new HSLFException("Couldn't instantiate the class for type with id " + type + " on class " + c + " : " + e, e); | |||||
} | } | ||||
// Handling for special kinds of records follow | // Handling for special kinds of records follow |
*/ | */ | ||||
public enum RecordTypes { | public enum RecordTypes { | ||||
Unknown(0,null), | Unknown(0,null), | ||||
UnknownRecordPlaceholder(-1, UnknownRecordPlaceholder.class), | |||||
Document(1000,Document.class), | |||||
DocumentAtom(1001,DocumentAtom.class), | |||||
UnknownRecordPlaceholder(-1, UnknownRecordPlaceholder::new), | |||||
Document(1000,Document::new), | |||||
DocumentAtom(1001,DocumentAtom::new), | |||||
EndDocument(1002,null), | EndDocument(1002,null), | ||||
Slide(1006,Slide.class), | |||||
SlideAtom(1007,SlideAtom.class), | |||||
Notes(1008,Notes.class), | |||||
NotesAtom(1009,NotesAtom.class), | |||||
Environment(1010,Environment.class), | |||||
SlidePersistAtom(1011,SlidePersistAtom.class), | |||||
Slide(1006,Slide::new), | |||||
SlideAtom(1007,SlideAtom::new), | |||||
Notes(1008,Notes::new), | |||||
NotesAtom(1009,NotesAtom::new), | |||||
Environment(1010,Environment::new), | |||||
SlidePersistAtom(1011,SlidePersistAtom::new), | |||||
SSlideLayoutAtom(1015,null), | SSlideLayoutAtom(1015,null), | ||||
MainMaster(1016,MainMaster.class), | |||||
SSSlideInfoAtom(1017,SSSlideInfoAtom.class), | |||||
MainMaster(1016,MainMaster::new), | |||||
SSSlideInfoAtom(1017,SSSlideInfoAtom::new), | |||||
SlideViewInfo(1018,null), | SlideViewInfo(1018,null), | ||||
GuideAtom(1019,null), | GuideAtom(1019,null), | ||||
ViewInfo(1020,null), | ViewInfo(1020,null), | ||||
ViewInfoAtom(1021,null), | ViewInfoAtom(1021,null), | ||||
SlideViewInfoAtom(1022,null), | SlideViewInfoAtom(1022,null), | ||||
VBAInfo(1023,VBAInfoContainer.class), | |||||
VBAInfoAtom(1024,VBAInfoAtom.class), | |||||
VBAInfo(1023,VBAInfoContainer::new), | |||||
VBAInfoAtom(1024,VBAInfoAtom::new), | |||||
SSDocInfoAtom(1025,null), | SSDocInfoAtom(1025,null), | ||||
Summary(1026,null), | Summary(1026,null), | ||||
DocRoutingSlip(1030,null), | DocRoutingSlip(1030,null), | ||||
OutlineViewInfo(1031,null), | OutlineViewInfo(1031,null), | ||||
SorterViewInfo(1032,null), | SorterViewInfo(1032,null), | ||||
ExObjList(1033,ExObjList.class), | |||||
ExObjListAtom(1034,ExObjListAtom.class), | |||||
PPDrawingGroup(1035,PPDrawingGroup.class), | |||||
PPDrawing(1036,PPDrawing.class), | |||||
ExObjList(1033,ExObjList::new), | |||||
ExObjListAtom(1034,ExObjListAtom::new), | |||||
PPDrawingGroup(1035,PPDrawingGroup::new), | |||||
PPDrawing(1036,PPDrawing::new), | |||||
NamedShows(1040,null), | NamedShows(1040,null), | ||||
NamedShow(1041,null), | NamedShow(1041,null), | ||||
NamedShowSlides(1042,null), | NamedShowSlides(1042,null), | ||||
SheetProperties(1044,null), | SheetProperties(1044,null), | ||||
RoundTripCustomTableStyles12Atom(1064,null), | RoundTripCustomTableStyles12Atom(1064,null), | ||||
List(2000,DocInfoListContainer.class), | |||||
FontCollection(2005,FontCollection.class), | |||||
List(2000,DocInfoListContainer::new), | |||||
FontCollection(2005,FontCollection::new), | |||||
BookmarkCollection(2019,null), | BookmarkCollection(2019,null), | ||||
SoundCollection(2020,SoundCollection.class), | |||||
SoundCollection(2020,SoundCollection::new), | |||||
SoundCollAtom(2021,null), | SoundCollAtom(2021,null), | ||||
Sound(2022,Sound.class), | |||||
SoundData(2023,SoundData.class), | |||||
Sound(2022,Sound::new), | |||||
SoundData(2023,SoundData::new), | |||||
BookmarkSeedAtom(2025,null), | BookmarkSeedAtom(2025,null), | ||||
ColorSchemeAtom(2032,ColorSchemeAtom.class), | |||||
ExObjRefAtom(3009,ExObjRefAtom.class), | |||||
OEPlaceholderAtom(3011,OEPlaceholderAtom.class), | |||||
ColorSchemeAtom(2032,ColorSchemeAtom::new), | |||||
ExObjRefAtom(3009,ExObjRefAtom::new), | |||||
OEPlaceholderAtom(3011,OEPlaceholderAtom::new), | |||||
GPopublicintAtom(3024,null), | GPopublicintAtom(3024,null), | ||||
GRatioAtom(3031,null), | GRatioAtom(3031,null), | ||||
OutlineTextRefAtom(3998,OutlineTextRefAtom.class), | |||||
TextHeaderAtom(3999,TextHeaderAtom.class), | |||||
TextCharsAtom(4000,TextCharsAtom.class), | |||||
StyleTextPropAtom(4001, StyleTextPropAtom.class),//0x0fa1 RT_StyleTextPropAtom | |||||
MasterTextPropAtom(4002, MasterTextPropAtom.class), | |||||
TxMasterStyleAtom(4003,TxMasterStyleAtom.class), | |||||
OutlineTextRefAtom(3998,OutlineTextRefAtom::new), | |||||
TextHeaderAtom(3999,TextHeaderAtom::new), | |||||
TextCharsAtom(4000,TextCharsAtom::new), | |||||
StyleTextPropAtom(4001, StyleTextPropAtom::new),//0x0fa1 RT_StyleTextPropAtom | |||||
MasterTextPropAtom(4002, MasterTextPropAtom::new), | |||||
TxMasterStyleAtom(4003,TxMasterStyleAtom::new), | |||||
TxCFStyleAtom(4004,null), | TxCFStyleAtom(4004,null), | ||||
TxPFStyleAtom(4005,null), | TxPFStyleAtom(4005,null), | ||||
TextRulerAtom(4006,TextRulerAtom.class), | |||||
TextRulerAtom(4006,TextRulerAtom::new), | |||||
TextBookmarkAtom(4007,null), | TextBookmarkAtom(4007,null), | ||||
TextBytesAtom(4008,TextBytesAtom.class), | |||||
TextBytesAtom(4008,TextBytesAtom::new), | |||||
TxSIStyleAtom(4009,null), | TxSIStyleAtom(4009,null), | ||||
TextSpecInfoAtom(4010, TextSpecInfoAtom.class), | |||||
TextSpecInfoAtom(4010, TextSpecInfoAtom::new), | |||||
DefaultRulerAtom(4011,null), | DefaultRulerAtom(4011,null), | ||||
StyleTextProp9Atom(4012, StyleTextProp9Atom.class), //0x0FAC RT_StyleTextProp9Atom | |||||
FontEntityAtom(4023,FontEntityAtom.class), | |||||
StyleTextProp9Atom(4012, StyleTextProp9Atom::new), //0x0FAC RT_StyleTextProp9Atom | |||||
FontEntityAtom(4023,FontEntityAtom::new), | |||||
FontEmbeddedData(4024,null), | FontEmbeddedData(4024,null), | ||||
CString(4026,CString.class), | |||||
CString(4026,CString::new), | |||||
MetaFile(4033,null), | MetaFile(4033,null), | ||||
ExOleObjAtom(4035,ExOleObjAtom.class), | |||||
ExOleObjAtom(4035,ExOleObjAtom::new), | |||||
SrKinsoku(4040,null), | SrKinsoku(4040,null), | ||||
HandOut(4041,DummyPositionSensitiveRecordWithChildren.class), | |||||
ExEmbed(4044,ExEmbed.class), | |||||
ExEmbedAtom(4045,ExEmbedAtom.class), | |||||
HandOut(4041,DummyPositionSensitiveRecordWithChildren::new), | |||||
ExEmbed(4044,ExEmbed::new), | |||||
ExEmbedAtom(4045,ExEmbedAtom::new), | |||||
ExLink(4046,null), | ExLink(4046,null), | ||||
BookmarkEntityAtom(4048,null), | BookmarkEntityAtom(4048,null), | ||||
ExLinkAtom(4049,null), | ExLinkAtom(4049,null), | ||||
SrKinsokuAtom(4050,null), | SrKinsokuAtom(4050,null), | ||||
ExHyperlinkAtom(4051,ExHyperlinkAtom.class), | |||||
ExHyperlink(4055,ExHyperlink.class), | |||||
ExHyperlinkAtom(4051,ExHyperlinkAtom::new), | |||||
ExHyperlink(4055,ExHyperlink::new), | |||||
SlideNumberMCAtom(4056,null), | SlideNumberMCAtom(4056,null), | ||||
HeadersFooters(4057,HeadersFootersContainer.class), | |||||
HeadersFootersAtom(4058,HeadersFootersAtom.class), | |||||
TxInteractiveInfoAtom(4063,TxInteractiveInfoAtom.class), | |||||
HeadersFooters(4057,HeadersFootersContainer::new), | |||||
HeadersFootersAtom(4058,HeadersFootersAtom::new), | |||||
TxInteractiveInfoAtom(4063,TxInteractiveInfoAtom::new), | |||||
CharFormatAtom(4066,null), | CharFormatAtom(4066,null), | ||||
ParaFormatAtom(4067,null), | ParaFormatAtom(4067,null), | ||||
RecolorInfoAtom(4071,null), | RecolorInfoAtom(4071,null), | ||||
ExQuickTimeMovie(4074,null), | ExQuickTimeMovie(4074,null), | ||||
ExQuickTimeMovieData(4075,null), | ExQuickTimeMovieData(4075,null), | ||||
ExControl(4078,ExControl.class), | |||||
SlideListWithText(4080,SlideListWithText.class), | |||||
InteractiveInfo(4082,InteractiveInfo.class), | |||||
InteractiveInfoAtom(4083,InteractiveInfoAtom.class), | |||||
UserEditAtom(4085,UserEditAtom.class), | |||||
ExControl(4078,ExControl::new), | |||||
SlideListWithText(4080,SlideListWithText::new), | |||||
InteractiveInfo(4082,InteractiveInfo::new), | |||||
InteractiveInfoAtom(4083,InteractiveInfoAtom::new), | |||||
UserEditAtom(4085,UserEditAtom::new), | |||||
CurrentUserAtom(4086,null), | CurrentUserAtom(4086,null), | ||||
DateTimeMCAtom(4087,null), | DateTimeMCAtom(4087,null), | ||||
GenericDateMCAtom(4088,null), | GenericDateMCAtom(4088,null), | ||||
FooterMCAtom(4090,null), | FooterMCAtom(4090,null), | ||||
ExControlAtom(4091,ExControlAtom.class), | |||||
ExMediaAtom(4100,ExMediaAtom.class), | |||||
ExVideoContainer(4101,ExVideoContainer.class), | |||||
ExAviMovie(4102,ExAviMovie.class), | |||||
ExMCIMovie(4103,ExMCIMovie.class), | |||||
ExControlAtom(4091,ExControlAtom::new), | |||||
ExMediaAtom(4100,ExMediaAtom::new), | |||||
ExVideoContainer(4101,ExVideoContainer::new), | |||||
ExAviMovie(4102,ExAviMovie::new), | |||||
ExMCIMovie(4103,ExMCIMovie::new), | |||||
ExMIDIAudio(4109,null), | ExMIDIAudio(4109,null), | ||||
ExCDAudio(4110,null), | ExCDAudio(4110,null), | ||||
ExWAVAudioEmbedded(4111,null), | ExWAVAudioEmbedded(4111,null), | ||||
ExWAVAudioLink(4112,null), | ExWAVAudioLink(4112,null), | ||||
ExOleObjStg(4113,ExOleObjStg.class), | |||||
ExOleObjStg(4113,ExOleObjStg::new), | |||||
ExCDAudioAtom(4114,null), | ExCDAudioAtom(4114,null), | ||||
ExWAVAudioEmbeddedAtom(4115,null), | ExWAVAudioEmbeddedAtom(4115,null), | ||||
AnimationInfo(4116,AnimationInfo.class), | |||||
AnimationInfoAtom(4081,AnimationInfoAtom.class), | |||||
AnimationInfo(4116,AnimationInfo::new), | |||||
AnimationInfoAtom(4081,AnimationInfoAtom::new), | |||||
RTFDateTimeMCAtom(4117,null), | RTFDateTimeMCAtom(4117,null), | ||||
ProgTags(5000,DummyPositionSensitiveRecordWithChildren.class), | |||||
ProgTags(5000,DummyPositionSensitiveRecordWithChildren::new), | |||||
ProgStringTag(5001,null), | ProgStringTag(5001,null), | ||||
ProgBinaryTag(5002,DummyPositionSensitiveRecordWithChildren.class), | |||||
BinaryTagData(5003, BinaryTagDataBlob.class),//0x138b RT_BinaryTagDataBlob | |||||
ProgBinaryTag(5002,DummyPositionSensitiveRecordWithChildren::new), | |||||
BinaryTagData(5003, BinaryTagDataBlob::new),//0x138b RT_BinaryTagDataBlob | |||||
PrpublicintOptions(6000,null), | PrpublicintOptions(6000,null), | ||||
PersistPtrFullBlock(6001,PersistPtrHolder.class), | |||||
PersistPtrIncrementalBlock(6002,PersistPtrHolder.class), | |||||
PersistPtrFullBlock(6001,PersistPtrHolder::new), | |||||
PersistPtrIncrementalBlock(6002,PersistPtrHolder::new), | |||||
GScalingAtom(10001,null), | GScalingAtom(10001,null), | ||||
GRColorAtom(10002,null), | GRColorAtom(10002,null), | ||||
// Records ~12000 seem to be related to the Comments used in PPT 2000/XP | // Records ~12000 seem to be related to the Comments used in PPT 2000/XP | ||||
// (Comments in PPT97 are normal Escher text boxes) | // (Comments in PPT97 are normal Escher text boxes) | ||||
Comment2000(12000,Comment2000.class), | |||||
Comment2000Atom(12001,Comment2000Atom.class), | |||||
Comment2000(12000,Comment2000::new), | |||||
Comment2000Atom(12001,Comment2000Atom::new), | |||||
Comment2000Summary(12004,null), | Comment2000Summary(12004,null), | ||||
Comment2000SummaryAtom(12005,null), | Comment2000SummaryAtom(12005,null), | ||||
// Records ~12050 seem to be related to Document Encryption | // Records ~12050 seem to be related to Document Encryption | ||||
DocumentEncryptionAtom(12052,DocumentEncryptionAtom.class), | |||||
DocumentEncryptionAtom(12052,DocumentEncryptionAtom::new), | |||||
OriginalMainMasterId(1052,null), | OriginalMainMasterId(1052,null), | ||||
CompositeMasterId(1052,null), | CompositeMasterId(1052,null), | ||||
RoundTripContentMasterInfo12(1054,null), | RoundTripContentMasterInfo12(1054,null), | ||||
RoundTripShapeId12(1055,null), | RoundTripShapeId12(1055,null), | ||||
RoundTripHFPlaceholder12(1056,RoundTripHFPlaceholder12.class), | |||||
RoundTripHFPlaceholder12(1056,RoundTripHFPlaceholder12::new), | |||||
RoundTripContentMasterId(1058,null), | RoundTripContentMasterId(1058,null), | ||||
RoundTripOArtTextStyles12(1059,null), | RoundTripOArtTextStyles12(1059,null), | ||||
RoundTripShapeCheckSumForCustomLayouts12(1062,null), | RoundTripShapeCheckSumForCustomLayouts12(1062,null), | ||||
// same as EscherTertiaryOptRecord.RECORD_ID | // same as EscherTertiaryOptRecord.RECORD_ID | ||||
EscherUserDefined(0xf122,null); | EscherUserDefined(0xf122,null); | ||||
@FunctionalInterface | |||||
public interface RecordConstructor<T extends Record> { | |||||
T apply(byte[] source, int start, int len); | |||||
} | |||||
private static final Map<Short,RecordTypes> LOOKUP; | private static final Map<Short,RecordTypes> LOOKUP; | ||||
static { | static { | ||||
} | } | ||||
public final short typeID; | public final short typeID; | ||||
public final Class<? extends Record> handlingClass; | |||||
public final RecordConstructor recordConstructor; | |||||
private RecordTypes(int typeID, Class<? extends Record> handlingClass) { | |||||
RecordTypes(int typeID, RecordConstructor recordConstructor) { | |||||
this.typeID = (short)typeID; | this.typeID = (short)typeID; | ||||
this.handlingClass = handlingClass; | |||||
this.recordConstructor = recordConstructor; | |||||
} | } | ||||
public static RecordTypes forTypeID(int typeID) { | public static RecordTypes forTypeID(int typeID) { | ||||
RecordTypes rt = LOOKUP.get((short)typeID); | RecordTypes rt = LOOKUP.get((short)typeID); | ||||
return (rt != null) ? rt : UnknownRecordPlaceholder; | return (rt != null) ? rt : UnknownRecordPlaceholder; | ||||
} | } | ||||
/** | |||||
* Returns name of the record by its type | |||||
* | |||||
* @param type section of the record header | |||||
* @return name of the record | |||||
*/ | |||||
// public static String recordName(int type) { | |||||
// String name = typeToName.get(Integer.valueOf(type)); | |||||
// return (name == null) ? ("Unknown" + type) : name; | |||||
// } | |||||
/** | |||||
* Returns the class handling a record by its type. | |||||
* If given an un-handled PowerPoint record, will return a dummy | |||||
* placeholder class. If given an unknown PowerPoint record, or | |||||
* and Escher record, will return null. | |||||
* | |||||
* @param type section of the record header | |||||
* @return class to handle the record, or null if an unknown (eg Escher) record | |||||
*/ | |||||
// public static Class<? extends Record> recordHandlingClass(int type) { | |||||
// Class<? extends Record> c = typeToClass.get(Integer.valueOf(type)); | |||||
// return c; | |||||
// } | |||||
// | |||||
// static { | |||||
// typeToName = new HashMap<Integer,String>(); | |||||
// typeToClass = new HashMap<Integer,Class<? extends Record>>(); | |||||
// try { | |||||
// Field[] f = RecordTypes.class.getFields(); | |||||
// for (int i = 0; i < f.length; i++){ | |||||
// Object val = f[i].get(null); | |||||
// | |||||
// // Escher record, only store ID -> Name | |||||
// if (val instanceof Integer) { | |||||
// typeToName.put((Integer)val, f[i].getName()); | |||||
// } | |||||
// // PowerPoint record, store ID -> Name and ID -> Class | |||||
// if (val instanceof Type) { | |||||
// Type t = (Type)val; | |||||
// Class<? extends Record> c = t.handlingClass; | |||||
// Integer id = Integer.valueOf(t.typeID); | |||||
// if(c == null) { c = UnknownRecordPlaceholder.class; } | |||||
// | |||||
// typeToName.put(id, f[i].getName()); | |||||
// typeToClass.put(id, c); | |||||
// } | |||||
// } | |||||
// } catch (IllegalAccessException e){ | |||||
// throw new HSLFException("Failed to initialize records types"); | |||||
// } | |||||
// } | |||||
/** | |||||
* Wrapper for the details of a PowerPoint or Escher record type. | |||||
* Contains both the type, and the handling class (if any), and | |||||
* offers methods to get either back out. | |||||
*/ | |||||
// public static class Type { | |||||
// public final int typeID; | |||||
// public final Class<? extends Record> handlingClass; | |||||
// public Type(int typeID, Class<? extends Record> handlingClass) { | |||||
// this.typeID = typeID; | |||||
// this.handlingClass = handlingClass; | |||||
// } | |||||
// } | |||||
} | } |
/* ==================================================================== | |||||
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.usermodel; | |||||
import org.apache.poi.hslf.record.Comment2000; | |||||
import org.apache.poi.sl.usermodel.Comment; | |||||
import org.apache.poi.util.Units; | |||||
import java.awt.geom.Point2D; | |||||
import java.util.Date; | |||||
public final class HSLFComment implements Comment { | |||||
private Comment2000 _comment2000; | |||||
public HSLFComment(Comment2000 comment2000) { | |||||
_comment2000 = comment2000; | |||||
} | |||||
protected Comment2000 getComment2000() { | |||||
return _comment2000; | |||||
} | |||||
/** | |||||
* Get the Author of this comment | |||||
*/ | |||||
public String getAuthor() { | |||||
return _comment2000.getAuthor(); | |||||
} | |||||
/** | |||||
* Set the Author of this comment | |||||
*/ | |||||
public void setAuthor(String author) { | |||||
_comment2000.setAuthor(author); | |||||
} | |||||
/** | |||||
* Get the Author's Initials of this comment | |||||
*/ | |||||
public String getAuthorInitials() { | |||||
return _comment2000.getAuthorInitials(); | |||||
} | |||||
/** | |||||
* Set the Author's Initials of this comment | |||||
*/ | |||||
public void setAuthorInitials(String initials) { | |||||
_comment2000.setAuthorInitials(initials); | |||||
} | |||||
/** | |||||
* Get the text of this comment | |||||
*/ | |||||
public String getText() { | |||||
return _comment2000.getText(); | |||||
} | |||||
/** | |||||
* Set the text of this comment | |||||
*/ | |||||
public void setText(String text) { | |||||
_comment2000.setText(text); | |||||
} | |||||
@Override | |||||
public Date getDate() { | |||||
return _comment2000.getComment2000Atom().getDate(); | |||||
} | |||||
@Override | |||||
public void setDate(Date date) { | |||||
_comment2000.getComment2000Atom().setDate(date); | |||||
} | |||||
@Override | |||||
public Point2D getOffset() { | |||||
final double x = Units.masterToPoints(_comment2000.getComment2000Atom().getXOffset()); | |||||
final double y = Units.masterToPoints(_comment2000.getComment2000Atom().getYOffset()); | |||||
return new Point2D.Double(x, y); | |||||
} | |||||
@Override | |||||
public void setOffset(Point2D offset) { | |||||
final int x = Units.pointsToMaster(offset.getX()); | |||||
final int y = Units.pointsToMaster(offset.getY()); | |||||
_comment2000.getComment2000Atom().setXOffset(x); | |||||
_comment2000.getComment2000Atom().setYOffset(y); | |||||
} | |||||
} |
import org.apache.poi.hslf.record.SheetContainer; | import org.apache.poi.hslf.record.SheetContainer; | ||||
import org.apache.poi.hslf.record.TextHeaderAtom; | import org.apache.poi.hslf.record.TextHeaderAtom; | ||||
import org.apache.poi.sl.usermodel.MasterSheet; | import org.apache.poi.sl.usermodel.MasterSheet; | ||||
import org.apache.poi.sl.usermodel.SimpleShape; | |||||
import org.apache.poi.util.Removal; | |||||
/** | /** | ||||
* The superclass of all master sheets - Slide masters, Notes masters, etc. | * The superclass of all master sheets - Slide masters, Notes masters, etc. | ||||
* | * | ||||
* | * | ||||
* @return true if the shape is a placeholder | * @return true if the shape is a placeholder | ||||
* | |||||
* @deprecated use {@link SimpleShape#isPlaceholder()} | |||||
*/ | */ | ||||
@Deprecated | |||||
@Removal(version="4.1.0") | |||||
public static boolean isPlaceholder(HSLFShape shape){ | public static boolean isPlaceholder(HSLFShape shape){ | ||||
if(!(shape instanceof HSLFTextShape)) return false; | |||||
HSLFTextShape tx = (HSLFTextShape)shape; | |||||
return tx.getPlaceholderAtom() != null; | |||||
return shape instanceof SimpleShape | |||||
&& ((SimpleShape<?,?>)shape).isPlaceholder(); | |||||
} | } | ||||
} | } |
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.List; | import java.util.List; | ||||
import org.apache.poi.hslf.model.HeadersFooters; | |||||
import org.apache.poi.hslf.record.HeadersFootersContainer; | |||||
import org.apache.poi.sl.usermodel.Notes; | import org.apache.poi.sl.usermodel.Notes; | ||||
import org.apache.poi.sl.usermodel.Placeholder; | |||||
import org.apache.poi.util.POILogFactory; | import org.apache.poi.util.POILogFactory; | ||||
import org.apache.poi.util.POILogger; | import org.apache.poi.util.POILogger; | ||||
public HSLFMasterSheet getMasterSheet() { | public HSLFMasterSheet getMasterSheet() { | ||||
return null; | return null; | ||||
} | } | ||||
/** | |||||
* Header / Footer settings for this slide. | |||||
* | |||||
* @return Header / Footer settings for this slide | |||||
*/ | |||||
@Override | |||||
public HeadersFooters getHeadersFooters() { | |||||
return new HeadersFooters(this, HeadersFootersContainer.NotesHeadersFootersContainer); | |||||
} | |||||
@Override | |||||
public HSLFPlaceholderDetails getPlaceholderDetails(Placeholder placeholder) { | |||||
if (placeholder == null) { | |||||
return null; | |||||
} | |||||
if (placeholder == Placeholder.HEADER || placeholder == Placeholder.FOOTER) { | |||||
return new HSLFPlaceholderDetails(this, placeholder); | |||||
} else { | |||||
return super.getPlaceholderDetails(placeholder); | |||||
} | |||||
} | |||||
} | } |
/* ==================================================================== | |||||
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.usermodel; | |||||
import org.apache.poi.hslf.model.HeadersFooters; | |||||
import org.apache.poi.sl.usermodel.Placeholder; | |||||
import org.apache.poi.sl.usermodel.PlaceholderDetails; | |||||
/** | |||||
* Extended placeholder details for HSLF sheets - mainly for headers and footers | |||||
* | |||||
* @since POI 4.0.0 | |||||
*/ | |||||
public class HSLFPlaceholderDetails implements PlaceholderDetails { | |||||
private final HSLFSheet sheet; | |||||
private final Placeholder placeholder; | |||||
HSLFPlaceholderDetails(final HSLFSheet sheet, final Placeholder placeholder) { | |||||
this.sheet = sheet; | |||||
this.placeholder = placeholder; | |||||
} | |||||
public boolean isVisible() { | |||||
final Placeholder ph = getPlaceholder(); | |||||
if (ph == null) { | |||||
return false; | |||||
} | |||||
final HeadersFooters headersFooters = sheet.getHeadersFooters(); | |||||
switch (ph) { | |||||
case HEADER: | |||||
return headersFooters.isHeaderVisible(); | |||||
case FOOTER: | |||||
return headersFooters.isFooterVisible(); | |||||
case DATETIME: | |||||
return headersFooters.isDateTimeVisible(); | |||||
case TITLE: | |||||
return headersFooters.isHeaderVisible(); | |||||
case SLIDE_NUMBER: | |||||
return headersFooters.isSlideNumberVisible(); | |||||
default: | |||||
return false; | |||||
} | |||||
} | |||||
public void setVisible(final boolean isVisible) { | |||||
final Placeholder ph = getPlaceholder(); | |||||
if (ph == null) { | |||||
return; | |||||
} | |||||
final HeadersFooters headersFooters = sheet.getHeadersFooters(); | |||||
switch (ph) { | |||||
case TITLE: | |||||
case HEADER: | |||||
headersFooters.setHeaderVisible(isVisible); | |||||
break; | |||||
case FOOTER: | |||||
headersFooters.setFooterVisible(isVisible); | |||||
break; | |||||
case DATETIME: | |||||
headersFooters.setDateTimeVisible(isVisible); | |||||
break; | |||||
case SLIDE_NUMBER: | |||||
headersFooters.setSlideNumberVisible(isVisible); | |||||
break; | |||||
} | |||||
} | |||||
@Override | |||||
public Placeholder getPlaceholder() { | |||||
return placeholder; | |||||
} | |||||
@Override | |||||
public void setPlaceholder(Placeholder placeholder) { | |||||
throw new UnsupportedOperationException("Only sub class(es) of HSLFPlaceholderDetails allow setting the placeholder"); | |||||
} | |||||
@Override | |||||
public PlaceholderSize getSize() { | |||||
return PlaceholderSize.full; | |||||
} | |||||
@Override | |||||
public void setSize(PlaceholderSize size) { | |||||
throw new UnsupportedOperationException("Only sub class(es) of HSLFPlaceholderDetails allow setting the size"); | |||||
} | |||||
@Override | |||||
public String getText() { | |||||
final Placeholder ph = getPlaceholder(); | |||||
if (ph == null) { | |||||
return null; | |||||
} | |||||
final HeadersFooters headersFooters = sheet.getHeadersFooters(); | |||||
switch (ph) { | |||||
case TITLE: | |||||
case HEADER: | |||||
return headersFooters.getHeaderText(); | |||||
case FOOTER: | |||||
return headersFooters.getFooterText(); | |||||
case DATETIME: | |||||
return headersFooters.getDateTimeText(); | |||||
case SLIDE_NUMBER: | |||||
default: | |||||
return null; | |||||
} | |||||
} | |||||
@Override | |||||
public void setText(final String text) { | |||||
final Placeholder ph = getPlaceholder(); | |||||
if (ph == null) { | |||||
return; | |||||
} | |||||
final HeadersFooters headersFooters = sheet.getHeadersFooters(); | |||||
switch (ph) { | |||||
case TITLE: | |||||
case HEADER: | |||||
headersFooters.setHeaderText(text); | |||||
break; | |||||
case FOOTER: | |||||
headersFooters.setFootersText(text); | |||||
break; | |||||
case DATETIME: | |||||
headersFooters.setDateTimeText(text); | |||||
break; | |||||
case SLIDE_NUMBER: | |||||
default: | |||||
break; | |||||
} | |||||
} | |||||
} |
/* ==================================================================== | |||||
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.usermodel; | |||||
import org.apache.poi.ddf.EscherProperties; | |||||
import org.apache.poi.ddf.EscherSpRecord; | |||||
import org.apache.poi.hslf.exceptions.HSLFException; | |||||
import org.apache.poi.hslf.record.HSLFEscherClientDataRecord; | |||||
import org.apache.poi.hslf.record.OEPlaceholderAtom; | |||||
import org.apache.poi.hslf.record.Record; | |||||
import org.apache.poi.hslf.record.RoundTripHFPlaceholder12; | |||||
import org.apache.poi.sl.usermodel.MasterSheet; | |||||
import org.apache.poi.sl.usermodel.Placeholder; | |||||
/** | |||||
* Extended placeholder details for HSLF shapes | |||||
* | |||||
* @since POI 4.0.0 | |||||
*/ | |||||
public class HSLFShapePlaceholderDetails extends HSLFPlaceholderDetails { | |||||
private enum PlaceholderContainer { | |||||
slide, master, notes, notesMaster | |||||
} | |||||
private final PlaceholderContainer source; | |||||
final HSLFSimpleShape shape; | |||||
private OEPlaceholderAtom oePlaceholderAtom; | |||||
private RoundTripHFPlaceholder12 roundTripHFPlaceholder12; | |||||
HSLFShapePlaceholderDetails(final HSLFSimpleShape shape) { | |||||
super(shape.getSheet(), null); | |||||
this.shape = shape; | |||||
final HSLFSheet sheet = shape.getSheet(); | |||||
if (sheet instanceof HSLFSlideMaster) { | |||||
source = PlaceholderContainer.master; | |||||
} else if (sheet instanceof HSLFNotes) { | |||||
source = PlaceholderContainer.notes; | |||||
} else if (sheet instanceof MasterSheet) { | |||||
// notes master aren't yet supported ... | |||||
source = PlaceholderContainer.notesMaster; | |||||
} else { | |||||
source = PlaceholderContainer.slide; | |||||
} | |||||
} | |||||
public Placeholder getPlaceholder() { | |||||
updatePlaceholderAtom(false); | |||||
final int phId; | |||||
if (oePlaceholderAtom != null) { | |||||
phId = oePlaceholderAtom.getPlaceholderId(); | |||||
} else if (roundTripHFPlaceholder12 != null) { | |||||
phId = roundTripHFPlaceholder12.getPlaceholderId(); | |||||
} else { | |||||
return null; | |||||
} | |||||
switch (source) { | |||||
case slide: | |||||
return Placeholder.lookupNativeSlide(phId); | |||||
default: | |||||
case master: | |||||
return Placeholder.lookupNativeSlideMaster(phId); | |||||
case notes: | |||||
return Placeholder.lookupNativeNotes(phId); | |||||
case notesMaster: | |||||
return Placeholder.lookupNativeNotesMaster(phId); | |||||
} | |||||
} | |||||
public void setPlaceholder(final Placeholder placeholder) { | |||||
final EscherSpRecord spRecord = shape.getEscherChild(EscherSpRecord.RECORD_ID); | |||||
int flags = spRecord.getFlags(); | |||||
if (placeholder == null) { | |||||
flags ^= EscherSpRecord.FLAG_HAVEMASTER; | |||||
} else { | |||||
flags |= EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HAVEMASTER; | |||||
} | |||||
spRecord.setFlags(flags); | |||||
// Placeholders can't be grouped | |||||
shape.setEscherProperty(EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, (placeholder == null ? -1 : 262144)); | |||||
if (placeholder == null) { | |||||
removePlaceholder(); | |||||
return; | |||||
} | |||||
// init client data | |||||
updatePlaceholderAtom(true); | |||||
final byte phId = getPlaceholderId(placeholder); | |||||
oePlaceholderAtom.setPlaceholderId(phId); | |||||
roundTripHFPlaceholder12.setPlaceholderId(phId); | |||||
} | |||||
public PlaceholderSize getSize() { | |||||
final Placeholder ph = getPlaceholder(); | |||||
if (ph == null) { | |||||
return null; | |||||
} | |||||
final int size = (oePlaceholderAtom != null) | |||||
? oePlaceholderAtom.getPlaceholderSize() | |||||
: OEPlaceholderAtom.PLACEHOLDER_HALFSIZE; | |||||
switch (size) { | |||||
case OEPlaceholderAtom.PLACEHOLDER_FULLSIZE: | |||||
return PlaceholderSize.full; | |||||
default: | |||||
case OEPlaceholderAtom.PLACEHOLDER_HALFSIZE: | |||||
return PlaceholderSize.half; | |||||
case OEPlaceholderAtom.PLACEHOLDER_QUARTSIZE: | |||||
return PlaceholderSize.quarter; | |||||
} | |||||
} | |||||
public void setSize(final PlaceholderSize size) { | |||||
final Placeholder ph = getPlaceholder(); | |||||
if (ph == null || size == null) { | |||||
return; | |||||
} | |||||
updatePlaceholderAtom(true); | |||||
final byte ph_size; | |||||
switch (size) { | |||||
case full: | |||||
ph_size = OEPlaceholderAtom.PLACEHOLDER_FULLSIZE; | |||||
break; | |||||
default: | |||||
case half: | |||||
ph_size = OEPlaceholderAtom.PLACEHOLDER_HALFSIZE; | |||||
break; | |||||
case quarter: | |||||
ph_size = OEPlaceholderAtom.PLACEHOLDER_QUARTSIZE; | |||||
break; | |||||
} | |||||
oePlaceholderAtom.setPlaceholderSize(ph_size); | |||||
} | |||||
private byte getPlaceholderId(final Placeholder placeholder) { | |||||
/* | |||||
* Extract from MSDN: | |||||
* | |||||
* There is a special case when the placeholder does not have a position in the layout. | |||||
* This occurs when the user has moved the placeholder from its original position. | |||||
* In this case the placeholder ID is -1. | |||||
*/ | |||||
final byte phId; | |||||
switch (source) { | |||||
default: | |||||
case slide: | |||||
phId = (byte)placeholder.nativeSlideId; | |||||
break; | |||||
case master: | |||||
phId = (byte)placeholder.nativeSlideMasterId; | |||||
break; | |||||
case notes: | |||||
phId = (byte)placeholder.nativeNotesId; | |||||
break; | |||||
case notesMaster: | |||||
phId = (byte)placeholder.nativeNotesMasterId; | |||||
break; | |||||
} | |||||
if (phId == -2) { | |||||
throw new HSLFException("Placeholder "+placeholder.name()+" not supported for this sheet type ("+shape.getSheet().getClass()+")"); | |||||
} | |||||
return phId; | |||||
} | |||||
private void removePlaceholder() { | |||||
final HSLFEscherClientDataRecord clientData = shape.getClientData(false); | |||||
if (clientData != null) { | |||||
clientData.removeChild(OEPlaceholderAtom.class); | |||||
clientData.removeChild(RoundTripHFPlaceholder12.class); | |||||
// remove client data if the placeholder was the only child to be carried | |||||
if (clientData.getChildRecords().isEmpty()) { | |||||
shape.getSpContainer().removeChildRecord(clientData); | |||||
} | |||||
} | |||||
oePlaceholderAtom = null; | |||||
roundTripHFPlaceholder12 = null; | |||||
} | |||||
private void updatePlaceholderAtom(final boolean create) { | |||||
final HSLFEscherClientDataRecord clientData = shape.getClientData(create); | |||||
if (clientData == null) { | |||||
oePlaceholderAtom = null; | |||||
roundTripHFPlaceholder12 = null; | |||||
if (!create) { | |||||
return; | |||||
} | |||||
throw new HSLFException("Placeholder aren't allowed for shape type: " + shape.getClass().getSimpleName()); | |||||
} | |||||
for (Record r : clientData.getHSLFChildRecords()) { | |||||
if (r instanceof OEPlaceholderAtom) { | |||||
oePlaceholderAtom = (OEPlaceholderAtom)r; | |||||
} else if (r instanceof RoundTripHFPlaceholder12) { | |||||
//special case for files saved in Office 2007 | |||||
roundTripHFPlaceholder12 = (RoundTripHFPlaceholder12)r; | |||||
} | |||||
} | |||||
if (!create) { | |||||
return; | |||||
} | |||||
if (oePlaceholderAtom == null) { | |||||
oePlaceholderAtom = new OEPlaceholderAtom(); | |||||
oePlaceholderAtom.setPlaceholderSize((byte)OEPlaceholderAtom.PLACEHOLDER_FULLSIZE); | |||||
// TODO: placement id only "SHOULD" be unique ... check other placeholders on sheet for unique id | |||||
oePlaceholderAtom.setPlacementId(-1); | |||||
clientData.addChild(oePlaceholderAtom); | |||||
} | |||||
if (roundTripHFPlaceholder12 == null) { | |||||
roundTripHFPlaceholder12 = new RoundTripHFPlaceholder12(); | |||||
clientData.addChild(roundTripHFPlaceholder12); | |||||
} | |||||
} | |||||
} |
import org.apache.poi.ddf.EscherDggRecord; | import org.apache.poi.ddf.EscherDggRecord; | ||||
import org.apache.poi.ddf.EscherRecord; | 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.model.HeadersFooters; | |||||
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.HeadersFootersContainer; | |||||
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; | ||||
addShape(s); | addShape(s); | ||||
return s; | return s; | ||||
} | } | ||||
/** | |||||
* Header / Footer settings for this slide. | |||||
* | |||||
* @return Header / Footer settings for this slide | |||||
*/ | |||||
public HeadersFooters getHeadersFooters() { | |||||
return new HeadersFooters(this, HeadersFootersContainer.SlideHeadersFootersContainer); | |||||
} | |||||
@Override | |||||
public HSLFPlaceholderDetails getPlaceholderDetails(Placeholder placeholder) { | |||||
final HSLFSimpleShape ph = getPlaceholder(placeholder); | |||||
return (ph == null) ? null : new HSLFShapePlaceholderDetails(ph); | |||||
} | |||||
} | } |
package org.apache.poi.hslf.usermodel; | package org.apache.poi.hslf.usermodel; | ||||
import java.awt.Color; | import java.awt.Color; | ||||
import java.util.List; | |||||
import org.apache.poi.ddf.AbstractEscherOptRecord; | import org.apache.poi.ddf.AbstractEscherOptRecord; | ||||
import org.apache.poi.ddf.EscherChildAnchorRecord; | import org.apache.poi.ddf.EscherChildAnchorRecord; | ||||
import org.apache.poi.ddf.EscherSimpleProperty; | import org.apache.poi.ddf.EscherSimpleProperty; | ||||
import org.apache.poi.ddf.EscherSpRecord; | import org.apache.poi.ddf.EscherSpRecord; | ||||
import org.apache.poi.hslf.exceptions.HSLFException; | import org.apache.poi.hslf.exceptions.HSLFException; | ||||
import org.apache.poi.hslf.record.HSLFEscherClientDataRecord; | |||||
import org.apache.poi.hslf.record.OEPlaceholderAtom; | |||||
import org.apache.poi.hslf.record.Record; | |||||
import org.apache.poi.hslf.record.RoundTripHFPlaceholder12; | |||||
import org.apache.poi.sl.draw.DrawPaint; | import org.apache.poi.sl.draw.DrawPaint; | ||||
import org.apache.poi.sl.draw.geom.CustomGeometry; | import org.apache.poi.sl.draw.geom.CustomGeometry; | ||||
import org.apache.poi.sl.draw.geom.Guide; | import org.apache.poi.sl.draw.geom.Guide; | ||||
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; | ||||
}; | }; | ||||
} | } | ||||
@Override | |||||
public HSLFShapePlaceholderDetails getPlaceholderDetails() { | |||||
return new HSLFShapePlaceholderDetails(this); | |||||
} | |||||
@Override | @Override | ||||
public Placeholder getPlaceholder() { | public Placeholder getPlaceholder() { | ||||
List<? extends Record> clRecords = getClientRecords(); | |||||
if (clRecords == 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) { | |||||
int phId; | |||||
if (r instanceof OEPlaceholderAtom) { | |||||
phId = ((OEPlaceholderAtom)r).getPlaceholderId(); | |||||
} else if (r instanceof RoundTripHFPlaceholder12) { | |||||
//special case for files saved in Office 2007 | |||||
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); | |||||
} | |||||
} | |||||
return null; | |||||
return getPlaceholderDetails().getPlaceholder(); | |||||
} | } | ||||
@Override | @Override | ||||
public void setPlaceholder(Placeholder placeholder) { | public void setPlaceholder(Placeholder placeholder) { | ||||
EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID); | |||||
int flags = spRecord.getFlags(); | |||||
if (placeholder == null) { | |||||
flags ^= EscherSpRecord.FLAG_HAVEMASTER; | |||||
} else { | |||||
flags |= EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HAVEMASTER; | |||||
} | |||||
spRecord.setFlags(flags); | |||||
// Placeholders can't be grouped | |||||
setEscherProperty(EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, (placeholder == null ? -1 : 262144)); | |||||
HSLFEscherClientDataRecord clientData = getClientData(false); | |||||
if (placeholder == null) { | |||||
if (clientData != null) { | |||||
clientData.removeChild(OEPlaceholderAtom.class); | |||||
clientData.removeChild(RoundTripHFPlaceholder12.class); | |||||
// remove client data if the placeholder was the only child to be carried | |||||
if (clientData.getChildRecords().isEmpty()) { | |||||
getSpContainer().removeChildRecord(clientData); | |||||
} | |||||
} | |||||
return; | |||||
} | |||||
if (clientData == null) { | |||||
clientData = getClientData(true); | |||||
} | |||||
// OEPlaceholderAtom tells powerpoint that this shape is a placeholder | |||||
OEPlaceholderAtom oep = null; | |||||
RoundTripHFPlaceholder12 rtp = null; | |||||
for (Record r : clientData.getHSLFChildRecords()) { | |||||
if (r instanceof OEPlaceholderAtom) { | |||||
oep = (OEPlaceholderAtom)r; | |||||
break; | |||||
} | |||||
if (r instanceof RoundTripHFPlaceholder12) { | |||||
rtp = (RoundTripHFPlaceholder12)r; | |||||
break; | |||||
} | |||||
} | |||||
/** | |||||
* Extract from MSDN: | |||||
* | |||||
* There is a special case when the placeholder does not have a position in the layout. | |||||
* This occurs when the user has moved the placeholder from its original position. | |||||
* In this case the placeholder ID is -1. | |||||
*/ | |||||
byte phId; | |||||
HSLFSheet sheet = getSheet(); | |||||
// TODO: implement/switch NotesMaster | |||||
if (sheet instanceof HSLFSlideMaster) { | |||||
phId = (byte)placeholder.nativeSlideMasterId; | |||||
} else if (sheet instanceof HSLFNotes) { | |||||
phId = (byte)placeholder.nativeNotesId; | |||||
} else { | |||||
phId = (byte)placeholder.nativeSlideId; | |||||
} | |||||
if (phId == -2) { | |||||
throw new HSLFException("Placeholder "+placeholder.name()+" not supported for this sheet type ("+sheet.getClass()+")"); | |||||
} | |||||
switch (placeholder) { | |||||
case HEADER: | |||||
case FOOTER: | |||||
if (rtp == null) { | |||||
rtp = new RoundTripHFPlaceholder12(); | |||||
rtp.setPlaceholderId(phId); | |||||
clientData.addChild(rtp); | |||||
} | |||||
if (oep != null) { | |||||
clientData.removeChild(OEPlaceholderAtom.class); | |||||
} | |||||
break; | |||||
default: | |||||
if (rtp != null) { | |||||
clientData.removeChild(RoundTripHFPlaceholder12.class); | |||||
} | |||||
if (oep == null) { | |||||
oep = new OEPlaceholderAtom(); | |||||
oep.setPlaceholderSize((byte)OEPlaceholderAtom.PLACEHOLDER_FULLSIZE); | |||||
// TODO: placement id only "SHOULD" be unique ... check other placeholders on sheet for unique id | |||||
oep.setPlacementId(-1); | |||||
oep.setPlaceholderId(phId); | |||||
clientData.addChild(oep); | |||||
} | |||||
break; | |||||
} | |||||
getPlaceholderDetails().setPlaceholder(placeholder); | |||||
} | } | ||||
protected void setHyperlink(HSLFHyperlink link) { | protected void setHyperlink(HSLFHyperlink link) { | ||||
_hyperlink = link; | _hyperlink = link; | ||||
} | } | ||||
@Override | |||||
public boolean isPlaceholder() { | |||||
// currently we only identify TextShapes as placeholders | |||||
return false; | |||||
} | |||||
} | } |
import org.apache.poi.ddf.EscherDggRecord; | import org.apache.poi.ddf.EscherDggRecord; | ||||
import org.apache.poi.ddf.EscherSpRecord; | import org.apache.poi.ddf.EscherSpRecord; | ||||
import org.apache.poi.hslf.exceptions.HSLFException; | import org.apache.poi.hslf.exceptions.HSLFException; | ||||
import org.apache.poi.hslf.model.Comment; | |||||
import org.apache.poi.hslf.model.HeadersFooters; | import org.apache.poi.hslf.model.HeadersFooters; | ||||
import org.apache.poi.hslf.record.ColorSchemeAtom; | import org.apache.poi.hslf.record.ColorSchemeAtom; | ||||
import org.apache.poi.hslf.record.Comment2000; | import org.apache.poi.hslf.record.Comment2000; | ||||
import org.apache.poi.hslf.record.EscherTextboxWrapper; | import org.apache.poi.hslf.record.EscherTextboxWrapper; | ||||
import org.apache.poi.hslf.record.HeadersFootersContainer; | import org.apache.poi.hslf.record.HeadersFootersContainer; | ||||
import org.apache.poi.hslf.record.Record; | |||||
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.SSSlideInfoAtom; | import org.apache.poi.hslf.record.SSSlideInfoAtom; | ||||
if (_paragraphs.isEmpty()) { | if (_paragraphs.isEmpty()) { | ||||
throw new HSLFException("No text records found for slide"); | throw new HSLFException("No text records found for slide"); | ||||
} | } | ||||
} else { | |||||
// No text on the slide, must just be pictures | |||||
} | } | ||||
// Grab text from slide's PPDrawing | // Grab text from slide's PPDrawing | ||||
*/ | */ | ||||
@Override | @Override | ||||
public HSLFBackground getBackground() { | public HSLFBackground getBackground() { | ||||
if(getFollowMasterBackground()) { | |||||
return getMasterSheet().getBackground(); | |||||
if (getFollowMasterBackground()) { | |||||
final HSLFMasterSheet ms = getMasterSheet(); | |||||
return (ms == null) ? null : ms.getBackground(); | |||||
} | } | ||||
return super.getBackground(); | return super.getBackground(); | ||||
} | } | ||||
*/ | */ | ||||
@Override | @Override | ||||
public ColorSchemeAtom getColorScheme() { | public ColorSchemeAtom getColorScheme() { | ||||
if(getFollowMasterScheme()){ | |||||
return getMasterSheet().getColorScheme(); | |||||
if (getFollowMasterScheme()) { | |||||
final HSLFMasterSheet ms = getMasterSheet(); | |||||
return (ms == null) ? null : ms.getColorScheme(); | |||||
} | } | ||||
return super.getColorScheme(); | return super.getColorScheme(); | ||||
} | } | ||||
private static RecordContainer selectContainer(final RecordContainer root, final int index, final RecordTypes... path) { | |||||
if (root == null || index >= path.length) { | |||||
return root; | |||||
} | |||||
final RecordContainer newRoot = (RecordContainer) root.findFirstOfType(path[index].typeID); | |||||
return selectContainer(newRoot, index+1, path); | |||||
} | |||||
/** | /** | ||||
* Get the comment(s) for this slide. | * Get the comment(s) for this slide. | ||||
* Note - for now, only works on PPT 2000 and | * Note - for now, only works on PPT 2000 and | ||||
* PPT 2003 files. Doesn't work for PPT 97 | * PPT 2003 files. Doesn't work for PPT 97 | ||||
* ones, as they do their comments oddly. | * ones, as they do their comments oddly. | ||||
*/ | */ | ||||
public Comment[] getComments() { | |||||
public List<HSLFComment> getComments() { | |||||
final List<HSLFComment> comments = new ArrayList<>(); | |||||
// If there are any, they're in | // If there are any, they're in | ||||
// ProgTags -> ProgBinaryTag -> BinaryTagData | // ProgTags -> ProgBinaryTag -> BinaryTagData | ||||
RecordContainer progTags = (RecordContainer) | |||||
getSheetContainer().findFirstOfType( | |||||
RecordTypes.ProgTags.typeID | |||||
); | |||||
if(progTags != null) { | |||||
RecordContainer progBinaryTag = (RecordContainer) | |||||
progTags.findFirstOfType( | |||||
RecordTypes.ProgBinaryTag.typeID | |||||
); | |||||
if(progBinaryTag != null) { | |||||
RecordContainer binaryTags = (RecordContainer) | |||||
progBinaryTag.findFirstOfType( | |||||
RecordTypes.BinaryTagData.typeID | |||||
); | |||||
if(binaryTags != null) { | |||||
// This is where they'll be | |||||
int count = 0; | |||||
for(int i=0; i<binaryTags.getChildRecords().length; i++) { | |||||
if(binaryTags.getChildRecords()[i] instanceof Comment2000) { | |||||
count++; | |||||
} | |||||
} | |||||
// Now build | |||||
Comment[] comments = new Comment[count]; | |||||
count = 0; | |||||
for(int i=0; i<binaryTags.getChildRecords().length; i++) { | |||||
if(binaryTags.getChildRecords()[i] instanceof Comment2000) { | |||||
comments[i] = new Comment( | |||||
(Comment2000)binaryTags.getChildRecords()[i] | |||||
); | |||||
count++; | |||||
} | |||||
} | |||||
return comments; | |||||
} | |||||
} | |||||
} | |||||
// None found | |||||
return new Comment[0]; | |||||
final RecordContainer binaryTags = | |||||
selectContainer(getSheetContainer(), 0, | |||||
RecordTypes.ProgTags, RecordTypes.ProgBinaryTag, RecordTypes.BinaryTagData); | |||||
if (binaryTags != null) { | |||||
for (final Record record : binaryTags.getChildRecords()) { | |||||
if (record instanceof Comment2000) { | |||||
comments.add(new HSLFComment((Comment2000)record)); | |||||
} | |||||
} | |||||
} | |||||
return comments; | |||||
} | } | ||||
/** | /** | ||||
public boolean isHidden() { | public boolean isHidden() { | ||||
SSSlideInfoAtom slideInfo = | SSSlideInfoAtom slideInfo = | ||||
(SSSlideInfoAtom)getSlideRecord().findFirstOfType(RecordTypes.SSSlideInfoAtom.typeID); | (SSSlideInfoAtom)getSlideRecord().findFirstOfType(RecordTypes.SSSlideInfoAtom.typeID); | ||||
return (slideInfo == null) | |||||
? false | |||||
: slideInfo.getEffectTransitionFlagByBit(SSSlideInfoAtom.HIDDEN_BIT); | |||||
return (slideInfo != null) && slideInfo.getEffectTransitionFlagByBit(SSSlideInfoAtom.HIDDEN_BIT); | |||||
} | } | ||||
@Override | @Override | ||||
} | } | ||||
@Override | @Override | ||||
public boolean getDisplayPlaceholder(Placeholder placeholder) { | |||||
HeadersFooters hf = getHeadersFooters(); | |||||
SlideLayoutType slt = getSlideRecord().getSlideAtom().getSSlideLayoutAtom().getGeometryType(); | |||||
boolean isTitle = | |||||
public boolean getDisplayPlaceholder(final Placeholder placeholder) { | |||||
final HeadersFooters hf = getHeadersFooters(); | |||||
final SlideLayoutType slt = getSlideRecord().getSlideAtom().getSSlideLayoutAtom().getGeometryType(); | |||||
final boolean isTitle = | |||||
(slt == SlideLayoutType.TITLE_SLIDE || slt == SlideLayoutType.TITLE_ONLY || slt == SlideLayoutType.MASTER_TITLE); | (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; | |||||
} | |||||
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: | |||||
return false; | |||||
} | } | ||||
return false; | |||||
} | } | ||||
} | } |
import org.apache.poi.ddf.EscherOptRecord; | import org.apache.poi.ddf.EscherOptRecord; | ||||
import org.apache.poi.hpsf.ClassID; | import org.apache.poi.hpsf.ClassID; | ||||
import org.apache.poi.hpsf.ClassIDPredefined; | import org.apache.poi.hpsf.ClassIDPredefined; | ||||
import org.apache.poi.hpsf.extractor.HPSFPropertiesExtractor; | |||||
import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException; | import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException; | ||||
import org.apache.poi.hslf.exceptions.HSLFException; | import org.apache.poi.hslf.exceptions.HSLFException; | ||||
import org.apache.poi.hslf.model.HeadersFooters; | import org.apache.poi.hslf.model.HeadersFooters; | ||||
return objectId; | return objectId; | ||||
} | } | ||||
@Override | |||||
public HPSFPropertiesExtractor getMetadataTextExtractor() { | |||||
return new HPSFPropertiesExtractor(getSlideShowImpl()); | |||||
} | |||||
protected int addToObjListAtom(RecordContainer exObj) { | protected int addToObjListAtom(RecordContainer exObj) { | ||||
ExObjList lst = getDocumentRecord().getExObjList(true); | ExObjList lst = getDocumentRecord().getExObjList(true); | ||||
ExObjListAtom objAtom = lst.getExObjListAtom(); | ExObjListAtom objAtom = lst.getExObjListAtom(); |
} | } | ||||
final String text = ((tba != null) ? tba.getText() : tca.getText()); | final String text = ((tba != null) ? tba.getText() : tca.getText()); | ||||
StyleTextPropAtom sta = (StyleTextPropAtom)_txtbox.findFirstOfType(StyleTextPropAtom._type); | StyleTextPropAtom sta = (StyleTextPropAtom)_txtbox.findFirstOfType(StyleTextPropAtom._type); | ||||
TextPropCollection paraStyle = null, charStyle = null; | TextPropCollection paraStyle = null, charStyle = null; | ||||
if (sta == null) { | if (sta == null) { | ||||
htp.setParagraphStyle(paraStyle); | htp.setParagraphStyle(paraStyle); | ||||
htp.setParentShape(this); | htp.setParentShape(this); | ||||
_paragraphs.add(htp); | _paragraphs.add(htp); | ||||
HSLFTextRun htr = new HSLFTextRun(htp); | HSLFTextRun htr = new HSLFTextRun(htp); | ||||
htr.setCharacterStyle(charStyle); | htr.setCharacterStyle(charStyle); | ||||
htr.setText(text); | htr.setText(text); | ||||
public Rectangle2D resizeToFitText() { | public Rectangle2D resizeToFitText() { | ||||
return resizeToFitText(null); | return resizeToFitText(null); | ||||
} | } | ||||
@Override | @Override | ||||
public Rectangle2D resizeToFitText(Graphics2D graphics) { | public Rectangle2D resizeToFitText(Graphics2D graphics) { | ||||
Rectangle2D anchor = getAnchor(); | Rectangle2D anchor = getAnchor(); | ||||
} else { | } else { | ||||
_paragraphs = pList; | _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"); | ||||
} | } | ||||
@Override | @Override | ||||
public boolean isPlaceholder() { | public boolean isPlaceholder() { | ||||
OEPlaceholderAtom oep = getPlaceholderAtom(); | |||||
if (oep != null) { | |||||
return true; | |||||
} | |||||
//special case for files saved in Office 2007 | |||||
RoundTripHFPlaceholder12 hldr = getHFPlaceholderAtom(); | |||||
if (hldr != null) { | |||||
return true; | |||||
} | |||||
return false; | |||||
return | |||||
((getPlaceholderAtom() != null) || | |||||
//special case for files saved in Office 2007 | |||||
(getHFPlaceholderAtom() != null)) && | |||||
// check for metro shape of complex placeholder | |||||
(!new HSLFMetroShape<HSLFShape>(this).hasMetroBlob()) | |||||
; | |||||
} | } | ||||
public double getTextHeight() { | public double getTextHeight() { | ||||
return getTextHeight(null); | return getTextHeight(null); | ||||
} | } | ||||
@Override | @Override | ||||
public double getTextHeight(Graphics2D graphics) { | public double getTextHeight(Graphics2D graphics) { | ||||
DrawFactory drawFact = DrawFactory.getInstance(graphics); | DrawFactory drawFact = DrawFactory.getInstance(graphics); |
import java.util.List; | import java.util.List; | ||||
import org.apache.poi.POIDataSamples; | import org.apache.poi.POIDataSamples; | ||||
import org.apache.poi.hslf.usermodel.HSLFObjectShape; | |||||
import org.apache.poi.hslf.usermodel.HSLFSlideShow; | import org.apache.poi.hslf.usermodel.HSLFSlideShow; | ||||
import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; | import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; | ||||
import org.apache.poi.hslf.usermodel.HSLFObjectShape; | |||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook; | import org.apache.poi.hssf.usermodel.HSSFWorkbook; | ||||
import org.apache.poi.hwpf.HWPFDocument; | import org.apache.poi.hwpf.HWPFDocument; | ||||
import org.apache.poi.poifs.filesystem.DirectoryNode; | import org.apache.poi.poifs.filesystem.DirectoryNode; | ||||
public void testReadSheetText() throws IOException { | public void testReadSheetText() throws IOException { | ||||
// Basic 2 page example | // Basic 2 page example | ||||
PowerPointExtractor ppe = openExtractor("basic_test_ppt_file.ppt"); | PowerPointExtractor ppe = openExtractor("basic_test_ppt_file.ppt"); | ||||
ensureTwoStringsTheSame(expectText, ppe.getText()); | |||||
assertEquals(expectText, ppe.getText()); | |||||
ppe.close(); | ppe.close(); | ||||
// 1 page example with text boxes | // 1 page example with text boxes | ||||
PowerPointExtractor ppe2 = openExtractor("with_textbox.ppt"); | PowerPointExtractor ppe2 = openExtractor("with_textbox.ppt"); | ||||
ensureTwoStringsTheSame(expectText2, ppe2.getText()); | |||||
assertEquals(expectText2, ppe2.getText()); | |||||
ppe2.close(); | ppe2.close(); | ||||
} | } | ||||
// Basic 2 page example | // Basic 2 page example | ||||
PowerPointExtractor ppe = openExtractor("basic_test_ppt_file.ppt"); | PowerPointExtractor ppe = openExtractor("basic_test_ppt_file.ppt"); | ||||
String notesText = ppe.getNotes(); | String notesText = ppe.getNotes(); | ||||
String expText = "These are the notes for page 1\nThese are the notes on page two, again lacking formatting\n"; | |||||
ensureTwoStringsTheSame(expText, notesText); | |||||
String expText = "\nThese are the notes for page 1\n\nThese are the notes on page two, again lacking formatting\n"; | |||||
assertEquals(expText, notesText); | |||||
ppe.close(); | ppe.close(); | ||||
// Other one doesn't have notes | // Other one doesn't have notes | ||||
PowerPointExtractor ppe2 = openExtractor("with_textbox.ppt"); | PowerPointExtractor ppe2 = openExtractor("with_textbox.ppt"); | ||||
notesText = ppe2.getNotes(); | notesText = ppe2.getNotes(); | ||||
expText = ""; | expText = ""; | ||||
ensureTwoStringsTheSame(expText, notesText); | |||||
assertEquals(expText, notesText); | |||||
ppe2.close(); | ppe2.close(); | ||||
} | } | ||||
"This is the title on page 2\nThis is page two\nIt has several blocks of text\nNone of them have formatting\n" | "This is the title on page 2\nThis is page two\nIt has several blocks of text\nNone of them have formatting\n" | ||||
}; | }; | ||||
String[] ntText = new String[]{ | String[] ntText = new String[]{ | ||||
"These are the notes for page 1\n", | |||||
"These are the notes on page two, again lacking formatting\n" | |||||
"\nThese are the notes for page 1\n", | |||||
"\nThese are the notes on page two, again lacking formatting\n" | |||||
}; | }; | ||||
PowerPointExtractor ppe = openExtractor("basic_test_ppt_file.ppt"); | PowerPointExtractor ppe = openExtractor("basic_test_ppt_file.ppt"); | ||||
ppe.setSlidesByDefault(true); | ppe.setSlidesByDefault(true); | ||||
ppe.setNotesByDefault(true); | ppe.setNotesByDefault(true); | ||||
assertEquals(slText[0] + slText[1] + "\n" + ntText[0] + ntText[1], ppe.getText()); | |||||
assertEquals(slText[0] + ntText[0] + slText[1] + ntText[1], ppe.getText()); | |||||
ppe.close(); | ppe.close(); | ||||
} | } | ||||
ppe.close(); | ppe.close(); | ||||
} | } | ||||
private void ensureTwoStringsTheSame(String exp, String act) { | |||||
assertEquals(exp.length(), act.length()); | |||||
char[] expC = exp.toCharArray(); | |||||
char[] actC = act.toCharArray(); | |||||
for (int i = 0; i < expC.length; i++) { | |||||
assertEquals("Char " + i, expC[i], actC[i]); | |||||
} | |||||
assertEquals(exp, act); | |||||
} | |||||
@Test | @Test | ||||
public void testExtractFromEmbeded() throws IOException { | public void testExtractFromEmbeded() throws IOException { | ||||
InputStream is = POIDataSamples.getSpreadSheetInstance().openResourceAsStream("excel_with_embeded.xls"); | InputStream is = POIDataSamples.getSpreadSheetInstance().openResourceAsStream("excel_with_embeded.xls"); | ||||
assertContains(text, "Prague"); | assertContains(text, "Prague"); | ||||
ppe.close(); | ppe.close(); | ||||
} | } | ||||
@Test | |||||
public void testExtractGroupedShapeText() throws Exception { | |||||
try (final PowerPointExtractor ppe = openExtractor("bug62092.ppt")) { | |||||
final String text = ppe.getText(); | |||||
//this tests that we're ignoring text shapes at depth=0 | |||||
//i.e. POI has already included them in the slide's getTextParagraphs() | |||||
assertContains(text, "Text box1"); | |||||
assertEquals(1, countMatches(text,"Text box1")); | |||||
//the WordArt and text box count tests will fail | |||||
//if this content is available via getTextParagraphs() of the slide in POI | |||||
//i.e. when POI is fixed, these tests will fail, and | |||||
//we'll have to remove the workaround in HSLFExtractor's extractGroupText(...) | |||||
assertEquals(1, countMatches(text,"WordArt1")); | |||||
assertEquals(1, countMatches(text,"WordArt2")); | |||||
assertEquals(1, countMatches(text,"Ungrouped text box"));//should only be 1 | |||||
assertContains(text, "Text box2"); | |||||
assertContains(text, "Text box3"); | |||||
assertContains(text, "Text box4"); | |||||
assertContains(text, "Text box5"); | |||||
//see below -- need to extract hyperlinks | |||||
assertContains(text, "tika"); | |||||
assertContains(text, "MyTitle"); | |||||
} | |||||
} | |||||
private static int countMatches(final String base, final String find) { | |||||
return base.split(find).length-1; | |||||
} | |||||
} | } |
package org.apache.poi.hslf.record; | package org.apache.poi.hslf.record; | ||||
import static org.junit.Assert.assertEquals; | |||||
import org.junit.Test; | import org.junit.Test; | ||||
import static org.junit.Assert.assertEquals; | |||||
/** | /** | ||||
* Tests that RecordTypes returns the right records and classes when asked | * Tests that RecordTypes returns the right records and classes when asked | ||||
*/ | */ | ||||
@Test | @Test | ||||
public void testPPTClassLookups() { | public void testPPTClassLookups() { | ||||
assertEquals(Slide.class, RecordTypes.Slide.handlingClass); | |||||
assertEquals(TextCharsAtom.class, RecordTypes.TextCharsAtom.handlingClass); | |||||
assertEquals(TextBytesAtom.class, RecordTypes.TextBytesAtom.handlingClass); | |||||
assertEquals(SlideListWithText.class, RecordTypes.SlideListWithText.handlingClass); | |||||
// If this record is ever implemented, change to one that isn't! | // If this record is ever implemented, change to one that isn't! | ||||
// This is checking the "unhandled default" stuff works | // This is checking the "unhandled default" stuff works | ||||
assertEquals(UnknownRecordPlaceholder.class, RecordTypes.forTypeID(-10).handlingClass); | |||||
assertEquals(RecordTypes.UnknownRecordPlaceholder, RecordTypes.forTypeID(-10)); | |||||
} | } | ||||
@Test | @Test | ||||
public void testEscherClassLookups() { | public void testEscherClassLookups() { | ||||
// Should all come back with null, as DDF handles them | // Should all come back with null, as DDF handles them | ||||
assertEquals(null, RecordTypes.EscherDggContainer.handlingClass); | |||||
assertEquals(null, RecordTypes.EscherBStoreContainer.handlingClass); | |||||
assertEquals(null, RecordTypes.EscherDggContainer.recordConstructor); | |||||
assertEquals(null, RecordTypes.EscherBStoreContainer.recordConstructor); | |||||
} | } | ||||
} | } |