Bug 55164 - Support for adding slide notes

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1635010 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2014-10-29 00:07:34 +00:00
parent 5dcf6b1a29
commit 1d84cd9828
8 changed files with 278 additions and 26 deletions

View File

@ -112,7 +112,16 @@ public abstract class POIXMLRelation {
}
/**
* Return type of the obejct used to construct instances of this relationship
* Returns the index of the filename within the package for the given part.
* e.g. 4 for /xl/comments4.xml
*/
public Integer getFileNameIndex(POIXMLDocumentPart part) {
String regex = _defaultName.replace("#", "(\\d+)");
return Integer.parseInt(part.getPackageRelationship().getTargetURI().getPath().replaceAll(regex, "$1"));
}
/**
* Return type of the object used to construct instances of this relationship
*
* @return the class of the object used to construct instances of this relation
*/

View File

@ -49,6 +49,8 @@ import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;
import org.openxmlformats.schemas.presentationml.x2006.main.CTNotesMasterIdList;
import org.openxmlformats.schemas.presentationml.x2006.main.CTNotesMasterIdListEntry;
import org.openxmlformats.schemas.presentationml.x2006.main.CTPresentation;
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideIdList;
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideIdListEntry;
@ -130,7 +132,7 @@ public class XMLSlideShow extends POIXMLDocument {
} else if (p instanceof XSLFSlideMaster) {
XSLFSlideMaster master = (XSLFSlideMaster)p;
_masters.put(p.getPackageRelationship().getId(), master);
}else if (p instanceof XSLFTableStyles){
} else if (p instanceof XSLFTableStyles){
_tableStyles = (XSLFTableStyles)p;
} else if (p instanceof XSLFNotesMaster) {
_notesMaster = (XSLFNotesMaster)p;
@ -155,7 +157,6 @@ public class XMLSlideShow extends POIXMLDocument {
}
}
@Override
protected void commit() throws IOException {
XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
@ -245,6 +246,95 @@ public class XMLSlideShow extends POIXMLDocument {
return createSlide(layout);
}
/**
* Return notes slide for the specified slide or create new if it does not exist yet.
*/
public XSLFNotes getNotesSlide(XSLFSlide slide) {
XSLFNotes notesSlide = slide.getNotes();
if (notesSlide == null) {
notesSlide = createNotesSlide(slide);
}
return notesSlide;
}
/**
* Create a blank notes slide.
*/
private XSLFNotes createNotesSlide(XSLFSlide slide) {
if (_notesMaster == null) {
createNotesMaster();
}
Integer slideIndex = XSLFRelation.SLIDE.getFileNameIndex(slide);
XSLFNotes notesSlide = (XSLFNotes) createRelationship(XSLFRelation.NOTES, XSLFFactory.getInstance(), slideIndex);
notesSlide.addRelation(_notesMaster.getPackageRelationship().getId(), _notesMaster);
PackagePartName notesMasterPackagePartName = _notesMaster.getPackagePart().getPartName();
notesSlide.getPackagePart().addRelationship(notesMasterPackagePartName, TargetMode.INTERNAL,
_notesMaster.getPackageRelationship().getRelationshipType());
slide.addRelation(notesSlide.getPackageRelationship().getId(), notesSlide);
PackagePartName notesSlidesPackagePartName = notesSlide.getPackagePart().getPartName();
slide.getPackagePart().addRelationship(notesSlidesPackagePartName, TargetMode.INTERNAL,
notesSlide.getPackageRelationship().getRelationshipType());
notesSlide.addRelation(slide.getPackageRelationship().getId(), slide);
PackagePartName slidesPackagePartName = slide.getPackagePart().getPartName();
notesSlide.getPackagePart().addRelationship(slidesPackagePartName, TargetMode.INTERNAL,
slide.getPackageRelationship().getRelationshipType());
notesSlide.importContent(_notesMaster);
return notesSlide;
}
/**
* Create a notes master.
*/
public void createNotesMaster() {
_notesMaster = (XSLFNotesMaster) createRelationship(XSLFRelation.NOTES_MASTER,
XSLFFactory.getInstance(), 1);
CTNotesMasterIdList notesMasterIdList = _presentation.addNewNotesMasterIdLst();
CTNotesMasterIdListEntry notesMasterId = notesMasterIdList.addNewNotesMasterId();
notesMasterId.setId(_notesMaster.getPackageRelationship().getId());
Integer themeIndex = 1;
List<Integer> themeIndexList = new ArrayList<Integer>();
for (POIXMLDocumentPart p : getRelations()) {
if (p instanceof XSLFTheme) {
themeIndexList.add(XSLFRelation.THEME.getFileNameIndex(p));
}
}
if (!themeIndexList.isEmpty()) {
Boolean found = false;
for (Integer i = 1; i <= themeIndexList.size(); i++) {
if (!themeIndexList.contains(i)) {
found = true;
themeIndex = i;
}
}
if (!found) {
themeIndex = themeIndexList.size() + 1;
}
}
XSLFTheme theme = (XSLFTheme) createRelationship(XSLFRelation.THEME,
XSLFFactory.getInstance(), themeIndex);
theme.importTheme(getSlides()[0].getTheme());
_notesMaster.addRelation(theme.getPackageRelationship().getId(), theme);
PackagePartName themePackagePartName = theme.getPackagePart().getPartName();
_notesMaster.getPackagePart().addRelationship(themePackagePartName, TargetMode.INTERNAL,
theme.getPackageRelationship().getRelationshipType());
}
/**
* Return the Notes Master, if there is one.
* (May not be present if no notes exist)

View File

@ -16,6 +16,8 @@
==================================================================== */
package org.apache.poi.xslf.usermodel;
import java.io.IOException;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship;
@ -25,8 +27,6 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTCommonSlideData;
import org.openxmlformats.schemas.presentationml.x2006.main.CTNotesSlide;
import org.openxmlformats.schemas.presentationml.x2006.main.NotesDocument;
import java.io.IOException;
@Beta
public final class XSLFNotes extends XSLFSheet {
private CTNotesSlide _notes;
@ -57,12 +57,10 @@ public final class XSLFNotes extends XSLFSheet {
setCommonSlideData(_notes.getCSld());
}
private static CTNotesSlide prototype(){
CTNotesSlide ctNotes = CTNotesSlide.Factory.newInstance();
CTCommonSlideData cSld = ctNotes.addNewCSld();
// TODO What else is needed for a mininum notes?
cSld.addNewSpTree();
return ctNotes;
}
@ -77,6 +75,11 @@ public final class XSLFNotes extends XSLFSheet {
return "notes";
}
@Override
public XSLFTheme getTheme(){
return getMasterSheet().getTheme();
}
@Override
public XSLFNotesMaster getMasterSheet() {
for (POIXMLDocumentPart p : getRelations()) {

View File

@ -16,15 +16,19 @@
==================================================================== */
package org.apache.poi.xslf.usermodel;
import java.io.IOException;
import java.io.InputStream;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.POIXMLException;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.util.Beta;
import org.apache.xmlbeans.XmlException;
import org.openxmlformats.schemas.drawingml.x2006.main.CTColorMapping;
import org.openxmlformats.schemas.presentationml.x2006.main.CTNotesMaster;
import org.openxmlformats.schemas.presentationml.x2006.main.NotesMasterDocument;
import java.io.IOException;
/**
* Notes master object associated with this layout.
* <p>
@ -44,10 +48,11 @@ import java.io.IOException;
@Beta
public class XSLFNotesMaster extends XSLFSheet {
private CTNotesMaster _slide;
private XSLFTheme _theme;
XSLFNotesMaster() {
super();
_slide = CTNotesMaster.Factory.newInstance();
_slide = prototype();
}
protected XSLFNotesMaster(PackagePart part, PackageRelationship rel) throws IOException, XmlException {
@ -58,6 +63,21 @@ import java.io.IOException;
setCommonSlideData(_slide.getCSld());
}
private static CTNotesMaster prototype() {
InputStream is = XSLFNotesMaster.class.getResourceAsStream("notesMaster.xml");
if (is == null) {
throw new POIXMLException("Missing resource 'notesMaster.xml'");
}
try {
NotesMasterDocument doc = NotesMasterDocument.Factory.parse(is);
CTNotesMaster slide = doc.getNotesMaster();
return slide;
} catch (Exception e) {
throw new POIXMLException("Can't initialize NotesMaster", e);
}
}
@Override
public CTNotesMaster getXmlObject() {
return _slide;
@ -73,4 +93,20 @@ import java.io.IOException;
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;
}
}

View File

@ -999,13 +999,22 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
"declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' " +
"declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' " +
".//p:txStyles/p:" + defaultStyleSelector +"/a:lvl" +(level+1)+ "pPr");
if(o.length == 1){
if (o.length == 1){
return (CTTextParagraphProperties)o[0];
} else {
o = masterSheet.getXmlObject().selectPath(
"declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' " +
"declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' " +
".//p:notesStyle/a:lvl" +(level+1)+ "pPr");
if (o.length == 1){
return (CTTextParagraphProperties)o[0];
}
throw new IllegalArgumentException("Failed to fetch default style for " +
defaultStyleSelector + " and level=" + level);
}
}
private boolean fetchParagraphProperty(ParagraphPropertyFetcher visitor){
boolean ok = false;

View File

@ -16,6 +16,13 @@
==================================================================== */
package org.apache.poi.xslf.usermodel;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import javax.xml.namespace.QName;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship;
@ -32,12 +39,6 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTOfficeStyleSheet;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.ThemeDocument;
import javax.xml.namespace.QName;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
/**
* A shared style sheet in a .pptx slide show
*
@ -61,6 +62,11 @@ public class XSLFTheme extends POIXMLDocumentPart {
initialize();
}
public void importTheme(XSLFTheme theme) {
_theme = theme.getXmlObject();
_schemeColors = theme._schemeColors;
}
private void initialize(){
CTBaseStyles elems = _theme.getThemeElements();
CTColorScheme scheme = elems.getClrScheme();

View File

@ -0,0 +1,97 @@
/* ====================================================================
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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import org.apache.poi.xslf.XSLFTestDataSamples;
import org.junit.Test;
public class TestXSLFNotes {
@Test
public void createNewNote() {
XMLSlideShow ppt = new XMLSlideShow();
XSLFSlide slide1 = ppt.createSlide();
assertNull(ppt.getNotesMaster());
assertNull(slide1.getNotes());
XSLFNotes notesSlide = ppt.getNotesSlide(slide1);
assertNotNull(ppt.getNotesMaster());
assertNotNull(notesSlide);
String note = null;
for (XSLFTextShape shape : notesSlide.getPlaceholders()) {
if (shape.getTextType() == Placeholder.BODY) {
shape.setText("New Note");
note = shape.getText();
break;
}
}
assertNotNull(note);
assertEquals("New Note", note);
}
@Test
public void addNote() {
XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("sample.pptx");
XSLFSlide slide = ppt.createSlide();
XSLFNotes notesSlide = ppt.getNotesSlide(slide);
assertNotNull(notesSlide);
String note = null;
for (XSLFTextShape shape : notesSlide.getPlaceholders()) {
if (shape.getTextType() == Placeholder.BODY) {
shape.setText("New Note");
note = shape.getText();
break;
}
}
assertNotNull(note);
assertEquals("New Note", note);
}
@Test
public void replaceNotes() {
XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("sample.pptx");
for (XSLFSlide slide : ppt.getSlides()) {
assertNotNull(slide.getNotes());
XSLFNotes notesSlide = ppt.getNotesSlide(slide);
assertNotNull(notesSlide);
String note = null;
for (XSLFTextShape shape : notesSlide.getPlaceholders()) {
if (shape.getTextType() == Placeholder.BODY) {
shape.setText("New Note");
note = shape.getText();
break;
}
}
assertNotNull(note);
assertEquals("New Note", note);
}
}
}

File diff suppressed because one or more lines are too long