You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ki...@apache.org on 2018/04/18 15:02:03 UTC

svn commit: r1829453 [1/3] - in /poi: site/src/documentation/content/xdocs/ trunk/src/java/org/apache/poi/sl/draw/ trunk/src/java/org/apache/poi/sl/extractor/ trunk/src/java/org/apache/poi/sl/usermodel/ trunk/src/ooxml/java/org/apache/poi/xslf/extracto...

Author: kiwiwings
Date: Wed Apr 18 15:02:02 2018
New Revision: 1829453

URL: http://svn.apache.org/viewvc?rev=1829453&view=rev
Log:
Bug 62092 - Text not extracted from grouped text shapes in HSLF

Added:
    poi/trunk/src/java/org/apache/poi/sl/extractor/
    poi/trunk/src/java/org/apache/poi/sl/extractor/SlideShowExtractor.java   (with props)
    poi/trunk/src/java/org/apache/poi/sl/usermodel/Comment.java   (with props)
    poi/trunk/src/java/org/apache/poi/sl/usermodel/PlaceholderDetails.java   (with props)
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFComment.java   (with props)
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPlaceholderDetails.java   (with props)
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFComment.java
      - copied, changed from r1829452, poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/Comment.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFPlaceholderDetails.java   (with props)
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapePlaceholderDetails.java   (with props)
    poi/trunk/test-data/slideshow/bug62092.ppt   (with props)
Removed:
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/Comment.java
Modified:
    poi/site/src/documentation/content/xdocs/status.xml
    poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java
    poi/trunk/src/java/org/apache/poi/sl/usermodel/Sheet.java
    poi/trunk/src/java/org/apache/poi/sl/usermodel/SimpleShape.java
    poi/trunk/src/java/org/apache/poi/sl/usermodel/Slide.java
    poi/trunk/src/java/org/apache/poi/sl/usermodel/SlideShow.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/extractor/XSLFPowerPointExtractor.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFComments.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFNotesMaster.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideLayout.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideMaster.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java
    poi/trunk/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXMLSlideShow.java
    poi/trunk/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextRun.java
    poi/trunk/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextShape.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/extractor/PowerPointExtractor.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/HeadersFooters.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/DocumentEncryptionAtom.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/HSLFEscherClientDataRecord.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/Record.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFMasterSheet.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFNotes.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlide.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShow.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextShape.java
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/extractor/TestExtractor.java
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/record/TestRecordTypes.java

Modified: poi/site/src/documentation/content/xdocs/status.xml
URL: http://svn.apache.org/viewvc/poi/site/src/documentation/content/xdocs/status.xml?rev=1829453&r1=1829452&r2=1829453&view=diff
==============================================================================
--- poi/site/src/documentation/content/xdocs/status.xml (original)
+++ poi/site/src/documentation/content/xdocs/status.xml Wed Apr 18 15:02:02 2018
@@ -68,6 +68,7 @@
         <summary-item>Provide new ooxml-schemas-1.4.jar</summary-item>
       </summary>
       <actions>
+        <action dev="PD" type="add" fixes-bug="62092" module="SL Common">Text not extracted from grouped text shapes in HSLF</action>
 		<action dev="PD" type="add" fixes-bug="62159" module="OPC">Support XML signature over windows certificate store</action>
         <action dev="PD" type="add" fixes-bug="57369" module="XDDF">Add support for major and minor units on chart axes</action>
         <action dev="PD" type="add" fixes-bug="55954" module="XWPF">Added methods to position table</action>

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java?rev=1829453&r1=1829452&r2=1829453&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java Wed Apr 18 15:02:02 2018
@@ -52,6 +52,7 @@ import org.apache.poi.sl.usermodel.TextR
 import org.apache.poi.sl.usermodel.TextRun.FieldType;
 import org.apache.poi.sl.usermodel.TextShape;
 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.POILogFactory;
 import org.apache.poi.util.POILogger;
@@ -381,7 +382,8 @@ public class DrawTextParagraph implement
         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 Locale loc = LocaleUtil.getUserLocale();
 

Added: poi/trunk/src/java/org/apache/poi/sl/extractor/SlideShowExtractor.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/extractor/SlideShowExtractor.java?rev=1829453&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/extractor/SlideShowExtractor.java (added)
+++ poi/trunk/src/java/org/apache/poi/sl/extractor/SlideShowExtractor.java Wed Apr 18 15:02:02 2018
@@ -0,0 +1,307 @@
+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);
+            }
+        }
+    }
+}

