| /************************************************************************ |
| * |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER |
| * |
| * Copyright 2008, 2010 Oracle and/or its affiliates. All rights reserved. |
| * |
| * Use is subject to license terms. |
| * |
| * Licensed 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. You can also |
| * obtain a copy of the License at http://odftoolkit.org/docs/license.txt |
| * |
| * 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.doc.office; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.SortedSet; |
| import java.util.TreeSet; |
| |
| import org.odftoolkit.odfdom.pkg.OdfElement; |
| import org.odftoolkit.odfdom.pkg.OdfFileDom; |
| import org.odftoolkit.odfdom.dom.element.OdfStylableElement; |
| import org.odftoolkit.odfdom.dom.element.number.NumberBooleanStyleElement; |
| import org.odftoolkit.odfdom.dom.element.number.NumberTextStyleElement; |
| import org.odftoolkit.odfdom.dom.element.office.OfficeAutomaticStylesElement; |
| import org.odftoolkit.odfdom.dom.style.OdfStyleFamily; |
| import org.odftoolkit.odfdom.incubator.doc.number.OdfNumberCurrencyStyle; |
| import org.odftoolkit.odfdom.incubator.doc.number.OdfNumberDateStyle; |
| import org.odftoolkit.odfdom.incubator.doc.number.OdfNumberPercentageStyle; |
| import org.odftoolkit.odfdom.incubator.doc.number.OdfNumberStyle; |
| import org.odftoolkit.odfdom.incubator.doc.number.OdfNumberTimeStyle; |
| import org.odftoolkit.odfdom.incubator.doc.style.OdfStyle; |
| import org.odftoolkit.odfdom.incubator.doc.style.OdfStylePageLayout; |
| import org.odftoolkit.odfdom.incubator.doc.text.OdfTextListStyle; |
| import org.w3c.dom.Node; |
| |
| /** |
| * Convenient functionalty for the parent ODF OpenDocument element |
| * |
| */ |
| public class OdfOfficeAutomaticStyles extends OfficeAutomaticStylesElement { |
| |
| private static final long serialVersionUID = -2925910664631016175L; |
| // styles that are only in OdfAutomaticStyles |
| private HashMap<String, OdfStylePageLayout> mPageLayouts; |
| // styles that are common for OdfStyles and OdfAutomaticStyles |
| private OdfStylesBase mStylesBaseImpl; |
| |
| public OdfOfficeAutomaticStyles(OdfFileDom ownerDoc) { |
| super(ownerDoc); |
| mStylesBaseImpl = new OdfStylesBase(); |
| } |
| |
| /** |
| * Create an <code>OdfStyle</code> element with style family |
| * |
| * @param styleFamily The <code>OdfStyleFamily</code> element |
| * @return an <code>OdfStyle</code> element |
| */ |
| public OdfStyle newStyle(OdfStyleFamily styleFamily) { |
| OdfFileDom dom = (OdfFileDom) this.ownerDocument; |
| OdfStyle newStyle = dom.newOdfElement(OdfStyle.class); |
| newStyle.setStyleFamilyAttribute(styleFamily.getName()); |
| |
| newStyle.setStyleNameAttribute(newUniqueStyleName(styleFamily)); |
| |
| this.appendChild(newStyle); |
| |
| return newStyle; |
| } |
| |
| /** |
| * Create an <code>OdfTextListStyle</code> element |
| * |
| * @return an <code>OdfTextListStyle</code> element |
| */ |
| public OdfTextListStyle newListStyle() { |
| OdfFileDom dom = (OdfFileDom) this.ownerDocument; |
| OdfTextListStyle newStyle = dom.newOdfElement(OdfTextListStyle.class); |
| |
| newStyle.setStyleNameAttribute(newUniqueStyleName(OdfStyleFamily.List)); |
| |
| this.appendChild(newStyle); |
| |
| return newStyle; |
| } |
| |
| /** Returns the <code>OdfStylePageLayout</code> element with the given name. |
| * |
| * @param name is the name of the page layout |
| * @return the page layout or null if there is no such page layout |
| */ |
| public OdfStylePageLayout getPageLayout(String name) { |
| if (mPageLayouts != null) { |
| return mPageLayouts.get(name); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Returns the <code>OdfStyleStyle</code> element with the given name and family. |
| * |
| * @param name is the name of the style |
| * @param familyType is the family of the style |
| * @return the style or null if there is no such style |
| */ |
| public OdfStyle getStyle(String name, OdfStyleFamily familyType) { |
| return mStylesBaseImpl.getStyle(name, familyType); |
| } |
| |
| /** |
| * Returns an iterator for all <code>OdfStyleStyle</code> elements for the given family. |
| * |
| * @param familyType |
| * @return an iterator for all <code>OdfStyleStyle</code> elements for the given family |
| */ |
| public Iterable<OdfStyle> getStylesForFamily(OdfStyleFamily familyType) { |
| return mStylesBaseImpl.getStylesForFamily(familyType); |
| } |
| |
| /** |
| * Returns an iterator for all <code>OdfStyleStyle</code> elements. |
| * |
| * @return an iterator for all <code>OdfStyleStyle</code> elements |
| */ |
| public Iterable<OdfStyle> getAllStyles() { |
| return mStylesBaseImpl.getAllOdfStyles(); |
| } |
| |
| /** |
| * Returns the <code>OdfTextListStyle</code> element with the given name. |
| * |
| * @param name is the name of the list style |
| * @return the list style or null if there is no such list style |
| */ |
| public OdfTextListStyle getListStyle(String name) { |
| return mStylesBaseImpl.getListStyle(name); |
| } |
| |
| /** |
| * Returns an iterator for all <code>OdfTextListStyle</code> elements. |
| * |
| * @return an iterator for all <code>OdfTextListStyle</code> elements |
| */ |
| public Iterable<OdfTextListStyle> getListStyles() { |
| return mStylesBaseImpl.getListStyles(); |
| } |
| |
| /** |
| * Returns the <code>OdfNumberNumberStyle</code> element with the given name. |
| * |
| * @param name is the name of the number style |
| * @return the number style or null if there is no such number style |
| */ |
| public OdfNumberStyle getNumberStyle(String name) { |
| return mStylesBaseImpl.getNumberStyle(name); |
| } |
| |
| /** |
| * Returns an iterator for all <code>OdfNumberNumberStyle</code> elements. |
| * |
| * @return an iterator for all <code>OdfNumberNumberStyle</code> elements |
| */ |
| public Iterable<OdfNumberStyle> getNumberStyles() { |
| return mStylesBaseImpl.getNumberStyles(); |
| } |
| |
| /** |
| * Returns the <code>OdfNumberDateStyle</code> element with the given name. |
| * |
| * @param name is the name of the date style |
| * @return the date style or null if there is no such date style |
| */ |
| public OdfNumberDateStyle getDateStyle(String name) { |
| return mStylesBaseImpl.getDateStyle(name); |
| } |
| |
| /** |
| * Returns an iterator for all <code>OdfNumberDateStyle</code> elements. |
| * |
| * @return an iterator for all <code>OdfNumberDateStyle</code> elements |
| */ |
| public Iterable<OdfNumberDateStyle> getDateStyles() { |
| return mStylesBaseImpl.getDateStyles(); |
| } |
| |
| /** |
| * Returns the <code>OdfNumberPercentageStyle</code> element with the given name. |
| * |
| * @param name is the name of the percentage style |
| * @return the percentage style null if there is no such percentage style |
| */ |
| public OdfNumberPercentageStyle getPercentageStyle(String name) { |
| return mStylesBaseImpl.getPercentageStyle(name); |
| } |
| |
| /** |
| * Returns an iterator for all <code>OdfNumberPercentageStyle</code> elements. |
| * |
| * @return an iterator for all <code>OdfNumberPercentageStyle</code> elements |
| */ |
| public Iterable<OdfNumberPercentageStyle> getPercentageStyles() { |
| return mStylesBaseImpl.getPercentageStyles(); |
| } |
| |
| /** |
| * Returns the <code>OdfNumberCurrencyStyle</code> element with the given name. |
| * |
| * @param name is the name of the currency style |
| * @return the currency style null if there is no such currency style |
| */ |
| public OdfNumberCurrencyStyle getCurrencyStyle(String name) { |
| return mStylesBaseImpl.getCurrencyStyle(name); |
| } |
| |
| /** |
| * Returns an iterator for all <code>OdfNumberCurrencyStyle</code> elements. |
| * |
| * @return an iterator for all <code>OdfNumberCurrencyStyle</code> elements |
| */ |
| public Iterable<OdfNumberCurrencyStyle> getCurrencyStyles() { |
| return mStylesBaseImpl.getCurrencyStyles(); |
| } |
| |
| /** |
| * Returns the <code>OdfNumberTimeStyle</code> element with the given name. |
| * |
| * @param name is the name of the time style |
| * @return the time style null if there is no such time style |
| */ |
| public OdfNumberTimeStyle getTimeStyle(String name) { |
| return mStylesBaseImpl.getTimeStyle(name); |
| } |
| |
| /** |
| * Returns an iterator for all <code>OdfNumberTimeStyle</code> elements. |
| * |
| * @return an iterator for all <code>OdfNumberTimeStyle</code> elements |
| */ |
| public Iterable<OdfNumberTimeStyle> getTimeStyles() { |
| return mStylesBaseImpl.getTimeStyles(); |
| } |
| |
| /** |
| * Returns the <code>NumberBooleanStyleElement</code> element with the given name. |
| * |
| * @param name is the name of the boolean style |
| * @return the boolean style null if there is no such boolean style |
| */ |
| public NumberBooleanStyleElement getBooleanStyle(String name) { |
| return mStylesBaseImpl.getBooleanStyle(name); |
| } |
| |
| /** |
| * Returns an iterator for all <code>OdfNumberBooleanStyle</code> elements. |
| * |
| * @return an iterator for all <code>OdfNumberBooleanStyle</code> elements |
| */ |
| public Iterable<NumberBooleanStyleElement> getBooleanStyles() { |
| return mStylesBaseImpl.getBooleanStyles(); |
| } |
| |
| /** |
| * Returns the <code>NumberTextStyleElement</code> element with the given name. |
| * |
| * @param name is the name of the text style |
| * @return the text style null if there is no such text style |
| */ |
| public NumberTextStyleElement getTextStyle(String name) { |
| return mStylesBaseImpl.getTextStyle(name); |
| } |
| |
| /** |
| * Returns an iterator for all <code>NumberTextStyleElement</code> elements. |
| * |
| * @return an iterator for all <code>NumberTextStyleElement</code> elements |
| */ |
| public Iterable<NumberTextStyleElement> getTextStyles() { |
| return mStylesBaseImpl.getTextStyles(); |
| } |
| |
| @Override |
| protected void onOdfNodeInserted(OdfElement node, Node refNode) { |
| if (node instanceof OdfStylePageLayout) { |
| OdfStylePageLayout pageLayout = (OdfStylePageLayout) node; |
| if (mPageLayouts == null) { |
| mPageLayouts = new HashMap<String, OdfStylePageLayout>(); |
| } |
| |
| mPageLayouts.put(pageLayout.getStyleNameAttribute(), pageLayout); |
| } else { |
| mStylesBaseImpl.onOdfNodeInserted(node, refNode); |
| } |
| } |
| |
| @Override |
| protected void onOdfNodeRemoved(OdfElement node) { |
| if (node instanceof OdfStylePageLayout) { |
| if (mPageLayouts != null) { |
| OdfStylePageLayout pageLayout = (OdfStylePageLayout) node; |
| mPageLayouts.remove(pageLayout.getStyleNameAttribute()); |
| } |
| } else { |
| mStylesBaseImpl.onOdfNodeRemoved(node); |
| } |
| } |
| |
| /** |
| * This methods removes all automatic styles that are currently not used by |
| * any styleable element. Additionally all duplicate automatic styles will |
| * be removed. |
| */ |
| public void optimize() { |
| Iterator<OdfStyle> iter = mStylesBaseImpl.getAllOdfStyles().iterator(); |
| SortedSet<OdfStyle> stylesSet = new TreeSet<OdfStyle>(); |
| while (iter.hasNext()) { |
| OdfStyle cur = iter.next(); |
| |
| // skip styles which are not in use: |
| if (cur.getStyleUserCount() < 1) { |
| continue; |
| } |
| |
| SortedSet<OdfStyle> tail = stylesSet.tailSet(cur); |
| OdfStyle found = tail.size() > 0 ? tail.first() : null; |
| if (found != null && found.equals(cur)) { |
| // cur already in set. Replace all usages of cur by found: |
| Iterator<OdfStylableElement> styleUsersIter = cur.getStyleUsers().iterator(); |
| ArrayList<OdfStylableElement> styleUsers = new ArrayList<OdfStylableElement>(); |
| while (styleUsersIter.hasNext()) { |
| styleUsers.add(styleUsersIter.next()); |
| } |
| styleUsersIter = styleUsers.iterator(); |
| while (styleUsersIter.hasNext()) { |
| OdfStylableElement elem = styleUsersIter.next(); |
| OdfStyle autoStyle = elem.getAutomaticStyle(); |
| if (autoStyle != null) { |
| elem.setStyleName(found.getStyleNameAttribute()); |
| } |
| } |
| } else { |
| stylesSet.add(cur); |
| } |
| } |
| |
| OdfStyle style = OdfElement.findFirstChildNode(OdfStyle.class, this); |
| while (style != null) { |
| OdfStyle nextStyle = OdfElement.findNextChildNode(OdfStyle.class, style); |
| if (style.getStyleUserCount() < 1) { |
| this.removeChild(style); |
| } |
| |
| style = nextStyle; |
| } |
| } |
| |
| /** |
| * This method makes the style unique |
| * |
| * @param referenceStyle The reference <code>OdfStyle</code> element |
| * @return an <code>OdfStyle</code> element |
| */ |
| public OdfStyle makeStyleUnique(OdfStyle referenceStyle) { |
| OdfStyle newStyle = null; |
| |
| if (referenceStyle.getOwnerDocument() != this.getOwnerDocument()) { |
| // import style from a different dom |
| newStyle = (OdfStyle) this.getOwnerDocument().importNode(referenceStyle, true); |
| } else { |
| // just clone |
| newStyle = (OdfStyle) referenceStyle.cloneNode(true); |
| } |
| |
| newStyle.setStyleNameAttribute(newUniqueStyleName(newStyle.getFamily())); |
| appendChild(newStyle); |
| |
| return newStyle; |
| } |
| |
| private String newUniqueStyleName(OdfStyleFamily styleFamily) { |
| String unique_name; |
| |
| if (styleFamily.equals(OdfStyleFamily.List)) { |
| do { |
| unique_name = String.format("l%06x", (int) (Math.random() * 0xffffff)); |
| } while (getListStyle(unique_name) != null); |
| } else { |
| do { |
| unique_name = String.format("a%06x", (int) (Math.random() * 0xffffff)); |
| } while (getStyle(unique_name, styleFamily) != null); |
| } |
| return unique_name; |
| } |
| } |