Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER Copyright 2008, 2010 Oracle and/or its affiliates. All rights reserved. Copyright 2009, 2010 IBM. 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.simple;
  
  import java.io.File;
  import java.net.URI;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Locale;
  import java.util.Set;
  
  
  import  org.odftoolkit.simple.Document;
  import org.w3c.dom.Attr;
  import org.w3c.dom.Node;
This abstract class is representing one of the possible ODF documents
 
 public abstract class Document extends OdfSchemaDocument implements TableContainer{
 	// Static parts of file references
 	private static final String SLASH = "/";
 	private Meta mOfficeMeta;
 	private long documentOpeningTime;
 	private static final Pattern CONTROL_CHAR_PATTERN = Pattern.compile("\\p{Cntrl}");
 	private static final String EMPTY_STRING = "";
 	
 	// FIXME: This field is only used in method copyResourcesFrom to improve
 	// copy performance, should not be used in any other way.
 	// methods loadDocument(String documentPath) and loadDocument(File file)
 	// will initialize it.
 	// This field and its methods should be removed after ODFDOM supplies batch
 	// copy.
 	private File mFile = null;
 
 	// 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
 	// the map is used to record if the renamed style name is appended to the
 	// current dom
 
 	// 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>();
 
 	// Using static factory instead of constructor
 	protected Document(OdfPackage pkgString internalPathOdfMediaType mediaType) {
 		super(pkginternalPathmediaType.getMediaTypeString());
 		 = mediaType;
 		// set document opening time.
 	}

This enum contains all possible media types of Document documents.
 
 	public enum OdfMediaType implements MediaType {
 		
 		CHART("application/vnd.oasis.opendocument.chart""odc"), 
 		CHART_TEMPLATE("application/vnd.oasis.opendocument.chart-template""otc"),
 		FORMULA("application/vnd.oasis.opendocument.formula""odf"),
 		FORMULA_TEMPLATE("application/vnd.oasis.opendocument.formula-template""otf"),
 		DATABASE_FRONT_END("application/vnd.oasis.opendocument.base""otf"),
 		GRAPHICS("application/vnd.oasis.opendocument.graphics""odg"), 
 		GRAPHICS_TEMPLATE("application/vnd.oasis.opendocument.graphics-template""otg"), 
 		IMAGE("application/vnd.oasis.opendocument.image""odi"), 
 		IMAGE_TEMPLATE("application/vnd.oasis.opendocument.image-template""oti"), 
 		PRESENTATION("application/vnd.oasis.opendocument.presentation""odp"), 
 		PRESENTATION_TEMPLATE("application/vnd.oasis.opendocument.presentation-template""otp"), 
 		SPREADSHEET("application/vnd.oasis.opendocument.spreadsheet""ods"), 
 		SPREADSHEET_TEMPLATE("application/vnd.oasis.opendocument.spreadsheet-template""ots"), 
 		TEXT("application/vnd.oasis.opendocument.text""odt"), 
 		TEXT_MASTER("application/vnd.oasis.opendocument.text-master""odm"), 
 		TEXT_TEMPLATE("application/vnd.oasis.opendocument.text-template""ott"), 
 		TEXT_WEB("application/vnd.oasis.opendocument.text-web""oth");
 		
 		private final String mMediaType;
 		private final String mSuffix;
 
 		OdfMediaType(String mediaTypeString suffix) {
 			this. = mediaType;
 			this. = suffix;
 		}

Returns:
the mediatype String of this document
 
 		public String getMediaTypeString() {
 			return ;
 		}

Returns:
the ODF filesuffix of this document
 
 		public String getSuffix() {
 			return ;
 		}

Parameters:
mediaType string defining an ODF document
Returns:
the according OdfMediatype encapuslating the given string and the suffix
 
 		public static OdfMediaType getOdfMediaType(String mediaType) {
 			OdfMediaType odfMediaType = null;
 			if (mediaType != null) {
 
 				String mediaTypeShort = mediaType.substring(mediaType.lastIndexOf(".") + 1, mediaType.length());
 				mediaTypeShort = mediaTypeShort.replace('-''_').toUpperCase();
 				try {
 					odfMediaType = OdfMediaType.valueOf(mediaTypeShort);
 
 				} catch (IllegalArgumentException e) {
 					throw new IllegalArgumentException("Given mediaType '" + mediaType
 							+ "' is either not yet supported or not an ODF mediatype!");
 				}
 			}
 			return odfMediaType;
 		}
 	}

Loads an Document from the given resource. NOTE: Initial meta data will be added in this method.

Parameters:
res a resource containing a package with a root document
odfMediaType the media type of the root document
Returns:
the Document document or NULL if the media type is not supported by SIMPLE.
Throws:
java.lang.Exception - if the document could not be created.
 
 	protected static Document loadTemplate(Resource resOdfMediaType odfMediaTypethrows Exception {
 		OdfPackage pkg = null;
 		try {
 			pkg = OdfPackage.loadPackage(in);
 		} finally {
 			in.close();
 		}
 		Document newDocument = newDocument(pkgodfMediaType);
 		// add initial meta data to new document.
 		initializeMetaData(newDocument);
 		return newDocument;
 	}

Loads a Document from the provided path.

Document relies on the file being available for read access over the whole lifecycle of Document.

Parameters:
documentPath - the path from where the document can be loaded
Returns:
the Document from the given path or NULL if the media type is not supported by SIMPLE.
Throws:
java.lang.Exception - if the document could not be created.
 
 	public static Document loadDocument(String documentPaththrows Exception {
 		File file = new File(documentPath);
 		Document doc = loadDocument(OdfPackage.loadPackage(documentPath));
 		doc.setFile(file);
 		return doc;
 	}

Creates a Document from the Document provided by a resource Stream.

Since an InputStream does not provide the arbitrary (non sequentiell) read access needed by Document, 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.

Parameters:
inStream - the InputStream of the ODF document.
Returns:
the document created from the given InputStream
Throws:
java.lang.Exception - if the document could not be created.
 
 	public static Document loadDocument(InputStream inStreamthrows Exception {
 		return loadDocument(OdfPackage.loadPackage(inStream));
 	}

Creates a Document from the Document provided by a File.

Document relies on the file being available for read access over the whole lifecycle of Document.

Parameters:
file - a file representing the ODF document.
Returns:
the document created from the given File
Throws:
java.lang.Exception - if the document could not be created.
 
 	public static Document loadDocument(File filethrows Exception {
 		Document doc = loadDocument(OdfPackage.loadPackage(file));
 		doc.setFile(file);
 		return doc;
 	}

Creates a Document from the Document provided by an ODF package.

Parameters:
odfPackage - the ODF package containing the ODF document.
Returns:
the root document of the given OdfPackage
Throws:
java.lang.Exception - if the ODF document could not be created.
 
 	public static Document loadDocument(OdfPackage odfPackagethrows Exception {
 		return loadDocument(odfPackage);
 	}

Creates a Document from the Document provided by an ODF package.

Parameters:
odfPackage - the ODF package containing the ODF document.
internalPath - the path to the ODF document relative to the package root.
Returns:
the root document of the given OdfPackage
Throws:
java.lang.Exception - if the ODF document could not be created.
 
 	public static Document loadDocument(OdfPackage odfPackageString internalPaththrows Exception {
 		String documentMediaType = odfPackage.getMediaTypeString(internalPath);
 		OdfMediaType odfMediaType = null;
 		try {
 			odfMediaType = OdfMediaType.getOdfMediaType(documentMediaType);
 		} catch (IllegalArgumentException e) {
 			// the returned NULL will be taking care of afterwards
 		}
 		if (odfMediaType == null) {
 			ErrorHandler errorHandler = odfPackage.getErrorHandler();
 			Matcher matcherCTRL = .matcher(documentMediaType);
 			if (matcherCTRL.find()) {
 				documentMediaType = matcherCTRL.replaceAll();
 			}
 					internalPathdocumentMediaType);
 			if (errorHandler != null) {
 				errorHandler.fatalError(ve);
 			}
 			throw ve;
 		}
 		return newDocument(odfPackageinternalPathodfMediaType);
 	}
 
 	// return null if the media type can not be recognized.
 	private static Document loadDocumentFromTemplate(OdfMediaType odfMediaTypethrows Exception {
 
 		switch (odfMediaType) {
 		case :
 		case :
 		case :
 			// documentTemplate = TextDocument.EMPTY_TEXT_DOCUMENT_RESOURCE;
 			TextDocument document = TextDocument.newTextDocument();
 			return document;
 
 		case :
 			SpreadsheetDocument spreadsheet = SpreadsheetDocument.newSpreadsheetDocument();
 			return spreadsheet;
 
 			SpreadsheetDocument spreadsheettemplate = SpreadsheetDocument.newSpreadsheetDocument();
 			return spreadsheettemplate;
 
 		case :
 			PresentationDocument presentation = PresentationDocument.newPresentationDocument();
 			return presentation;
 
 			PresentationDocument presentationtemplate = PresentationDocument.newPresentationDocument();
 			return presentationtemplate;
 
 		case :
 			GraphicsDocument graphics = GraphicsDocument.newGraphicsDocument();
 			return graphics;
 
 			GraphicsDocument graphicstemplate = GraphicsDocument.newGraphicsDocument();
 			return graphicstemplate;
 
 		case :
 			ChartDocument chart = ChartDocument.newChartDocument();
 			return chart;
 
 			ChartDocument charttemplate = ChartDocument.newChartDocument();
 			return charttemplate;
 
 			// case IMAGE:
 			// case IMAGE_TEMPLATE:
 
 		default:
 			throw new IllegalArgumentException("Given mediaType '" + odfMediaType.toString()
 					+ "' is either not yet supported or not an ODF mediatype!");
 		}
 	}

Creates one of the ODF documents based a given mediatype.

Parameters:
odfMediaType The ODF Mediatype of the ODF document to be created.
Returns:
The ODF document, which mediatype dependends on the parameter or NULL if media type were not supported.
 
 	private static Document newDocument(OdfPackage pkgString internalPathOdfMediaType odfMediaType) {
 		Document newDoc = null;
 		switch (odfMediaType) {
 		case :
 			newDoc = new TextDocument(pkginternalPath..);
 			break;
 
 			newDoc = new TextDocument(pkginternalPath..);
 			break;
 
 		case :
 			newDoc = new TextDocument(pkginternalPath..);
 			break;
 
 		case :
 			newDoc = new TextDocument(pkginternalPath..);
 			break;
 
 		case :
 			newDoc = new SpreadsheetDocument(pkginternalPath..);
 			break;
 
 			break;
 
 		case :
 			newDoc = new PresentationDocument(pkginternalPath..);
 			break;
 
 			break;
 
 		case :
 			newDoc = new GraphicsDocument(pkginternalPath..);
 			break;
 
 			newDoc = new GraphicsDocument(pkginternalPath..);
 			break;
 
 		case :
 			newDoc = new ChartDocument(pkginternalPath..);
 			break;
 
 			newDoc = new ChartDocument(pkginternalPath..);
 			break;
 		// case IMAGE:
 		// case IMAGE_TEMPLATE:
 
 		default:
 			newDoc = null;
 			throw new IllegalArgumentException("Given mediaType '" + odfMediaType.mMediaType
 					+ "' is not yet supported!");
 		}
 		// returning null if MediaType is not supported
 		return newDoc;
 	}

Returns an embedded OdfPackageDocument from the given package path.

Parameters:
documentPath path to the ODF document within the package. The path is relative to the current document.
Returns:
an embedded Document
 
 	public Document getEmbeddedDocument(String documentPath) {
 		String internalPath = getDocumentPath() + documentPath;
 		internalPath = normalizeDocumentPath(internalPath);
 		Document embeddedDocument = (Document.getCachedDocument(internalPath);
 		// if the document was not already loaded, fine mimetype and create a
 		// new instance
 		if (embeddedDocument == null) {
 			String mediaTypeString = getMediaTypeString();
 			OdfMediaType odfMediaType = OdfMediaType.getOdfMediaType(mediaTypeString);
 			if (odfMediaType == null) {
 				embeddedDocument = newDocument(internalPathodfMediaType);
 			} else {
 				try {
 					String documentMediaType = .getMediaTypeString(internalPath);
 					odfMediaType = OdfMediaType.getOdfMediaType(documentMediaType);
 					if (odfMediaType == null) {
 						return null;
 					}
 					embeddedDocument = Document.loadDocument(internalPath);
 				} catch (Exception ex) {
 					Logger.getLogger(OdfPackageDocument.class.getName()).log(.nullex);
 				}
 			}
 		}
 		return embeddedDocument;
 	}

Method returns all embedded OdfPackageDocuments, which match a valid OdfMediaType, of the root OdfPackageDocument.

Returns:
a list with all embedded documents of the root OdfPackageDocument
 
 	// ToDo: (Issue 219 - PackageRefactoring) - Better return Path of
 	// Documents??
 		List<DocumentembeddedObjects = new ArrayList<Document>();
 		// ToDo: (Issue 219 - PackageRefactoring) - Algorithm enhancement:
 		// Instead going through all the files for each mimetype, better
 		// Check all files, which have a mimetype if it is one of the desired,
 		// perhaps start with ODF prefix
 		for (OdfMediaType mediaType : OdfMediaType.values()) {
 			embeddedObjects.addAll(getEmbeddedDocuments(mediaType));
 		}
 		return embeddedObjects;
 	}

Method returns all embedded OdfPackageDocuments of the root OdfPackageDocument matching the according MediaType. This is done by matching the subfolder entries of the manifest file with the given OdfMediaType.

Parameters:
mediaType media type which is used as a filter
Returns:
embedded documents of the root OdfPackageDocument matching the given media type
 
 		String wantedMediaString = null;
 		if (mediaType != null) {
 			wantedMediaString = mediaType.getMediaTypeString();
 		}
 		List<DocumentembeddedObjects = new ArrayList<Document>();
 		// check manifest for current embedded OdfPackageDocuments
 		Set<StringmanifestEntries = .getFilePaths();
 		for (String path : manifestEntries) {
 			// any directory that is not the root document "/"
 			if (path.length() > 1 && path.endsWith()) {
 				String entryMediaType = .getFileEntry(path).getMediaTypeString();
 				// if the entry is a document (directory has mediaType)
 				if (entryMediaType != null) {
 					// if a specific ODF mediatype was requested
 					if (wantedMediaString != null) {
 						// test if the desired mediatype matches the current
 						if (entryMediaType.equals(wantedMediaString)) {
 							embeddedObjects.add(getEmbeddedDocument(path));
 						}
 					} else {
 						// test if any ODF mediatype matches the current
 						for (OdfMediaType type : OdfMediaType.values()) {
 							if (entryMediaType.equals(type.getMediaTypeString())) {
 								embeddedObjects.add(getEmbeddedDocument(path));
 							}
 						}
 					}
 				}
 			}
 		}
 		return embeddedObjects;
 	}

Embed an OdfPackageDocument to the current OdfPackageDocument. All the file entries of child document will be embedded as well to the current document package.

Parameters:
documentPath to the directory the ODF document should be inserted (relative to the current document).
sourceDocument the OdfPackageDocument to be embedded.
 
 	public void insertDocument(OdfPackageDocument sourceDocumentString documentPath) {
 		super.insertDocument(sourceDocumentdocumentPath);
 	}

Sets the media type of the Document

Parameters:
odfMediaType media type to be set
 
 	protected void setOdfMediaType(OdfMediaType odfMediaType) {
 		 = odfMediaType;
 		super.setMediaTypeString(odfMediaType.getMediaTypeString());
 	}

Gets the media type of the Document
 
 	protected OdfMediaType getOdfMediaType() {
 		return ;
 	}

Get the meta data feature instance of the current document

Returns:
the meta data feature instance which represent office:meta in the meta.xml
 
 	public Meta getOfficeMetadata() {
 		if ( == null) {
 			try {
 			} catch (Exception ex) {
 				Logger.getLogger(Document.class.getName()).log(.nullex);
 			}
 		}
 		return ;
 	}

Save the document to an OutputStream. Delegate to the root document and save possible embedded Documents.

If the input file has been cached (this is the case when loading from an InputStream), the input file can be overwritten.

If not, the OutputStream may not point to the input file! Otherwise this will result in unwanted behaviour and broken files.

When save the embedded document to a stand alone document, all the file entries of the embedded document will be copied to a new document package. If the embedded document is outside of the current document directory, you have to embed it to the sub directory and refresh the link of the embedded document. you should reload it from the stream to get the saved embedded document.

Parameters:
out - the OutputStream to write the file to
Throws:
java.lang.Exception if the document could not be saved
 
 	public void save(OutputStream outthrows Exception {
 		// 2DO FLUSH AND SAVE IN PACKAGE
 		if (!isRootDocument()) {
 			newDoc.updateMetaData();
 			newDoc.mPackage.save(out);
 			// ToDo: (Issue 219 - PackageRefactoring) - Return the document,
 			// when not closing!
 			// Should we close the sources now? User will never receive the open
 			// package!
 		} else {
 			// 2DO MOVE CACHE TO PACKAGE
 			// // the root document only have to flush the DOM of all open child
 			// documents
 			// flushAllDOMs();
 			.save(out);
 		}
 	}

Save the document to a given file.

If the input file has been cached (this is the case when loading from an InputStream), the input file can be overwritten.

Otherwise it's allowed to overwrite the input file as long as the same path name is used that was used for loading (no symbolic link foo2.odt pointing to the loaded file foo1.odt, no network path X:\foo.odt pointing to the loaded file D:\foo.odt).

When saving the embedded document to a stand alone document, all files of the embedded document will be copied to a new document package. If the embedded document is outside of the current document directory, you have to embed it to the sub directory and refresh the link of the embedded document. You should reload it from the given file to get the saved embedded document.

Parameters:
file - the file to save the document
Throws:
java.lang.Exception if the document could not be saved
 
 	public void save(File filethrows Exception {
 		// 2DO FLUSH AND SAVE IN PACKAGE
 		if (!isRootDocument()) {
 			newDoc.updateMetaData();
 			newDoc.mPackage.save(file);
 			// ToDo: (Issue 219 - PackageRefactoring) - Return the document,
 			// when not closing!
 			// Should we close the sources now? User will never receive the open
 			// package!
 		} else {
 			this..save(file);
 		}
 	}

Close the OdfPackage and release all temporary created data. Acter execution of this method, this class is no longer usable. Do this as the last action to free resources. Closing an already closed document has no effect. Note that this will not close any cached documents.
 
 	public void close() {
 		// set all member variables explicit to null
 		 = null;
 		 = null;
 		super.close();
 	}

Get the content root of a document. You may prefer to use the getContentRoot methods of subclasses of Document. Their return parameters are already casted to respective subclasses of OdfElement.

Parameters:
clazz the type of the content root, depend on the document type
Returns:
the child element of office:body, e.g. office:text for text docs
Throws:
java.lang.Exception if the file DOM could not be created.
 
 	@SuppressWarnings("unchecked")
 	protected <T extends OdfElement> T getContentRoot(Class<T> clazzthrows Exception {
 		OdfElement contentRoot = getContentDom().getRootElement();
 		OfficeBodyElement contentBody = OdfElement.findFirstChildNode(OfficeBodyElement.classcontentRoot);
 		NodeList childs = contentBody.getChildNodes();
 		for (int i = 0; i < childs.getLength(); i++) {
 			Node cur = childs.item(i);
 			if ((cur != null) && clazz.isInstance(cur)) {
 				return (T) cur;
 			}
 		}
 		return null;
 	}

Get the content root of a document. You may prefer to use the getContentRoot methods of subclasses of Document.

Returns:
the child element of office:body, e.g. office:text for text docs
Throws:
java.lang.Exception if the file DOM could not be created.
 
 	public OdfElement getContentRoot() throws Exception {
 		return getContentRoot(OdfElement.class);
 	}
 
 	public String toString() {
 		return "\n" + getMediaTypeString() + " - ID: " + this.hashCode() + " " + getPackage().getBaseURI();
 	}

Insert an Image from the specified uri to the end of the Document.

Parameters:
imageUri The URI of the image that will be added to the document, add image stream to the package, in the 'Pictures/' graphic directory with the same image file name as in the URI. If the imageURI is relative first the user.dir is taken to make it absolute.
Returns:
Returns the internal package path of the image, which was created based on the given URI.
 
 	public String newImage(URI imageUri) {
 		try {
 			OdfContentDom contentDom = this.getContentDom();
 			OdfDrawFrame drawFrame = contentDom.newOdfElement(OdfDrawFrame.class);
 			XPath xpath = contentDom.getXPath();
 			if (this instanceof SpreadsheetDocument) {
 				TableTableCellElement lastCell = (TableTableCellElementxpath.evaluate("//table:table-cell[last()]",
 						contentDom.);
 				lastCell.appendChild(drawFrame);
 				drawFrame.removeAttribute("text:anchor-type");
 
 			} else if (this instanceof TextDocument) {
 				TextPElement lastPara = (TextPElementxpath.evaluate("//text:p[last()]"contentDom,
 				if (lastPara == null) {
 					lastPara = ((TextDocumentthis).newParagraph();
 				}
 				lastPara.appendChild(drawFrame);
 			} else if (this instanceof PresentationDocument) {
 				DrawPageElement lastPage = (DrawPageElementxpath.evaluate("//draw:page[last()]"contentDom,
 				lastPage.appendChild(drawFrame);
 			}
 			OdfDrawImage image = (OdfDrawImagedrawFrame.newDrawImageElement();
 			String imagePath = image.newImage(imageUri);
 			return imagePath;
 		} catch (Exception ex) {
 			Logger.getLogger(Document.class.getName()).log(.nullex);
 		}
 		return null;
 	}

Meta data about the document will be initialized. Following metadata data is being added:
  • The initial creator name will be the Java user.name System property.
  • The date and time when this document was created using the current data.
  • The number of times this document has been edited.
  • The default language will be the Java user.language System property.

Parameters:
newDoc the Document object which need to initialize meta data. TODO:This method will be moved to OdfMetadata class. see http://odftoolkit.org/bugzilla/show_bug.cgi?id=204
 
 	private static void initializeMetaData(Document newDoc) {
 		Meta metaData = newDoc.getOfficeMetadata();
 		// add initial-creator info.
 		String creator = System.getProperty("user.name");
 		metaData.setInitialCreator(creator);
 		// add creation-date info.
 		Calendar calendar = Calendar.getInstance();
 		metaData.setCreationDate(calendar);
 		// add editing-cycles info.
 		metaData.setEditingCycles(0);
 		// add language info.
 		String language = System.getProperty("user.language");
 		if (language != null) {
 			metaData.setLanguage(language);
 		}
 	}

Update document meta data in the ODF document. Following metadata data is being updated:
  • The name of the person who last modified this document will be the Java user.name System property
  • The date and time when the document was last modified using current data
  • The number of times this document has been edited is incremented by 1
  • The total time spent editing this document
TODO:This method will be moved to OdfMetadata class. see http://odftoolkit.org/bugzilla/show_bug.cgi?id=204

 
 	private void updateMetaData() throws Exception {
 		if ( != null) {
 			Meta metaData = getOfficeMetadata();
 			String creator = System.getProperty("user.name");
 			// update creator info.
 			metaData.setCreator(creator);
 			// update date info.
 			Calendar calendar = Calendar.getInstance();
 			metaData.setDcdate(calendar);
 			// update editing-cycles info.
 			Integer cycle = metaData.getEditingCycles();
 			if (cycle != null) {
 				metaData.setEditingCycles(++cycle);
 			} else {
 				metaData.setEditingCycles(1);
 			}
 			// update editing-duration info.
 			long editingDuration = calendar.getTimeInMillis() - ;
 			editingDuration = (editingDuration < 1) ? 1 : editingDuration;
 			try {
 				DatatypeFactory aFactory = DatatypeFactory.newInstance();
 				metaData.setEditingDuration(new Duration(aFactory.newDurationDayTime(editingDuration)));
 						"editing duration update fail as DatatypeFactory can not be instanced"e);
 			}
 		}
 	}
 
 	// /////////////////
 	// Following is the implementation of locale settings
 	// ////////////////
 

Unicode characters are in general divided by office applications into three different types:

1) There is CJK: the Chinese, Japanese and Korean script (also old Vietnamese belong to this group). See http://en.wikipedia.org/wiki/CJK_characters

2) There is CTL: Complex Text Layout, which uses BIDI algorithms and/or glyph modules. See http://en.wikipedia.org/wiki/Complex_Text_Layout

3) And there is all the rest, which was once called by MS Western.

 
 	public enum ScriptType {
Western language
 
 		WESTERN,
Chinese, Japanese and Korean
 
 		CJK,
Complex Text Layout language
 
 		CTL;
 
 	}
 
 	private final static HashSet<StringCJKLanguage = new HashSet<String>();
 	private final static HashSet<StringCTLLanguage = new HashSet<String>();
 	{
 		.add("zh"); // LANGUAGE_CHINES
 		.add("ja"); // LANGUAGE_JAPANESE
 		.add("ko"); // LANGUAGE_KOREANE
 
 		.add("am"); // LANGUAGE_AMHARIC_ETHIOPIA
 		.add("ar"); // LANGUAGE_ARABIC_SAUDI_ARABIA
 		.add("as"); // LANGUAGE_ASSAMESE
 		.add("bn"); // LANGUAGE_BENGALI
 		.add("bo"); // LANGUAGE_TIBETAN
 		.add("brx");// LANGUAGE_USER_BODO_INDIA
 		.add("dgo");// LANGUAGE_USER_DOGRI_INDIA
 		.add("dv"); // LANGUAGE_DHIVEHI
 		.add("dz"); // LANGUAGE_DZONGKHA
 		.add("fa"); // LANGUAGE_FARSI
 		.add("gu"); // LANGUAGE_GUJARATI
 		.add("he"); // LANGUAGE_HEBREW
 		.add("hi"); // LANGUAGE_HINDI
 		.add("km"); // LANGUAGE_KHMER
 		.add("kn"); // LANGUAGE_KANNADA
 		.add("ks"); // LANGUAGE_KASHMIRI
 		.add("ku"); // LANGUAGE_USER_KURDISH_IRAQ
 		.add("lo"); // LANGUAGE_LAO
 		.add("mai");// LANGUAGE_USER_MAITHILI_INDIA
 		.add("ml"); // LANGUAGE_MALAYALAM
 		.add("mn"); // LANGUAGE_MONGOLIAN_MONGOLIAN
 		.add("mni");// LANGUAGE_MANIPURI
 		.add("mr"); // LANGUAGE_MARATHI
 		.add("my"); // LANGUAGE_BURMESE
 		.add("ne"); // LANGUAGE_NEPALI
 		.add("or"); // LANGUAGE_ORIYA
 		.add("pa"); // LANGUAGE_PUNJABI
 		.add("sa"); // LANGUAGE_SANSKRIT
 		.add("sd"); // LANGUAGE_SINDHI
 		.add("si"); // LANGUAGE_SINHALESE_SRI_LANKA
 		.add("syr");// LANGUAGE_SYRIAC
 		.add("ta"); // LANGUAGE_TAMIL
 		.add("te"); // LANGUAGE_TELUGU
 		.add("th"); // LANGUAGE_THAI
 		.add("ug"); // LANGUAGE_UIGHUR_CHINA
		.add("ur"); // LANGUAGE_URDU
		.add("yi"); // LANGUAGE_YIDDISH
	}

Set a locale information.

The locale information will affect the language and country setting of the document. Thus the font settings, the spell checkings and etc will be affected.

Parameters:
locale - an instance of Locale
	public void setLocale(Locale locale) {
		setLocale(localegetScriptType(locale));
	public static ScriptType getScriptType(Locale locale) {
		String language = locale.getLanguage();
		if (.contains(language))
		if (.contains(language))
	}

Set a locale of a specific script type.

If the locale is not belone to the script type, nothing will happen.

Parameters:
locale - Locale information
scriptType - The script type
	public void setLocale(Locale localeScriptType scriptType) {
		try {
			switch (scriptType) {
			case :
				break;
			case :
				break;
			case :
				break;
catch (Exception e) {
			Logger.getLogger(Document.class.getName()).log(."Failed to set locale"e);
	}

Get a locale information of a specific script type.

Parameters:
scriptType - The script type
Returns:
the Locale information
	public Locale getLocale(ScriptType scriptType) {
		try {
			switch (scriptType) {
			case :
			case :
			case :
catch (Exception e) {
			Logger.getLogger(Document.class.getName()).log(."Failed to get locale"e);
		return null;
	}

This method will set the default language and country information of the document, based on the parameter of the Locale information.

Parameters:
locale - an instance of Locale that the default language and country will be set to.
Throws:
java.lang.Exception
	private void setWesternLanguage(Locale localethrows Exception {
			return;
		Iterable<OdfDefaultStyledefaultStyles = styles.getDefaultStyles();
		if (defaultStyles != null) {
			Iterator<OdfDefaultStyleitera = defaultStyles.iterator();
			while (itera.hasNext()) {
				OdfDefaultStyle style = itera.next();
			throws Exception {
		String lang = nullctry = null;
		// get language and country setting from default style setting for
		// paragraph
		if (defaultStyle != null) {
			if (defaultStyle.hasProperty(countryProp) && defaultStyle.hasProperty(languageProp)) {
				ctry = defaultStyle.getProperty(countryProp);
				lang = defaultStyle.getProperty(languageProp);
				return new Locale(langctry);
		// if no default style setting for paragraph
		// get language and country setting from other default style settings
		Iterable<OdfDefaultStyledefaultStyles = styles.getDefaultStyles();
		Iterator<OdfDefaultStyleitera = defaultStyles.iterator();
		while (itera.hasNext()) {
			OdfDefaultStyle style = itera.next();
			if (style.hasProperty(countryProp) && style.hasProperty(languageProp)) {
				ctry = style.getProperty(countryProp);
				lang = style.getProperty(languageProp);
				return new Locale(langctry);
		return null;
	}

This method will return an instance of Locale, which presents the default language and country information settings in this document.

Returns:
an instance of Locale that the default language and country is set to.
This method will set the default Asian language and country information of the document, based on the parameter of the Locale information. If the Locale instance is not set a Asian language (Chinese, Traditional Chinese, Japanese and Korean, nothing will take effect.

Parameters:
locale - an instance of Locale that the default Asian language and country will be set to.
Throws:
java.lang.Exception
	private void setDefaultAsianLanguage(Locale localethrows Exception {
		if (getScriptType(locale) != .)
			return;
		String user_language = locale.getLanguage();
		if (!user_language.equals(..getLanguage())
				&& !user_language.equals(..getLanguage())
				&& !user_language.equals(..getLanguage()))
			return;
		Iterable<OdfDefaultStyledefaultStyles = styles.getDefaultStyles();
		if (defaultStyles != null) {
			Iterator<OdfDefaultStyleitera = defaultStyles.iterator();
			while (itera.hasNext()) {
				OdfDefaultStyle style = itera.next();
	}

This method will set the default complex language and country information of the document, based on the parameter of the Locale information.

Parameters:
locale - an instance of Locale that the default complex language and country will be set to.
Throws:
java.lang.Exception
	private void setDefaultComplexLanguage(Locale localethrows Exception {
		if (getScriptType(locale) != .)
			return;
		Iterable<OdfDefaultStyledefaultStyles = styles.getDefaultStyles();
		if (defaultStyles != null) {
			Iterator<OdfDefaultStyleitera = defaultStyles.iterator();
			while (itera.hasNext()) {
				OdfDefaultStyle style = itera.next();
	}

This method will search both the document content and header/footer, return an iterator of section objects.

The sections defined in embed document won't be covered.

Returns:
an iterator of Section objects
		ArrayList<Sectionlist = new ArrayList<Section>();
		try {
			// search in content.xml
			OfficeBodyElement officeBody = OdfElement.findFirstChildNode(OfficeBodyElement.classroot);
			NodeList sectionList = officeBody.getElementsByTagNameNS(..getUri(), "section");
			for (int i = 0; i < sectionList.getLength(); i++) {
				element = (TextSectionElementsectionList.item(i);
				list.add(Section.getInstance(element));
			// Search in style.xml
			OfficeMasterStylesElement masterStyle = OdfElement
			sectionList = masterStyle.getElementsByTagNameNS(..getUri(), "section");
			for (int i = 0; i < sectionList.getLength(); i++) {
				element = (TextSectionElementsectionList.item(i);
				list.add(Section.getInstance(element));
catch (Exception e) {
			Logger.getLogger(Document.class.getName()).log(."Failed in sectionIterator"e);
		return list.iterator();
	}

This method will search both the document content and header/footer, return a section with a specific name.

This method won't search in the embed document.

Null will be returned if there is no section found.

Parameters:
name - the name of a section
Returns:
a section object with a specific name
	public Section getSectionByName(String name) {
		try {
			OfficeBodyElement officeBody = OdfElement.findFirstChildNode(OfficeBodyElement.classroot);
			String xpathValue = ".//text:section[@text:name=\"" + name + "\"]";
			element = (TextSectionElementxpath.evaluate(xpathValueofficeBody.);
			if (element != null) {
				return Section.getInstance(element);
			OfficeMasterStylesElement masterStyle = OdfElement
			xpath = getStylesDom().getXPath();
			element = (TextSectionElementxpath.evaluate(".//text:section[@text:name=\"" + name + "\"]"masterStyle,
			if (element != null) {
				return Section.getInstance(element);
catch (Exception e) {
			Logger.getLogger(Document.class.getName()).log(."Failed in getSectionByName"e);
		return null;
	}

Remove an ODF element from the document. All the resources that are only related with this element will be removed at the same time.

Parameters:
odfElement - the odf element that would be moved.
	public boolean removeElementLinkedResource(OdfElement odfElement) {
		boolean success = deleteLinkedRef(odfElement);
		success &= deleteStyleRef(odfElement);
		return success;
	}

Return a unique string with a character "a" followed by randomly generating 6 hex numbers

Returns:
a unique string
		return String.format("a%06x", (int) (Math.random() * 0xffffff));
	private String getNewUniqueString(String oldStr) {
		int lastIndex = oldStr.lastIndexOf("-");
		if (lastIndex == -1) {
			return oldStr + "-" + makeUniqueName();
		String suffix = oldStr.substring(lastIndex + 1);
		if (suffix.matches("a[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]")) {
			return oldStr.substring(0, lastIndex + 1) + makeUniqueName();
else
			return oldStr + "-" + makeUniqueName();
	private void updateAttribute(Attr attr) {
		String oldID = attr.getValue();
		String newID = getNewUniqueString(oldID);
		attr.setValue(newID);
	}

Make a content copy of the specified element, and the returned element should have the specified ownerDocument.

Parameters:
element The element that need to be copied
dom The specified DOM tree that the returned element belong to
deep If true, recursively clone the subtree under the element, false, only clone the element itself
Returns:
Returns a duplicated element which is not in the DOM tree with the specified element
	Node cloneForeignElement(Node elementOdfFileDom domboolean deep) {
		if (element instanceof OdfElement) {
			OdfElement cloneElement = dom.createElementNS(((OdfElementelement).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(), qnameitem.getNodeValue());
			if (deep) {
				Node childNode = element.getFirstChild();
				while (childNode != null) {
					cloneElement.appendChild(cloneForeignElement(childNodedomtrue));
					childNode = childNode.getNextSibling();
			return cloneElement;
else {
			return dom.createTextNode(element.getNodeValue());
	}

This method will update all the attribute "xml:id" to make it unique within the whole document content

This method is usually be invoked before inserting a copied ODF element to document content.

Parameters:
element - the element that need to be inserted.
	void updateXMLIds(OdfElement element) {
		try {
			String xpathValue = "//*[@xml:id]";
			NodeList childList = (NodeListxpath.evaluate(xpathValueelement.);
			if (childList == null)
				return;
			for (int i = 0; i < childList.getLength(); i++) {
				OdfElement ele = (OdfElementchildList.item(i);
catch (Exception e) {
			Logger.getLogger(Document.class.getName()).log(."Failed in updateXMLIds"e);
	}

This method will update all the attribute "text:name","table:name","draw:name","chart:name", to make it unique within the whole document content.

This method is usually be invoked before inserting a copied ODF element to document content.

Parameters:
element - the element that need to be inserted.
	// anim:name, chart:name, config:name, office:name, presentation:name,
	// svg:name,
	void updateNames(OdfElement element) {
		try {
			String xpathValue = "descendant-or-self::node()[@text:name|@table:name|@draw:name|@chart:name]";
			NodeList childList = (NodeListxpath.evaluate(xpathValueelement.);
			if (childList == null)
				return;
			for (int i = 0; i < childList.getLength(); i++) {
				OdfElement ele = (OdfElementchildList.item(i);
				if (attri != null)
				if (attri != null)
				if (ele instanceof DrawFrameElement)// only update draw:frame
					if (attri != null)
catch (Exception e) {
			Logger.getLogger(Document.class.getName()).log(."Failed in updateXMLIds"e);
	}

This method will copy the linked resource of the element which need to be copied, from the source package to the target package.

If the target package contains a resource with the same path and name, the name of the resource will be renamed.

This method will copy resources all in one batch.

Parameters:
sourceCloneEle - the element that need to be copied
srcDocument - the source document
	void copyLinkedRefInBatch(OdfElement sourceCloneEleDocument srcDocument) {
		try {
			OdfFileDom fileDom = (OdfFileDomsourceCloneEle.getOwnerDocument();
			XPath xpath;
			if (fileDom instanceof OdfContentDom) {
				xpath = ((OdfContentDomfileDom).getXPath();
else {
				xpath = ((OdfStylesDomfileDom).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<StringStringobjectRenameMap = new HashMap<StringString>();
			NodeList linkNodes = (NodeListxpath.evaluate(".//*[@xlink:href]"sourceCloneEle.);
			for (int i = 0; i <= linkNodes.getLength(); i++) {