![JAR search and dependency download from the Maven repository](/logo.png)
org.odftoolkit.odfdom.doc.OdfPresentationDocument Maven / Gradle / Ivy
Show all versions of odfdom-java Show documentation
/************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* Copyright 2008, 2010 Oracle and/or its affiliates. All rights reserved.
*
* Use is subject to license terms.
*
* Licensed 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. You can also
* obtain a copy of the License at http://odftoolkit.org/docs/license.txt
*
* 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.odftoolkit.odfdom.doc;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import org.odftoolkit.odfdom.pkg.OdfElement;
import org.odftoolkit.odfdom.pkg.OdfFileDom;
import org.odftoolkit.odfdom.pkg.OdfName;
import org.odftoolkit.odfdom.pkg.OdfNamespace;
import org.odftoolkit.odfdom.doc.presentation.OdfSlide;
import org.odftoolkit.odfdom.dom.OdfContentDom;
import org.odftoolkit.odfdom.dom.OdfDocumentNamespace;
import org.odftoolkit.odfdom.dom.OdfStylesDom;
import org.odftoolkit.odfdom.dom.attribute.presentation.PresentationClassAttribute;
import org.odftoolkit.odfdom.dom.element.OdfStyleBase;
import org.odftoolkit.odfdom.dom.element.draw.DrawFrameElement;
import org.odftoolkit.odfdom.dom.element.draw.DrawPageElement;
import org.odftoolkit.odfdom.dom.element.draw.DrawPageThumbnailElement;
import org.odftoolkit.odfdom.dom.element.office.OfficePresentationElement;
import org.odftoolkit.odfdom.dom.element.presentation.PresentationNotesElement;
import org.odftoolkit.odfdom.dom.element.style.StyleGraphicPropertiesElement;
import org.odftoolkit.odfdom.dom.element.style.StylePresentationPageLayoutElement;
import org.odftoolkit.odfdom.incubator.doc.office.OdfOfficeAutomaticStyles;
import org.odftoolkit.odfdom.incubator.doc.office.OdfOfficeStyles;
import org.odftoolkit.odfdom.pkg.MediaType;
import org.odftoolkit.odfdom.pkg.OdfPackage;
import org.odftoolkit.odfdom.pkg.OdfPackageDocument;
import org.odftoolkit.odfdom.pkg.manifest.OdfFileEntry;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* This class represents an empty ODF presentation.
*
* @deprecated As of release 0.8.8, replaced by {@link org.odftoolkit.simple.PresentationDocument} in Simple API.
*/
public class OdfPresentationDocument extends OdfDocument {
private static final String EMPTY_PRESENTATION_DOCUMENT_PATH = "/OdfPresentationDocument.odp";
static final Resource EMPTY_PRESENTATION_DOCUMENT_RESOURCE = new Resource(EMPTY_PRESENTATION_DOCUMENT_PATH);
/**
* This enum contains all possible media types of OdfPresentationDocument
* documents.
*/
public enum OdfMediaType implements MediaType {
PRESENTATION(OdfDocument.OdfMediaType.PRESENTATION),
PRESENTATION_TEMPLATE(OdfDocument.OdfMediaType.PRESENTATION_TEMPLATE);
private final OdfDocument.OdfMediaType mMediaType;
OdfMediaType(OdfDocument.OdfMediaType mediaType) {
this.mMediaType = mediaType;
}
/**
* @return the ODF mediatype of this document
*/
public OdfDocument.OdfMediaType getOdfMediaType() {
return mMediaType;
}
/**
* @return the mediatype of this document
*/
public String getMediaTypeString() {
return mMediaType.getMediaTypeString();
}
/**
* @return the ODF filesuffix of this document
*/
public String getSuffix() {
return mMediaType.getSuffix();
}
/**
*
* @param mediaType string defining an ODF document
* @return the according OdfMediatype encapuslating the given string and the suffix
*/
public static OdfDocument.OdfMediaType getOdfMediaType(String mediaType) {
return OdfDocument.OdfMediaType.getOdfMediaType(mediaType);
}
}
/**
* Creates an empty presentation document.
* @return ODF presentation document based on a default template
* @throws java.lang.Exception - if the document could not be created
*/
public static OdfPresentationDocument newPresentationDocument() throws Exception {
return (OdfPresentationDocument) OdfDocument.loadTemplate(EMPTY_PRESENTATION_DOCUMENT_RESOURCE, OdfDocument.OdfMediaType.PRESENTATION);
}
/**
* Creates an empty presentation template.
* @return ODF presentation template based on a default
* @throws Exception - if the template could not be created
*/
public static OdfPresentationDocument newPresentationTemplateDocument() throws Exception {
OdfPresentationDocument doc = (OdfPresentationDocument) OdfDocument.loadTemplate(EMPTY_PRESENTATION_DOCUMENT_RESOURCE, OdfDocument.OdfMediaType.PRESENTATION_TEMPLATE);
doc.changeMode(OdfMediaType.PRESENTATION_TEMPLATE);
return doc;
}
/** To avoid data duplication a new document is only created, if not already opened.
* A document is cached by this constructor using the internalpath as key. */
protected OdfPresentationDocument(OdfPackage pkg, String internalPath, OdfPresentationDocument.OdfMediaType odfMediaType) throws SAXException {
super(pkg, internalPath, odfMediaType.mMediaType);
}
/**
* Creates an OdfPresentationDocument from the OpenDocument provided by a resource Stream.
*
* Since an InputStream does not provide the arbitrary (non sequentiell)
* read access needed by OdfPresentationDocument, the InputStream is cached. This usually
* takes more time compared to the other createInternalDocument methods.
* An advantage of caching is that there are no problems overwriting
* an input file.
*
* If the resource stream is not a ODF presentation document, ClassCastException might be thrown.
*
* @param inputStream - the InputStream of the ODF presentation document.
* @return the presentation document created from the given InputStream
* @throws java.lang.Exception - if the document could not be created.
*/
public static OdfPresentationDocument loadDocument(InputStream inputStream) throws Exception {
return (OdfPresentationDocument) OdfDocument.loadDocument(inputStream);
}
/**
* Loads an OdfPresentationDocument from the provided path.
*
* OdfPresentationDocument relies on the file being available for read access over
* the whole lifecycle of OdfPresentationDocument.
*
* If the resource stream is not a ODF presentation document, ClassCastException might be thrown.
*
* @param documentPath - the path from where the document can be loaded
* @return the presentation document from the given path
* or NULL if the media type is not supported by ODFDOM.
* @throws java.lang.Exception - if the document could not be created.
*/
public static OdfPresentationDocument loadDocument(String documentPath) throws Exception {
return (OdfPresentationDocument) OdfDocument.loadDocument(documentPath);
}
/**
* Creates an OdfPresentationDocument from the OpenDocument provided by a File.
*
* OdfPresentationDocument relies on the file being available for read access over
* the whole lifecycle of OdfPresentationDocument.
*
* If the resource stream is not a ODF presentation document, ClassCastException might be thrown.
*
* @param file - a file representing the ODF presentation document.
* @return the presentation document created from the given File
* @throws java.lang.Exception - if the document could not be created.
*/
public static OdfPresentationDocument loadDocument(File file) throws Exception {
return (OdfPresentationDocument) OdfDocument.loadDocument(file);
}
/**
* Get the content root of a presentation document.
*
* @return content root, representing the office:presentation tag
* @throws Exception if the file DOM could not be created.
*/
@Override
public OfficePresentationElement getContentRoot() throws Exception {
return super.getContentRoot(OfficePresentationElement.class);
}
/**
* Switches this instance to the given type. This method can be used to e.g.
* convert a document instance to a template and vice versa.
* Changes take affect in the package when saving the document.
*
* @param type the compatible ODF mediatype.
*/
public void changeMode(OdfMediaType type) {
setOdfMediaType(type.mMediaType);
}
private boolean hasCheckSlideName = false;
//if the copy foreign slide for several times,
//the same style might be copied for several times with the different name
//so use styleRenameMap to keep track the renamed style so we can reuse the style,
//rather than new several styles which only have the different style names.
//while if the style elements really have the same style name but with different content
//such as that these style elements are from different document
//so the value for each key should be a list
private HashMap> styleRenameMap = new HashMap>();
//the map is used to record if the renamed style name is appended to the current dom
private HashMap styleAppendMap = new HashMap();
//the object rename map for image.
//can not easily recognize if the embedded document are the same.
// private HashMap objectRenameMap = new HashMap();
/**
* Return the slide at a specified position in this presentation.
* Return null if the index is out of range.
*
* @param index the index of the slide to be returned
* @return a draw slide at the specified position
*/
public OdfSlide getSlideByIndex(int index) {
checkAllSlideName();
OfficePresentationElement contentRoot = null;
try {
contentRoot = getContentRoot();
} catch (Exception e) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e);
return null;
}
NodeList slideNodes = contentRoot.getElementsByTagNameNS(OdfDocumentNamespace.DRAW.getUri(), "page");
if ((index >= slideNodes.getLength()) || (index < 0)) {
return null;
}
DrawPageElement slideElement = (DrawPageElement) slideNodes.item(index);
return OdfSlide.getInstance(slideElement);
}
/**
* Get the number of the slides in this presentation.
*
* @return the number of slides
*/
public int getSlideCount() {
checkAllSlideName();
OfficePresentationElement contentRoot = null;
try {
contentRoot = getContentRoot();
} catch (Exception e) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e);
return 0;
}
NodeList slideNodes = contentRoot.getElementsByTagNameNS(OdfDocumentNamespace.DRAW.getUri(), "page");
return slideNodes.getLength();
}
/**
* Return the slide which have a specified slide name in this presentation.
*
* According to the odf specification
* "The draw:name attribute specifies a name by which this element can be referenced.
* It is optional but if present, must be unique within the document instance.
* If not present, an application may generate a unique name."
*
* If the name is null, then return null because all the slide must has its own unique name.
*
* @param name the specified slide name
* @return the slide whose name equals to the specified name
*/
public OdfSlide getSlideByName(String name) {
checkAllSlideName();
if (name == null) {
return null;
}
OfficePresentationElement contentRoot = null;
try {
contentRoot = getContentRoot();
} catch (Exception e) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e);
return null;
}
NodeList slideNodes = contentRoot.getElementsByTagNameNS(OdfDocumentNamespace.DRAW.getUri(), "page");
for (int i = 0; i < slideNodes.getLength(); i++) {
DrawPageElement slideElement = (DrawPageElement) slideNodes.item(i);
OdfSlide slide = OdfSlide.getInstance(slideElement);
String slideName = slide.getSlideName();
if (slideName.equals(name)) {
return slide;
}
}
return null;
}
//when access slide related method, this function should be called
private void checkAllSlideName() {
//check if this function is called or not
if (hasCheckSlideName) {
return;
}
List slideNameList = new ArrayList();
OfficePresentationElement contentRoot = null;
try {
contentRoot = getContentRoot();
} catch (Exception e) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e);
return;
}
NodeList slideNodes = contentRoot.getElementsByTagNameNS(OdfDocumentNamespace.DRAW.getUri(), "page");
for (int i = 0; i < slideNodes.getLength(); i++) {
DrawPageElement slideElement = (DrawPageElement) slideNodes.item(i);
String slideName = slideElement.getDrawNameAttribute();
if ((slideName == null) || slideNameList.contains(slideName)) {
slideName = "page" + (i + 1) + "-" + makeUniqueName();
slideElement.setDrawNameAttribute(slideName);
}
slideNameList.add(slideName);
}
hasCheckSlideName = true;
}
/**
* Return a list iterator containing all slides in this presentation.
*
* @return a list iterator containing all slides in this presentation
*/
public Iterator getSlides() {
checkAllSlideName();
OfficePresentationElement contentRoot = null;
try {
contentRoot = getContentRoot();
} catch (Exception e) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e);
return null;
}
ArrayList slideList = new ArrayList();
NodeList slideNodes = contentRoot.getElementsByTagNameNS(OdfDocumentNamespace.DRAW.getUri(), "page");
for (int i = 0; i < slideNodes.getLength(); i++) {
DrawPageElement slideElement = (DrawPageElement) slideNodes.item(i);
slideList.add(OdfSlide.getInstance(slideElement));
}
return slideList.iterator();
}
/**
* Delete the slide at a specified position in this presentation.
*
* @param index the index of the slide that need to be delete
*
* Throw IndexOutOfBoundsException if the slide index is out of the presentation document slide count.
* @return false if the operation was not successful
*/
public boolean deleteSlideByIndex(int index) {
boolean success = true;
checkAllSlideName();
OfficePresentationElement contentRoot = null;
try {
contentRoot = getContentRoot();
} catch (Exception e) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e);
success = false;
return success;
}
NodeList slideNodes = contentRoot.getElementsByTagNameNS(OdfDocumentNamespace.DRAW.getUri(), "page");
if ((index >= slideNodes.getLength()) || (index < 0)) {
throw new IndexOutOfBoundsException("the specified Index is out of slide count when call deleteSlideByIndex method.");
}
DrawPageElement slideElement = (DrawPageElement) slideNodes.item(index);
//remove all the content of the current page
//1. the reference of the path that contained in this slide is 1, then remove it
success &= deleteLinkRef(slideElement);
//2.the reference of the style is 1, then remove it
//in order to save time, do not delete the style here
success &= deleteStyleRef(slideElement);
//remove the current page element
contentRoot.removeChild(slideElement);
adjustNotePageNumber(index);
return success;
}
private boolean deleteStyleRef(DrawPageElement slideEle) {
boolean success = true;
try {
//method 1:
//1.1. iterate child element of the content element
//1.2. if the child element is an OdfStylableElement, get the style-name ref count
////////////////
//method 2:
//2.1. get the list of the style definition
ArrayList removeStyles = new ArrayList();
OdfOfficeAutomaticStyles autoStyles = getContentDom().getAutomaticStyles();
NodeList stylesList = autoStyles.getChildNodes();
OdfContentDom contentDom = getContentDom();
XPath xpath = contentDom.getXPath();
//2.2. get the reference of each style which occurred in the current page
for (int i = 0; i < stylesList.getLength(); i++) {
Node item = stylesList.item(i);
if (item instanceof OdfElement) {
OdfElement node = (OdfElement) item;
String styleName = node.getAttributeNS(OdfDocumentNamespace.STYLE.getUri(), "name");
if (styleName != null) {
//search the styleName contained at the current page element
NodeList styleNodes = (NodeList) xpath.evaluate("//*[@*='" + styleName + "']", contentDom, XPathConstants.NODESET);
int styleCnt = styleNodes.getLength();
if (styleCnt > 1) {
//the first styleName is occurred in the style definition
//so check if the second styleName and last styleName is occurred in the current page element
//if yes, then remove it
OdfElement elementFirst = (OdfElement) styleNodes.item(1);
OdfElement elementLast = (OdfElement) styleNodes.item(styleCnt - 1);
boolean isSamePage = false;
if (elementFirst instanceof DrawPageElement) {
DrawPageElement tempPage = (DrawPageElement) elementFirst;
if (tempPage.equals(slideEle)) {
isSamePage = true;
}
}
int relationFirst = slideEle.compareDocumentPosition(elementFirst);
int relationLast = slideEle.compareDocumentPosition(elementLast);
//if slide element contains the child element which has the styleName reference
if (((relationFirst & Node.DOCUMENT_POSITION_CONTAINED_BY) > 0
&& (relationLast & Node.DOCUMENT_POSITION_CONTAINED_BY) > 0)
|| (isSamePage && (styleCnt == 1))) {
if (node instanceof OdfStyleBase) {
removeStyles.add(node);
}
}
} else {
continue;
}
}
}
}
for (int i = 0; i < removeStyles.size(); i++) {
autoStyles.removeChild(removeStyles.get(i));
}
} catch (Exception e) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e);
success = false;
}
return success;
}
//delete all the xlink:href object which is contained in slideElement and does not referred by other slides
private boolean deleteLinkRef(DrawPageElement slideEle) {
boolean success = true;
try {
OdfContentDom contentDom = getContentDom();
XPath xpath = contentDom.getXPath();
NodeList linkNodes = (NodeList) xpath.evaluate("//*[@xlink:href]", contentDom, XPathConstants.NODESET);
for (int i = 0; i < linkNodes.getLength(); i++) {
OdfElement object = (OdfElement) linkNodes.item(i);
String refObjPath = object.getAttributeNS(OdfDocumentNamespace.XLINK.getUri(), "href");
int relation = slideEle.compareDocumentPosition(object);
//if slide element contains the returned element which has the xlink:href reference
if ((relation & Node.DOCUMENT_POSITION_CONTAINED_BY) > 0 && refObjPath != null && refObjPath.length() > 0) {
//the path of the object is start with "./"
NodeList pathNodes = (NodeList) xpath.evaluate("//*[@xlink:href='" + refObjPath + "']", getContentDom(), XPathConstants.NODESET);
int refCount = pathNodes.getLength();
if (refCount == 1) {
//delete "./"
if (refObjPath.startsWith("./")) {
refObjPath = refObjPath.substring(2);
}
//check if the current document contains the same path
OdfFileEntry fileEntry = getPackage().getFileEntry(refObjPath);
if (fileEntry != null) {
//it is a stream, such as image, binary file
getPackage().remove(refObjPath);
} else {
//note: if refObjPath is a directory, it must end with '/'
fileEntry = getPackage().getFileEntry(refObjPath + "/");
removeDocument(refObjPath);
}
}
}
}
} catch (XPathExpressionException e) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e);
success = false;
} catch (Exception e) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e);
success = false;
}
return success;
}
/**
* Delete all the slides with a specified name in this presentation.
*
* @param name the name of the slide that need to be delete
* @return false if the operation was not successful
*/
public boolean deleteSlideByName(String name) {
boolean success = true;
checkAllSlideName();
OfficePresentationElement contentRoot = null;
try {
contentRoot = getContentRoot();
} catch (Exception e) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e);
success = false;
return success;
}
OdfSlide slide = getSlideByName(name);
DrawPageElement slideElement = slide.getOdfElement();
//remove all the content of the current page
//1. the reference of the path that contained in this slide is 1, then remove its
success &= deleteLinkRef(slideElement);
//2.the reference of the style is 1, then remove it
//in order to save time, do not delete style here
success &= deleteStyleRef(slideElement);
//remove the current page element
contentRoot.removeChild(slideElement);
adjustNotePageNumber(0);
return success;
}
/**
* Make a copy of the slide at a specified position to another position in this presentation.
* The original slide which at the dest index and after the dest index will move after.
*
* @param source the source position of the slide need to be copied
* @param dest the destination position of the slide need to be copied
* @param newName the new name of the copied slide
* @return the new slide at the destination position with the specified name, and it has the same content
* with the slide at the source position.
*
* Throw IndexOutOfBoundsException if the slide index is out of the presentation document slide count.
* If copy the slide at the end of document, destIndex should set the same value with the slide count.
*/
public OdfSlide copySlide(int source, int dest, String newName) {
checkAllSlideName();
OfficePresentationElement contentRoot = null;
try {
contentRoot = getContentRoot();
} catch (Exception e) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e);
return null;
}
NodeList slideList = contentRoot.getElementsByTagNameNS(OdfDocumentNamespace.DRAW.getUri(), "page");
int slideCount = slideList.getLength();
if ((source < 0) || (source >= slideCount)
|| (dest < 0) || (dest > slideCount)) {
throw new IndexOutOfBoundsException("the specified Index is out of slide count when call copySlide method.");
}
DrawPageElement sourceSlideElement = (DrawPageElement) slideList.item(source);
DrawPageElement cloneSlideElement = (DrawPageElement) sourceSlideElement.cloneNode(true);
cloneSlideElement.setDrawNameAttribute(newName);
if (dest == slideCount) {
contentRoot.appendChild(cloneSlideElement);
} else {
DrawPageElement refSlide = (DrawPageElement) slideList.item(dest);
contentRoot.insertBefore(cloneSlideElement, refSlide);
}
adjustNotePageNumber(Math.min(source, dest));
//in case that the appended new slide have the same name with the original slide
hasCheckSlideName = false;
checkAllSlideName();
return OdfSlide.getInstance(cloneSlideElement);
}
/**
* Move the slide at a specified position to the destination position.
*
* @param source the current index of the slide that need to be moved
* @param dest The index of the destination position before the move action
*
* Throw IndexOutOfBoundsException if the slide index is out of the presentation document slide count.
*/
public void moveSlide(int source, int dest) {
checkAllSlideName();
OfficePresentationElement contentRoot = null;
try {
contentRoot = getContentRoot();
} catch (Exception e) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e);
return;
}
NodeList slideList = contentRoot.getElementsByTagNameNS(OdfDocumentNamespace.DRAW.getUri(), "page");
int slideCount = slideList.getLength();
if ((source < 0) || (source >= slideCount)
|| (dest < 0) || (dest > slideCount)) {
throw new IndexOutOfBoundsException("the specified Index is out of slide count when call moveSlide method.");
}
DrawPageElement sourceSlide = (DrawPageElement) slideList.item(source);
if (dest == slideCount) {
contentRoot.appendChild(sourceSlide);
} else {
DrawPageElement refSlide = (DrawPageElement) slideList.item(dest);
contentRoot.insertBefore(sourceSlide, refSlide);
}
adjustNotePageNumber(Math.min(source, dest));
}
/**
* Append all the slides of the specified presentation document to the current document.
* @param srcDoc the specified OdfPresentationDocument
that need to be appended
*/
public void appendPresentation(OdfPresentationDocument srcDoc) {
checkAllSlideName();
OfficePresentationElement contentRoot = null;
OdfFileDom contentDom = null;
OfficePresentationElement srcContentRoot = null;
try {
contentRoot = getContentRoot();
contentDom = getContentDom();
srcContentRoot = srcDoc.getContentRoot();
} catch (Exception e) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e);
}
NodeList slideList = contentRoot.getElementsByTagNameNS(OdfDocumentNamespace.DRAW.getUri(), "page");
int slideNum = slideList.getLength();
//clone the srcContentRoot, and make a modification on this clone node.
OfficePresentationElement srcCloneContentRoot = (OfficePresentationElement) srcContentRoot.cloneNode(true);
//copy all the referred xlink:href here
copyForeignLinkRef(srcCloneContentRoot);
//copy all the referred style definition here
copyForeignStyleRef(srcCloneContentRoot, srcDoc);
Node child = srcCloneContentRoot.getFirstChild();
while (child != null) {
Node cloneElement = cloneForeignElement(child, contentDom, true);
contentRoot.appendChild(cloneElement);
child = child.getNextSibling();
}
adjustNotePageNumber(slideNum - 1);
//in case that the appended new slide have the same name with the original slide
hasCheckSlideName = false;
checkAllSlideName();
}
/**
* Make a copy of slide which locates at the specified position of the source presentation document
* and insert it to the current presentation document at the new position.
* The original slide which at the dest index and after the dest index will move after.
* @param destIndex the new position of the copied slide in the current document
* @param srcDoc the source document of the copied slide
* @param srcIndex the slide index of the source document that need to be copied
* @return the new slide which has the same content with the source slide
*
* Throw IndexOutOfBoundsException if the slide index is out of the presentation document slide count
* If insert the foreign slide at the end of document, destIndex should set the same value
* with the slide count of the current presentation document.
*/
public OdfSlide copyForeignSlide(int destIndex,
OdfPresentationDocument srcDoc, int srcIndex) {
checkAllSlideName();
OfficePresentationElement contentRoot = null;
OdfFileDom contentDom = null;
try {
contentRoot = getContentRoot();
contentDom = getContentDom();
} catch (Exception e) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e);
return null;
}
NodeList slideList = contentRoot.getElementsByTagNameNS(OdfDocumentNamespace.DRAW.getUri(), "page");
int slideCount = slideList.getLength();
if ((destIndex < 0) || (destIndex > slideCount)) {
throw new IndexOutOfBoundsException("the specified Index is out of slide count when call copyForeignSlide method.");
}
OdfSlide sourceSlide = srcDoc.getSlideByIndex(srcIndex);
DrawPageElement sourceSlideElement = sourceSlide.getOdfElement();
//clone the sourceSlideEle, and make a modification on this clone node.
DrawPageElement sourceCloneSlideElement = (DrawPageElement) sourceSlideElement.cloneNode(true);
//copy all the referred xlink:href here
copyForeignLinkRef(sourceCloneSlideElement);
//copy all the referred style definition here
copyForeignStyleRef(sourceCloneSlideElement, srcDoc);
//clone the sourceCloneSlideEle, and this cloned element should in the current dom tree
DrawPageElement cloneSlideElement = (DrawPageElement) cloneForeignElement(sourceCloneSlideElement, contentDom, true);
if (destIndex == slideCount) {
contentRoot.appendChild(cloneSlideElement);
} else {
DrawPageElement refSlide = (DrawPageElement) slideList.item(destIndex);
contentRoot.insertBefore(cloneSlideElement, refSlide);
}
adjustNotePageNumber(destIndex);
//in case that the appended new slide have the same name with the original slide
hasCheckSlideName = false;
checkAllSlideName();
return OdfSlide.getInstance(cloneSlideElement);
}
//clone the source clone element's referred object path to the current package
//if the current package contains the same name with the referred object path,
//rename the object path and path reference of this slide element
//notes: the source clone element is the copied one to avoid changing the content of the source document.
private void copyForeignLinkRef(OdfElement sourceCloneEle) {
try {
OdfFileDom fileDom = (OdfFileDom) sourceCloneEle.getOwnerDocument();
XPath xpath;
if (fileDom instanceof OdfContentDom) {
xpath = ((OdfContentDom) fileDom).getXPath();
} else {
xpath = ((OdfStylesDom) fileDom).getXPath();
}
OdfPackageDocument srcDoc = fileDom.getDocument();
//new a map to put the original name and the rename string, in case that the same name might be referred by the slide several times.
HashMap objectRenameMap = new HashMap();
NodeList linkNodes = (NodeList) xpath.evaluate(".//*[@xlink:href]", sourceCloneEle, XPathConstants.NODESET);
for (int i = 0; i <= linkNodes.getLength(); i++) {
OdfElement object = null;
if (linkNodes.getLength() == i) {
if (sourceCloneEle.hasAttributeNS(OdfDocumentNamespace.XLINK.getUri(), "href")) {
object = sourceCloneEle;
} else {
break;
}
} else {
object = (OdfElement) linkNodes.item(i);
}
String refObjPath = object.getAttributeNS(OdfDocumentNamespace.XLINK.getUri(), "href");
if (refObjPath != null && refObjPath.length() > 0) {
//the path of the object is start with "./"
boolean hasPrefix = false;
String prefix = "./";
if (refObjPath.startsWith(prefix)) {
refObjPath = refObjPath.substring(2);
hasPrefix = true;
}
//check if the current document contains the same path
OdfFileEntry fileEntry = getPackage().getFileEntry(refObjPath);
//note: if refObjPath is a directory, it must end with '/'
if (fileEntry == null) {
fileEntry = getPackage().getFileEntry(refObjPath + "/");
}
String newObjPath = refObjPath;
if (fileEntry != null) {
//rename the object path
newObjPath = objectRenameMap.get(refObjPath);
if (newObjPath == null) {
//if refObjPath still contains ".", it means that it has the suffix
//then change the name before the suffix string
int dotIndex = refObjPath.indexOf(".");
if (dotIndex != -1) {
newObjPath = refObjPath.substring(0, dotIndex) + "-" + makeUniqueName() + refObjPath.substring(dotIndex);
} else {
newObjPath = refObjPath + "-" + makeUniqueName();
}
objectRenameMap.put(refObjPath, newObjPath);
}
object.setAttributeNS(OdfDocumentNamespace.XLINK.getUri(), "xlink:href", hasPrefix ? (prefix + newObjPath) : newObjPath);
}
InputStream is = srcDoc.getPackage().getInputStream(refObjPath);
if (is != null) {
String mediaType = srcDoc.getPackage().getFileEntry(refObjPath).getMediaTypeString();
getPackage().insert(is, newObjPath, mediaType);
} else {
OdfDocument embedDoc = (OdfDocument) srcDoc.loadSubDocument(refObjPath);
if (embedDoc != null) {
insertDocument(embedDoc, newObjPath);
}
}
}
}
} catch (Exception e) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e);
}
}
private void copyForeignStyleRef(OdfElement sourceCloneEle,
OdfPresentationDocument doc) {
try {
OdfContentDom contentDom = getContentDom();
XPath xpath = contentDom.getXPath();
//1. collect all the referred style element which has "style:name" attribute
//1.1. style:name of content.xml
String styleQName = "style:name";
NodeList srcStyleDefNodeList = (NodeList) xpath.evaluate("//*[@" + styleQName + "]", contentDom, XPathConstants.NODESET);
HashMap> srcContentStyleCloneEleList = new HashMap>();
HashMap appendContentStyleList = new HashMap();
getCopyStyleList(null, sourceCloneEle, styleQName, srcStyleDefNodeList, srcContentStyleCloneEleList, appendContentStyleList, true);
//1.2. style:name of styles.xml
srcStyleDefNodeList = (NodeList) xpath.evaluate("//*[@" + styleQName + "]", doc.getStylesDom(), XPathConstants.NODESET);
HashMap> srcStylesStyleCloneEleList = new HashMap>();
HashMap appendStylesStyleList = new HashMap();
getCopyStyleList(null, sourceCloneEle, styleQName, srcStyleDefNodeList, srcStylesStyleCloneEleList, appendStylesStyleList, true);
//1.3 rename, copy the referred style element to the corresponding position in the dom tree
insertCollectedStyle(styleQName, srcContentStyleCloneEleList, getContentDom(), appendContentStyleList);
insertCollectedStyle(styleQName, srcStylesStyleCloneEleList, getStylesDom(), appendStylesStyleList);
//2. collect all the referred style element which has "draw:name" attribute
//2.1 draw:name of styles.xml
//the value of draw:name is string or StyleName,
//only when the value is StyleName type, the style definition should be cloned to the destination document
//in ODF spec, such attribute type is only exist in element, so only search it in styles.xml dom
styleQName = "draw:name";
srcStyleDefNodeList = (NodeList) xpath.evaluate("//*[@" + styleQName + "]", doc.getStylesDom(), XPathConstants.NODESET);
HashMap> srcDrawStyleCloneEleList = new HashMap>();
HashMap appendDrawStyleList = new HashMap();
Iterator iter = appendContentStyleList.keySet().iterator();
while (iter.hasNext()) {
OdfElement styleElement = iter.next();
OdfElement cloneStyleElement = appendContentStyleList.get(styleElement);
getCopyStyleList(styleElement, cloneStyleElement, styleQName, srcStyleDefNodeList, srcDrawStyleCloneEleList, appendDrawStyleList, false);
}
iter = appendStylesStyleList.keySet().iterator();
while (iter.hasNext()) {
OdfElement styleElement = iter.next();
OdfElement cloneStyleElement = appendStylesStyleList.get(styleElement);
getCopyStyleList(styleElement, cloneStyleElement, styleQName, srcStyleDefNodeList, srcDrawStyleCloneEleList, appendDrawStyleList, false);
}
//2.2 rename, copy the referred style element to the corresponding position in the dom tree
//note: "draw:name" style element only exist in styles.dom
insertCollectedStyle(styleQName, srcDrawStyleCloneEleList, getStylesDom(), appendDrawStyleList);
} catch (Exception e) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e);
}
}
//1. modified the style name of the style definition element which has the same name with the source document
//2. As to the style definition which match 1) condition, modified the referred style name of the element which reference this style
//3. All the style which also contains other style reference, should be copied to the source document.
private void insertCollectedStyle(String styleQName,
HashMap> srcStyleCloneEleList, OdfFileDom dom, HashMap appendStyleList) {
try {
String stylePrefix = OdfNamespace.getPrefixPart(styleQName);
String styleLocalName = OdfNamespace.getLocalPart(styleQName);
String styleURI = OdfDocumentNamespace.STYLE.getUri();
// is the DOM always the styles.xml
XPath xpath = dom.getXPath();
NodeList destStyleNodeList = (NodeList) xpath.evaluate("//*[@" + styleQName + "]", dom, XPathConstants.NODESET);
// HashMap styleRenameMap = new HashMap();
Iterator iter = srcStyleCloneEleList.keySet().iterator();
while (iter.hasNext()) {
OdfElement styleElement = iter.next();
OdfElement cloneStyleElement = appendStyleList.get(styleElement);
if (cloneStyleElement == null) {
cloneStyleElement = (OdfElement) styleElement.cloneNode(true);
appendStyleList.put(styleElement, cloneStyleElement);
}
String styleName = styleElement.getAttributeNS(styleURI, styleLocalName);
List newStyleNameList = styleRenameMap.get(styleName);
// if the newStyleNameList != null, means that styleName exists in dest document
// and it has already been renamed
if ((newStyleNameList != null)
|| (isStyleNameExist(destStyleNodeList, styleName) != null)) {
String newStyleName = null;
if (newStyleNameList == null) {
newStyleNameList = new ArrayList();
newStyleName = styleName + "-" + makeUniqueName();
newStyleNameList.add(newStyleName);
styleRenameMap.put(styleName, newStyleNameList);
} else {
for (int i = 0; i < newStyleNameList.size(); i++) {
String styleNameIter = newStyleNameList.get(i);
OdfElement destStyleElementWithNewName = isStyleNameExist(destStyleNodeList, styleNameIter);
//check if the two style elements have the same content
//if not, the cloneStyleElement should rename, rather than reuse the new style name
cloneStyleElement.setAttributeNS(styleURI, styleQName, styleNameIter);
if ((destStyleElementWithNewName != null) && destStyleElementWithNewName.equals(cloneStyleElement)) {
newStyleName = styleNameIter;
break;
}
}
if (newStyleName == null) {
newStyleName = styleName + "-" + makeUniqueName();
newStyleNameList.add(newStyleName);
}
}
// if newStyleName has been set in the element as the new name
// which means that the newStyleName is conform to the odf spec
// then change element style reference name
if (changeStyleRefName(srcStyleCloneEleList.get(styleElement), styleName, newStyleName)) {
cloneStyleElement.setAttributeNS(styleURI, styleQName, newStyleName);
//if display name should also be renamed
String displayName = cloneStyleElement.getAttributeNS(styleURI, "display-name");
if ((displayName != null) && (displayName.length() > 0)) {
cloneStyleElement.setAttributeNS(styleURI, stylePrefix + ":display-name",
displayName + newStyleName.substring(newStyleName.length() - 8));
}
}
}
}
iter = appendStyleList.keySet().iterator();
while (iter.hasNext()) {
OdfElement styleElement = iter.next();
OdfElement cloneStyleElement = appendStyleList.get(styleElement);
String newStyleName = cloneStyleElement.getAttributeNS(styleURI, styleLocalName);
Boolean isAppended = styleAppendMap.get(newStyleName);
//if styleAppendMap contain the newStyleName,
//means that cloneStyleElement has already been appended
if ((isAppended != null) && isAppended.booleanValue() == true) {
continue;
} else {
styleAppendMap.put(newStyleName, true);
}
OdfElement cloneForeignStyleElement = (OdfElement) cloneForeignElement(cloneStyleElement, dom, true);
String styleElePath = getElementPath(styleElement);
appendForeignStyleElement(cloneForeignStyleElement, dom, styleElePath);
copyForeignLinkRef(cloneStyleElement);
}
} catch (Exception e) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e);
}
}
//get all the copy of referred style element which is directly referred or indirectly referred by cloneEle
//all the style are defined in srcStyleNodeList
//and these style are all have the styleName defined in styleQName attribute
//the key of copyStyleEleList is the style definition element
//the value of the corresponding key is the clone of the element which refer to the key,
//the cloned element can be the content of slide or the style element.
//the key of appendStyleList is the style definition element which has the other style reference
//the value of the corresponding key is the the style definition clone element
//loop means if recursive call this function
//if loop == true, get the style definition element reference other style definition element
private void getCopyStyleList(OdfElement ele, OdfElement cloneEle, String styleQName, NodeList srcStyleNodeList,
HashMap> copyStyleEleList, HashMap appendStyleList, boolean loop) {
try {
String styleLocalName = OdfNamespace.getLocalPart(styleQName);
String styleURI = OdfDocumentNamespace.STYLE.getUri();
//OdfElement override the "toString" method
String cloneEleStr = cloneEle.toString();
for (int i = 0; i < srcStyleNodeList.getLength(); i++) {
OdfElement styleElement = (OdfElement) srcStyleNodeList.item(i);
String styleName = styleElement.getAttributeNS(styleURI, styleLocalName);
if (styleName != null) {
int index = 0;
index = cloneEleStr.indexOf("=\"" + styleName + "\"", index);
while (index >= 0) {
String subStr = cloneEleStr.substring(0, index);
int lastSpaceIndex = subStr.lastIndexOf(' ');
String attrStr = subStr.substring(lastSpaceIndex + 1, index);
XPath xpath = ((OdfFileDom) cloneEle.getOwnerDocument()).getXPath();
NodeList styleRefNodes = (NodeList) xpath.evaluate(".//*[@" + attrStr + "='" + styleName + "']", cloneEle, XPathConstants.NODESET);
boolean isExist = false;
for (int j = 0; j <= styleRefNodes.getLength(); j++) {
OdfElement styleRefElement = null;
if (j == styleRefNodes.getLength()) {
isExist = isStyleNameRefExist(cloneEle, styleName, false);
if (isExist) {
styleRefElement = cloneEle;
} else {
continue;
}
} else {
OdfElement tmpElement = (OdfElement) styleRefNodes.item(j);
if (isStyleNameRefExist(tmpElement, styleName, false)) {
styleRefElement = tmpElement;
} else {
continue;
}
}
boolean hasLoopStyleDef = true;
if (copyStyleEleList.get(styleElement) == null) {
List styleRefEleList = new ArrayList();
copyStyleEleList.put(styleElement, styleRefEleList);
hasLoopStyleDef = false;
}
copyStyleEleList.get(styleElement).add(styleRefElement);
OdfElement cloneStyleElement = appendStyleList.get(styleElement);
if (cloneStyleElement == null) {
cloneStyleElement = (OdfElement) styleElement.cloneNode(true);
appendStyleList.put(styleElement, cloneStyleElement);
}
if (loop && !hasLoopStyleDef) {
getCopyStyleList(styleElement, cloneStyleElement, styleQName, srcStyleNodeList, copyStyleEleList, appendStyleList, loop);
}
}
index = cloneEleStr.indexOf("=\"" + styleName + "\"", index + styleName.length());
}
}
}
} catch (Exception e) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e);
}
}
//append the cloneStyleElement to the contentDom which position is defined by styleElePath
private void appendForeignStyleElement(OdfElement cloneStyleEle,
OdfFileDom dom, String styleElePath) {
StringTokenizer token = new StringTokenizer(styleElePath, "/");
boolean isExist = true;
Node iterNode = dom.getFirstChild();
Node parentNode = dom;
while (token.hasMoreTokens()) {
String onePath = token.nextToken();
while ((iterNode != null) && isExist) {
String path = iterNode.getNamespaceURI();
String prefix = iterNode.getPrefix();
if (prefix == null) {
path += "@" + iterNode.getLocalName();
} else {
path += "@" + prefix + ":" + iterNode.getLocalName();
}
if (!path.equals(onePath)) {
//not found, then get the next sibling to find such path node
iterNode = iterNode.getNextSibling();
} else {
//found, then get the child nodes to find the next path node
parentNode = iterNode;
iterNode = iterNode.getFirstChild();
break;
}
}
if (iterNode == null) {
//should new the element since the current path node
if (isExist) {
isExist = false;
}
StringTokenizer token2 = new StringTokenizer(onePath, "@");
OdfElement newElement = dom.createElementNS(OdfName.newName(token2.nextToken(), token2.nextToken()));
parentNode.appendChild(newElement);
parentNode = newElement;
}
}
parentNode.appendChild(cloneStyleEle);
}
//The returned string is a path from the top of the dom tree to the specified element
//and the path is split by "/" between each node
private String getElementPath(OdfElement styleEle) {
String path = "";
Node parentNode = styleEle.getParentNode();
while (!(parentNode instanceof OdfFileDom)) {
String qname = null;
String prefix = parentNode.getPrefix();
if (prefix == null) {
qname = parentNode.getLocalName();
} else {
qname = prefix + ":" + parentNode.getLocalName();
}
path = parentNode.getNamespaceURI() + "@" + qname + "/" + path;
parentNode = parentNode.getParentNode();
}
return path;
}
//change the element referred oldStyleName to the new name
//if true then set newStyleName attribute value successfully
//if false means that the newStyleName value is not conform to the ODF spec, so do not modify the oldStyleName
private boolean changeStyleRefName(List list, String oldStyleName, String newStyleName) {
boolean rtn = false;
for (int index = 0; index < list.size(); index++) {
OdfElement element = list.get(index);
NamedNodeMap attributes = element.getAttributes();
if (attributes != null) {
for (int i = 0; i < attributes.getLength(); i++) {
Node item = attributes.item(i);
String value = item.getNodeValue();
if (oldStyleName.equals(value)) {
try {
item.setNodeValue(newStyleName);
rtn = true;
break;
} catch (IllegalArgumentException e) {
return false;
}
}
}
}
}
return rtn;
}
//check if the element contains the referred styleName
private boolean isStyleNameRefExist(Node element, String styleName, boolean deep) {
NamedNodeMap attributes = element.getAttributes();
if (attributes != null) {
for (int i = 0; i < attributes.getLength(); i++) {
Node item = attributes.item(i);
if (item.getNodeValue().equals(styleName)
&& !item.getNodeName().equals("style:name")) //this is style definition, not reference
{
return true;
}
}
}
if (deep) {
Node childNode = element.getFirstChild();
while (childNode != null) {
if (!isStyleNameRefExist(childNode, styleName, true)) {
childNode = childNode.getNextSibling();
} else {
return true;
}
}
}
return false;
}
//check if nodeList contains the node that "style:name" attribute has the same value with styleName
//Note: nodeList here is all the style definition list
private OdfElement isStyleNameExist(NodeList nodeList,
String styleName) {
for (int i = 0; i < nodeList.getLength(); i++) {
OdfElement element = (OdfElement) nodeList.item(i);
String name = element.getAttributeNS(OdfDocumentNamespace.STYLE.getUri(), "name");
if (name.equals(styleName)) //return true;
{
return element;
}
}
//return false;
return null;
}
private String makeUniqueName() {
return String.format("a%06x", (int) (Math.random() * 0xffffff));
}
/**
* Make a content copy of the specified element,
* and the returned element should have the specified ownerDocument.
* @param element The element that need to be copied
* @param dom The specified DOM tree that the returned element belong to
* @param deep If true, recursively clone the subtree under the element,
* false, only clone the element itself
* @return Returns a duplicated element which is not in the DOM tree with the specified element
*/
public Node cloneForeignElement(Node element, OdfFileDom dom, boolean deep) {
checkAllSlideName();
if (element instanceof OdfElement) {
OdfElement cloneElement = dom.createElementNS(((OdfElement) element).getOdfName());
NamedNodeMap attributes = element.getAttributes();
if (attributes != null) {
for (int i = 0; i < attributes.getLength(); i++) {
Node item = attributes.item(i);
String qname = null;
String prefix = item.getPrefix();
if (prefix == null) {
qname = item.getLocalName();
} else {
qname = prefix + ":" + item.getLocalName();
}
cloneElement.setAttributeNS(item.getNamespaceURI(), qname, item.getNodeValue());
}
}
if (deep) {
Node childNode = element.getFirstChild();
while (childNode != null) {
cloneElement.appendChild(cloneForeignElement(childNode, dom, true));
childNode = childNode.getNextSibling();
}
}
return cloneElement;
} else {
return dom.createTextNode(element.getNodeValue());
}
}
/**
* New a slide at the specified position with the specified name,
* and use the specified slide template.
* See OdfDrawPage.SlideLayout
.
*
* If index is invalid, such as larger than the current document
* slide number or is negative,
* then append the new slide at the end of the document.
*
* The slide name can be null.
* @param index the new slide position
* @param name the new slide name
* @param slideLayout the new slide template
* @return the new slide which locate at the specified position
* with the specified name and apply the specified slide template.
* If slideLayout is null, then use the default slide template which is a blank slide.
*
* Throw IndexOutOfBoundsException if index is out of the presentation document slide count.
*/
public OdfSlide newSlide(int index, String name, OdfSlide.SlideLayout slideLayout) {
checkAllSlideName();
OfficePresentationElement contentRoot = null;
try {
contentRoot = getContentRoot();
} catch (Exception e) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e);
return null;
}
NodeList slideList = contentRoot.getElementsByTagNameNS(OdfDocumentNamespace.DRAW.getUri(), "page");
int slideCount = slideList.getLength();
if ((index < 0) || (index > slideCount)) {
throw new IndexOutOfBoundsException("the specified Index is out of slide count when call newSlide method.");
}
//if insert page at the beginning of the document,
//get the next page style as the new page style
//else get the previous page style as the new page style
DrawPageElement refStyleSlide = null;
int refSlideIndex = 0;
if (index > 0) {
refSlideIndex = index - 1;
}
refStyleSlide = (DrawPageElement) slideList.item(refSlideIndex);
String masterPageStyleName = "Default";
String masterName = refStyleSlide.getDrawMasterPageNameAttribute();
if (masterName != null) {
masterPageStyleName = masterName;
}
DrawPageElement newSlideElement = contentRoot.newDrawPageElement(masterPageStyleName);
newSlideElement.setDrawNameAttribute(name);
String drawStyleName = refStyleSlide.getDrawStyleNameAttribute();
if (drawStyleName != null) {
newSlideElement.setDrawStyleNameAttribute(drawStyleName);
}
String pageLayoutName = refStyleSlide.getPresentationPresentationPageLayoutNameAttribute();
if (pageLayoutName != null) {
newSlideElement.setPresentationPresentationPageLayoutNameAttribute(pageLayoutName);
}
setSlideLayout(newSlideElement, slideLayout);
//insert notes page
NodeList noteNodes = refStyleSlide.getElementsByTagNameNS(OdfDocumentNamespace.PRESENTATION.getUri(), "notes");
if (noteNodes.getLength() > 0) {
PresentationNotesElement notePage = (PresentationNotesElement) noteNodes.item(0);
PresentationNotesElement cloneNotePage = (PresentationNotesElement) notePage.cloneNode(true);
newSlideElement.appendChild(cloneNotePage);
}
if (index < slideCount) {
DrawPageElement refSlide = (DrawPageElement) slideList.item(index);
contentRoot.insertBefore(newSlideElement, refSlide);
}
adjustNotePageNumber(index);
//in case that the appended new slide have the same name with the original slide
hasCheckSlideName = false;
checkAllSlideName();
return OdfSlide.getInstance(newSlideElement);
}
//when insert a slide, the note page for this slide is also inserted.
//note page refer the slide index in order to show the corresponding slide notes view
//this function is used to adjust note page referred slide index since startIndex
//when the slide at startIndex has been delete or insert
private void adjustNotePageNumber(int startIndex) {
try {
OfficePresentationElement contentRoot = getContentRoot();
NodeList slideList = contentRoot.getElementsByTagNameNS(OdfDocumentNamespace.DRAW.getUri(), "page");
for (int i = startIndex; i < getSlideCount(); i++) {
DrawPageElement page = (DrawPageElement) slideList.item(i);
NodeList noteNodes = page.getElementsByTagNameNS(OdfDocumentNamespace.PRESENTATION.getUri(), "notes");
if (noteNodes.getLength() > 0) {
PresentationNotesElement notePage = (PresentationNotesElement) noteNodes.item(0);
NodeList thumbnailList = notePage.getElementsByTagNameNS(OdfDocumentNamespace.DRAW.getUri(), "page-thumbnail");
if (thumbnailList.getLength() > 0) {
DrawPageThumbnailElement thumbnail = (DrawPageThumbnailElement) thumbnailList.item(0);
thumbnail.setDrawPageNumberAttribute(i + 1);
}
}
}
} catch (Exception e) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e);
}
}
//covered element
//, ,
//
private void setSlideLayout(DrawPageElement page,
OdfSlide.SlideLayout slideLayout) {
if (slideLayout == null) {
slideLayout = OdfSlide.SlideLayout.BLANK;
}
OdfOfficeStyles styles = getOrCreateDocumentStyles();
String layoutName;
if (slideLayout.toString().equals(OdfSlide.SlideLayout.TITLE_ONLY.toString())) {
layoutName = "AL1T" + makeUniqueName();
try {
StylePresentationPageLayoutElement layout = styles.newStylePresentationPageLayoutElement(layoutName);
layout.newPresentationPlaceholderElement("title", "2.058cm", "1.743cm", "23.91cm", "3.507cm");
} catch (Exception e1) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e1);
}
page.setPresentationPresentationPageLayoutNameAttribute(layoutName);
DrawFrameElement frame1 = page.newDrawFrameElement();
frame1.setProperty(StyleGraphicPropertiesElement.StyleShadow, "true");
frame1.setProperty(StyleGraphicPropertiesElement.AutoGrowHeight, "true");
frame1.setProperty(StyleGraphicPropertiesElement.MinHeight, "3.507");
frame1.setPresentationStyleNameAttribute(frame1.getStyleName());
frame1.setDrawLayerAttribute("layout");
frame1.setSvgHeightAttribute("3.006cm");
frame1.setSvgWidthAttribute("24.299cm");
frame1.setSvgXAttribute("1.35cm");
frame1.setSvgYAttribute("0.717cm");
frame1.setPresentationClassAttribute(PresentationClassAttribute.Value.TITLE.toString());
frame1.setPresentationPlaceholderAttribute(true);
frame1.newDrawTextBoxElement();
} else if (slideLayout.toString().equals(OdfSlide.SlideLayout.TITLE_OUTLINE.toString())) {
layoutName = makeUniqueName();
try {
styles = super.getStylesDom().getOfficeStyles();
if (styles == null) {
styles = super.getStylesDom().newOdfElement(OdfOfficeStyles.class);
}
StylePresentationPageLayoutElement layout = styles.newStylePresentationPageLayoutElement(layoutName);
layout.newPresentationPlaceholderElement("title", "2.058cm", "1.743cm", "23.91cm", "3.507cm");
layout.newPresentationPlaceholderElement("outline", "2.058cm", "1.743cm", "23.91cm", "3.507cm");
} catch (Exception e1) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e1);
}
page.setPresentationPresentationPageLayoutNameAttribute(layoutName);
DrawFrameElement frame1 = page.newDrawFrameElement();
frame1.setProperty(StyleGraphicPropertiesElement.StyleShadow, "true");
frame1.setProperty(StyleGraphicPropertiesElement.AutoGrowHeight, "true");
frame1.setProperty(StyleGraphicPropertiesElement.MinHeight, "3.507");
frame1.setPresentationStyleNameAttribute(frame1.getStyleName());
frame1.setDrawLayerAttribute("layout");
frame1.setSvgHeightAttribute("3.006cm");
frame1.setSvgWidthAttribute("24.299cm");
frame1.setSvgXAttribute("1.35cm");
frame1.setSvgYAttribute("0.717cm");
frame1.setPresentationClassAttribute(PresentationClassAttribute.Value.TITLE.toString());
frame1.setPresentationPlaceholderAttribute(true);
frame1.newDrawTextBoxElement();
DrawFrameElement frame2 = page.newDrawFrameElement();
frame2.setProperty(StyleGraphicPropertiesElement.FillColor, "#ffffff");
frame2.setProperty(StyleGraphicPropertiesElement.MinHeight, "13.114");
frame2.setPresentationStyleNameAttribute(frame2.getStyleName());
frame2.setDrawLayerAttribute("layout");
frame2.setSvgHeightAttribute("11.629cm");
frame2.setSvgWidthAttribute("24.199cm");
frame2.setSvgXAttribute("1.35cm");
frame2.setSvgYAttribute("4.337cm");
frame2.setPresentationClassAttribute(PresentationClassAttribute.Value.OUTLINE.toString());
frame2.setPresentationPlaceholderAttribute(true);
frame2.newDrawTextBoxElement();
} else if (slideLayout.toString().equals(OdfSlide.SlideLayout.TITLE_PLUS_TEXT.toString())) {
layoutName = makeUniqueName();
try {
styles = super.getStylesDom().getOfficeStyles();
if (styles == null) {
styles = super.getStylesDom().newOdfElement(OdfOfficeStyles.class);
}
StylePresentationPageLayoutElement layout = styles.newStylePresentationPageLayoutElement(layoutName);
layout.newPresentationPlaceholderElement("title", "2.058cm", "1.743cm", "23.91cm", "1.743cm");
layout.newPresentationPlaceholderElement("subtitle", "2.058cm", "5.838cm", "23.91cm", "13.23cm");
} catch (Exception e1) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e1);
}
page.setPresentationPresentationPageLayoutNameAttribute(layoutName);
DrawFrameElement frame1 = page.newDrawFrameElement();
frame1.setProperty(StyleGraphicPropertiesElement.AutoGrowHeight, "true");
frame1.setProperty(StyleGraphicPropertiesElement.MinHeight, "3.507");
frame1.setPresentationStyleNameAttribute(frame1.getStyleName());
frame1.setDrawLayerAttribute("layout");
frame1.setSvgHeightAttribute("3.006cm");
frame1.setSvgWidthAttribute("24.299cm");
frame1.setSvgXAttribute("1.35cm");
frame1.setSvgYAttribute("0.717cm");
frame1.setPresentationClassAttribute(PresentationClassAttribute.Value.TITLE.toString());
frame1.setPresentationPlaceholderAttribute(true);
frame1.newDrawTextBoxElement();
DrawFrameElement frame2 = page.newDrawFrameElement();
frame2.setProperty(StyleGraphicPropertiesElement.AutoGrowHeight, "true");
frame2.setProperty(StyleGraphicPropertiesElement.MinHeight, "3.507");
frame2.setPresentationStyleNameAttribute(frame2.getStyleName());
frame2.setDrawLayerAttribute("layout");
frame2.setSvgHeightAttribute("11.88cm");
frame2.setSvgWidthAttribute("24.299cm");
frame2.setSvgXAttribute("1.35cm");
frame2.setSvgYAttribute("4.712cm");
frame2.setPresentationClassAttribute(PresentationClassAttribute.Value.SUBTITLE.toString());
frame2.setPresentationPlaceholderAttribute(true);
frame2.newDrawTextBoxElement();
} else if (slideLayout.toString().equals(OdfSlide.SlideLayout.TITLE_PLUS_2_TEXT_BLOCK.toString())) {
layoutName = makeUniqueName();
try {
styles = super.getStylesDom().getOfficeStyles();
if (styles == null) {
styles = super.getStylesDom().newOdfElement(OdfOfficeStyles.class);
}
StylePresentationPageLayoutElement layout = styles.newStylePresentationPageLayoutElement(layoutName);
layout.newPresentationPlaceholderElement("outline", "2.058cm", "1.743cm", "23.91cm", "1.743cm");
layout.newPresentationPlaceholderElement("outline", "1.35cm", "4.212cm", "11.857cm", "11.629cm");
layout.newPresentationPlaceholderElement("outline", "4.212cm", "13.8cm", "11.857cm", "11.629cm");
} catch (Exception e1) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e1);
}
DrawFrameElement frame1 = page.newDrawFrameElement();
frame1.setProperty(StyleGraphicPropertiesElement.AutoGrowHeight, "true");
frame1.setProperty(StyleGraphicPropertiesElement.MinHeight, "3.507");
frame1.setPresentationStyleNameAttribute(frame1.getStyleName());
frame1.setDrawLayerAttribute("layout");
frame1.setSvgHeightAttribute("3.006cm");
frame1.setSvgWidthAttribute("24.299cm");
frame1.setSvgXAttribute("1.35cm");
frame1.setSvgYAttribute("0.717cm");
frame1.setPresentationClassAttribute(PresentationClassAttribute.Value.TITLE.toString());
frame1.setPresentationPlaceholderAttribute(true);
frame1.newDrawTextBoxElement();
DrawFrameElement frame2 = page.newDrawFrameElement();
frame2.setProperty(StyleGraphicPropertiesElement.AutoGrowHeight, "true");
frame2.setProperty(StyleGraphicPropertiesElement.MinHeight, "3.507");
frame2.setPresentationStyleNameAttribute(frame2.getStyleName());
frame2.setDrawLayerAttribute("layout");
frame2.setSvgHeightAttribute("11.629cm");
frame2.setSvgWidthAttribute("11.857cm");
frame2.setSvgXAttribute("1.35cm");
frame2.setSvgYAttribute("4.212cm");
frame2.setPresentationClassAttribute(PresentationClassAttribute.Value.OUTLINE.toString());
frame2.setPresentationPlaceholderAttribute(true);
frame2.newDrawTextBoxElement();
DrawFrameElement frame3 = page.newDrawFrameElement();
frame3.setProperty(StyleGraphicPropertiesElement.AutoGrowHeight, "true");
frame3.setProperty(StyleGraphicPropertiesElement.MinHeight, "3.507");
frame3.setPresentationStyleNameAttribute(frame3.getStyleName());
frame3.setDrawLayerAttribute("layout");
frame3.setSvgHeightAttribute("11.62cm");
frame3.setSvgWidthAttribute("11.857cm");
frame3.setSvgXAttribute("13.8cm");
frame3.setSvgYAttribute("4.212cm");
frame3.setPresentationClassAttribute(PresentationClassAttribute.Value.OUTLINE.toString());
frame3.setPresentationPlaceholderAttribute(true);
frame3.newDrawTextBoxElement();
page.setPresentationPresentationPageLayoutNameAttribute(layoutName);
}
}
}