OdfPresentationDocument.java
/**
* **********************************************************************
*
* <p>DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* <p>Copyright 2008, 2010 Oracle and/or its affiliates. All rights reserved.
*
* <p>Use is subject to license terms.
*
* <p>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
*
* <p>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.
*
* <p>See the License for the specific language governing permissions and limitations under the
* License.
*
* <p>**********************************************************************
*/
package org.odftoolkit.odfdom.doc;
import java.io.File;
import java.io.IOException;
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.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.OdfElement;
import org.odftoolkit.odfdom.pkg.OdfFileDom;
import org.odftoolkit.odfdom.pkg.OdfName;
import org.odftoolkit.odfdom.pkg.OdfNamespace;
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. */
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.
*
* <p>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.
*
* <p>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.
*
* <p>OdfPresentationDocument relies on the file being available for read access over the whole
* lifecycle of OdfPresentationDocument.
*
* <p>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.
*
* <p>OdfPresentationDocument relies on the file being available for read access over the whole
* lifecycle of OdfPresentationDocument.
*
* <p>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<String, List<String>> styleRenameMap = new HashMap<String, List<String>>();
// the map is used to record if the renamed style name is appended to the current dom
private HashMap<String, Boolean> styleAppendMap = new HashMap<String, Boolean>();
// the object rename map for image.
// can not easily recognize if the embedded document are the same.
// private HashMap<String, String> objectRenameMap = new HashMap<String, String>();
/**
* 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.
*
* <p>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."
*
* <p>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<String> slideNameList = new ArrayList<String>();
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<OdfSlide> getSlides() {
checkAllSlideName();
OfficePresentationElement contentRoot = null;
try {
contentRoot = getContentRoot();
} catch (Exception e) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, e);
return null;
}
ArrayList<OdfSlide> slideList = new ArrayList<OdfSlide>();
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
* <p>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<OdfElement> removeStyles = new ArrayList<OdfElement>();
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.
*
* <p>
*
* @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.
* <p>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
* <p>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 <code>OdfPresentationDocument</code> 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
* <p>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<String, String> objectRenameMap = new HashMap<String, String>();
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<OdfElement, List<OdfElement>> srcContentStyleCloneEleList =
new HashMap<OdfElement, List<OdfElement>>();
HashMap<OdfElement, OdfElement> appendContentStyleList =
new HashMap<OdfElement, OdfElement>();
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<OdfElement, List<OdfElement>> srcStylesStyleCloneEleList =
new HashMap<OdfElement, List<OdfElement>>();
HashMap<OdfElement, OdfElement> appendStylesStyleList = new HashMap<OdfElement, OdfElement>();
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 <office:styles> element, so only search
// it in styles.xml dom
styleQName = "draw:name";
srcStyleDefNodeList =
(NodeList)
xpath.evaluate(
"//*[@" + styleQName + "]", doc.getStylesDom(), XPathConstants.NODESET);
HashMap<OdfElement, List<OdfElement>> srcDrawStyleCloneEleList =
new HashMap<OdfElement, List<OdfElement>>();
HashMap<OdfElement, OdfElement> appendDrawStyleList = new HashMap<OdfElement, OdfElement>();
Iterator<OdfElement> 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<OdfElement, List<OdfElement>> srcStyleCloneEleList,
OdfFileDom dom,
HashMap<OdfElement, OdfElement> 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<String, String> styleRenameMap = new HashMap<String, String>();
Iterator<OdfElement> 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<String> 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<String>();
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<OdfElement, List<OdfElement>> copyStyleEleList,
HashMap<OdfElement, OdfElement> 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<OdfElement> styleRefEleList = new ArrayList<OdfElement>();
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<OdfElement> 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 <code>OdfDrawPage.SlideLayout</code>.
*
* <p>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.
*
* <p>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.
* <p>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
// <presentation:notes>, <draw:page-thumbnail>, <draw:frame>
// <style:presentation-page-layout>
private void setSlideLayout(DrawPageElement page, OdfSlide.SlideLayout slideLayout) {
if (slideLayout == null) {
slideLayout = OdfSlide.SlideLayout.BLANK;
}
OdfOfficeStyles styles = null;
try {
styles = this.getStylesDom().getOrCreateOfficeStyles();
} catch (SAXException ex) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(OdfPresentationDocument.class.getName()).log(Level.SEVERE, null, ex);
}
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);
}
}
}