incubator-odf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From svanteschub...@apache.org
Subject svn commit: r1792545 [2/3] - in /incubator/odf/trunk/simple/src: main/java/org/odftoolkit/simple/common/navigation/TextSelection.java test/java/org/odftoolkit/simple/text/SpanTest.java
Date Mon, 24 Apr 2017 20:42:06 GMT

Modified: incubator/odf/trunk/simple/src/main/java/org/odftoolkit/simple/common/navigation/TextSelection.java
URL: http://svn.apache.org/viewvc/incubator/odf/trunk/simple/src/main/java/org/odftoolkit/simple/common/navigation/TextSelection.java?rev=1792545&r1=1792544&r2=1792545&view=diff
==============================================================================
--- incubator/odf/trunk/simple/src/main/java/org/odftoolkit/simple/common/navigation/TextSelection.java (original)
+++ incubator/odf/trunk/simple/src/main/java/org/odftoolkit/simple/common/navigation/TextSelection.java Mon Apr 24 20:42:06 2017
@@ -1,1299 +1,1301 @@
-/* 
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
-*/
-
-package org.odftoolkit.simple.common.navigation;
-
-import java.net.URI;
-import java.net.URL;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Map;
-import java.util.TreeMap;
-
-import org.odftoolkit.odfdom.dom.OdfContentDom;
-import org.odftoolkit.odfdom.dom.OdfDocumentNamespace;
-import org.odftoolkit.odfdom.dom.OdfStylesDom;
-import org.odftoolkit.odfdom.dom.element.OdfStylableElement;
-import org.odftoolkit.odfdom.dom.element.OdfStyleBase;
-import org.odftoolkit.odfdom.dom.element.dc.DcCreatorElement;
-import org.odftoolkit.odfdom.dom.element.dc.DcDateElement;
-import org.odftoolkit.odfdom.dom.element.office.OfficeAnnotationElement;
-import org.odftoolkit.odfdom.dom.element.style.StyleParagraphPropertiesElement;
-import org.odftoolkit.odfdom.dom.element.style.StyleTextPropertiesElement;
-import org.odftoolkit.odfdom.dom.element.text.TextAElement;
-import org.odftoolkit.odfdom.dom.element.text.TextConditionalTextElement;
-import org.odftoolkit.odfdom.dom.element.text.TextPElement;
-import org.odftoolkit.odfdom.dom.element.text.TextParagraphElementBase;
-import org.odftoolkit.odfdom.dom.element.text.TextSElement;
-import org.odftoolkit.odfdom.dom.element.text.TextSpanElement;
-import org.odftoolkit.odfdom.dom.element.text.TextUserFieldDeclElement;
-import org.odftoolkit.odfdom.dom.element.text.TextVariableDeclElement;
-import org.odftoolkit.odfdom.dom.style.OdfStyleFamily;
-import org.odftoolkit.odfdom.dom.style.props.OdfStylePropertiesSet;
-import org.odftoolkit.odfdom.dom.style.props.OdfStyleProperty;
-import org.odftoolkit.odfdom.incubator.doc.office.OdfOfficeAutomaticStyles;
-import org.odftoolkit.odfdom.incubator.doc.style.OdfStyle;
-import org.odftoolkit.odfdom.incubator.doc.text.OdfTextHeading;
-import org.odftoolkit.odfdom.incubator.doc.text.OdfTextParagraph;
-import org.odftoolkit.odfdom.incubator.doc.text.OdfTextSpan;
-import org.odftoolkit.odfdom.pkg.OdfElement;
-import org.odftoolkit.odfdom.pkg.OdfFileDom;
-import org.odftoolkit.simple.Document;
-import org.odftoolkit.simple.TextDocument;
-import org.odftoolkit.simple.common.TextExtractor;
-import org.odftoolkit.simple.common.field.ConditionField;
-import org.odftoolkit.simple.common.field.Field;
-import org.odftoolkit.simple.common.field.Field.FieldType;
-import org.odftoolkit.simple.common.field.Fields;
-import org.odftoolkit.simple.common.field.VariableField;
-import org.odftoolkit.simple.draw.Image;
-import org.odftoolkit.simple.table.Table;
-import org.odftoolkit.simple.text.Paragraph;
-import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-/**
- * <code>TextSelection</code> describes a sub element in a paragraph element or
- * a heading element. It is recognized by the container element, which type
- * should be {@link org.odftoolkit.odfdom.incubator.doc.text.OdfTextParagraph
- * OdfTextParagraph} or
- * {@link org.odftoolkit.odfdom.incubator.doc.text.OdfTextHeading
- * OdfTextHeading}, the start index of text content in container element and the
- * text content of this <code>Selection</code>.
- */
-public class TextSelection extends Selection {
-
-	String mMatchedText;
-	private OdfTextParagraph mParagraph;
-	private OdfTextHeading mHeading;
-	private int mIndexInContainer;
-	private boolean mIsInserted;
-	private boolean isSelectionReplaced = false;
-
-	/**
-	 * Constructor of <code>TextSelection</code>.
-	 * 
-	 * @param text
-	 *            the text content of this <code>TextSelection</code>
-	 * @param containerElement
-	 *            the paragraph element or heading element that contains this
-	 *            <code>TextSelection</code>
-	 * @param index
-	 *            the start index of the text content in container element
-	 * 
-	 */
-	TextSelection(Navigation search, String text, OdfElement containerElement,
-			int index) {
-		this.search = search;
-		mMatchedText = text;
-		if (containerElement instanceof OdfTextParagraph) {
-			mParagraph = (OdfTextParagraph) containerElement;
-		} else if (containerElement instanceof OdfTextHeading) {
-			mHeading = (OdfTextHeading) containerElement;
-		}
-		mIndexInContainer = index;
-	}
-
-	public TextNavigation getTextNavigation() {
-		if (search instanceof TextNavigation) {
-			return (TextNavigation) search;
-		}
-		return null;
-	}
-	/**
-	 * Create a new <code>TextSelection</code>.
-	 * 
-	 * @param text
-	 *            the text content of this <code>TextSelection</code>
-	 * @param containerElement
-	 *            the paragraph element or heading element that contains this
-	 *            <code>TextSelection</code>
-	 * @param index
-	 *            the start index of the text content in container element
-	 * 
-	 * @since 0.5.5
-	 */
-	public static TextSelection newTextSelection(Navigation search,
-			String text, OdfElement containerElement, int index) {
-		TextSelection selection = new TextSelection(search, text,
-				containerElement, index);
-		Selection.SelectionManager.registerItem(selection);
-		return selection;
-	}
-
-	/**
-	 * Get the paragraph element or heading element that contains this
-	 * <code>TextSelection</code>.
-	 * 
-	 * @return OdfElement the container element
-	 */
-	@Override
-	public OdfElement getElement() {
-		return getContainerElement();
-	}
-
-	/**
-	 * Get the paragraph element or heading element that contains this text.
-	 * 
-	 * @return OdfElement
-	 */
-	public OdfElement getContainerElement() {
-		if (mParagraph != null) {
-			return mParagraph;
-		} else {
-			return mHeading;
-		}
-	}
-
-	/**
-	 * Get the start index of the text content of its container element.
-	 * 
-	 * @return index the start index of the text content of its container
-	 *         element
-	 */
-	@Override
-	public int getIndex() {
-		return mIndexInContainer;
-	}
-
-	/**
-	 * Get the text content of this <code>TextSelection</code>.
-	 * 
-	 * @return text the text content
-	 */
-	public String getText() {
-		return mMatchedText;
-	}
-
-	/**
-	 * Delete the selection from the document the other matched selection in the
-	 * same container element will be updated automatically because the start
-	 * index of the following selections will be changed when the previous
-	 * selection has been deleted.
-	 * 
-	 * @throws InvalidNavigationException
-	 *             if the selection is unavailable.
-	 */
-	@Override
-	public void cut() throws InvalidNavigationException {
-		if (validate() == false) {
-			throw new InvalidNavigationException("No matched string at this position");
-		}
-		OdfElement container = getContainerElement();
-		delete(mIndexInContainer, mMatchedText.length(), container);
-		SelectionManager.refreshAfterCut(this);
-		mMatchedText = "";
-	}
-
-	/**
-	 * Apply a style to the selection so that the text style of this selection
-	 * will append the specified style.
-	 * 
-	 * @param style
-	 *            the style can be from the current document or user defined
-	 * @throws InvalidNavigationException
-	 *             if the selection is unavailable.
-	 */
-	public void applyStyle(OdfStyleBase style) throws InvalidNavigationException {
-		// append the specified style to the selection
-		if (validate() == false) {
-			throw new InvalidNavigationException("No matched string at this position");
-		}
-		OdfElement parentElement = getContainerElement();
-
-		int leftLength = getText().length();
-		int index = mIndexInContainer;
-
-		appendStyle(index, leftLength, parentElement, style);
-
-	}
-
-	/**
-	 * Replace the text content of selection with a new string.
-	 * 
-	 * @param newText
-	 *            the replace text String
-	 * @throws InvalidNavigationException
-	 *             if the selection is unavailable.
-	 */
-	public void replaceWith(String newText) throws InvalidNavigationException {
-		if (validate() == false) {
-			throw new InvalidNavigationException("No matched string at this position");
-		}
-		OdfElement parentElement = getContainerElement();
-		int leftLength = getText().length();
-		int index = mIndexInContainer;
-		delete(index, leftLength, parentElement);
-		OdfTextSpan textSpan = new OdfTextSpan((OdfFileDom) parentElement.getOwnerDocument());
-		textSpan.addContentWhitespace(newText);
-		mIsInserted = false;
-		insertOdfElement(textSpan, index, parentElement);
-		// optimize the parent element
-		optimize(parentElement);
-		int offset = newText.length() - leftLength;
-		SelectionManager.refresh(getContainerElement(), offset, index + getText().length());
-		mMatchedText = newText;
-	}
-	
-	/**
-	 * Replace the text content of selection with a new Table.
-	 * 
-	 * @param newTable
-	 *            the replace Table
-	 * @return 
-	 * @throws InvalidNavigationException
-	 *             if the selection is unavailable.
-	 * @return the new Table in the TextDocument
-	 */
-	public Table replaceWith(Table newTable) throws InvalidNavigationException {
-		if (validate() == false) {
-			throw new InvalidNavigationException("No matched string at this position");
-		}
-		TableSelection nextTableSelection=new TableSelection(this);
-		return nextTableSelection.replaceWithTable(newTable);
-	}
-	/**
-	 * Replace the text content of selection with a new Image.
-	 * 
-	 * @param newImage
-	 *            the replace Image
-	 * @return 
-	 * @throws InvalidNavigationException
-	 *             if the selection is unavailable.
-	 * @return the new Image in the TextDocument,the image name is set to "replace" + System.currentTimeMillis(), please update the name to others by yourself.
-	 */
-	public Image replaceWith(Image newImage) throws InvalidNavigationException {
-		if (validate() == false) {
-			throw new InvalidNavigationException("No matched string at this position");
-		}
-		ImageSelection nextImageSelection=new ImageSelection(this);
-		return nextImageSelection.replaceWithImage(newImage);
-	}
-	/**
-	 * Replace the text content of selection with a new Image.
-	 * 
-	 * @param imageUri
-	 *            the replace Image URI
-	 * @throws InvalidNavigationException
-	 *             if the selection is unavailable.
-	 * @return the new Image in the TextDocument,the image name is set to "replace" + System.currentTimeMillis(), please update the name to others by yourself.
-	 */
-	public Image replaceWith(URI imageUri) throws InvalidNavigationException {
-		if (validate() == false) {
-			throw new InvalidNavigationException("No matched string at this position");
-		}
-		ImageSelection nextImageSelection=new ImageSelection(this);
-		return nextImageSelection.replaceWithImage(imageUri);
-	}
-	/**
-	 * Replace the content with a Field
-	 * 
-	 * @param orgField
-	 *            the reference Field to replace.
-     * @throws InvalidNavigationException
-	 *             if the selection is unavailable.   
-	 * @return the created field.         
-	 */
-	public Field replaceWith(Field orgField) throws InvalidNavigationException {
-		if (validate() == false) {
-			throw new InvalidNavigationException("No matched string at this position");
-		}
-		Field newfield=null;
-		OdfElement parentElement = getContainerElement();
-		Paragraph orgparagraph = Paragraph.getInstanceof((TextParagraphElementBase) parentElement);
-		TextDocument document = (TextDocument) orgparagraph.getOwnerDocument();
-		
-		FieldSelection nextFieldSelection=new FieldSelection(this);
-		FieldType fieldType = orgField.getFieldType();
-	
-		switch (fieldType) {
-		case DATE_FIELD:
-			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
-			break;
-		case FIXED_DATE_FIELD:
-			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
-			break;
-		case TIME_FIELD:
-			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
-			break;
-		case FIXED_TIME_FIELD:
-			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
-			break;
-		case PREVIOUS_PAGE_NUMBER_FIELD:
-			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
-			break;
-		case CURRENT_PAGE_NUMBER_FIELD:
-			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
-			break;
-		case NEXT_PAGE_NUMBER_FIELD:
-			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
-			break;
-		case PAGE_COUNT_FIELD:
-			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
-			break;
-		case TITLE_FIELD:
-			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
-			break;
-		case SUBJECT_FIELD:
-			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
-			break;
-		case AUTHOR_NAME_FIELD:
-			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
-			break;
-		case AUTHOR_INITIALS_FIELD:
-			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
-			break;
-		case CHAPTER_FIELD:
-			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
-			break;
-		case SIMPLE_VARIABLE_FIELD:
-			VariableField SimpleVariableField = (VariableField)orgField;
-			String simplefieldname = SimpleVariableField.getVariableName();
-			VariableField simplefield=Fields.createSimpleVariableField(document, simplefieldname);
-			nextFieldSelection.replaceWithVariableField(simplefield);
-			newfield=simplefield;
-			break;
-		case USER_VARIABLE_FIELD:
-			VariableField userVariableField = (VariableField)orgField;
-			TextUserFieldDeclElement textUserFieldDeclElement =(TextUserFieldDeclElement) userVariableField.getOdfElement();
-			String fieldname = userVariableField.getVariableName();
-			String value=textUserFieldDeclElement.getOfficeStringValueAttribute();
-			VariableField variableField=Fields.createUserVariableField(document, fieldname,value);
-			nextFieldSelection.replaceWithVariableField(variableField);
-			newfield=variableField;
-			break;
-		case CONDITION_FIELD:
-			ConditionField conditionField = (ConditionField)orgField;
-			TextConditionalTextElement textConditionalTextElement =(TextConditionalTextElement) conditionField.getOdfElement();
-			String StringValueIfFalse=textConditionalTextElement.getTextStringValueIfFalseAttribute();
-			String StringValueIfTrue=textConditionalTextElement.getTextStringValueIfTrueAttribute();
-			String StringCondition=textConditionalTextElement.getTextConditionAttribute();
-			boolean CurrentValue=textConditionalTextElement.getTextCurrentValueAttribute();
-			ConditionField newdConditionField = nextFieldSelection.replaceWithConditionField(StringCondition, StringValueIfTrue, StringValueIfFalse);
-			TextConditionalTextElement newTextConditionalTextElement=(TextConditionalTextElement)newdConditionField.getOdfElement();
-			newTextConditionalTextElement.setTextCurrentValueAttribute(CurrentValue);
-			newfield=newdConditionField;
-			break;
-		case HIDDEN_TEXT_FIELD:
-			ConditionField conditionFieldHIDDEN = (ConditionField)orgField;
-			TextConditionalTextElement textConditionalTextElementHIDDEN =(TextConditionalTextElement) conditionFieldHIDDEN.getOdfElement();
-			String StringValueIfFalseHIDDEN=textConditionalTextElementHIDDEN.getTextStringValueIfFalseAttribute();
-			String StringConditionHIDDEN=textConditionalTextElementHIDDEN.getTextConditionAttribute();
-			boolean CurrentValueHIDDEN=textConditionalTextElementHIDDEN.getTextCurrentValueAttribute();
-			ConditionField newdConditionFieldHIDDEN = nextFieldSelection.replaceWithHiddenTextField(StringConditionHIDDEN, StringValueIfFalseHIDDEN);
-			TextConditionalTextElement newTextConditionalTextElementHIDDEN=(TextConditionalTextElement)newdConditionFieldHIDDEN.getOdfElement();
-			newTextConditionalTextElementHIDDEN.setTextCurrentValueAttribute(CurrentValueHIDDEN);
-			newfield=newdConditionFieldHIDDEN;
-			break;
-		case REFERENCE_FIELD:
-		default: throw new IllegalArgumentException("Simple Java API for ODF doesn't support this type now.");
-		}
-		return newfield;
-	}
-	
-	/**
-	 * Replace the content with a paragraph, the paragraph can be in the same TextDocument or in a different Document.
-	 * 
-	 * @param newParagraph
-	 *            the reference paragraph to replace.
-     * @throws InvalidNavigationException
-	 *             if the selection is unavailable.   
-	 * @return the replaced Paragraph.             
-	 */
-	public Paragraph replaceWith(Paragraph newParagraph) throws InvalidNavigationException {
-		if (validate() == false) {
-			throw new InvalidNavigationException("No matched string at this position");
-		}
-		ParagraphSelection nextParagraphSelection=new ParagraphSelection(this);
-		return nextParagraphSelection.replaceWithParagraph(newParagraph);
-	}
-	/**
-	 * Replace the content with a TextDocument with Styles.
-	 * Note: You need cache the TextNavigation.nextSelection item because after
-	 * you replace currtenTextSelection with TextDocument, TextNavigation.nextSelection will search from the inserted Content, 
-	 * it will make you into a loop if the Search keyword also can be found in the new inserted Content.
-	 * </p>
-	 * The right way to use this replaceWithTextDocument(TextDocument textDocument) method should like this: 
-	 * <Code>
-	 * <p>	search = new TextNavigation("SIMPLE", doc);    </p>
-	 * <p>	TextSelection currtenTextSelection,nextTextSelection=null;</p>
-	 * <p>		while (search.hasNext()) {</p>
-	 * <p>			if(nextTextSelection!=null){</p>
-	 * <p>				currtenTextSelection=nextTextSelection;</p>
-	 * <p>			}else {</p>
-	 * <p>			 	currtenTextSelection = (TextSelection) search.nextSelection();</p>
-	 * <p>			}</p>
-	 * <p>			nextTextSelection = (TextSelection) search.nextSelection();</p>
-	 * <p>			if(currtenTextSelection!=null){</p>
-	 * <p>				try {</p>
-	 * <p>					nextTextSelection.replaceWithTextDocument(sourcedoc);</p>
-	 * <p>				} catch (Exception e) {</p>
-	 * <p>					e.printStackTrace();</p>
-	 * <p>				}</p>
-	 * <p>			}</p>
-	 * <p>		}</p>
-	 * <p>		if(nextTextSelection!=null){</p>
-	 * <p>			try {</p>
-	 * <p>				nextTextSelection.replaceWithTextDocument(sourcedoc);</p>
-	 * <p>			} catch (Exception e) {</p>
-	 * <p>				e.printStackTrace();</p>
-	 * <p>			}</p>
-	 * <p>		}</p>
-	 * </Code>
-	 * 
-	 * @param newTextDocument
-	 *            the reference TextDocument to replace.
-	 * @throws InvalidNavigationException 
-	 */
-	public void replaceWith(TextDocument newTextDocument) throws InvalidNavigationException{
-		if (validate() == false) {
-			throw new InvalidNavigationException("No matched string at this position");
-		}
-		TextDocumentSelection nextTextDocumentSelection=new TextDocumentSelection(this);
-		try {
-			nextTextDocumentSelection.replaceWithTextDocument(newTextDocument);
-		} catch (Exception e) {
-			e.printStackTrace();
-		}
-	}
-	/**
-	 * Create a span element for this text selection.
-	 * 
-	 * @return the created text span element for this selection
-	 * @throws InvalidNavigationException
-	 *             if the selection is unavailable.
-	 * @since 0.5.5
-	 */
-	public TextSpanElement createSpanElement() throws InvalidNavigationException {
-		if (validate() == false) {
-			throw new InvalidNavigationException("No matched string at this position");
-		}
-		OdfElement parentElement = getContainerElement();
-		int leftLength = getText().length();
-		int index = mIndexInContainer;
-		delete(index, leftLength, parentElement);
-		OdfTextSpan textSpan = new OdfTextSpan((OdfFileDom) parentElement.getOwnerDocument());
-		textSpan.addContentWhitespace(getText());
-		mIsInserted = false;
-		insertOdfElement(textSpan, index, parentElement);
-		// optimize the parent element
-		optimize(parentElement);
-
-		return textSpan;
-	}
-
-	/**
-	 * Paste this selection just before a specific selection.
-	 * 
-	 * @param positionItem
-	 *            a selection that is used to point out the position
-	 * @throws InvalidNavigationException
-	 *             if the selection is unavailable.
-	 */
-	@Override
-	public void pasteAtFrontOf(Selection positionItem) throws InvalidNavigationException {
-		if (validate() == false) {
-			throw new InvalidNavigationException("No matched string at this position");
-		}
-		int indexOfNew = 0;
-		OdfElement newElement = positionItem.getElement();
-		if (positionItem instanceof TextSelection) {
-			indexOfNew = ((TextSelection) positionItem).getIndex();
-			newElement = ((TextSelection) positionItem).getContainerElement();
-		}
-
-		OdfTextSpan textSpan = getSpan((OdfFileDom) positionItem.getElement().getOwnerDocument());
-		mIsInserted = false;
-		insertOdfElement(textSpan, indexOfNew, newElement);
-		adjustStyle(newElement, textSpan, null);
-		SelectionManager.refreshAfterPasteAtFrontOf(this, positionItem);
-	}
-
-	/**
-	 * Paste this selection just after a specific selection.
-	 * 
-	 * @param positionItem
-	 *            a selection that is used to point out the position
-	 * @throws InvalidNavigationException
-	 *             if the selection is unavailable.
-	 */
-	@Override
-	public void pasteAtEndOf(Selection positionItem) throws InvalidNavigationException {
-		if (validate() == false) {
-			throw new InvalidNavigationException("No matched string at this position");
-		}
-		// TODO: think about and test if search item is a element selection
-		int indexOfNew = 0;
-		OdfElement newElement = positionItem.getElement();
-		if (positionItem instanceof TextSelection) {
-			indexOfNew = ((TextSelection) positionItem).getIndex() + ((TextSelection) positionItem).getText().length();
-			newElement = ((TextSelection) positionItem).getContainerElement();
-		}
-		OdfTextSpan textSpan = getSpan((OdfFileDom) positionItem.getElement().getOwnerDocument());
-		mIsInserted = false;
-		insertOdfElement(textSpan, indexOfNew, newElement);
-		adjustStyle(newElement, textSpan, null);
-		SelectionManager.refreshAfterPasteAtEndOf(this, positionItem);
-	}
-	public void setSelectionReplaced(boolean b) {
-		this.isSelectionReplaced = b;
-	}
-	public boolean isSelectionReplaced() {
-		return this.isSelectionReplaced;
-	}
-
-	/**
-	 * Add a hypertext reference to the selection.
-	 * 
-	 * @param url
-	 *            the URL of this hypertext reference
-	 * @throws InvalidNavigationException
-	 *             if the selection is unavailable.
-	 */
-	public void addHref(URL url) throws InvalidNavigationException {
-		if (validate() == false) {
-			throw new InvalidNavigationException("No matched string at this position");
-		}
-		OdfElement parentElement = getContainerElement();
-		int leftLength = getText().length();
-		int index = mIndexInContainer;
-		addHref(index, leftLength, parentElement, url.toString());
-	}
-	
-	/**
-	 * Add a comment to the selection.
-	 * 
-	 * @param content
-	 *            the content of this comment.
-	 * @param creator
-	 *            the creator of this comment, if <code>creator</code> is null,
-	 *            the value of <code>System.getProperty("user.name")</code> will
-	 *            be used.
-	 * @throws InvalidNavigationException
-	 *            if the selection is unavailable.
-	 * @since 0.6.5
-	 */
-	public void addComment(String content, String creator) throws InvalidNavigationException {
-		if (validate() == false) {
-			throw new InvalidNavigationException("No matched string at this position");
-		}
-		// create annotation element
-		OdfElement parentElement = getContainerElement();
-		OdfFileDom dom = (OdfFileDom) parentElement.getOwnerDocument();
-		OfficeAnnotationElement annotationElement = dom.newOdfElement(OfficeAnnotationElement.class);
-		// set creator
-		DcCreatorElement dcCreatorElement = annotationElement.newDcCreatorElement();
-		if (creator == null) {
-			creator = System.getProperty("user.name");
-		}
-		dcCreatorElement.setTextContent(creator);
-		// set date
-		String dcDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").format(new Date());
-		DcDateElement dcDateElement = annotationElement.newDcDateElement();
-		dcDateElement.setTextContent(dcDate);
-		TextPElement notePElement = annotationElement.newTextPElement();
-		TextSpanElement noteSpanElement = notePElement.newTextSpanElement();
-		// set comment style
-		OdfOfficeAutomaticStyles styles = null;
-		if (dom instanceof OdfContentDom) {
-			styles = ((OdfContentDom) dom).getAutomaticStyles();
-		} else if (dom instanceof OdfStylesDom) {
-			styles = ((OdfStylesDom) dom).getAutomaticStyles();
-		}
-		OdfStyle textStyle = styles.newStyle(OdfStyleFamily.Text);
-		StyleTextPropertiesElement styleTextPropertiesElement = textStyle.newStyleTextPropertiesElement(null);
-		styleTextPropertiesElement.setStyleFontNameAttribute("Tahoma");
-		styleTextPropertiesElement.setFoFontSizeAttribute("10pt");
-		styleTextPropertiesElement.setStyleFontNameAsianAttribute("Lucida Sans Unicode");
-		styleTextPropertiesElement.setStyleFontSizeAsianAttribute("12pt");
-		noteSpanElement.setStyleName(textStyle.getStyleNameAttribute());
-		// set comment content
-		noteSpanElement.setTextContent(content);
-		// insert comment to its position
-		insertOdfElement(annotationElement, mIndexInContainer, parentElement);
-		// three text length plus two '\r'
-		int offset = content.length() + 1 + dcDate.length() + 1 + creator.length();
-		SelectionManager.refresh(getContainerElement(), offset, getIndex());
-	}
-	
-	/**
-	 * return a String Object representing this selection value the text content
-	 * of the selection, start index in the container element and the text
-	 * content of the container element will be provided.
-	 * 
-	 * @return a String representation of the value of this
-	 *         <code>TextSelection</code>
-	 */
-	@Override
-	public String toString() {
-		return "[" + mMatchedText + "] started from " + mIndexInContainer + " in paragraph:"
-				+ TextExtractor.getText(getContainerElement());
-	}
-
-	@Override
-	protected void refreshAfterFrontalDelete(Selection deleteItem) {
-		if (deleteItem instanceof TextSelection) {
-			mIndexInContainer -= ((TextSelection) deleteItem).getText().length();
-		}
-	}
-
-	@Override
-	protected void refreshAfterFrontalInsert(Selection pasteItem) {
-		if (pasteItem instanceof TextSelection) {
-			mIndexInContainer += ((TextSelection) pasteItem).getText().length();
-		}
-	}
-
-	@Override
-	protected void refresh(int offset) {
-		mIndexInContainer += offset;
-		if (mIndexInContainer < 0) {
-			mIndexInContainer = 0;
-		}
-	}
-
-	void cleanBreakProperty(Paragraph paragraph) {
-		TextNavigation search = this.getTextNavigation();
-		if (search == null)
-			throw new IllegalStateException("Navigation is null");
-		OdfStyleBase styleElement = paragraph.getStyleHandler()
-				.getStyleElementForRead();
-		String name = styleElement.getAttribute("style:name");
-		String newName = null;
-		OdfElement modifiedStyleElement = search
-				.getModifiedStyleElement(styleElement);
-		if (modifiedStyleElement == null) {
-			modifiedStyleElement = (OdfElement) styleElement.cloneNode(true);
-			search.addModifiedStyleElement(styleElement, modifiedStyleElement);
-			NodeList paragraphProperties = modifiedStyleElement
-					.getElementsByTagName("style:paragraph-properties");
-			if (paragraphProperties != null
-					&& paragraphProperties.getLength() > 0) {
-				StyleParagraphPropertiesElement property = (StyleParagraphPropertiesElement) paragraphProperties
-						.item(0);
-				property.removeAttribute("fo:break-before");
-				property.removeAttribute("fo:break-after");
-				property.removeAttribute("style:page-number");
-			}
-			modifiedStyleElement.removeAttribute("style:master-page-name");
-			newName = name + "-" + makeUniqueName();
-			NamedNodeMap attributes = modifiedStyleElement.getAttributes();
-			if (attributes != null) {
-				for (int i = 0; i < attributes.getLength(); i++) {
-					Node item = attributes.item(i);
-					String value = item.getNodeValue();
-					if (name.equals(value)) {
-						item.setNodeValue(newName);
-						break;
-					}
-				}
-			}
-			styleElement.getParentNode().appendChild(modifiedStyleElement);
-		} else {
-			newName = modifiedStyleElement.getAttribute("style:name");
-		}
-		NamedNodeMap attributes = paragraph.getOdfElement().getAttributes();
-		if (attributes != null) {
-			for (int i = 0; i < attributes.getLength(); i++) {
-				Node item = attributes.item(i);
-				String value = item.getNodeValue();
-				if (name.equals(value)) {
-					item.setNodeValue(newName);
-					break;
-				}
-			}
-		}
-		this.getTextNavigation().setHandlePageBreak(true);
-	}
-	String makeUniqueName() {
-		return String.format("p%06x", (int) (Math.random() * 0xffffff));
-	}
-	/*
-	 * Return a new span that cover this selection and keep the original style
-	 * of this <code>Selection</code>.
-	 */
-	private OdfTextSpan getSpan(OdfFileDom ownerDoc) {
-
-		OdfElement parentElement = getContainerElement();
-		if (parentElement != null) {
-			OdfElement copyParentNode = (OdfElement) parentElement.cloneNode(true);
-			if (ownerDoc != parentElement.getOwnerDocument()) {
-				copyParentNode = (OdfElement) ownerDoc.adoptNode(copyParentNode);
-			}
-			OdfTextSpan textSpan = new OdfTextSpan(ownerDoc);
-			int sIndex = mIndexInContainer;
-			int eIndex = sIndex + mMatchedText.length();
-			// delete the content except the selection string
-			// delete from the end to start, so that the postion will not be
-			// impact by delete action
-			delete(eIndex, TextExtractor.getText(copyParentNode).length() - eIndex, copyParentNode);
-			delete(0, sIndex, copyParentNode);
-			optimize(copyParentNode);
-			Node childNode = copyParentNode.getFirstChild();
-			while (childNode != null) {
-				textSpan.appendChild(childNode.cloneNode(true));
-				childNode = childNode.getNextSibling();
-			}
-			// apply text style for the textSpan
-			if (copyParentNode instanceof OdfStylableElement) {
-				applyTextStyleProperties(getTextStylePropertiesDeep((OdfStylableElement) copyParentNode), textSpan);
-			}
-			return textSpan;
-		}
-		return null;
-	}
-
-	/*
-	 * Optimize the text element by deleting the empty text node.
-	 */
-	private void optimize(Node pNode) {
-		// check if the text:a can be optimized
-		Node node = pNode.getFirstChild();
-		while (node != null) {
-			Node nextNode = node.getNextSibling();
-			// if ((node.getNodeType() == Node.ELEMENT_NODE) &&
-			// (node.getPrefix().equals("text"))) {
-			if (node instanceof OdfTextSpan) {
-				if (TextExtractor.getText((OdfTextSpan) node).length() == 0) {
-					node.getParentNode().removeChild(node);
-				} else {
-					optimize(node);
-				}
-			}
-			node = nextNode;
-		}
-	}
-
-	/*
-	 * Apply the <code>styleMap</code> to the <code>toElement</code> reserve the
-	 * style property of toElement, if it is also exist in <code>styleMap</code>
-	 */
-	private void applyTextStyleProperties(Map<OdfStyleProperty, String> styleMap, OdfStylableElement toElement) {
-		if (styleMap != null) {
-			// preserve the style property of toElement if it is also exist in
-			// styleMap
-			OdfStyle resultStyleElement = toElement.getAutomaticStyles().newStyle(OdfStyleFamily.Text);
-			for (Map.Entry<OdfStyleProperty, String> entry : styleMap.entrySet()) {
-				if (toElement.hasProperty(entry.getKey())) {
-					resultStyleElement.setProperty(entry.getKey(), toElement.getProperty(entry.getKey()));
-				} else {
-					resultStyleElement.setProperty(entry.getKey(), entry.getValue());
-				}
-			}
-			toElement.setStyleName(resultStyleElement.getStyleNameAttribute());
-		}
-	}
-
-	/*
-	 * Insert <code>odfElement</code>, span or annotation, into the from index of <code>pNode<code>.
-	 */
-	private void insertOdfElement(OdfElement odfElement, int fromIndex, Node pNode) {
-		if (fromIndex < 0) {
-			fromIndex = 0;
-		}
-		if (fromIndex == 0 && mIsInserted) {
-			return;
-		}
-		int nodeLength = 0;
-		Node node = pNode.getFirstChild();
-		while (node != null) {
-			if (fromIndex <= 0 && mIsInserted) {
-				return;
-			}
-			if (node.getNodeType() == Node.TEXT_NODE) {
-				nodeLength = node.getNodeValue().length();
-				if ((fromIndex != 0) && (nodeLength < fromIndex)) {
-					fromIndex -= nodeLength;
-				} else {
-					// insert result after node, and insert an new text node
-					// after the result node
-					String value = node.getNodeValue();
-					StringBuffer buffer = new StringBuffer();
-					buffer.append(value.substring(0, fromIndex));
-					// insert the text span in appropriate position
-					node.setNodeValue(buffer.toString());
-					Node nextNode = node.getNextSibling();
-					Node parNode = node.getParentNode();
-					Node newNode = node.cloneNode(true);
-					newNode.setNodeValue(value.substring(fromIndex, value.length()));
-					if (nextNode != null) {
-						parNode.insertBefore(odfElement, nextNode);
-						parNode.insertBefore(newNode, nextNode);
-					} else {
-						parNode.appendChild(odfElement);
-						parNode.appendChild(newNode);
-					}
-					mIsInserted = true;
-					return;
-				}
-			} else if (node.getNodeType() == Node.ELEMENT_NODE) {
-				// text:s
-				if (node.getLocalName().equals("s")) {
-					try {
-						nodeLength = Integer.parseInt(((Element) node).getAttributeNS(OdfDocumentNamespace.TEXT
-								.getUri(), "c"));
-					} catch (Exception e) {
-						nodeLength = 1;
-					}
-					fromIndex -= nodeLength;
-				} else if (node.getLocalName().equals("line-break")) {
-					nodeLength = 1;
-					fromIndex--;
-				} else if (node.getLocalName().equals("tab")) {
-					nodeLength = 1;
-					fromIndex--;
-				} else {
-					nodeLength = TextExtractor.getText((OdfElement) node).length();
-					insertOdfElement(odfElement, fromIndex, node);
-					fromIndex -= nodeLength;
-				}
-			}
-			node = node.getNextSibling();
-		}
-	}
-
-	/*
-	 * The <code>textSpan</code> must be the child element of
-	 * <code>parentNode</code> this method is used to keep the style of text
-	 * span when it has been insert into the <code>parentNode</code> if we don't
-	 * deal with the style, the inserted span will also have the style of
-	 * <code>parentNode</code>.
-	 */
-	private void adjustStyle(Node parentNode, OdfTextSpan textSpan, Map<OdfStyleProperty, String> styleMap) {
-		if (parentNode instanceof OdfStylableElement) {
-			OdfStylableElement pStyleNode = (OdfStylableElement) parentNode;
-			if (styleMap == null) {
-				styleMap = getTextStylePropertiesDeep(pStyleNode);
-			}
-			Node node = parentNode.getFirstChild();
-			while (node != null) {
-				if (node.getNodeType() == Node.TEXT_NODE) {
-					if (node.getTextContent().length() > 0) {
-						Node nextNode = node.getNextSibling();
-						OdfTextSpan span = new OdfTextSpan((OdfFileDom) node.getOwnerDocument());
-						span.appendChild(node);
-						if (nextNode != null) {
-							parentNode.insertBefore(span, nextNode);
-						} else {
-							parentNode.appendChild(span);
-						}
-						node = span;
-						applyTextStyleProperties(styleMap, (OdfStylableElement) node);
-					}
-				} else if ((node instanceof OdfStylableElement)) {
-					if (!node.equals(textSpan)) {
-						Map<OdfStyleProperty, String> styles = getTextStylePropertiesDeep(pStyleNode);
-						Map<OdfStyleProperty, String> styles1 = getTextStylePropertiesDeep((OdfStylableElement) node);
-						if (styles == null) {
-							styles = styles1;
-						} else if (styles1 != null) {
-							styles.putAll(styles1);
-						}
-						int comp = node.compareDocumentPosition(textSpan);
-						// if node contains textSpan, then recurse the node
-						if ((comp & Node.DOCUMENT_POSITION_CONTAINED_BY) > 0) {
-							adjustStyle(node, textSpan, styles);
-						} else {
-							applyTextStyleProperties(styles, (OdfStylableElement) node);
-						}
-					}
-				}
-				node = node.getNextSibling();
-			}
-			// change the parentNode to default style
-			// here we don't know the default style name, so here just
-			// remove the text:style-name attribute
-			pStyleNode.removeAttributeNS(OdfDocumentNamespace.TEXT.getUri(), "style-name");
-		}
-	}
-
-	/*
-	 * Delete the <code>pNode<code> from the <code>fromIndex</code> text, and
-	 * delete <code>leftLength</code> text.
-	 */
-	private void delete(int fromIndex, int leftLength, Node pNode) {
-		if ((fromIndex == 0) && (leftLength == 0)) {
-			return;
-		}
-		int nodeLength = 0;
-		Node node = pNode.getFirstChild();
-		while (node != null) {
-			if ((fromIndex == 0) && (leftLength == 0)) {
-				return;
-			}
-			if (node.getNodeType() == Node.TEXT_NODE) {
-				nodeLength = node.getNodeValue().length();
-			} else if (node.getNodeType() == Node.ELEMENT_NODE) {
-				// text:s
-				if (node.getLocalName().equals("s")) {
-					try {
-						nodeLength = Integer.parseInt(((Element) node).getAttributeNS(OdfDocumentNamespace.TEXT
-								.getUri(), "c"));
-					} catch (Exception e) {
-						nodeLength = 1;
-					}
-				} else if (node.getLocalName().equals("line-break")) {
-					nodeLength = 1;
-				} else if (node.getLocalName().equals("tab")) {
-					nodeLength = 1;
-				} else {
-					nodeLength = TextExtractor.getText((OdfElement) node).length();
-				}
-			}
-			if (nodeLength <= fromIndex) {
-				fromIndex -= nodeLength;
-			} else {
-				// the start index is in this node
-				if (node.getNodeType() == Node.TEXT_NODE) {
-					String value = node.getNodeValue();
-					StringBuffer buffer = new StringBuffer();
-					buffer.append(value.substring(0, fromIndex));
-					int endLength = fromIndex + leftLength;
-					int nextLength = value.length() - endLength;
-					fromIndex = 0;
-					if (nextLength >= 0) {
-						// delete the result
-						buffer.append(value.substring(endLength, value.length()));
-						leftLength = 0;
-					} else {
-						leftLength = endLength - value.length();
-					}
-					node.setNodeValue(buffer.toString());
-
-				} else if (node.getNodeType() == Node.ELEMENT_NODE) {
-					// if text:s?????????
-					// text:s
-					if (node.getLocalName().equals("s")) {
-						// delete space
-						((TextSElement) node).setTextCAttribute(new Integer(nodeLength - fromIndex));
-						leftLength = leftLength - (nodeLength - fromIndex);
-						fromIndex = 0;
-					} else if (node.getLocalName().equals("line-break") || node.getLocalName().equals("tab")) {
-						fromIndex = 0;
-						leftLength--;
-					} else {
-						delete(fromIndex, leftLength, node);
-						int length = (fromIndex + leftLength) - nodeLength;
-						leftLength = length > 0 ? length : 0;
-						fromIndex = 0;
-					}
-				}
-			}
-			node = node.getNextSibling();
-		}
-	}
-
-	/*
-	 * Add href for a range text of <code>pNode<code> from the
-	 * <code>fromIndex</code> text, and the href will cover
-	 * <code>leftLength</code> text.
-	 */
-	private void addHref(int fromIndex, int leftLength, Node pNode, String href) {
-		if ((fromIndex == 0) && (leftLength == 0)) {
-			return;
-		}
-		int nodeLength = 0;
-		Node node = pNode.getFirstChild();
-
-		while (node != null) {
-			if ((fromIndex == 0) && (leftLength == 0)) {
-				return;
-			}
-			if (node.getNodeType() == Node.TEXT_NODE) {
-				nodeLength = node.getNodeValue().length();
-			} else if (node.getNodeType() == Node.ELEMENT_NODE) {
-				// text:s
-				if (node.getLocalName().equals("s")) {
-					try {
-						nodeLength = Integer.parseInt(((Element) node).getAttributeNS(OdfDocumentNamespace.TEXT
-								.getUri(), "c"));
-					} catch (Exception e) {
-						nodeLength = 1;
-					}
-				} else if (node.getLocalName().equals("line-break")) {
-					nodeLength = 1;
-				} else if (node.getLocalName().equals("tab")) {
-					nodeLength = 1;
-				} else {
-					nodeLength = TextExtractor.getText((OdfElement) node).length();
-				}
-
-			}
-			if (nodeLength <= fromIndex) {
-				fromIndex -= nodeLength;
-			} else {
-				// the start index is in this node
-				if (node.getNodeType() == Node.TEXT_NODE) {
-					String value = node.getNodeValue();
-					node.setNodeValue(value.substring(0, fromIndex));
-					int endLength = fromIndex + leftLength;
-					int nextLength = value.length() - endLength;
-
-					Node nextNode = node.getNextSibling();
-					Node parNode = node.getParentNode();
-					// init text:a
-					TextAElement textLink = new TextAElement((OdfFileDom) node.getOwnerDocument());
-					Node newNode = null;
-					if (nextLength >= 0) {
-						textLink.setTextContent(value.substring(fromIndex, endLength));
-						newNode = node.cloneNode(true);
-						newNode.setNodeValue(value.substring(endLength, value.length()));
-						leftLength = 0;
-					} else {
-						textLink.setTextContent(value.substring(fromIndex, value.length()));
-						leftLength = endLength - value.length();
-					}
-					textLink.setXlinkTypeAttribute("simple");
-					textLink.setXlinkHrefAttribute(href);
-
-					if (nextNode != null) {
-						parNode.insertBefore(textLink, nextNode);
-						if (newNode != null) {
-							parNode.insertBefore(newNode, nextNode);
-						}
-					} else {
-						parNode.appendChild(textLink);
-						if (newNode != null) {
-							parNode.appendChild(newNode);
-						}
-					}
-					fromIndex = 0;
-					if (nextNode != null) {
-						node = nextNode;
-					} else {
-						node = textLink;
-					}
-
-				} else if (node.getNodeType() == Node.ELEMENT_NODE) {
-					// if text:s?????????
-					// text:s
-					if (node.getLocalName().equals("s")) {
-						// delete space
-						((TextSElement) node).setTextCAttribute(new Integer(nodeLength - fromIndex));
-						leftLength = leftLength - (nodeLength - fromIndex);
-						fromIndex = 0;
-
-					} else if (node.getLocalName().equals("line-break") || node.getLocalName().equals("tab")) {
-						fromIndex = 0;
-						leftLength--;
-					} else {
-						addHref(fromIndex, leftLength, node, href);
-						int length = (fromIndex + leftLength) - nodeLength;
-						leftLength = length > 0 ? length : 0;
-						fromIndex = 0;
-					}
-				}
-			}
-			node = node.getNextSibling();
-		}
-	}
-
-	/*
-	 * Get a map containing text properties of the specified styleable
-	 * <code>element</code>.
-	 * 
-	 * @return a map of text properties.
-	 */
-	private Map<OdfStyleProperty, String> getTextStyleProperties(OdfStylableElement element) {
-		String styleName = element.getStyleName();
-		OdfStyleBase styleElement = element.getAutomaticStyles().getStyle(styleName, element.getStyleFamily());
-
-		if (styleElement == null) {
-			styleElement = element.getDocumentStyle();
-		}
-		if (styleElement != null) {
-			// check if it is the style:defaut-style
-			if ((styleElement.getPropertiesElement(OdfStylePropertiesSet.ParagraphProperties) == null)
-					&& (styleElement.getPropertiesElement(OdfStylePropertiesSet.TextProperties) == null)) {
-				styleElement = ((Document) ((OdfFileDom) styleElement.getOwnerDocument()).getDocument())
-						.getDocumentStyles().getDefaultStyle(styleElement.getFamily());
-			}
-			TreeMap<OdfStyleProperty, String> result = new TreeMap<OdfStyleProperty, String>();
-			OdfStyleFamily family = OdfStyleFamily.Text;
-			if (family != null) {
-				for (OdfStyleProperty property : family.getProperties()) {
-					if (styleElement.hasProperty(property)) {
-						result.put(property, styleElement.getProperty(property));
-					}
-				}
-			}
-			return result;
-		}
-		return null;
-	}
-
-	/*
-	 * Get a map containing text properties of the specified styleable
-	 * <code>element</code>. The map will also include any properties set by
-	 * parent styles.
-	 * 
-	 * @return a map of text properties.
-	 */
-	private Map<OdfStyleProperty, String> getTextStylePropertiesDeep(OdfStylableElement element) {
-		String styleName = element.getStyleName();
-		OdfStyleBase styleElement = element.getAutomaticStyles().getStyle(styleName, element.getStyleFamily());
-		if (styleElement == null) {
-			styleElement = element.getDocumentStyle();
-		}
-		TreeMap<OdfStyleProperty, String> result = new TreeMap<OdfStyleProperty, String>();
-		while (styleElement != null) {
-			// check if it is the style:defaut-style
-			if ((styleElement.getPropertiesElement(OdfStylePropertiesSet.ParagraphProperties) == null)
-					&& (styleElement.getPropertiesElement(OdfStylePropertiesSet.TextProperties) == null)) {
-				styleElement = ((Document) ((OdfFileDom) styleElement.getOwnerDocument()).getDocument())
-						.getDocumentStyles().getDefaultStyle(styleElement.getFamily());
-			}
-			OdfStyleFamily family = OdfStyleFamily.Text;
-			if (family != null) {
-				for (OdfStyleProperty property : family.getProperties()) {
-					if (styleElement.hasProperty(property)) {
-						result.put(property, styleElement.getProperty(property));
-					}
-				}
-			}
-			styleElement = styleElement.getParentStyle();
-		}
-		return result;
-	}
-
-	/*
-	 * Validate if the <code>Selection</code> is still available.
-	 * 
-	 * @return true if the selection is available; false if the
-	 * <code>Selection</code> is not available.
-	 */
-	private boolean validate() {
-		if (getContainerElement() == null) {
-			return false;
-		}
-		OdfElement container = getContainerElement();
-		if (container == null) {
-			return false;
-		}
-		String content = TextExtractor.getText(container);
-		if (content.indexOf(mMatchedText, mIndexInContainer) == mIndexInContainer) {
-			return true;
-		} else {
-			return false;
-		}
-	}
-
-	/*
-	 * Append specified style for a range text of <code>pNode<code> from
-	 * <code>fromIndex</code> and cover <code>leftLength</code>
-	 */
-	private void appendStyle(int fromIndex, int leftLength, Node pNode, OdfStyleBase style) {
-		if ((fromIndex == 0) && (leftLength == 0)) {
-			return;
-		}
-		int nodeLength = 0;
-		Node node = pNode.getFirstChild();
-		while (node != null) {
-			if ((fromIndex == 0) && (leftLength == 0)) {
-				return;
-			}
-			if (node.getNodeType() == Node.TEXT_NODE) {
-				nodeLength = node.getNodeValue().length();
-			} else if (node.getNodeType() == Node.ELEMENT_NODE) {
-				// text:s
-				if (node.getLocalName().equals("s")) {
-					try {
-						nodeLength = Integer.parseInt(((Element) node).getAttributeNS(OdfDocumentNamespace.TEXT
-								.getUri(), "c"));
-					} catch (Exception e) {
-						nodeLength = 1;
-					}
-				} else if (node.getLocalName().equals("line-break")) {
-					nodeLength = 1;
-				} else if (node.getLocalName().equals("tab")) {
-					nodeLength = 1;
-				} else {
-					nodeLength = TextExtractor.getText((OdfElement) node).length();
-				}
-			}
-			if (nodeLength <= fromIndex) {
-				fromIndex -= nodeLength;
-			} else {
-				// the start index is in this node
-				if (node.getNodeType() == Node.TEXT_NODE) {
-					String value = node.getNodeValue();
-					node.setNodeValue(value.substring(0, fromIndex));
-					int endLength = fromIndex + leftLength;
-					int nextLength = value.length() - endLength;
-
-					Node nextNode = node.getNextSibling();
-					Node parNode = node.getParentNode();
-					// init text:a
-					OdfTextSpan textSpan = new OdfTextSpan((OdfFileDom) node.getOwnerDocument());
-					Node newNode = null;
-					if (nextLength >= 0) {
-						textSpan.setTextContent(value.substring(fromIndex, endLength));
-						newNode = node.cloneNode(true);
-						newNode.setNodeValue(value.substring(endLength, value.length()));
-						leftLength = 0;
-					} else {
-						textSpan.setTextContent(value.substring(fromIndex, value.length()));
-						leftLength = endLength - value.length();
-					}
-					textSpan.setProperties(style.getStyleProperties());
-
-					if (nextNode != null) {
-						parNode.insertBefore(textSpan, nextNode);
-						if (newNode != null) {
-							parNode.insertBefore(newNode, nextNode);
-						}
-					} else {
-						parNode.appendChild(textSpan);
-						if (newNode != null) {
-							parNode.appendChild(newNode);
-						}
-					}
-					fromIndex = 0;
-					if (nextNode != null) {
-						node = nextNode;
-					} else {
-						node = textSpan;
-					}
-
-				} else if (node.getNodeType() == Node.ELEMENT_NODE) {
-					// if text:s?????????
-					// text:s
-					if (node.getLocalName().equals("s")) {
-						// delete space
-						((TextSElement) node).setTextCAttribute(new Integer(nodeLength - fromIndex));
-						leftLength = leftLength - (nodeLength - fromIndex);
-						fromIndex = 0;
-
-					} else if (node.getLocalName().equals("line-break") || node.getLocalName().equals("tab")) {
-						fromIndex = 0;
-						leftLength--;
-					} else {
-						appendStyle(fromIndex, leftLength, node, style);
-						int length = (fromIndex + leftLength) - nodeLength;
-						leftLength = length > 0 ? length : 0;
-						fromIndex = 0;
-					}
-				}
-			}
-			node = node.getNextSibling();
-		}
-	}
-}
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+package org.odftoolkit.simple.common.navigation;
+
+import java.net.URI;
+import java.net.URL;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Map;
+import java.util.TreeMap;
+import org.odftoolkit.odfdom.dom.OdfContentDom;
+import org.odftoolkit.odfdom.dom.OdfDocumentNamespace;
+import org.odftoolkit.odfdom.dom.OdfStylesDom;
+import org.odftoolkit.odfdom.dom.element.OdfStylableElement;
+import org.odftoolkit.odfdom.dom.element.OdfStyleBase;
+import org.odftoolkit.odfdom.dom.element.dc.DcCreatorElement;
+import org.odftoolkit.odfdom.dom.element.dc.DcDateElement;
+import org.odftoolkit.odfdom.dom.element.office.OfficeAnnotationElement;
+import org.odftoolkit.odfdom.dom.element.style.StyleParagraphPropertiesElement;
+import org.odftoolkit.odfdom.dom.element.style.StyleTextPropertiesElement;
+import org.odftoolkit.odfdom.dom.element.text.TextAElement;
+import org.odftoolkit.odfdom.dom.element.text.TextConditionalTextElement;
+import org.odftoolkit.odfdom.dom.element.text.TextPElement;
+import org.odftoolkit.odfdom.dom.element.text.TextParagraphElementBase;
+import org.odftoolkit.odfdom.dom.element.text.TextSElement;
+import org.odftoolkit.odfdom.dom.element.text.TextSpanElement;
+import org.odftoolkit.odfdom.dom.element.text.TextUserFieldDeclElement;
+import org.odftoolkit.odfdom.dom.style.OdfStyleFamily;
+import org.odftoolkit.odfdom.dom.style.props.OdfStylePropertiesSet;
+import org.odftoolkit.odfdom.dom.style.props.OdfStyleProperty;
+import org.odftoolkit.odfdom.incubator.doc.office.OdfOfficeAutomaticStyles;
+import org.odftoolkit.odfdom.incubator.doc.style.OdfStyle;
+import org.odftoolkit.odfdom.incubator.doc.text.OdfTextHeading;
+import org.odftoolkit.odfdom.incubator.doc.text.OdfTextParagraph;
+import org.odftoolkit.odfdom.incubator.doc.text.OdfTextSpan;
+import org.odftoolkit.odfdom.pkg.OdfElement;
+import org.odftoolkit.odfdom.pkg.OdfFileDom;
+import org.odftoolkit.simple.Document;
+import org.odftoolkit.simple.TextDocument;
+import org.odftoolkit.simple.common.TextExtractor;
+import org.odftoolkit.simple.common.field.ConditionField;
+import org.odftoolkit.simple.common.field.Field;
+import org.odftoolkit.simple.common.field.Field.FieldType;
+import org.odftoolkit.simple.common.field.Fields;
+import org.odftoolkit.simple.common.field.VariableField;
+import org.odftoolkit.simple.draw.Image;
+import org.odftoolkit.simple.table.Table;
+import org.odftoolkit.simple.text.Paragraph;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * <code>TextSelection</code> describes a sub element in a paragraph element or
+ * a heading element. It is recognized by the container element, which type
+ * should be {@link org.odftoolkit.odfdom.incubator.doc.text.OdfTextParagraph
+ * OdfTextParagraph} or
+ * {@link org.odftoolkit.odfdom.incubator.doc.text.OdfTextHeading
+ * OdfTextHeading}, the start index of text content in container element and the
+ * text content of this <code>Selection</code>.
+ */
+public class TextSelection extends Selection {
+
+	String mMatchedText;
+	private OdfTextParagraph mParagraph;
+	private OdfTextHeading mHeading;
+	private int mIndexInContainer;
+	private boolean mIsInserted;
+	private boolean isSelectionReplaced = false;
+
+	/**
+	 * Constructor of <code>TextSelection</code>.
+	 *
+	 * @param text
+	 *            the text content of this <code>TextSelection</code>
+	 * @param containerElement
+	 *            the paragraph element or heading element that contains this
+	 *            <code>TextSelection</code>
+	 * @param index
+	 *            the start index of the text content in container element
+	 *
+	 */
+	TextSelection(Navigation search, String text, OdfElement containerElement,
+			int index) {
+		this.search = search;
+		mMatchedText = text;
+		if (containerElement instanceof OdfTextParagraph) {
+			mParagraph = (OdfTextParagraph) containerElement;
+		} else if (containerElement instanceof OdfTextHeading) {
+			mHeading = (OdfTextHeading) containerElement;
+		}
+		mIndexInContainer = index;
+	}
+
+	public TextNavigation getTextNavigation() {
+		if (search instanceof TextNavigation) {
+			return (TextNavigation) search;
+		}
+		return null;
+	}
+	/**
+	 * Create a new <code>TextSelection</code>.
+	 *
+	 * @param text
+	 *            the text content of this <code>TextSelection</code>
+	 * @param containerElement
+	 *            the paragraph element or heading element that contains this
+	 *            <code>TextSelection</code>
+	 * @param index
+	 *            the start index of the text content in container element
+	 *
+	 * @since 0.5.5
+	 */
+	public static TextSelection newTextSelection(Navigation search,
+			String text, OdfElement containerElement, int index) {
+		TextSelection selection = new TextSelection(search, text,
+				containerElement, index);
+		Selection.SelectionManager.registerItem(selection);
+		return selection;
+	}
+
+	/**
+	 * Get the paragraph element or heading element that contains this
+	 * <code>TextSelection</code>.
+	 *
+	 * @return OdfElement the container element
+	 */
+	@Override
+	public OdfElement getElement() {
+		return getContainerElement();
+	}
+
+	/**
+	 * Get the paragraph element or heading element that contains this text.
+	 *
+	 * @return OdfElement
+	 */
+	public OdfElement getContainerElement() {
+		if (mParagraph != null) {
+			return mParagraph;
+		} else {
+			return mHeading;
+		}
+	}
+
+	/**
+	 * Get the start index of the text content of its container element.
+	 *
+	 * @return index the start index of the text content of its container
+	 *         element
+	 */
+	@Override
+	public int getIndex() {
+		return mIndexInContainer;
+	}
+
+	/**
+	 * Get the text content of this <code>TextSelection</code>.
+	 *
+	 * @return text the text content
+	 */
+	public String getText() {
+		return mMatchedText;
+	}
+
+	/**
+	 * Delete the selection from the document the other matched selection in the
+	 * same container element will be updated automatically because the start
+	 * index of the following selections will be changed when the previous
+	 * selection has been deleted.
+	 *
+	 * @throws InvalidNavigationException
+	 *             if the selection is unavailable.
+	 */
+	@Override
+	public void cut() throws InvalidNavigationException {
+		if (validate() == false) {
+			throw new InvalidNavigationException("No matched string at this position");
+		}
+		OdfElement container = getContainerElement();
+		delete(mIndexInContainer, mMatchedText.length(), container);
+		SelectionManager.refreshAfterCut(this);
+		mMatchedText = "";
+	}
+
+	/**
+	 * Apply a style to the selection so that the text style of this selection
+	 * will append the specified style.
+	 *
+	 * @param style
+	 *            the style can be from the current document or user defined
+	 * @throws InvalidNavigationException
+	 *             if the selection is unavailable.
+	 */
+	public void applyStyle(OdfStyleBase style) throws InvalidNavigationException {
+		// append the specified style to the selection
+		if (validate() == false) {
+			throw new InvalidNavigationException("No matched string at this position");
+		}
+		OdfElement parentElement = getContainerElement();
+
+		int leftLength = getText().length();
+		int index = mIndexInContainer;
+
+		appendStyle(index, leftLength, parentElement, style);
+
+	}
+
+	/**
+	 * Replace the text content of selection with a new string.
+	 *
+	 * @param newText
+	 *            the replace text String
+	 * @throws InvalidNavigationException
+	 *             if the selection is unavailable.
+	 */
+	public void replaceWith(String newText) throws InvalidNavigationException {
+		if (validate() == false) {
+			throw new InvalidNavigationException("No matched string at this position");
+		}
+		OdfElement parentElement = getContainerElement();
+		int leftLength = getText().length();
+		int index = mIndexInContainer;
+		delete(index, leftLength, parentElement);
+		OdfTextSpan textSpan = new OdfTextSpan((OdfFileDom) parentElement.getOwnerDocument());
+		textSpan.addContentWhitespace(newText);
+		mIsInserted = false;
+		insertOdfElement(textSpan, index, parentElement);
+		// optimize the parent element
+		optimize(parentElement);
+		int offset = newText.length() - leftLength;
+		SelectionManager.refresh(getContainerElement(), offset, index + getText().length());
+		mMatchedText = newText;
+	}
+
+	/**
+	 * Replace the text content of selection with a new Table.
+	 *
+	 * @param newTable
+	 *            the replace Table
+	 * @return
+	 * @throws InvalidNavigationException
+	 *             if the selection is unavailable.
+	 * @return the new Table in the TextDocument
+	 */
+	public Table replaceWith(Table newTable) throws InvalidNavigationException {
+		if (validate() == false) {
+			throw new InvalidNavigationException("No matched string at this position");
+		}
+		TableSelection nextTableSelection=new TableSelection(this);
+		return nextTableSelection.replaceWithTable(newTable);
+	}
+	/**
+	 * Replace the text content of selection with a new Image.
+	 *
+	 * @param newImage
+	 *            the replace Image
+	 * @return
+	 * @throws InvalidNavigationException
+	 *             if the selection is unavailable.
+	 * @return the new Image in the TextDocument,the image name is set to "replace" + System.currentTimeMillis(), please update the name to others by yourself.
+	 */
+	public Image replaceWith(Image newImage) throws InvalidNavigationException {
+		if (validate() == false) {
+			throw new InvalidNavigationException("No matched string at this position");
+		}
+		ImageSelection nextImageSelection=new ImageSelection(this);
+		return nextImageSelection.replaceWithImage(newImage);
+	}
+	/**
+	 * Replace the text content of selection with a new Image.
+	 *
+	 * @param imageUri
+	 *            the replace Image URI
+	 * @throws InvalidNavigationException
+	 *             if the selection is unavailable.
+	 * @return the new Image in the TextDocument,the image name is set to "replace" + System.currentTimeMillis(), please update the name to others by yourself.
+	 */
+	public Image replaceWith(URI imageUri) throws InvalidNavigationException {
+		if (validate() == false) {
+			throw new InvalidNavigationException("No matched string at this position");
+		}
+		ImageSelection nextImageSelection=new ImageSelection(this);
+		return nextImageSelection.replaceWithImage(imageUri);
+	}
+	/**
+	 * Replace the content with a Field
+	 *
+	 * @param orgField
+	 *            the reference Field to replace.
+     * @throws InvalidNavigationException
+	 *             if the selection is unavailable.
+	 * @return the created field.
+	 */
+	public Field replaceWith(Field orgField) throws InvalidNavigationException {
+		if (validate() == false) {
+			throw new InvalidNavigationException("No matched string at this position");
+		}
+		Field newfield=null;
+		OdfElement parentElement = getContainerElement();
+		Paragraph orgparagraph = Paragraph.getInstanceof((TextParagraphElementBase) parentElement);
+		TextDocument document = (TextDocument) orgparagraph.getOwnerDocument();
+
+		FieldSelection nextFieldSelection=new FieldSelection(this);
+		FieldType fieldType = orgField.getFieldType();
+
+		switch (fieldType) {
+		case DATE_FIELD:
+			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
+			break;
+		case FIXED_DATE_FIELD:
+			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
+			break;
+		case TIME_FIELD:
+			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
+			break;
+		case FIXED_TIME_FIELD:
+			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
+			break;
+		case PREVIOUS_PAGE_NUMBER_FIELD:
+			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
+			break;
+		case CURRENT_PAGE_NUMBER_FIELD:
+			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
+			break;
+		case NEXT_PAGE_NUMBER_FIELD:
+			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
+			break;
+		case PAGE_COUNT_FIELD:
+			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
+			break;
+		case TITLE_FIELD:
+			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
+			break;
+		case SUBJECT_FIELD:
+			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
+			break;
+		case AUTHOR_NAME_FIELD:
+			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
+			break;
+		case AUTHOR_INITIALS_FIELD:
+			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
+			break;
+		case CHAPTER_FIELD:
+			newfield=nextFieldSelection.replaceWithSimpleField(fieldType);
+			break;
+		case SIMPLE_VARIABLE_FIELD:
+			VariableField SimpleVariableField = (VariableField)orgField;
+			String simplefieldname = SimpleVariableField.getVariableName();
+			VariableField simplefield=Fields.createSimpleVariableField(document, simplefieldname);
+			nextFieldSelection.replaceWithVariableField(simplefield);
+			newfield=simplefield;
+			break;
+		case USER_VARIABLE_FIELD:
+			VariableField userVariableField = (VariableField)orgField;
+			TextUserFieldDeclElement textUserFieldDeclElement =(TextUserFieldDeclElement) userVariableField.getOdfElement();
+			String fieldname = userVariableField.getVariableName();
+			String value=textUserFieldDeclElement.getOfficeStringValueAttribute();
+			VariableField variableField=Fields.createUserVariableField(document, fieldname,value);
+			nextFieldSelection.replaceWithVariableField(variableField);
+			newfield=variableField;
+			break;
+		case CONDITION_FIELD:
+			ConditionField conditionField = (ConditionField)orgField;
+			TextConditionalTextElement textConditionalTextElement =(TextConditionalTextElement) conditionField.getOdfElement();
+			String StringValueIfFalse=textConditionalTextElement.getTextStringValueIfFalseAttribute();
+			String StringValueIfTrue=textConditionalTextElement.getTextStringValueIfTrueAttribute();
+			String StringCondition=textConditionalTextElement.getTextConditionAttribute();
+			boolean CurrentValue=textConditionalTextElement.getTextCurrentValueAttribute();
+			ConditionField newdConditionField = nextFieldSelection.replaceWithConditionField(StringCondition, StringValueIfTrue, StringValueIfFalse);
+			TextConditionalTextElement newTextConditionalTextElement=(TextConditionalTextElement)newdConditionField.getOdfElement();
+			newTextConditionalTextElement.setTextCurrentValueAttribute(CurrentValue);
+			newfield=newdConditionField;
+			break;
+		case HIDDEN_TEXT_FIELD:
+			ConditionField conditionFieldHIDDEN = (ConditionField)orgField;
+			TextConditionalTextElement textConditionalTextElementHIDDEN =(TextConditionalTextElement) conditionFieldHIDDEN.getOdfElement();
+			String StringValueIfFalseHIDDEN=textConditionalTextElementHIDDEN.getTextStringValueIfFalseAttribute();
+			String StringConditionHIDDEN=textConditionalTextElementHIDDEN.getTextConditionAttribute();
+			boolean CurrentValueHIDDEN=textConditionalTextElementHIDDEN.getTextCurrentValueAttribute();
+			ConditionField newdConditionFieldHIDDEN = nextFieldSelection.replaceWithHiddenTextField(StringConditionHIDDEN, StringValueIfFalseHIDDEN);
+			TextConditionalTextElement newTextConditionalTextElementHIDDEN=(TextConditionalTextElement)newdConditionFieldHIDDEN.getOdfElement();
+			newTextConditionalTextElementHIDDEN.setTextCurrentValueAttribute(CurrentValueHIDDEN);
+			newfield=newdConditionFieldHIDDEN;
+			break;
+		case REFERENCE_FIELD:
+		default: throw new IllegalArgumentException("Simple Java API for ODF doesn't support this type now.");
+		}
+		return newfield;
+	}
+
+	/**
+	 * Replace the content with a paragraph, the paragraph can be in the same TextDocument or in a different Document.
+	 *
+	 * @param newParagraph
+	 *            the reference paragraph to replace.
+     * @throws InvalidNavigationException
+	 *             if the selection is unavailable.
+	 * @return the replaced Paragraph.
+	 */
+	public Paragraph replaceWith(Paragraph newParagraph) throws InvalidNavigationException {
+		if (validate() == false) {
+			throw new InvalidNavigationException("No matched string at this position");
+		}
+		ParagraphSelection nextParagraphSelection=new ParagraphSelection(this);
+		return nextParagraphSelection.replaceWithParagraph(newParagraph);
+	}
+	/**
+	 * Replace the content with a TextDocument with Styles.
+	 * Note: You need cache the TextNavigation.nextSelection item because after
+	 * you replace currtenTextSelection with TextDocument, TextNavigation.nextSelection will search from the inserted Content,
+	 * it will make you into a loop if the Search keyword also can be found in the new inserted Content.
+	 * </p>
+	 * The right way to use this replaceWithTextDocument(TextDocument textDocument) method should like this:
+	 * <Code>
+	 * <p>	search = new TextNavigation("SIMPLE", doc);    </p>
+	 * <p>	TextSelection currtenTextSelection,nextTextSelection=null;</p>
+	 * <p>		while (search.hasNext()) {</p>
+	 * <p>			if(nextTextSelection!=null){</p>
+	 * <p>				currtenTextSelection=nextTextSelection;</p>
+	 * <p>			}else {</p>
+	 * <p>			 	currtenTextSelection = (TextSelection) search.nextSelection();</p>
+	 * <p>			}</p>
+	 * <p>			nextTextSelection = (TextSelection) search.nextSelection();</p>
+	 * <p>			if(currtenTextSelection!=null){</p>
+	 * <p>				try {</p>
+	 * <p>					nextTextSelection.replaceWithTextDocument(sourcedoc);</p>
+	 * <p>				} catch (Exception e) {</p>
+	 * <p>					e.printStackTrace();</p>
+	 * <p>				}</p>
+	 * <p>			}</p>
+	 * <p>		}</p>
+	 * <p>		if(nextTextSelection!=null){</p>
+	 * <p>			try {</p>
+	 * <p>				nextTextSelection.replaceWithTextDocument(sourcedoc);</p>
+	 * <p>			} catch (Exception e) {</p>
+	 * <p>				e.printStackTrace();</p>
+	 * <p>			}</p>
+	 * <p>		}</p>
+	 * </Code>
+	 *
+	 * @param newTextDocument
+	 *            the reference TextDocument to replace.
+	 * @throws InvalidNavigationException
+	 */
+	public void replaceWith(TextDocument newTextDocument) throws InvalidNavigationException{
+		if (validate() == false) {
+			throw new InvalidNavigationException("No matched string at this position");
+		}
+		TextDocumentSelection nextTextDocumentSelection=new TextDocumentSelection(this);
+		try {
+			nextTextDocumentSelection.replaceWithTextDocument(newTextDocument);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+	/**
+	 * Create a span element for this text selection.
+	 *
+	 * @return the created text span element for this selection
+	 * @throws InvalidNavigationException
+	 *             if the selection is unavailable.
+	 * @since 0.5.5
+	 */
+	public TextSpanElement createSpanElement() throws InvalidNavigationException {
+		if (validate() == false) {
+			throw new InvalidNavigationException("No matched string at this position");
+		}
+		OdfElement parentElement = getContainerElement();
+		int leftLength = getText().length();
+		int index = mIndexInContainer;
+		delete(index, leftLength, parentElement);
+		OdfTextSpan textSpan = new OdfTextSpan((OdfFileDom) parentElement.getOwnerDocument());
+		textSpan.addContentWhitespace(getText());
+		mIsInserted = false;
+		insertOdfElement(textSpan, index, parentElement);
+		// optimize the parent element
+		optimize(parentElement);
+
+		return textSpan;
+	}
+
+	/**
+	 * Paste this selection just before a specific selection.
+	 *
+	 * @param positionItem
+	 *            a selection that is used to point out the position
+	 * @throws InvalidNavigationException
+	 *             if the selection is unavailable.
+	 */
+	@Override
+	public void pasteAtFrontOf(Selection positionItem) throws InvalidNavigationException {
+		if (validate() == false) {
+			throw new InvalidNavigationException("No matched string at this position");
+		}
+		int indexOfNew = 0;
+		OdfElement newElement = positionItem.getElement();
+		if (positionItem instanceof TextSelection) {
+			indexOfNew = ((TextSelection) positionItem).getIndex();
+			newElement = ((TextSelection) positionItem).getContainerElement();
+		}
+
+		OdfTextSpan textSpan = getSpan((OdfFileDom) positionItem.getElement().getOwnerDocument());
+		mIsInserted = false;
+		insertOdfElement(textSpan, indexOfNew, newElement);
+		adjustStyle(newElement, textSpan, null);
+		SelectionManager.refreshAfterPasteAtFrontOf(this, positionItem);
+	}
+
+	/**
+	 * Paste this selection just after a specific selection.
+	 *
+	 * @param positionItem
+	 *            a selection that is used to point out the position
+	 * @throws InvalidNavigationException
+	 *             if the selection is unavailable.
+	 */
+	@Override
+	public void pasteAtEndOf(Selection positionItem) throws InvalidNavigationException {
+		if (validate() == false) {
+			throw new InvalidNavigationException("No matched string at this position");
+		}
+		// TODO: think about and test if search item is a element selection
+		int indexOfNew = 0;
+		OdfElement newElement = positionItem.getElement();
+		if (positionItem instanceof TextSelection) {
+			indexOfNew = ((TextSelection) positionItem).getIndex() + ((TextSelection) positionItem).getText().length();
+			newElement = ((TextSelection) positionItem).getContainerElement();
+		}
+		OdfTextSpan textSpan = getSpan((OdfFileDom) positionItem.getElement().getOwnerDocument());
+		mIsInserted = false;
+		insertOdfElement(textSpan, indexOfNew, newElement);
+		adjustStyle(newElement, textSpan, null);
+		SelectionManager.refreshAfterPasteAtEndOf(this, positionItem);
+	}
+	public void setSelectionReplaced(boolean b) {
+		this.isSelectionReplaced = b;
+	}
+	public boolean isSelectionReplaced() {
+		return this.isSelectionReplaced;
+	}
+
+	/**
+	 * Add a hypertext reference to the selection.
+	 *
+	 * @param url
+	 *            the URL of this hypertext reference
+	 * @throws InvalidNavigationException
+	 *             if the selection is unavailable.
+	 */
+	public void addHref(URL url) throws InvalidNavigationException {
+		if (validate() == false) {
+			throw new InvalidNavigationException("No matched string at this position");
+		}
+		OdfElement parentElement = getContainerElement();
+		int leftLength = getText().length();
+		int index = mIndexInContainer;
+		addHref(index, leftLength, parentElement, url.toString());
+	}
+
+	/**
+	 * Add a comment to the selection.
+	 *
+	 * @param content
+	 *            the content of this comment.
+	 * @param creator
+	 *            the creator of this comment, if <code>creator</code> is null,
+	 *            the value of <code>System.getProperty("user.name")</code> will
+	 *            be used.
+	 * @throws InvalidNavigationException
+	 *            if the selection is unavailable.
+	 * @since 0.6.5
+	 */
+	public void addComment(String content, String creator) throws InvalidNavigationException {
+		if (validate() == false) {
+			throw new InvalidNavigationException("No matched string at this position");
+		}
+		// create annotation element
+		OdfElement parentElement = getContainerElement();
+		OdfFileDom dom = (OdfFileDom) parentElement.getOwnerDocument();
+		OfficeAnnotationElement annotationElement = dom.newOdfElement(OfficeAnnotationElement.class);
+		// set creator
+		DcCreatorElement dcCreatorElement = annotationElement.newDcCreatorElement();
+		if (creator == null) {
+			creator = System.getProperty("user.name");
+		}
+		dcCreatorElement.setTextContent(creator);
+		// set date
+		String dcDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").format(new Date());
+		DcDateElement dcDateElement = annotationElement.newDcDateElement();
+		dcDateElement.setTextContent(dcDate);
+		TextPElement notePElement = annotationElement.newTextPElement();
+		TextSpanElement noteSpanElement = notePElement.newTextSpanElement();
+		// set comment style
+		OdfOfficeAutomaticStyles styles = null;
+		if (dom instanceof OdfContentDom) {
+			styles = ((OdfContentDom) dom).getAutomaticStyles();
+		} else if (dom instanceof OdfStylesDom) {
+			styles = ((OdfStylesDom) dom).getAutomaticStyles();
+		}
+		OdfStyle textStyle = styles.newStyle(OdfStyleFamily.Text);
+		StyleTextPropertiesElement styleTextPropertiesElement = textStyle.newStyleTextPropertiesElement(null);
+		styleTextPropertiesElement.setStyleFontNameAttribute("Tahoma");
+		styleTextPropertiesElement.setFoFontSizeAttribute("10pt");
+		styleTextPropertiesElement.setStyleFontNameAsianAttribute("Lucida Sans Unicode");
+		styleTextPropertiesElement.setStyleFontSizeAsianAttribute("12pt");
+		noteSpanElement.setStyleName(textStyle.getStyleNameAttribute());
+		// set comment content
+		noteSpanElement.setTextContent(content);
+		// insert comment to its position
+		insertOdfElement(annotationElement, mIndexInContainer, parentElement);
+		// three text length plus two '\r'
+		int offset = content.length() + 1 + dcDate.length() + 1 + creator.length();
+		SelectionManager.refresh(getContainerElement(), offset, getIndex());
+	}
+
+	/**
+	 * return a String Object representing this selection value the text content
+	 * of the selection, start index in the container element and the text
+	 * content of the container element will be provided.
+	 *
+	 * @return a String representation of the value of this
+	 *         <code>TextSelection</code>
+	 */
+	@Override
+	public String toString() {
+		return "[" + mMatchedText + "] started from " + mIndexInContainer + " in paragraph:"
+				+ TextExtractor.getText(getContainerElement());
+	}
+
+	@Override
+	protected void refreshAfterFrontalDelete(Selection deleteItem) {
+		if (deleteItem instanceof TextSelection) {
+			mIndexInContainer -= ((TextSelection) deleteItem).getText().length();
+		}
+	}
+
+	@Override
+	protected void refreshAfterFrontalInsert(Selection pasteItem) {
+		if (pasteItem instanceof TextSelection) {
+			mIndexInContainer += ((TextSelection) pasteItem).getText().length();
+		}
+	}
+
+	@Override
+	protected void refresh(int offset) {
+		mIndexInContainer += offset;
+		if (mIndexInContainer < 0) {
+			mIndexInContainer = 0;
+		}
+	}
+
+	void cleanBreakProperty(Paragraph paragraph) {
+		TextNavigation search = this.getTextNavigation();
+		if (search == null)
+			throw new IllegalStateException("Navigation is null");
+		OdfStyleBase styleElement = paragraph.getStyleHandler()
+				.getStyleElementForRead();
+		String name = styleElement.getAttribute("style:name");
+		String newName = null;
+		OdfElement modifiedStyleElement = search
+				.getModifiedStyleElement(styleElement);
+		if (modifiedStyleElement == null) {
+			modifiedStyleElement = (OdfElement) styleElement.cloneNode(true);
+			search.addModifiedStyleElement(styleElement, modifiedStyleElement);
+			NodeList paragraphProperties = modifiedStyleElement
+					.getElementsByTagName("style:paragraph-properties");
+			if (paragraphProperties != null
+					&& paragraphProperties.getLength() > 0) {
+				StyleParagraphPropertiesElement property = (StyleParagraphPropertiesElement) paragraphProperties
+						.item(0);
+				property.removeAttribute("fo:break-before");
+				property.removeAttribute("fo:break-after");
+				property.removeAttribute("style:page-number");
+			}
+			modifiedStyleElement.removeAttribute("style:master-page-name");
+			newName = name + "-" + makeUniqueName();
+			NamedNodeMap attributes = modifiedStyleElement.getAttributes();
+			if (attributes != null) {
+				for (int i = 0; i < attributes.getLength(); i++) {
+					Node item = attributes.item(i);
+					String value = item.getNodeValue();
+					if (name.equals(value)) {
+						item.setNodeValue(newName);
+						break;
+					}
+				}
+			}
+			styleElement.getParentNode().appendChild(modifiedStyleElement);
+		} else {
+			newName = modifiedStyleElement.getAttribute("style:name");
+		}
+		NamedNodeMap attributes = paragraph.getOdfElement().getAttributes();
+		if (attributes != null) {
+			for (int i = 0; i < attributes.getLength(); i++) {
+				Node item = attributes.item(i);
+				String value = item.getNodeValue();
+				if (name.equals(value)) {
+					item.setNodeValue(newName);
+					break;
+				}
+			}
+		}
+		this.getTextNavigation().setHandlePageBreak(true);
+	}
+	String makeUniqueName() {
+		return String.format("p%06x", (int) (Math.random() * 0xffffff));
+	}
+	/*
+	 * Return a new span that cover this selection and keep the original style
+	 * of this <code>Selection</code>.
+	 */
+	private OdfTextSpan getSpan(OdfFileDom ownerDoc) {
+
+		OdfElement parentElement = getContainerElement();
+		if (parentElement != null) {
+			OdfElement copyParentNode = (OdfElement) parentElement.cloneNode(true);
+			if (ownerDoc != parentElement.getOwnerDocument()) {
+				copyParentNode = (OdfElement) ownerDoc.adoptNode(copyParentNode);
+			}
+			OdfTextSpan textSpan = new OdfTextSpan(ownerDoc);
+			int sIndex = mIndexInContainer;
+			int eIndex = sIndex + mMatchedText.length();
+			// delete the content except the selection string
+			// delete from the end to start, so that the postion will not be
+			// impact by delete action
+			delete(eIndex, TextExtractor.getText(copyParentNode).length() - eIndex, copyParentNode);
+			delete(0, sIndex, copyParentNode);
+			optimize(copyParentNode);
+			Node childNode = copyParentNode.getFirstChild();
+			while (childNode != null) {
+				textSpan.appendChild(childNode.cloneNode(true));
+				childNode = childNode.getNextSibling();
+			}
+			// apply text style for the textSpan
+			if (copyParentNode instanceof OdfStylableElement) {
+				applyTextStyleProperties(getTextStylePropertiesDeep((OdfStylableElement) copyParentNode), textSpan);
+			}
+			return textSpan;
+		}
+		return null;
+	}
+
+	/*
+	 * Optimize the text element by deleting the empty text node.
+	 */
+	private void optimize(Node pNode) {
+		// check if the text:a can be optimized
+		Node node = pNode.getFirstChild();
+		while (node != null) {
+			Node nextNode = node.getNextSibling();
+			// if ((node.getNodeType() == Node.ELEMENT_NODE) &&
+			// (node.getPrefix().equals("text"))) {
+			if (node instanceof OdfTextSpan) {
+				if (TextExtractor.getText((OdfTextSpan) node).length() == 0) {
+					node.getParentNode().removeChild(node);
+				} else {
+					optimize(node);
+				}
+			}
+			node = nextNode;
+		}
+	}
+
+	/*
+	 * Apply the <code>styleMap</code> to the <code>toElement</code> reserve the
+	 * style property of toElement, if it is also exist in <code>styleMap</code>
+	 */
+	private void applyTextStyleProperties(Map<OdfStyleProperty, String> styleMap, OdfStylableElement toElement) {
+		if (styleMap != null) {
+			// preserve the style property of toElement if it is also exist in
+			// styleMap
+			OdfStyle resultStyleElement = toElement.getAutomaticStyles().newStyle(OdfStyleFamily.Text);
+			for (Map.Entry<OdfStyleProperty, String> entry : styleMap.entrySet()) {
+				if (toElement.hasProperty(entry.getKey())) {
+					resultStyleElement.setProperty(entry.getKey(), toElement.getProperty(entry.getKey()));
+				} else {
+					resultStyleElement.setProperty(entry.getKey(), entry.getValue());
+				}
+			}
+			toElement.setStyleName(resultStyleElement.getStyleNameAttribute());
+		}
+	}
+
+	/*
+	 * Insert <code>odfElement</code>, span or annotation, into the from index of <code>pNode<code>.
+	 */
+	private void insertOdfElement(OdfElement odfElement, int fromIndex, Node pNode) {
+		if (fromIndex < 0) {
+			fromIndex = 0;
+		}
+		if (fromIndex == 0 && mIsInserted) {
+			return;
+		}
+		int nodeLength = 0;
+		Node node = pNode.getFirstChild();
+		while (node != null) {
+			if (fromIndex <= 0 && mIsInserted) {
+				return;
+			}
+			if (node.getNodeType() == Node.TEXT_NODE) {
+				nodeLength = node.getNodeValue().length();
+				if ((fromIndex != 0) && (nodeLength < fromIndex)) {
+					fromIndex -= nodeLength;
+				} else {
+					// insert result after node, and insert an new text node
+					// after the result node
+					String value = node.getNodeValue();
+					StringBuffer buffer = new StringBuffer();
+					buffer.append(value.substring(0, fromIndex));
+					// insert the text span in appropriate position
+					node.setNodeValue(buffer.toString());
+					Node nextNode = node.getNextSibling();
+					Node parNode = node.getParentNode();
+					Node newNode = node.cloneNode(true);
+					newNode.setNodeValue(value.substring(fromIndex, value.length()));
+					if (nextNode != null) {
+						parNode.insertBefore(odfElement, nextNode);
+						parNode.insertBefore(newNode, nextNode);
+					} else {
+						parNode.appendChild(odfElement);
+						parNode.appendChild(newNode);
+					}
+					mIsInserted = true;
+					return;
+				}
+			} else if (node.getNodeType() == Node.ELEMENT_NODE) {
+				// text:s
+				if (node.getLocalName().equals("s")) {
+					try {
+						nodeLength = Integer.parseInt(((Element) node).getAttributeNS(OdfDocumentNamespace.TEXT
+								.getUri(), "c"));
+					} catch (Exception e) {
+						nodeLength = 1;
+					}
+					fromIndex -= nodeLength;
+				} else if (node.getLocalName().equals("line-break")) {
+					nodeLength = 1;
+					fromIndex--;
+				} else if (node.getLocalName().equals("tab")) {
+					nodeLength = 1;
+					fromIndex--;
+				} else {
+					nodeLength = TextExtractor.getText((OdfElement) node).length();
+					insertOdfElement(odfElement, fromIndex, node);
+					fromIndex -= nodeLength;
+				}
+			}
+			node = node.getNextSibling();
+		}
+	}
+
+	/*
+	 * The <code>textSpan</code> must be the child element of
+	 * <code>parentNode</code> this method is used to keep the style of text
+	 * span when it has been insert into the <code>parentNode</code> if we don't
+	 * deal with the style, the inserted span will also have the style of
+	 * <code>parentNode</code>.
+	 */
+	private void adjustStyle(Node parentNode, OdfTextSpan textSpan, Map<OdfStyleProperty, String> styleMap) {
+		if (parentNode instanceof OdfStylableElement) {
+			OdfStylableElement pStyleNode = (OdfStylableElement) parentNode;
+			if (styleMap == null) {
+				styleMap = getTextStylePropertiesDeep(pStyleNode);
+			}
+			Node node = parentNode.getFirstChild();
+			while (node != null) {
+				if (node.getNodeType() == Node.TEXT_NODE) {
+					if (node.getTextContent().length() > 0) {
+						Node nextNode = node.getNextSibling();
+						OdfTextSpan span = new OdfTextSpan((OdfFileDom) node.getOwnerDocument());
+						span.appendChild(node);
+						if (nextNode != null) {
+							parentNode.insertBefore(span, nextNode);
+						} else {
+							parentNode.appendChild(span);
+						}
+						node = span;
+						applyTextStyleProperties(styleMap, (OdfStylableElement) node);
+					}
+				} else if ((node instanceof OdfStylableElement)) {
+					if (!node.equals(textSpan)) {
+						Map<OdfStyleProperty, String> styles = getTextStylePropertiesDeep(pStyleNode);
+						Map<OdfStyleProperty, String> styles1 = getTextStylePropertiesDeep((OdfStylableElement) node);
+						if (styles == null) {
+							styles = styles1;
+						} else if (styles1 != null) {
+							styles.putAll(styles1);
+						}
+						int comp = node.compareDocumentPosition(textSpan);
+						// if node contains textSpan, then recurse the node
+						if ((comp & Node.DOCUMENT_POSITION_CONTAINED_BY) > 0) {
+							adjustStyle(node, textSpan, styles);
+						} else {
+							applyTextStyleProperties(styles, (OdfStylableElement) node);
+						}
+					}
+				}
+				node = node.getNextSibling();
+			}
+			// change the parentNode to default style
+			// here we don't know the default style name, so here just
+			// remove the text:style-name attribute
+			pStyleNode.removeAttributeNS(OdfDocumentNamespace.TEXT.getUri(), "style-name");
+		}
+	}
+
+	/*
+	 * Delete the <code>pNode<code> from the <code>fromIndex</code> text, and
+	 * delete <code>leftLength</code> text.
+	 */
+	private void delete(int fromIndex, int leftLength, Node pNode) {
+		if ((fromIndex == 0) && (leftLength == 0)) {
+			return;
+		}
+		int nodeLength = 0;
+		Node node = pNode.getFirstChild();
+		while (node != null) {
+			if ((fromIndex == 0) && (leftLength == 0)) {
+				return;
+			}
+			if (node.getNodeType() == Node.TEXT_NODE) {
+				nodeLength = node.getNodeValue().length();
+			} else if (node.getNodeType() == Node.ELEMENT_NODE) {
+				// text:s
+				if (node.getLocalName().equals("s")) {
+					try {
+						nodeLength = Integer.parseInt(((Element) node).getAttributeNS(OdfDocumentNamespace.TEXT
+								.getUri(), "c"));
+					} catch (Exception e) {
+						nodeLength = 1;
+					}
+				} else if (node.getLocalName().equals("line-break")) {
+					nodeLength = 1;
+				} else if (node.getLocalName().equals("tab")) {
+					nodeLength = 1;
+				} else {
+					nodeLength = TextExtractor.getText((OdfElement) node).length();
+				}
+			}
+			if (nodeLength <= fromIndex) {
+				fromIndex -= nodeLength;
+			} else {
+				// the start index is in this node
+				if (node.getNodeType() == Node.TEXT_NODE) {
+					String value = node.getNodeValue();
+					StringBuffer buffer = new StringBuffer();
+					buffer.append(value.substring(0, fromIndex));
+					int endLength = fromIndex + leftLength;
+					int nextLength = value.length() - endLength;
+					fromIndex = 0;
+					if (nextLength >= 0) {
+						// delete the result
+						buffer.append(value.substring(endLength, value.length()));
+						leftLength = 0;
+					} else {
+						leftLength = endLength - value.length();
+					}
+					node.setNodeValue(buffer.toString());
+
+				} else if (node.getNodeType() == Node.ELEMENT_NODE) {
+					// if text:s?????????
+					// text:s
+					if (node.getLocalName().equals("s")) {
+						// delete space
+						((TextSElement) node).setTextCAttribute(new Integer(nodeLength - fromIndex));
+						leftLength = leftLength - (nodeLength - fromIndex);
+						fromIndex = 0;
+					} else if (node.getLocalName().equals("line-break") || node.getLocalName().equals("tab")) {
+						fromIndex = 0;
+						leftLength--;
+						Node nodeMerker = node.getNextSibling();
+						pNode.removeChild(node);
+						node = nodeMerker;
+						continue;
+					} else {
+						delete(fromIndex, leftLength, node);
+						int length = (fromIndex + leftLength) - nodeLength;
+						leftLength = length > 0 ? length : 0;
+						fromIndex = 0;
+					}
+				}
+			}
+			node = node.getNextSibling();
+		}
+	}
+
+	/*
+	 * Add href for a range text of <code>pNode<code> from the
+	 * <code>fromIndex</code> text, and the href will cover
+	 * <code>leftLength</code> text.
+	 */
+	private void addHref(int fromIndex, int leftLength, Node pNode, String href) {
+		if ((fromIndex == 0) && (leftLength == 0)) {
+			return;
+		}
+		int nodeLength = 0;
+		Node node = pNode.getFirstChild();
+
+		while (node != null) {
+			if ((fromIndex == 0) && (leftLength == 0)) {
+				return;
+			}
+			if (node.getNodeType() == Node.TEXT_NODE) {
+				nodeLength = node.getNodeValue().length();
+			} else if (node.getNodeType() == Node.ELEMENT_NODE) {
+				// text:s
+				if (node.getLocalName().equals("s")) {
+					try {

[... 275 lines stripped ...]


Mime
View raw message