summaryrefslogtreecommitdiff
path: root/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/ParaStyle.java
diff options
context:
space:
mode:
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.java601
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);
+ }
+ }
+}
+