diff options
Diffstat (limited to 'xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/ParaStyle.java')
-rw-r--r-- | xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/ParaStyle.java | 601 |
1 files changed, 601 insertions, 0 deletions
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/ParaStyle.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/ParaStyle.java new file mode 100644 index 000000000000..e68327792374 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/ParaStyle.java @@ -0,0 +1,601 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +package org.openoffice.xmerge.converter.xml; + +import org.w3c.dom.NodeList; +import org.w3c.dom.Node; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Element; + +import org.openoffice.xmerge.util.Debug; + + +abstract class conversionAlgorithm { + int I(String val) { + return 0; + } +} + + /* + * This algorithm expects only values in millimeters, e.g. "20.3mm". + */ +class horizSize extends conversionAlgorithm { + int I(String value) { + if (value.endsWith("mm")) { + float size = (float)0.0; + String num = value.substring(0, value.length() - 2); + try { + size = Float.parseFloat(num); + } catch (Exception e) { + Debug.log(Debug.ERROR, "Error parsing " + value, e); + } + size *= 100; + return (int)size; + } else { + Debug.log(Debug.ERROR, "Unexpected value (" + value + + ") in horizSize.I()"); + return 0; + } + } +} + + +/* + * This algorithm does line height - can be either millimeters or + * a percentage. + */ +class lineHeight extends conversionAlgorithm { + int I(String value) { + if (value.endsWith("mm")) { + float size = (float)0.0; + String num = value.substring(0, value.length() - 2); + try { + size = Float.parseFloat(num); + } catch (Exception e) { + Debug.log(Debug.ERROR, "Error parsing " + value, e); + } + size *= 100; + return (int)size; + } else if (value.endsWith("%")) { + float size = (float)0.0; + String num = value.substring(0, value.length() - 1); + try { + size = Float.parseFloat(num); + } catch (Exception e) { + Debug.log(Debug.ERROR, "Error parsing " + value, e); + } + int retval = (int) size; + retval |= ParaStyle.LH_PCT; + return retval; + } + return 0; + } +} + + +/** + * This class converts alignment values. + */ +class alignment extends conversionAlgorithm { + int I(String value) { + if (value.equals("end")) + return ParaStyle.ALIGN_RIGHT; + if (value.equals("right")) + return ParaStyle.ALIGN_RIGHT; + if (value.equals("center")) + return ParaStyle.ALIGN_CENTER; + if (value.equals("justify")) + return ParaStyle.ALIGN_JUST; + if (value.equals("justified")) + return ParaStyle.ALIGN_JUST; + if (value.equals("start")) + return ParaStyle.ALIGN_LEFT; + if (value.equals("left")) + return ParaStyle.ALIGN_LEFT; + Debug.log(Debug.ERROR, "Unknown string (" + + value + ") in alignment.I()"); + return ParaStyle.ALIGN_LEFT; + } +} + + +/** + * <p>This class represents a paragraph <code>Style</code>.</p> + * + * <p><table border="1" cellpadding="1"><tr><td> + * Attribute </td><td>Value + * </td></tr><tr><td> + * MARGIN_LEFT </td><td>mm * 100 + * </td></tr><tr><td> + * MARGIN_RIGHT </td><td>mm * 100 + * </td></tr><tr><td> + * MARGIN_TOP </td><td>mm * 100 (space on top of paragraph) + * </td></tr><tr><td> + * MARGIN_BOTTOM </td><td>mm * 100 + * </td></tr><tr><td> + * TEXT_INDENT </td><td>mm * 100 (first line indent) + * </td></tr><tr><td> + * LINE_HEIGHT </td><td>mm * 100, unless or'ed with LH_PCT, in which + * case it is a percentage (e.g. 200% for double spacing) + * Can also be or'ed with LH_ATLEAST. Value is stored + * in bits indicated by LH_VALUEMASK. + * </td></tr><tr><td> + * TEXT_ALIGN </td><td>ALIGN_RIGHT, ALIGN_CENTER, ALIGN_JUST, ALIGN_LEFT + * </td></tr></table></p> + * + * @author David Proulx + */ +public class ParaStyle extends Style implements Cloneable { + + /** The left margin property. */ + public static final int MARGIN_LEFT = 0; + /** The right margin property. */ + public static final int MARGIN_RIGHT = 1; + /** The top margin property. */ + public static final int MARGIN_TOP = 2; + /** The bottom margin property. */ + public static final int MARGIN_BOTTOM = 3; + /** Indent left property. */ + public static final int TEXT_INDENT = 4; + /** Indent right property. */ + public static final int LINE_HEIGHT = 5; + /** Align text property. */ + public static final int TEXT_ALIGN = 6; + // This must always be one more than highest property + /** Total number of properties. */ + protected static final int NR_PROPERTIES = 7; + + /** + * Array of flags indicating which attributes are set for this + * paragraph <code>Style</code>. + */ + protected boolean isSet[] = new boolean[NR_PROPERTIES]; + /** Array of attribute values for this paragraph <code>tyle</code>. */ + protected int value[] = new int[NR_PROPERTIES]; + /** Array of attribute names for this paragraph <code>Style</code>. */ + protected String attrName[] = { + "fo:margin-left", + "fo:margin-right", + "fo:margin-top", + "fo:margin-bottom", + "fo:text-indent", + "fo:line-height", + "fo:text-align" + }; + + /** Array of attribute structures for this paragraph <code>Style</code>. */ + protected Class algor[] = { + horizSize.class, + horizSize.class, + horizSize.class, + horizSize.class, + horizSize.class, + lineHeight.class, + alignment.class + }; + + /** Align right. */ + public static final int ALIGN_RIGHT = 1; + /** Align center. */ + public static final int ALIGN_CENTER = 2; + /** Align justified. */ + public static final int ALIGN_JUST = 3; + /** Align left. */ + public static final int ALIGN_LEFT = 4; + + /** Line height percentage. */ + public static final int LH_PCT = 0x40000000; + /** Line height minimum value. */ + public static final int LH_ATLEAST = 0x20000000; + /** Line height mask. */ + public static final int LH_VALUEMASK = 0x00FFFFFF; + + /** Ignored tags. */ + private static String[] ignored = { + "style:font-name", "fo:font-size", "fo:font-weight", "fo:color", + "fo:language", "fo:country", "style:font-name-asian", + "style:font-size-asian", "style:language-asian", + "style:country-asian", "style:font-name-complex", + "style:font-size-complex", "style:language-complex", + "style:country-complex", "style:text-autospace", "style:punctuation-wrap", + "style:line-break", "fo:keep-with-next", "fo:font-style", + "text:number-lines", "text:line-number" + }; + + + /** + * Constructor for use when going from DOM to client device format. + * + * @param node A <i>style:style</i> <code>Node</code> which, which + * is assumed to have <i>family</i> attribute of + * <i>paragraph</i>. + * @param sc The <code>StyleCatalog</code>, which is used for + * looking up ancestor <code>Style</code> objects. + */ + public ParaStyle(Node node, StyleCatalog sc) { + + super(node, sc); + + // Look for children. Only ones we care about are "style:properties" + // nodes. If any are found, recursively traverse them, passing + // along the style element to add properties to. + // + if (node.hasChildNodes()) { + NodeList children = node.getChildNodes(); + int len = children.getLength(); + for (int i = 0; i < len; i++) { + Node child = children.item(i); + String name = child.getNodeName(); + if (name.equals("style:properties")) { + NamedNodeMap childAttrNodes = child.getAttributes(); + if (childAttrNodes != null) { + int nChildAttrNodes = childAttrNodes.getLength(); + for (int j = 0; j < nChildAttrNodes; j++) { + Node attr = childAttrNodes.item(j); + setAttribute(attr.getNodeName(), attr.getNodeValue()); + } + } + } + } + } + } + + + /** + * Constructor for use when going from client device format to DOM. + * + * @param name Name of the <code>Style</code>. Can be null. + * @param familyName Family of the <code>Style</code> - usually + * <i>paragraph</i>, <i>text</i>, etc. Can be null. + * @param parentName Name of the parent <code>Style</code>, or null + * if none. + * @param attribs Array of attributes to set. + * @param values Array of values to set. + * @param sc The <code>StyleCatalog</code>, which is used for + * looking up ancestor <code>Style</code> objects. + */ + public ParaStyle(String name, String familyName, String parentName, + String attribs[], String values[], StyleCatalog sc) { + super(name, familyName, parentName, sc); + if (attribs != null) + for (int i = 0; i < attribs.length; i++) + setAttribute(attribs[i], values[i]); + } + + + /** + * Alternate constructor for use when going from client device + * format to DOM. + * + * @param name Name of the <code>Style</code>. Can be null. + * @param familyName Family of the <code>Style</code> - usually + * <i>paragraph</i>, <i>text</i>, etc. Can be null. + * @param parentName Name of the parent <code>Style</code>, or + * null if none. + * @param attribs Array of attributes indices to set. + * @param values Array of values to set. + * @param lookup The <code>StyleCatalog</code>, which is used for + * looking up ancestor <code>Style</code> objects. + */ + public ParaStyle(String name, String familyName, String parentName, + int attribs[], String values[], StyleCatalog lookup) { + super(name, familyName, parentName, lookup); + if (attribs != null) + for (int i = 0; i < attribs.length; i++) + setAttribute(attribs[i], values[i]); + } + + + /** + * This code checks whether an attribute is one that we + * intentionally ignore. + * + * @param attribute The attribute to check. + * + * @return true if attribute can be ignored, false otherwise. + */ + private boolean isIgnored(String attribute) { + for (int i = 0; i < ignored.length; i++) { + if (ignored[i].equals(attribute)) + return true; + } + return false; + } + + + /** + * Set an attribute for this paragraph <code>Style</code>. + * + * @param attr The attribute to set. + * @param value The attribute value to set. + */ + public void setAttribute(String attr, String value) { + for (int i = 0; i < NR_PROPERTIES; i++) { + if (attr.equals(attrName[i])) { + setAttribute(i, value); + return; + } + } + if (!isIgnored(attr)) + Debug.log(Debug.INFO, "ParaStyle Unhandled: " + attr + "=" + value); + } + + + /** + * Check whether an attribute is set in this <code>Style</code>. + * + * @param attrIndex The attribute index to check. + * + * @return true if the attribute at specified index is set, + * false otherwise. + */ + public boolean isAttributeSet(int attrIndex) { + return isSet[attrIndex]; + } + + + /** + * Get the value of an integer attribute. + * + * @param attrIndex Index of the attribute. + * + * @return Value of the attribute, 0 if not set. + */ + public int getAttribute(int attrIndex) { + if (isSet[attrIndex]) + return value[attrIndex]; + else return 0; + } + + + /** + * Set an attribute for this paragraph <code>Style</code>. + * + * @param attr The attribute index to set. + * @param value The attribute value to set. + */ + public void setAttribute(int attr, String value) { + isSet[attr] = true; + try { + this.value[attr] = (((conversionAlgorithm)algor[attr].newInstance())).I(value); + } catch (Exception e) { + Debug.log(Debug.ERROR, "Instantiation error", e); + } + } + + + /** + * Return the <code>Style</code> in use. + * + * @return The fully-resolved copy of the <code>Style</code> in use. + */ + public Style getResolved() { + ParaStyle resolved = null; + try { + resolved = (ParaStyle)this.clone(); + } catch (Exception e) { + Debug.log(Debug.ERROR, "Can't clone", e); + } + + // Look up the parent style. (If there is no style catalog + // specified, we can't do any lookups). + ParaStyle parentStyle = null; + if (sc != null) { + if (parent != null) { + parentStyle = (ParaStyle)sc.lookup(parent, family, null, + this.getClass()); + if (parentStyle == null) + Debug.log(Debug.ERROR, "parent style lookup of " + + parent + " failed!"); + else + parentStyle = (ParaStyle)parentStyle.getResolved(); + } else if (!name.equals("DEFAULT_STYLE")) { + parentStyle = (ParaStyle)sc.lookup("DEFAULT_STYLE", null, null, + this.getClass()); + } + } + + // If we found a parent, for any attributes which we don't have + // set, try to get the values from the parent. + if (parentStyle != null) { + parentStyle = (ParaStyle)parentStyle.getResolved(); + for (int i = 0; i < NR_PROPERTIES; i++) { + if (!isSet[i] && parentStyle.isSet[i]) { + resolved.isSet[i] = true; + resolved.value[i] = parentStyle.value[i]; + } + } + } + return resolved; + } + + + /** + * Private function to return the value as an element in + * a Comma Separated Value (CSV) format. + * + * @param value The value to format. + * + * @return The formatted value. + */ + private static String toCSV(String value) { + if (value != null) + return "\"" + value + "\","; + else + return "\"\","; + } + + + /** + * Private function to return the value as a last element in + * a Comma Separated Value (CSV) format. + * + * @param value The value to format. + * + * @return The formatted value. + */ + private static String toLastCSV(String value) { + if (value != null) + return "\"" + value + "\""; + else + return "\"\""; + } + + + /** + * Print a Comma Separated Value (CSV) header line for the + * spreadsheet dump. + */ + public static void dumpHdr() { + System.out.println(toCSV("Name") + toCSV("Family") + toCSV("parent") + + toCSV("left mgn") + toCSV("right mgn") + + toCSV("top mgn") + toCSV("bottom mgn") + toCSV("txt indent") + + toCSV("line height") + toLastCSV("txt align")); + } + + + /** + * Dump this <code>Style</code> as a Comma Separated Value (CSV) + * line. + */ + public void dumpCSV() { + String attributes = ""; + for (int index = 0; index <= 6; index++) { + if (isSet[index]) { + attributes += toCSV("" + value[index]); + } + else + attributes += toCSV(null); // unspecified + } + System.out.println(toCSV(name) + toCSV(family) + toCSV(parent) + + attributes + toLastCSV(null)); + } + + + /** + * Create the <code>Node</code> with the specified elements. + * + * @param parentDoc Parent <code>Document</code> of the + * <code>Node</code> to create. + * @param name Name of the <code>Node</code>. + * + * @return The created <code>Node</code>. + */ + public Node createNode(org.w3c.dom.Document parentDoc, String name) { + Element node = parentDoc.createElement(name); + writeAttributes(node); + return node; + } + + + /** + * Return true if <code>style</code> is a subset of the + * <code>Style</code>. + * + * @param style <code>Style</code> to check. + * + * @return true if <code>style</code> is a subset, false + * otherwise. + */ + public boolean isSubset(Style style) { + + if (!super.isSubset(style)) + return false; + if (!this.getClass().isAssignableFrom(style.getClass())) + return false; + ParaStyle ps = (ParaStyle)style; + + for (int i = 0; i < NR_PROPERTIES; i++) { + if (ps.isSet[i]) { + // if (!isSet[i]) return false; + + if (i < NR_PROPERTIES - 1) { + // Compare the actual values. We allow a margin of error + // here because the conversion loses precision. + int diff; + if (value[i] > ps.value[i]) + diff = value[i] - ps.value[i]; + else + diff = ps.value[i] - value[i]; + if (diff > 32) + return false; + } else { + if (i == TEXT_ALIGN) + if ((value[i] == 0) && (ps.value[i] == 4)) + continue; + if (value[i] != ps.value[i]) + return false; + } + } + } + return true; + } + + + /** + * Add <code>Style</code> attributes to the given + * <code>Node</code>. This may involve writing child + * <code>Node</code> objects as well. + * + * @param node The <code>Node</code> to add <code>Style</code> + * attributes. + */ + public void writeAttributes(Element node) { + for (int i = 0; i <= TEXT_INDENT; i++) { + if (isSet[i]) { + double temp = value[i] / 100.0; + String stringVal = (new Double(temp)).toString() + "mm"; + node.setAttribute(attrName[i], stringVal); + } + } + + if (isSet[LINE_HEIGHT]) { + String stringVal; + if ((value[LINE_HEIGHT] & LH_PCT) != 0) + stringVal = (new Integer(value[LINE_HEIGHT] & LH_VALUEMASK)).toString() + "%"; + else { + double temp = (value[LINE_HEIGHT] & LH_VALUEMASK) / 100.0; + stringVal = (new Double(temp)).toString() + "mm"; + } + node.setAttribute(attrName[LINE_HEIGHT], stringVal); + } + + if (isSet[TEXT_ALIGN]) { + String val; + switch (value[TEXT_ALIGN]) { + case ALIGN_RIGHT: val = "end"; break; + case ALIGN_CENTER: val = "center"; break; + case ALIGN_JUST: val = "justify"; break; + case ALIGN_LEFT: val = "left"; break; + default: val = "unknown"; break; + } + node.setAttribute(attrName[TEXT_ALIGN], val); + } + } +} + |