org.odftoolkit.odfdom.incubator.search.TextSelection Maven / Gradle / Ivy
Show all versions of odfdom-java Show documentation
/**
* **********************************************************************
*
* 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.odfdom.incubator.search;
import java.net.URL;
import java.util.Map;
import java.util.TreeMap;
import org.odftoolkit.odfdom.doc.OdfDocument;
import org.odftoolkit.odfdom.dom.OdfDocumentNamespace;
import org.odftoolkit.odfdom.dom.element.OdfStylableElement;
import org.odftoolkit.odfdom.dom.element.OdfStyleBase;
import org.odftoolkit.odfdom.dom.element.text.TextAElement;
import org.odftoolkit.odfdom.dom.element.text.TextSElement;
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.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.incubator.doc.text.OdfWhitespaceProcessor;
import org.odftoolkit.odfdom.pkg.OdfElement;
import org.odftoolkit.odfdom.pkg.OdfFileDom;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* A TextSelection can describe a sub element in a mParagraph element or a mHeading element. it is
* recognized by the container element(which type should be OdfTextParagraph or OdfTextHeadingt),
* the start index of the text content of the container element and the text content of this
* selection.
*/
public class TextSelection extends Selection {
private String mMatchedText;
private OdfTextParagraph mParagraph;
private OdfTextHeading mHeading;
private int mIndexInContainer;
private boolean mIsInserted;
private SelectionManager mSelectionManager;
/**
* Constructor of TextSelection
*
* @param text the text content of this TextSelection
* @param containerElement the mParagraph element or mHeading element that contain this
* TextSelection
* @param index the start index of the text content of the container element
*/
TextSelection(
String text, OdfElement containerElement, int index, SelectionManager selectionManager) {
mMatchedText = text;
mSelectionManager = selectionManager;
if (containerElement instanceof OdfTextParagraph) {
mParagraph = (OdfTextParagraph) containerElement;
} else if (containerElement instanceof OdfTextHeading) {
mHeading = (OdfTextHeading) containerElement;
}
mIndexInContainer = index;
}
/**
* Get the mParagraph element or mHeading element that contain this TextSelection
*
* @return OdfElement the container element
*/
@Override
public OdfElement getElement() {
return getContainerElement();
}
/**
* Get the mParagraph element or mHeading element that contain 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 TextSelection
*
* @return text the text content
*/
public String getText() {
return mMatchedText;
}
/*
* Validate if the selection is still available.
* @return true if the selection is available; false if the selection is not available.
*/
private boolean validate() {
if (getContainerElement() == null) {
return false;
}
OdfElement container = getContainerElement();
if (container == null) {
return false;
}
OdfWhitespaceProcessor textProcessor = new OdfWhitespaceProcessor();
String content = textProcessor.getText(container);
if (content.indexOf(mMatchedText, mIndexInContainer) == mIndexInContainer) {
return true;
} else {
return false;
}
}
/**
* 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);
mSelectionManager.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);
}
/*
* append specified style for a range text of pNode
* from 'fromindex' and cover 'leftLength'
*/
private void appendStyle(int fromindex, int leftLength, Node pNode, OdfStyleBase style) {
if ((fromindex == 0) && (leftLength == 0)) {
return;
}
int nodeLength = 0;
Node node = pNode.getFirstChild();
OdfWhitespaceProcessor textProcessor = new OdfWhitespaceProcessor();
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) {
if (node.getLocalName().equals("s")) // text: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 = textProcessor.getText((OdfElement) node).length();
}
}
if (nodeLength <= fromindex) {
fromindex -= nodeLength;
} else {
// the start index is in this node
if (node.getNodeType() == Node.TEXT_NODE
|| (node.getNodeType() == Node.ELEMENT_NODE && node.getLocalName().equals("s"))) {
int endLength = fromindex + leftLength;
int nextLength = nodeLength - endLength;
String value = null;
if (node.getNodeType() == Node.TEXT_NODE) {
value = node.getNodeValue();
node.setNodeValue(value.substring(0, fromindex));
} else {
((TextSElement) node).setTextCAttribute(fromindex);
}
Node nextNode = node.getNextSibling();
Node parNode = node.getParentNode();
// init text:span
OdfTextSpan textSpan = new OdfTextSpan((OdfFileDom) node.getOwnerDocument());
Node newNode = null;
if (nextLength >= 0) {
newNode = node.cloneNode(true);
if (node.getNodeType() == Node.TEXT_NODE) {
textSpan.setTextContent(value.substring(fromindex, endLength));
newNode.setNodeValue(value.substring(endLength, nodeLength));
} else {
Node newS = node.cloneNode(true);
((TextSElement) newS).setTextCAttribute(endLength - fromindex);
textSpan.appendChild(newS);
((TextSElement) newNode).setTextCAttribute(nodeLength - endLength);
}
leftLength = 0;
} else {
if (node.getNodeType() == Node.TEXT_NODE) {
textSpan.setTextContent(value.substring(fromindex, nodeLength));
} else {
Node newS = node.cloneNode(true);
((TextSElement) newS).setTextCAttribute(nodeLength - fromindex);
textSpan.appendChild(newS);
}
leftLength = endLength - nodeLength;
}
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);
}
}
if (fromindex == 0) // node only contains the prefix, is it empty?
{
parNode.removeChild(node);
}
fromindex = 0;
if (nextNode != null) {
node = nextNode;
} else {
node = textSpan;
}
} else if (node.getNodeType() == Node.ELEMENT_NODE) {
assert (!node.getLocalName().equals("s")); // was handled above
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();
}
}
/**
* 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");
return;
}
OdfElement parentElement = getContainerElement();
int leftLength = getText().length();
int index = mIndexInContainer;
delete(index, leftLength, parentElement);
OdfTextSpan textSpan = new OdfTextSpan((OdfFileDom) parentElement.getOwnerDocument());
textSpan.addContentWhitespace(newText);
/*if (startElement instanceof OdfStyleBase)
textSpan.setProperties(((OdfStyleBase) startElement)
.getStyleProperties());*/
mIsInserted = false;
insertSpan(textSpan, index, parentElement);
// optimize the parent element
optimize(parentElement);
int offset = newText.length() - leftLength;
mSelectionManager.refresh(this.getContainerElement(), offset, index + getText().length());
mMatchedText = newText;
}
/**
* 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;
insertSpan(textSpan, indexOfNew, newElement);
adjustStyle(newElement, textSpan, null);
mSelectionManager.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");
}
int indexOfNew = 0; // TODO: think about and test if searchitem is a element selection
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;
insertSpan(textSpan, indexOfNew, newElement);
adjustStyle(newElement, textSpan, null);
mSelectionManager.refreshAfterPasteAtEndOf(this, positionItem);
}
/**
* Add a hypertext reference to the selection
*
* @param url the url of the 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 href for a range text of pNode from the 'fromindex' text, and the href will cover
* 'leftLength' 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();
OdfWhitespaceProcessor textProcessor = new OdfWhitespaceProcessor();
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) {
if (node.getLocalName().equals("s")) // text: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 = textProcessor.getText((OdfElement) node).length();
}
}
if (nodeLength <= fromindex) {
fromindex -= nodeLength;
} else {
// the start index is in this node
if (node.getNodeType() == Node.TEXT_NODE
|| (node.getNodeType() == Node.ELEMENT_NODE && node.getLocalName().equals("s"))) {
int endLength = fromindex + leftLength;
int nextLength = nodeLength - endLength;
String value = null;
if (node.getNodeType() == Node.TEXT_NODE) {
value = node.getNodeValue();
node.setNodeValue(value.substring(0, fromindex));
} else {
((TextSElement) node).setTextCAttribute(fromindex);
}
Node nextNode = node.getNextSibling();
Node parNode = node.getParentNode();
// init text:a
TextAElement textLink = new TextAElement((OdfFileDom) node.getOwnerDocument());
Node newNode = null;
if (nextLength >= 0) {
newNode = node.cloneNode(true);
if (node.getNodeType() == Node.TEXT_NODE) {
textLink.setTextContent(value.substring(fromindex, endLength));
newNode.setNodeValue(value.substring(endLength, nodeLength));
} else {
Node newS = node.cloneNode(true);
((TextSElement) newS).setTextCAttribute(endLength - fromindex);
textLink.appendChild(newS);
((TextSElement) newNode).setTextCAttribute(nodeLength - endLength);
}
leftLength = 0;
} else {
if (node.getNodeType() == Node.TEXT_NODE) {
textLink.setTextContent(value.substring(fromindex, value.length()));
} else {
Node newS = node.cloneNode(true);
((TextSElement) newS).setTextCAttribute(nodeLength - fromindex);
textLink.appendChild(newS);
}
leftLength = endLength - nodeLength;
}
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);
}
}
if (fromindex == 0) // node only contains the prefix, is it empty?
{
parNode.removeChild(node);
}
fromindex = 0;
if (nextNode != null) {
node = nextNode;
} else {
node = textLink;
}
} else if (node.getNodeType() == Node.ELEMENT_NODE) {
assert (!node.getLocalName().equals("s")); // was handled above
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();
}
}
/*
* delete the pNode from the fromindex text, and delete leftLength text
*/
private void delete(int fromindex, int leftLength, Node pNode) {
if ((fromindex == 0) && (leftLength == 0)) {
return;
}
int nodeLength = 0;
Node node = pNode.getFirstChild();
OdfWhitespaceProcessor textProcessor = new OdfWhitespaceProcessor();
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) {
if (node.getLocalName().equals("s")) // text: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 = textProcessor.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?????????
if (node.getLocalName().equals("s")) // text:s
{
// delete space
if (0 < fromindex || leftLength < nodeLength) {
final int deleted = Math.min(leftLength, nodeLength - fromindex);
((TextSElement) node).setTextCAttribute(new Integer(nodeLength - deleted));
leftLength = leftLength - deleted;
} else {
Node nodeMerker = node.getNextSibling();
pNode.removeChild(node);
node = nodeMerker;
leftLength = leftLength - nodeLength;
}
fromindex = 0;
continue;
} 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();
}
}
@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;
}
/**
* 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 TextSelection
*/
@Override
public String toString() {
OdfWhitespaceProcessor textProcessor = new OdfWhitespaceProcessor();
return "["
+ mMatchedText
+ "] started from "
+ mIndexInContainer
+ " in paragraph:"
+ textProcessor.getText(getContainerElement());
}
// return a new span that cover this selection
// and keep the original style of this selection
private OdfTextSpan getSpan(OdfFileDom ownerDoc) {
OdfElement parentElement = getContainerElement();
if (parentElement != null) {
Node copyParentNode = parentElement.cloneNode(true);
if (ownerDoc != parentElement.getOwnerDocument()) {
copyParentNode = 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
OdfWhitespaceProcessor textProcessor = new OdfWhitespaceProcessor();
delete(eIndex, textProcessor.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
*
* @param element
*/
private void optimize(Node pNode) {
// check if the text:a can be optimized
OdfWhitespaceProcessor textProcess = new OdfWhitespaceProcessor();
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 (textProcess.getText(node).length() == 0) {
node.getParentNode().removeChild(node);
} else {
optimize(node);
}
}
node = nextNode;
}
}
/*
* apply the styleMap to the toElement
* reserve the style property of toElement if it is also exist in styleMap
*/
private void applyTextStyleProperties(
Map styleMap, OdfStylableElement toElement) {
if (styleMap != null) {
// preserve the style property of toElement if it is also exist in styleMap
OdfStyle resultStyleElement =
toElement.getOrCreateAutomaticStyles().newStyle(OdfStyleFamily.Text);
for (Map.Entry 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 textSpan into the from index of pNode
*/
private void insertSpan(OdfTextSpan textSpan, int fromindex, Node pNode) {
if (fromindex < 0) {
fromindex = 0;
}
if (fromindex == 0 && mIsInserted) {
return;
}
OdfWhitespaceProcessor textProcessor = new OdfWhitespaceProcessor();
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(textSpan, nextNode);
parNode.insertBefore(newNode, nextNode);
} else {
parNode.appendChild(textSpan);
parNode.appendChild(newNode);
}
mIsInserted = true;
return;
}
} else if (node.getNodeType() == Node.ELEMENT_NODE) {
if (node.getLocalName().equals("s")) // text: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 if (node.getLocalName().equals("span")) {
// nodeLength = 1;
// fromindex--;
} else {
nodeLength = textProcessor.getText(node).length();
insertSpan(textSpan, fromindex, node);
fromindex -= nodeLength;
}
}
node = node.getNextSibling();
}
}
/*
* the textSpan must be the child element of parentNode
* this method is used to keep the style of text span when it has been insert into the parentNode
* if we don't deal with the style, the inserted span will also have the style of parentNode
*
*/
private void adjustStyle(
Node parentNode, OdfTextSpan textSpan, Map 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 styles = getTextStylePropertiesDeep(pStyleNode);
Map 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");
}
}
/*
* get a map containing text properties of the specified styleable element.
* @return a map of text properties.
*/
private Map getTextStyleProperties(OdfStylableElement element) {
String styleName = element.getStyleName();
OdfStyleBase styleElement =
element.getOrCreateAutomaticStyles().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 =
((OdfDocument) ((OdfFileDom) styleElement.getOwnerDocument()).getDocument())
.getDocumentStyles()
.getDefaultStyle(styleElement.getFamily());
}
TreeMap result = new TreeMap();
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 element.
* The map will also include any properties set by parent styles
* @return a map of text properties.
*
*/
private Map getTextStylePropertiesDeep(OdfStylableElement element) {
String styleName = element.getStyleName();
OdfStyleBase styleElement =
element.getOrCreateAutomaticStyles().getStyle(styleName, element.getStyleFamily());
if (styleElement == null) {
styleElement = element.getDocumentStyle();
}
TreeMap result = new TreeMap();
while (styleElement != null) {
// check if it is the style:defaut-style
if ((styleElement.getPropertiesElement(OdfStylePropertiesSet.ParagraphProperties) == null)
&& (styleElement.getPropertiesElement(OdfStylePropertiesSet.TextProperties) == null)) {
styleElement =
((OdfDocument) ((OdfFileDom) styleElement.getOwnerDocument()).getDocument())
.getDocumentStyles()
.getDefaultStyle(styleElement.getFamily());
}
OdfStyleFamily family = OdfStyleFamily.Text;
if (family != null && styleElement != null) {
for (OdfStyleProperty property : family.getProperties()) {
if (styleElement.hasProperty(property)) {
result.put(property, styleElement.getProperty(property));
}
}
}
if (styleElement != null) {
styleElement = styleElement.getParentStyle();
}
}
return result;
}
}