Propchange: poi/trunk/src/java/org/apache/poi/sl/extractor/SlideShowExtractor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: poi/trunk/src/java/org/apache/poi/sl/usermodel/Comment.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/usermodel/Comment.java?rev=1829453&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/usermodel/Comment.java (added)
+++ poi/trunk/src/java/org/apache/poi/sl/usermodel/Comment.java Wed Apr 18 15:02:02 2018
@@ -0,0 +1,85 @@
+/* ====================================================================
+   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);
+}

Propchange: poi/trunk/src/java/org/apache/poi/sl/usermodel/Comment.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: poi/trunk/src/java/org/apache/poi/sl/usermodel/PlaceholderDetails.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/usermodel/PlaceholderDetails.java?rev=1829453&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/usermodel/PlaceholderDetails.java (added)
+++ poi/trunk/src/java/org/apache/poi/sl/usermodel/PlaceholderDetails.java Wed Apr 18 15:02:02 2018
@@ -0,0 +1,69 @@
+/* ====================================================================
+   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);
+}

Propchange: poi/trunk/src/java/org/apache/poi/sl/usermodel/PlaceholderDetails.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: poi/trunk/src/java/org/apache/poi/sl/usermodel/Sheet.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/usermodel/Sheet.java?rev=1829453&r1=1829452&r2=1829453&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/usermodel/Sheet.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/usermodel/Sheet.java Wed Apr 18 15:02:02 2018
@@ -46,4 +46,16 @@ public interface Sheet<
 	 * @param 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);
 }

Modified: poi/trunk/src/java/org/apache/poi/sl/usermodel/SimpleShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/usermodel/SimpleShape.java?rev=1829453&r1=1829452&r2=1829453&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/usermodel/SimpleShape.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/usermodel/SimpleShape.java Wed Apr 18 15:02:02 2018
@@ -65,6 +65,24 @@ public interface SimpleShape<
      */
     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();
 
     /**

Modified: poi/trunk/src/java/org/apache/poi/sl/usermodel/Slide.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/usermodel/Slide.java?rev=1829453&r1=1829452&r2=1829453&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/usermodel/Slide.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/usermodel/Slide.java Wed Apr 18 15:02:02 2018
@@ -17,6 +17,8 @@
 
 package org.apache.poi.sl.usermodel;
 
+import java.util.List;
+
 public interface Slide<
     S extends Shape<S,P>,
     P extends TextParagraph<S,P,? extends TextRun>
@@ -48,7 +50,7 @@ public interface Slide<
      * whereas in HSLF they are activated via a HeadersFooter configuration.
      * 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
      * @since POI 3.16-beta2
      */
@@ -69,4 +71,9 @@ public interface Slide<
      * @since POI 4.0.0
      */
     boolean isHidden();
+
+    /**
+     * @return the comment(s) for this slide
+     */
+    List<? extends Comment> getComments();
 }

Modified: poi/trunk/src/java/org/apache/poi/sl/usermodel/SlideShow.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/usermodel/SlideShow.java?rev=1829453&r1=1829452&r2=1829453&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/usermodel/SlideShow.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/usermodel/SlideShow.java Wed Apr 18 15:02:02 2018
@@ -25,6 +25,7 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.List;
 
+import org.apache.poi.POITextExtractor;
 import org.apache.poi.sl.usermodel.PictureData.PictureType;
 
 public interface SlideShow<
@@ -118,4 +119,11 @@ public interface SlideShow<
      *             OutputStream
      */
     void write(OutputStream out) throws IOException;
+
+    /**
+     * @return an extractor for the slideshow metadata
+     * 
+     * @since POI 4.0.0
+     */
+    POITextExtractor getMetadataTextExtractor();
 }

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xslf/extractor/XSLFPowerPointExtractor.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/extractor/XSLFPowerPointExtractor.java?rev=1829453&r1=1829452&r2=1829453&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/extractor/XSLFPowerPointExtractor.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/extractor/XSLFPowerPointExtractor.java Wed Apr 18 15:02:02 2018
@@ -21,202 +21,188 @@ import java.io.IOException;
 import org.apache.poi.POIXMLTextExtractor;
 import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
 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.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.XSLFShape;
-import org.apache.poi.xslf.usermodel.XSLFShapeContainer;
 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.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.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 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() {
-		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);
+    }
 }

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java?rev=1829453&r1=1829452&r2=1829453&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java Wed Apr 18 15:02:02 2018
@@ -35,10 +35,10 @@ import java.util.regex.Pattern;
 import org.apache.poi.POIXMLDocument;
 import org.apache.poi.POIXMLDocumentPart;
 import org.apache.poi.POIXMLException;
