| /************************************************************************ |
| * |
| * 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.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 |
| * |
| * @deprecated As of release 0.8.8, replaced by {@link org.odftoolkit.simple.common.navigation.TextStyleNavigation} in Simple API. |
| */ |
| 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)); |
| } |
| } |
| } |
| } |
| |
| } |
| } |