TextStyleNavigation.java
/**
* **********************************************************************
*
* <p>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
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* <p>**********************************************************************
*/
package org.odftoolkit.odfdom.incubator.search;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.odftoolkit.odfdom.doc.OdfTextDocument;
import org.odftoolkit.odfdom.dom.OdfDocumentNamespace;
import org.odftoolkit.odfdom.dom.element.OdfStylableElement;
import org.odftoolkit.odfdom.dom.style.OdfStyleFamily;
import org.odftoolkit.odfdom.dom.style.props.OdfStyleProperty;
import org.odftoolkit.odfdom.incubator.doc.style.OdfDefaultStyle;
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.pkg.OdfElement;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* A derived Navigation class used for navigate the mText content it is used to search the document
* and find the matched style properties and would return TextSelection instance
*/
public class TextStyleNavigation extends Navigation {
private OdfTextDocument mTextDocument;
private TextSelection mCurrentSelectedItem;
private int mCurrentIndex;
private Map<OdfStyleProperty, String> mProps;
private String mText;
private Node mPhNode;
private int mIndex;
private Node mNode;
/**
* Construct TextStyleNavigation with style properties condition and navigation scope
*
* @param props the matched style properties conditions
* @param doc the navigation search scope
*/
public TextStyleNavigation(Map<OdfStyleProperty, String> props, OdfTextDocument doc) {
mTextDocument = doc;
mCurrentSelectedItem = null;
this.mProps = props;
}
/*
* Find next TextSelection which match specified style
*/
private TextSelection findnext(TextSelection selected) {
OdfElement element = null;
if (selected == null) {
try {
mNode = getNextMatchElement((Node) mTextDocument.getContentRoot());
} catch (Exception ex) {
Logger.getLogger(TextStyleNavigation.class.getName())
.log(Level.SEVERE, ex.getMessage(), ex);
}
} else {
try {
mNode = getNextMatchElement(mNode);
} catch (Exception ex) {
Logger.getLogger(TextStyleNavigation.class.getName())
.log(Level.SEVERE, ex.getMessage(), ex);
}
}
if (mNode != null) {
element = (OdfElement) getPHElement(mNode);
TextSelection item = new TextSelection(mText, element, mCurrentIndex);
return item;
}
return null;
}
private Node getPHElement(Node node) {
// get paragraph or heading element
if (node instanceof OdfTextParagraph) {
mPhNode = node;
} else if (node instanceof OdfTextHeading) {
mPhNode = node;
} else {
getPHElement(node.getParentNode());
}
return mPhNode;
}
/* (non-Javadoc)
* get current TextSelection
* @see org.odftoolkit.odfdom.incubator.search.Navigation#getCurrentItem()
*/
@Override
public Selection getCurrentItem() {
Selection.SelectionManager.registerItem(mCurrentSelectedItem);
return mCurrentSelectedItem;
}
/* (non-Javadoc)
* check if has next TextSelection with satisfied style
* @see org.odftoolkit.odfdom.incubator.search.Navigation#hasNext()
*/
@Override
public boolean hasNext() {
mCurrentSelectedItem = findnext(mCurrentSelectedItem);
return (mCurrentSelectedItem != null);
}
/**
* check if the element has the specified style properties
*
* @param element navigate this element
* @return true if this element has the specified style properties false if not match
*/
@Override
public boolean match(Node element) {
boolean match = false;
if (element.getNodeType() == Node.TEXT_NODE && !element.getNodeValue().trim().equals("")) {
if (element.getParentNode() instanceof OdfStylableElement) {
OdfStylableElement parStyleElement = (OdfStylableElement) element.getParentNode();
String parStyleName = getStyleName(parStyleElement);
if (getMatchStyleNames().contains(parStyleName)) {
match = true;
mText = element.getNodeValue();
NodeList nodes = getPHElement(element.getParentNode()).getChildNodes();
mIndex = 0;
getIndex(nodes, element);
}
}
}
return match;
}
private void getIndex(NodeList nodes, Node element) {
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
if (node == element) {
mCurrentIndex = mIndex;
break;
} else {
if (node.getNodeType() == Node.TEXT_NODE) {
mIndex = mIndex + node.getNodeValue().length();
} else if (node.getNodeType() == Node.ELEMENT_NODE) {
if (node.getLocalName().equals("s")) // mText:s
{
try {
mIndex =
mIndex
+ Integer.parseInt(
((Element) node).getAttributeNS(OdfDocumentNamespace.TEXT.getUri(), "c"));
} catch (Exception e) {
mIndex++;
}
} else if (node.getLocalName().equals("line-break")) {
mIndex++;
} else if (node.getLocalName().equals("tab")) {
mIndex++;
} else {
getIndex(node.getChildNodes(), element);
}
}
}
}
}
private String getStyleName(OdfStylableElement element) {
String stylename = element.getStyleName();
if (stylename == null) {
if (element.getParentNode() instanceof OdfStylableElement) {
getStyleName((OdfStylableElement) element.getParentNode());
} else {
stylename = "defaultstyle";
}
}
return stylename;
}
private Set<String> getMatchStyleNames() {
Set<String> styleNames = new HashSet<String>();
String sname;
HashMap<String, OdfDefaultStyle> defaultStyles = new HashMap<String, OdfDefaultStyle>();
try {
NodeList defStyleList =
mTextDocument.getDocumentStyles().getElementsByTagName("style:default-style");
for (int i = 0; i < defStyleList.getLength(); i++) {
OdfDefaultStyle defStyle = (OdfDefaultStyle) defStyleList.item(i);
defaultStyles.put(defStyle.getFamilyName(), defStyle);
}
NodeList styleList = mTextDocument.getDocumentStyles().getElementsByTagName("style:style");
for (int i = 0; i < styleList.getLength(); i++) {
OdfStyle sStyle = (OdfStyle) styleList.item(i);
// get default properties and style properties
Map<OdfStyleProperty, String> map = sStyle.getStylePropertiesDeep();
// check if properties include all search properties and value equal
Iterator<OdfStyleProperty> pIter = mProps.keySet().iterator();
boolean isStyle = false;
while (pIter.hasNext()) {
isStyle = false;
OdfStyleProperty p = pIter.next();
if (map.containsKey(p)) {
if (map.get(p).equals(mProps.get(p))) {
isStyle = true;
} else {
break;
}
} else {
break;
}
}
// put all match style names
if (isStyle) {
sname = sStyle.getStyleNameAttribute();
// if(sname.contains("default"))sname="defaultstyle";
styleNames.add(sname);
}
}
// get all automatic styles
Iterator<OdfStyle> cStyles =
mTextDocument.getContentDom().getAutomaticStyles().getAllStyles().iterator();
while (cStyles.hasNext()) {
OdfStyle cStyle = cStyles.next();
// get default properties and style properties
Map<OdfStyleProperty, String> map = cStyle.getStylePropertiesDeep();
if (cStyle.getParentStyle() == null) {
if (cStyle.getFamilyName().equals("text")) {
if (defaultStyles.containsKey("text")) {
getTextDefaultProperties("text", defaultStyles, map);
} else {
getTextDefaultProperties("paragraph", defaultStyles, map);
}
}
}
// check if the search properties is in properties
Iterator<OdfStyleProperty> pIter = mProps.keySet().iterator();
boolean isStyle = false;
while (pIter.hasNext()) {
isStyle = false;
OdfStyleProperty p = pIter.next();
if (map.containsKey(p)) {
if (map.get(p).equals(mProps.get(p))) {
isStyle = true;
} else {
break;
}
} else {
break;
}
}
// put all match style names
if (isStyle) {
styleNames.add(cStyle.getStyleNameAttribute());
}
}
} catch (Exception e1) {
Logger.getLogger(TextStyleNavigation.class.getName()).log(Level.SEVERE, e1.getMessage(), e1);
}
return styleNames;
}
private void getTextDefaultProperties(
String familyName,
HashMap<String, OdfDefaultStyle> defaultStyles,
Map<OdfStyleProperty, String> map) {
OdfDefaultStyle defStyle = defaultStyles.get(familyName);
if (defStyle != null) {
OdfStyleFamily family = defStyle.getFamily();
if (family != null) {
for (OdfStyleProperty property : family.getProperties()) {
if (!map.containsKey(property) && defStyle.hasProperty(property)) {
map.put(property, defStyle.getProperty(property));
}
}
}
}
}
}