+import org.apache.poi.POIXMLPropertiesTextExtractor;
 import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
 import org.apache.poi.openxml4j.opc.OPCPackage;
 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.PictureData.PictureType;
 import org.apache.poi.sl.usermodel.Resources;
@@ -626,4 +626,9 @@ public class XMLSlideShow extends POIXML
         // TODO: implement!
         throw new UnsupportedOperationException();
     }
+    
+    @Override
+    public POIXMLPropertiesTextExtractor getMetadataTextExtractor() {
+        return new POIXMLPropertiesTextExtractor(this);
+    }
 }

Added: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFComment.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFComment.java?rev=1829453&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFComment.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFComment.java Wed Apr 18 15:02:02 2018
@@ -0,0 +1,126 @@
+/* ====================================================================
+   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()));
+    }
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFComment.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFComments.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFComments.java?rev=1829453&r1=1829452&r2=1829453&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFComments.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFComments.java Wed Apr 18 15:02:02 2018
@@ -31,42 +31,37 @@ import org.openxmlformats.schemas.presen
 
 @Beta
 public class XSLFComments extends POIXMLDocumentPart {
-    private final CTCommentList _comments;
-    
+    private final CmLstDocument doc;
+
     /**
      * Create a new set of slide comments
      */
     XSLFComments() {
-       super();
-       CmLstDocument doc = CmLstDocument.Factory.newInstance();
-       _comments = doc.addNewCmLst();
+        doc = CmLstDocument.Factory.newInstance();
     }
 
     /**
      * Construct a SpreadsheetML slide comments from a package part
      *
      * @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
      */
     XSLFComments(PackagePart part) throws IOException, XmlException {
         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() {
-       return _comments;
+        return doc.getCmLst();
     }
-    
+
     public int getNumberOfComments() {
-       return _comments.sizeOfCmArray();
+        return doc.getCmLst().sizeOfCmArray();
     }
-    
+
     public CTComment getCommentAt(int pos) {
-       return _comments.getCmArray(pos);
+        return doc.getCmLst().getCmArray(pos);
     }
 }

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFNotesMaster.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFNotesMaster.java?rev=1829453&r1=1829452&r2=1829453&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFNotesMaster.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFNotesMaster.java Wed Apr 18 15:02:02 2018
@@ -51,7 +51,6 @@ import org.openxmlformats.schemas.presen
  public class XSLFNotesMaster extends XSLFSheet
      implements MasterSheet<XSLFShape,XSLFTextParagraph> {
 	 private CTNotesMaster _slide;
-     private XSLFTheme _theme;
 
     XSLFNotesMaster() {
         super();
@@ -100,21 +99,15 @@ import org.openxmlformats.schemas.presen
     public MasterSheet<XSLFShape,XSLFTextParagraph> getMasterSheet() {
         return null;
     }
-    
+
+
     @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();
+    }
 }
\ No newline at end of file

Added: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPlaceholderDetails.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPlaceholderDetails.java?rev=1829453&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPlaceholderDetails.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPlaceholderDetails.java Wed Apr 18 15:02:02 2018
@@ -0,0 +1,203 @@
+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) {
+    }
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPlaceholderDetails.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java?rev=1829453&r1=1829452&r2=1829453&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java Wed Apr 18 15:02:02 2018
@@ -38,7 +38,9 @@ import org.apache.poi.sl.usermodel.Paint
 import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint;
 import org.apache.poi.sl.usermodel.PlaceableShape;
 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.SimpleShape;
 import org.apache.poi.util.Beta;
 import org.apache.poi.util.Internal;
 import org.apache.poi.xslf.model.PropertyFetcher;
@@ -58,7 +60,6 @@ import org.openxmlformats.schemas.drawin
 import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrix;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrixReference;
 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.CTPlaceholder;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
@@ -69,7 +70,7 @@ import org.openxmlformats.schemas.presen
  */
 @Beta
 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 XSLFSheet _sheet;
@@ -77,7 +78,6 @@ public abstract class XSLFShape implemen
 
     private CTShapeStyle _spStyle;
     private CTNonVisualDrawingProps _nvPr;
