org.odftoolkit.simple.common.navigation.TextStyleNavigation Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of simple-odf Show documentation
Show all versions of simple-odf Show documentation
A simple API for easy manipulation of ODF documents.
The newest version!
/*
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.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.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.odftoolkit.simple.TextDocument;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* A derived Navigation
class used to navigate the text content,
* which can search the document and find matched style properties and return
* TextSelection
instance(s).
*/
public class TextStyleNavigation extends Navigation {
private TextDocument mTextDocument;
private TextSelection mNextSelectedItem;
private TextSelection mTempSelectedItem;
private int mCurrentIndex;
private Map 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 props, TextDocument doc) {
mTextDocument = doc;
mNextSelectedItem = null;
mTempSelectedItem = null;
this.mProps = props;
}
/**
* Check if has next TextSelection
with satisfied style.
*
* @see org.odftoolkit.simple.common.navigation.Navigation#hasNext()
*/
@Override
public boolean hasNext() {
mTempSelectedItem = findNext(mNextSelectedItem);
return (mTempSelectedItem != null);
}
/**
* Get next TextSelection
.
*
* @see org.odftoolkit.simple.common.navigation.Navigation#nextSelection()
*/
@Override
public Selection nextSelection() {
if(mTempSelectedItem !=null){
mNextSelectedItem = mTempSelectedItem;
mTempSelectedItem = null;
}else{
mNextSelectedItem = findNext(mNextSelectedItem);
}
if (mNextSelectedItem == null) {
return null;
} else {
Selection.SelectionManager.registerItem(mNextSelectedItem);
return mNextSelectedItem;
}
}
/**
* Check if the element has specified style properties, which are stated
* when the TextStyleNavigation
created.
*
* @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;
}
/*
* Find next TextSelection
which match specified style.
*/
private TextSelection findNext(TextSelection selected) {
OdfElement element = null;
try {
Node rootNode = mTextDocument.getContentRoot();
if (selected == null) {
mNode = getNextMatchElementInTree(rootNode, rootNode);
} else {
mNode = getNextMatchElementInTree(mNode, rootNode);
}
} 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(this, 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;
}
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) {
// mText:s
if (node.getLocalName().equals("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 getMatchStyleNames() {
Set styleNames = new HashSet();
String sname;
HashMap defaultStyles = new HashMap();
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 map = sStyle.getStylePropertiesDeep();
// check if properties include all search properties and value
// equal
Iterator 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 cStyles = mTextDocument.getContentDom().getAutomaticStyles().getAllStyles().iterator();
while (cStyles.hasNext()) {
OdfStyle cStyle = cStyles.next();
// get default properties and style properties
Map 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 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 defaultStyles,
Map 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));
}
}
}
}
}
}