-    private CTPlaceholder _ph;
 
     protected XSLFShape(XmlObject shape, XSLFSheet sheet) {
         _shape = shape;
@@ -238,45 +238,32 @@ public abstract class XSLFShape implemen
         cur.dispose();
         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() {
-        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
      * child classes work with a {@link CTShape} object, but often contain the same
@@ -315,7 +302,7 @@ public abstract class XSLFShape implemen
             return true;
         }
 
-        CTPlaceholder ph = getCTPlaceholder();
+        final CTPlaceholder ph = getPlaceholderDetails().getCTPlaceholder(false);
         if (ph == null) {
             return false;
         }

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java?rev=1829453&r1=1829452&r2=1829453&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java Wed Apr 18 15:02:02 2018
@@ -18,6 +18,7 @@ package org.apache.poi.xslf.usermodel;
 
 import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
 
+import javax.xml.namespace.QName;
 import java.awt.Dimension;
 import java.awt.Graphics2D;
 import java.io.IOException;
@@ -28,8 +29,7 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-
-import javax.xml.namespace.QName;
+import java.util.Optional;
 
 import org.apache.poi.POIXMLDocumentPart;
 import org.apache.poi.POIXMLException;
@@ -56,6 +56,7 @@ import org.apache.xmlbeans.XmlException;
 import org.apache.xmlbeans.XmlObject;
 import org.apache.xmlbeans.XmlOptions;
 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.CTGraphicalObjectFrame;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;
@@ -72,6 +73,7 @@ implements XSLFShapeContainer, Sheet<XSL
     private XSLFDrawing _drawing;
     private List<XSLFShape> _shapes;
     private CTGroupShape _spTree;
+    private XSLFTheme _theme;
 
     private List<XSLFTextShape>_placeholders;
     private Map<Integer, XSLFSimpleShape> _placeholderByIdMap;
@@ -456,7 +458,36 @@ implements XSLFShapeContainer, Sheet<XSL
      *  Sheets that support the notion of themes (slides, masters, layouts, etc.) should override this
      *  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;
     }
 
@@ -488,16 +519,16 @@ implements XSLFShapeContainer, Sheet<XSL
         return shape;
     }
 
-    void initPlaceholders() {
+    private void initPlaceholders() {
         if(_placeholders == null) {
             _placeholders = new ArrayList<>();
             _placeholderByIdMap = new HashMap<>();
             _placeholderByTypeMap = new HashMap<>();
 
-            for(XSLFShape sh : getShapes()){
+            for(final XSLFShape sh : getShapes()){
                 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) {
                         _placeholders.add(sShape);
                         if(ph.isSetIdx()) {
@@ -513,7 +544,7 @@ implements XSLFShapeContainer, Sheet<XSL
         }
     }
 
-    XSLFSimpleShape getPlaceholderById(int id) {
+    private XSLFSimpleShape getPlaceholderById(int id) {
         initPlaceholders();
         return _placeholderByIdMap.get(id);
     }
@@ -574,7 +605,7 @@ implements XSLFShapeContainer, Sheet<XSL
     /**
      * Render this sheet into the supplied graphics object
      *
-     * @param graphics
+     * @param graphics the graphics context to draw to
      */
     @Override
     public void draw(Graphics2D graphics){
@@ -645,4 +676,12 @@ implements XSLFShapeContainer, Sheet<XSL
     void removePictureRelation(XSLFPictureShape pictureShape) {
         removeRelation(pictureShape.getBlipId());
     }
+
+
+    @Override
+    public XSLFPlaceholderDetails getPlaceholderDetails(Placeholder placeholder) {
+        final XSLFSimpleShape ph = getPlaceholder(placeholder);
+        return (ph == null) ? null : new XSLFPlaceholderDetails(ph);
+    }
+
 }

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java?rev=1829453&r1=1829452&r2=1829453&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java Wed Apr 18 15:02:02 2018
@@ -36,7 +36,6 @@ import org.apache.poi.sl.usermodel.LineD
 import org.apache.poi.sl.usermodel.LineDecoration.DecorationSize;
 import org.apache.poi.sl.usermodel.PaintStyle;
 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.SimpleShape;
 import org.apache.poi.sl.usermodel.StrokeStyle;
@@ -980,11 +979,6 @@ public abstract class XSLFSimpleShape ex
         return ds; 
     }
 
-    public boolean isPlaceholder() {
-        CTPlaceholder ph = getCTPlaceholder();
-        return ph != null;
-    }
-
     @Override
     public Guide getAdjustValue(String name) {
         XSLFGeometryProperties gp = XSLFPropertiesDelegate.getGeometryDelegate(getShapeProperties());
@@ -1106,11 +1100,6 @@ public abstract class XSLFSimpleShape ex
     }
     
     @Override
-    public void setPlaceholder(Placeholder placeholder) {
-        super.setPlaceholder(placeholder);
-    }
-    
-    @Override
     public XSLFHyperlink getHyperlink() {
         CTNonVisualDrawingProps cNvPr = getCNvPr();
         if (!cNvPr.isSetHlinkClick()) {

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java?rev=1829453&r1=1829452&r2=1829453&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java Wed Apr 18 15:02:02 2018
@@ -20,6 +20,8 @@ import static org.apache.poi.POIXMLTypeL
 
 import java.awt.Graphics2D;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 
 import org.apache.poi.POIXMLDocumentPart;
 import org.apache.poi.openxml4j.opc.PackagePart;
@@ -38,6 +40,7 @@ import org.openxmlformats.schemas.drawin
 import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
 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.CTGroupShape;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShapeNonVisual;
@@ -52,6 +55,7 @@ implements Slide<XSLFShape,XSLFTextParag
     private final CTSlide _slide;
     private XSLFSlideLayout _layout;
     private XSLFComments _comments;
+    private XSLFCommentAuthors _commentAuthors;
     private XSLFNotes _notes;
 
     /**
@@ -155,22 +159,55 @@ implements Slide<XSLFShape,XSLFTextParag
         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) {
             for (POIXMLDocumentPart p : getRelations()) {
                 if (p instanceof XSLFComments) {
                     _comments = (XSLFComments)p;
+                    break;
                 }
             }
         }
-        if(_comments == null) {
-            // This slide lacks comments
-            // Not all have them, sorry...
-            return null;
-        }
+
         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
     public XSLFNotes getNotes() {
         if(_notes == null) {

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideLayout.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideLayout.java?rev=1829453&r1=1829452&r2=1829453&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideLayout.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideLayout.java Wed Apr 18 15:02:02 2018
@@ -28,21 +28,15 @@ import org.apache.poi.util.Beta;
 import org.apache.poi.util.Internal;
 import org.apache.xmlbeans.XmlException;
 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.SldLayoutDocument;
 
 @Beta
 public class XSLFSlideLayout extends XSLFSheet
 implements MasterSheet<XSLFShape,XSLFTextParagraph> {
-    private CTSlideLayout _layout;
+    private final CTSlideLayout _layout;
     private XSLFSlideMaster _master;
 
-    XSLFSlideLayout() {
-        super();
-        _layout = CTSlideLayout.Factory.newInstance();
-    }
-
     /**
      * @since POI 3.14-Beta1
      */
@@ -111,14 +105,7 @@ implements MasterSheet<XSLFShape,XSLFTex
      */
     @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;
+        return !(shape instanceof XSLFSimpleShape) || !shape.isPlaceholder();
     }
 
 

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideMaster.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideMaster.java?rev=1829453&r1=1829452&r2=1829453&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideMaster.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideMaster.java Wed Apr 18 15:02:02 2018
@@ -32,7 +32,6 @@ import org.apache.xmlbeans.XmlException;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTColorMapping;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTTextListStyle;
 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.CTSlideMasterTextStyles;
 import org.openxmlformats.schemas.presentationml.x2006.main.SldMasterDocument;
@@ -43,7 +42,6 @@ import org.openxmlformats.schemas.presen
 *  Within a slide master slide are contained all elements
 * that describe the objects and their corresponding formatting
 * for within a presentation slide.
-* </p>
 * <p>
 * Within a slide master slide are two main elements.
 * The cSld element specifies the common slide elements such as shapes and
@@ -52,21 +50,12 @@ import org.openxmlformats.schemas.presen
 * 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
 * transition information for all corresponding presentation slides.
-* </p>
- *
- * @author Yegor Kozlov
 */
 @Beta
  public class XSLFSlideMaster extends XSLFSheet
  implements MasterSheet<XSLFShape,XSLFTextParagraph> {
 	private CTSlideMaster _slide;
     private Map<String, XSLFSlideLayout> _layouts;
-    private XSLFTheme _theme;
-
-    XSLFSlideMaster() {
-        super();
-        _slide = CTSlideMaster.Factory.newInstance();
-    }
 
     /**
      * @since POI 3.14-Beta1
@@ -142,23 +131,9 @@ import org.openxmlformats.schemas.presen
     }
 
 
-    @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) {
         CTTextListStyle props;
         CTSlideMasterTextStyles txStyles = getXmlObject().getTxStyles();
@@ -183,15 +158,8 @@ import org.openxmlformats.schemas.presen
      *
      */
     @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
@@ -203,4 +171,14 @@ import org.openxmlformats.schemas.presen
             return null;
         }
     }
+
+    @Override
+    boolean isSupportTheme() {
+        return true;
+    }
+
+    @Override
+    CTColorMapping getColorMapping() {
+        return _slide.getClrMap();
+    }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org