summaryrefslogtreecommitdiff
path: root/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc
diff options
context:
space:
mode:
Diffstat (limited to 'xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc')
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/BookSettings.java228
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/CellStyle.java510
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/ColumnRowInfo.java195
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/ColumnStyle.java300
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/DocumentMergerImpl.java198
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/Format.java475
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/NameDefinition.java215
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/RowStyle.java300
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SheetSettings.java373
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SpreadsheetDecoder.java180
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SpreadsheetEncoder.java129
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcConstants.java49
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocument.java92
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocumentDeserializer.java792
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocumentSerializer.java993
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcPluginFactory.java82
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/package.html40
17 files changed, 5151 insertions, 0 deletions
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/BookSettings.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/BookSettings.java
new file mode 100644
index 000000000000..9c1ae2768524
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/BookSettings.java
@@ -0,0 +1,228 @@
+/*************************************************************************
+ *
+ * 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.sxc;
+
+import java.util.Vector;
+import java.util.Enumeration;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.XmlUtil;
+
+/**
+ * This is a class representing the different attributes for a worksheet
+ * contained in settings.xml.
+ *
+ * @author Martin Maher
+ */
+public class BookSettings implements OfficeConstants {
+
+ /** A w3c <code>Document</code>. */
+ private org.w3c.dom.Document settings = null;
+
+ private boolean hasColumnRowHeaders = true;
+ private String activeSheet = new String();
+ private Vector worksheetSettings = new Vector();
+
+ /**
+ * Default Constructor for a <code>BookSettings</code>
+ *
+ * @param dimension if it's a row the height, a column the width
+ * @param repeated
+ */
+ public BookSettings(Node root) {
+ readNode(root);
+ }
+
+ /**
+ * Default Constructor for a <code>BookSettings</code>
+ *
+ * @param worksheetSettings if it's a row the height, a column the width
+ */
+ public BookSettings(Vector worksheetSettings) {
+ this.worksheetSettings = worksheetSettings;
+ }
+
+ /**
+ *
+ */
+ public void setColumnRowHeaders(boolean hasColumnRowHeaders) {
+ this.hasColumnRowHeaders = hasColumnRowHeaders;
+ }
+
+ /**
+ *
+ */
+ public boolean hasColumnRowHeaders() {
+ return hasColumnRowHeaders;
+ }
+
+ /**
+ * Gets the <code>Vector</code> of <code>SheetSettings</code>
+ *
+ * @return <code>Vector</code> of <code>SheetSettings</code>
+ */
+ public Vector getSheetSettings() {
+ return worksheetSettings;
+ }
+
+ /**
+ * Gets the active sheet name
+ *
+ * @return the active sheet name
+ */
+ public String getActiveSheet() {
+
+ return activeSheet;
+ }
+
+ /**
+ * Sets the active sheet name
+ *
+ * @param activeSheet the active sheet name
+ */
+ public void setActiveSheet(String activeSheet) {
+
+ this.activeSheet = activeSheet;
+ }
+
+
+ /**
+ * Adds an XML entry for a particular setting
+ *
+ * @param root the root node at which to add the xml entry
+ * @param attriute the name of the attribute to add
+ * @param type the attribute type (int, short etc)
+ * @param value the value of the attribute
+ */
+ private void addConfigItem(Node root, String attribute, String type, String value) {
+
+ Element configItem = settings.createElement(TAG_CONFIG_ITEM);
+ configItem.setAttribute(ATTRIBUTE_CONFIG_NAME, attribute);
+ configItem.setAttribute(ATTRIBUTE_CONFIG_TYPE, type);
+
+ configItem.appendChild(settings.createTextNode(value));
+
+ root.appendChild(configItem);
+ }
+
+ /**
+ * Writes out a settings.xml entry for this BookSettings object
+ *
+ * @param settings a <code>Document</code> object representing the settings.xml
+ * @param root the root xml node to add to
+ */
+ public void writeNode(org.w3c.dom.Document settings, Node root) {
+
+ this.settings = settings;
+ Element configItemMapNamed = (Element) settings.createElement(TAG_CONFIG_ITEM_MAP_NAMED);
+ configItemMapNamed.setAttribute(ATTRIBUTE_CONFIG_NAME, "Tables");
+ for(Enumeration e = worksheetSettings.elements();e.hasMoreElements();) {
+ SheetSettings s = (SheetSettings) e.nextElement();
+ s.writeNode(settings, configItemMapNamed);
+ }
+ addConfigItem(root, "ActiveTable", "string", activeSheet);
+ String booleanValue = Boolean.toString(hasColumnRowHeaders);
+ addConfigItem(root, "HasColumnRowHeaders", "boolean", booleanValue);
+ root.appendChild(configItemMapNamed);
+ }
+
+ /**
+ * Sets a variable based on a String value read from XML
+ *
+ * @param name xml name of the attribute to set
+ * @param value String value fo the attribute
+ */
+ public void addAttribute(String name, String value) {
+
+ if(name.equals("ActiveTable")) {
+ activeSheet = value;
+ } else if(name.equals("HasColumnRowHeaders")) {
+ Boolean b = Boolean.valueOf(value);
+ hasColumnRowHeaders = b.booleanValue();
+ }
+ }
+
+ /**
+ * Reads document settings from xml and inits SheetSettings variables
+ *
+ * @param root XML Node to read from
+ */
+ public void readNode(Node root) {
+
+ if (root.hasChildNodes()) {
+
+ NodeList nodeList = root.getChildNodes();
+ int len = nodeList.getLength();
+ for (int i = 0; i < len; i++) {
+ Node child = nodeList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String nodeName = child.getNodeName();
+
+ if (nodeName.equals(TAG_CONFIG_ITEM)) {
+
+ NamedNodeMap cellAtt = child.getAttributes();
+
+ Node configNameNode =
+ cellAtt.getNamedItem(ATTRIBUTE_CONFIG_NAME);
+
+ String name = configNameNode.getNodeValue();
+ NodeList nodeList2 = child.getChildNodes();
+ int len2 = nodeList2.getLength();
+ String s = "";
+ for (int j = 0; j < len2; j++) {
+ Node child2 = nodeList2.item(j);
+ if (child2.getNodeType() == Node.TEXT_NODE) {
+ s = child2.getNodeValue();
+ }
+ }
+ addAttribute(name, s);
+
+ } else if (nodeName.equals(TAG_CONFIG_ITEM_MAP_NAMED)) {
+
+ readNode(child);
+
+ } else if (nodeName.equals(TAG_CONFIG_ITEM_MAP_ENTRY)) {
+
+ SheetSettings s = new SheetSettings(child);
+ worksheetSettings.add(s);
+
+ } else {
+
+ Debug.log(Debug.TRACE, "<OTHERS " + XmlUtil.getNodeInfo(child) + " />");
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/CellStyle.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/CellStyle.java
new file mode 100644
index 000000000000..2e3e34b6d620
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/CellStyle.java
@@ -0,0 +1,510 @@
+/*************************************************************************
+ *
+ * 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.sxc;
+
+import java.awt.Color;
+
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Element;
+
+import org.openoffice.xmerge.converter.xml.Style;
+import org.openoffice.xmerge.converter.xml.StyleCatalog;
+import org.openoffice.xmerge.util.Debug;
+
+/**
+ * Represents a text <code>Style</code> in an OpenOffice document.
+ *
+ * @author Martin Maher
+ */
+public class CellStyle extends Style implements Cloneable {
+
+ private Format fmt = new Format();
+
+ /**
+ * Constructor for use when going from DOM to client device format.
+ *
+ * @param Node The <i>style:style</i> <code>Node</code> containing
+ * the <code>Style</code>. (This <code>Node</code> is
+ * assumed have a <i>family</i> attribute of <i>text</i>).
+ * @param sc The <code>StyleCatalog</code>, which is used for
+ * looking up ancestor <code>Style</code> objects.
+ */
+ public CellStyle(Node node, StyleCatalog sc) {
+ super(node, sc);
+
+ // Run through the attributes of this node, saving
+ // the ones we're interested in.
+ NamedNodeMap attrNodes = node.getAttributes();
+ if (attrNodes != null) {
+ int len = attrNodes.getLength();
+ for (int i = 0; i < len; i++) {
+ Node attr = attrNodes.item(i);
+ handleAttribute(attr.getNodeName(), attr.getNodeValue());
+ }
+ }
+
+ // 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);
+ handleAttribute(attr.getNodeName(),
+ attr.getNodeValue());
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Constructor for use when going from client device format to DOM
+ *
+ * @param name Name of cell <code>Style</code>. Can be null.
+ * @param family Family of text <code>Style</code> (usually
+ * <i>text</i>). Can be null.
+ * @param parent Name of parent text <code>Style</code>, or null
+ * for none.
+ * @param fmt size in points.
+ * @param sc The <code>StyleCatalog</code>, which is used for
+ * looking up ancestor <code>Style</code> objects.
+ */
+ public CellStyle(String name, String family, String parent,Format fmt, StyleCatalog sc) {
+ super(name, family, parent, sc);
+ this.fmt = fmt;
+ }
+
+ /**
+ * Returns the <code>Format</code> object for this particular style
+ *
+ * @return the <code>Format</code> object
+ */
+ public Format getFormat() {
+ return fmt;
+ }
+
+ /**
+ * Parse a color specification of the form <i>#rrggbb</i>
+ *
+ * @param value <code>Color</code> specification to parse.
+ *
+ * @return The <code>Color</code> associated the value.
+ */
+ private Color parseColorString(String value) {
+ // Assume color value is of form #rrggbb
+ String r = value.substring(1, 3);
+ String g = value.substring(3, 5);
+ String b = value.substring(5, 7);
+ int red = 0;
+ int green = 0;
+ int blue = 0;
+ try {
+ red = Integer.parseInt(r, 16);
+ green = Integer.parseInt(g, 16);
+ blue = Integer.parseInt(b, 16);
+ } catch (NumberFormatException e) {
+ Debug.log(Debug.ERROR, "Problem parsing a color string", e);
+ }
+ return new Color(red, green, blue, 0);
+ }
+
+
+ /**
+ * Set an attribute.
+ *
+ * @param attr The attribute to set.
+ * @param value The attribute value to set.
+ */
+ private void handleAttribute(String attr, String value) {
+
+ if (attr.equals("fo:font-weight")) {
+ fmt.setAttribute(Format.BOLD, value.equals("bold"));
+ }
+
+ else if (attr.equals("fo:font-style")) {
+ if (value.equals("italic") || value.equals("oblique"))
+ fmt.setAttribute(Format.ITALIC, true);
+ else if (value.equals("normal"))
+ fmt.setAttribute(Format.ITALIC, false);
+ }
+
+ else if (attr.equals("style:text-underline")) {
+ fmt.setAttribute(Format.UNDERLINE, !value.equals("none"));
+ }
+
+ else if (attr.equals("style:text-crossing-out")) {
+ fmt.setAttribute(Format.STRIKETHRU, !value.equals("none"));
+ }
+
+ else if (attr.equals("style:text-position")) {
+ if (value.startsWith("super "))
+ fmt.setAttribute(Format.SUPERSCRIPT, true);
+ else if (value.startsWith("sub "))
+ fmt.setAttribute(Format.SUBSCRIPT, true);
+ else if (value.startsWith("0% "))
+ fmt.setAttribute(Format.SUPERSCRIPT | Format.SUBSCRIPT, false);
+ else {
+ String firstPart = value.substring(0, value.indexOf(" "));
+ if (firstPart.endsWith("%")) {
+ firstPart = firstPart.substring(0, value.indexOf("%"));
+ int amount;
+ try {
+ amount = Integer.parseInt(firstPart);
+ } catch (NumberFormatException e) {
+ amount = 0;
+ Debug.log(Debug.ERROR, "Problem with style:text-position tag", e);
+ }
+ if (amount < 0) fmt.setAttribute(Format.SUBSCRIPT, true);
+ else if (amount > 0) fmt.setAttribute(Format.SUPERSCRIPT, false);
+ }
+ }
+ }
+
+ else if (attr.equals("fo:font-size")) {
+ if (value.endsWith("pt")) {
+ String num = value.substring(0, value.length() - 2);
+ fmt.setFontSize(Integer.parseInt(num));
+ }
+ }
+
+ else if (attr.equals("style:font-name"))
+ fmt.setFontName(value);
+
+ else if (attr.equals("fo:color"))
+ fmt.setForeground(parseColorString(value));
+
+ else if (attr.equals("fo:background-color"))
+ fmt.setBackground(parseColorString(value));
+
+ else if (attr.equals("fo:text-align")) {
+ if(value.equals("center")) {
+ fmt.setAlign(Format.CENTER_ALIGN);
+ } else if(value.equals("end")) {
+ fmt.setAlign(Format.RIGHT_ALIGN);
+ } else if(value.equals("start")) {
+ fmt.setAlign(Format.LEFT_ALIGN);
+ }
+ }
+
+ else if (attr.equals("fo:vertical-align")) {
+ if(value.equals("top")) {
+ fmt.setVertAlign(Format.TOP_ALIGN);
+ } else if(value.equals("middle")) {
+ fmt.setVertAlign(Format.MIDDLE_ALIGN);
+ } else if(value.equals("bottom")) {
+ fmt.setVertAlign(Format.BOTTOM_ALIGN);
+ }
+ }
+
+ else if (attr.equals("fo:border")) {
+ fmt.setAttribute(Format.TOP_BORDER, !value.equals("none"));
+ fmt.setAttribute(Format.BOTTOM_BORDER, !value.equals("none"));
+ fmt.setAttribute(Format.LEFT_BORDER, !value.equals("none"));
+ fmt.setAttribute(Format.RIGHT_BORDER, !value.equals("none"));
+ }
+ else if (attr.equals("fo:border-top")) {
+ fmt.setAttribute(Format.TOP_BORDER, !value.equals("none"));
+ }
+ else if (attr.equals("fo:border-bottom")) {
+ fmt.setAttribute(Format.BOTTOM_BORDER, !value.equals("none"));
+ }
+ else if (attr.equals("fo:border-left")) {
+ fmt.setAttribute(Format.LEFT_BORDER, !value.equals("none"));
+ }
+ else if (attr.equals("fo:border-right")) {
+ fmt.setAttribute(Format.RIGHT_BORDER, !value.equals("none"));
+ }
+ else if (attr.equals("fo:wrap-option")) {
+ fmt.setAttribute(Format.WORD_WRAP, value.equals("wrap"));
+ }
+
+ else if (isIgnored(attr)) {}
+
+ else {
+ Debug.log(Debug.INFO, "CellStyle Unhandled: " + attr + "=" + value);
+ }
+ }
+
+
+ /**
+ * Return a <code>Style</code> object corresponding to this one,
+ * but with all of the inherited information from parent
+ * <code>Style</code> objects filled in. The object returned will
+ * be a new object, not a reference to this object, even if it does
+ * not need any information added.
+ *
+ * @return The <code>StyleCatalog</code> in which to look up
+ * ancestors.
+ */
+ public Style getResolved() {
+ // Create a new object to return, which is a clone of this one.
+ CellStyle resolved = null;
+ try {
+ resolved = (CellStyle)this.clone();
+ } catch (Exception e) {
+ Debug.log(Debug.ERROR, "Can't clone", e);
+ }
+
+ // Look up the parentStyle. (If there is no style catalog
+ // specified, we can't do any lookups.)
+ CellStyle parentStyle = null;
+ if (sc != null) {
+ if (parent != null) {
+ parentStyle = (CellStyle)sc.lookup(parent, family, null,
+ this.getClass());
+ if (parentStyle == null)
+ Debug.log(Debug.ERROR, "parent style lookup of "
+ + parent + " failed!");
+ else
+ parentStyle = (CellStyle)parentStyle.getResolved();
+
+ } else if (!name.equals("DEFAULT_STYLE")) {
+ parentStyle = (CellStyle)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 = (CellStyle)parentStyle.getResolved();
+ Format parentFormat = parentStyle.getFormat();
+ Format resolvedFormat = resolved.getFormat();
+
+ if ((fmt.getAlign() == Format.LEFT_ALIGN) && (parentFormat.getAlign() != Format.LEFT_ALIGN))
+ resolvedFormat.setAlign(parentFormat.getAlign());
+ if ((fmt.getVertAlign() == Format.BOTTOM_ALIGN) && (parentFormat.getVertAlign() != Format.BOTTOM_ALIGN))
+ resolvedFormat.setVertAlign(parentFormat.getVertAlign());
+ if ((fmt.getFontSize() == 0) && (parentFormat.getFontSize() != 0))
+ resolvedFormat.setFontSize(parentFormat.getFontSize());
+ if ((fmt.getFontName() == null) && (parentFormat.getFontName() != null))
+ resolvedFormat.setFontName(parentFormat.getFontName());
+ if ((fmt.getForeground() == null) && (parentFormat.getForeground() != null))
+ resolvedFormat.setForeground(parentFormat.getForeground());
+ if ((fmt.getBackground() == null) && (parentFormat.getBackground() != null))
+ resolvedFormat.setBackground(parentFormat.getBackground());
+ for (int m = Format.BOLD; m <= Format.SUBSCRIPT; m = m << 1) {
+ if ((fmt.getAttribute(m)) && (parentFormat.getAttribute(m))) {
+ resolvedFormat.setAttribute(m, parentFormat.getAttribute(m));
+ }
+ }
+
+ }
+ return resolved;
+ }
+
+
+ /**
+ * Create a new <code>Node</code> in the <code>Document</code>, and
+ * write this <code>Style</code> to it.
+ *
+ * @param parentDoc Parent <code>Document</code> of the
+ * <code>Node</code> to create.
+ * @param name Name to use for the new <code>Node</code> (e.g.
+ * <i>style:style</i>)
+ *
+ * @return 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> specifies as much or less
+ * than this <code>Style</code>, and nothing it specifies
+ * contradicts this <code>Style</code>.
+ *
+ * @param style The <code>Style</code> to check.
+ *
+ * @return true if <code>style</code> is a subset, false
+ * otherwise.
+ */
+ public boolean isSubset(Style style) {
+ if (style.getClass() != this.getClass())
+ return false;
+ CellStyle tStyle = (CellStyle)style;
+
+ Format rhs = tStyle.getFormat();
+
+ if(!fmt.isSubset(rhs))
+ return false;
+
+ return true;
+ }
+
+
+ /**
+ * Write this <code>Style</code> object's attributes to a
+ * <code>Node</code> in the <code>Document</code>.
+ *
+ * @param node The <code>Node</code> to add <code>Style</code>
+ * attributes.
+ */
+ public void writeAttributes(Element node) {
+
+ if (fmt.getAlign()==Format.RIGHT_ALIGN)
+ node.setAttribute("fo:text-align", "end");
+
+ if (fmt.getAlign()==Format.LEFT_ALIGN)
+ node.setAttribute("fo:text-align", "start");
+
+ if (fmt.getAlign()==Format.CENTER_ALIGN)
+ node.setAttribute("fo:text-align", "center");
+
+ if (fmt.getVertAlign()==Format.TOP_ALIGN)
+ node.setAttribute("fo:vertical-align", "top");
+
+ if (fmt.getVertAlign()==Format.MIDDLE_ALIGN)
+ node.setAttribute("fo:vertical-align", "middle");
+
+ if (fmt.getVertAlign()==Format.BOTTOM_ALIGN)
+ node.setAttribute("fo:vertical-align", "bottom");
+
+ if (fmt.getAttribute(Format.BOLD))
+ node.setAttribute("fo:font-weight", "bold");
+
+ if (fmt.getAttribute(Format.ITALIC))
+ node.setAttribute("fo:font-style", "italic");
+
+ if (fmt.getAttribute(Format.UNDERLINE))
+ node.setAttribute("style:text-underline", "single");
+
+ if (fmt.getAttribute(Format.STRIKETHRU))
+ node.setAttribute("style:text-crossing-out", "single-line");
+
+ if (fmt.getAttribute(Format.SUPERSCRIPT))
+ node.setAttribute("style:text-position", "super 58%");
+
+ if (fmt.getAttribute(Format.SUBSCRIPT))
+ node.setAttribute("style:text-position", "sub 58%");
+
+ if (fmt.getFontSize() != 0) {
+ Integer fs = new Integer(fmt.getFontSize());
+ node.setAttribute("fo:font-size", fs.toString() + "pt");
+ }
+
+ if (fmt.getFontName() != null)
+ node.setAttribute("style:font-name", fmt.getFontName());
+
+ if (fmt.getForeground() != null)
+ node.setAttribute("fo:color", buildColorString(fmt.getForeground()));
+
+ if (fmt.getBackground() != null)
+ node.setAttribute("fo:background-color",
+ buildColorString(fmt.getBackground()));
+
+ if (fmt.getAttribute(Format.TOP_BORDER))
+ node.setAttribute("fo:border-top", "0.0008inch solid #000000");
+
+ if (fmt.getAttribute(Format.BOTTOM_BORDER))
+ node.setAttribute("fo:border-bottom", "0.0008inch solid #000000");
+
+ if (fmt.getAttribute(Format.RIGHT_BORDER))
+ node.setAttribute("fo:border-right", "0.0008inch solid #000000");
+
+ if (fmt.getAttribute(Format.LEFT_BORDER))
+ node.setAttribute("fo:border-left", "0.0008inch solid #000000");
+
+ if (fmt.getAttribute(Format.WORD_WRAP))
+ node.setAttribute("fo:wrap-option", "wrap");
+
+ }
+
+
+ /**
+ * Given a <code>Color</code>, return a string of the form
+ * <i>#rrggbb</i>.
+ *
+ * @param c The <code>Color</code> value.
+ *
+ * @return The <code>Color</code> value in the form <i>#rrggbb</i>.
+ */
+ private String buildColorString(Color c) {
+ int v[] = new int[3];
+ v[0] = c.getRed();
+ v[1] = c.getGreen();
+ v[2] = c.getBlue();
+ String colorString = new String("#");
+ for (int i = 0; i <= 2; i++) {
+ String xx = Integer.toHexString(v[i]);
+ if (xx.length() < 2)
+ xx = "0" + xx;
+ colorString += xx;
+ }
+ return colorString;
+ }
+
+
+ private static String[] ignored = {
+ "style:text-autospace", "style:text-underline-color",
+ "fo:margin-left", "fo:margin-right", "fo:text-indent",
+ "fo:margin-top", "fo:margin-bottom", "text:line-number",
+ "text:number-lines", "style:country-asian",
+ "style:font-size-asian", "style:font-name-complex",
+ "style:language-complex", "style:country-complex",
+ "style:font-size-complex", "style:punctuation-wrap",
+ "fo:language", "fo:country",
+ "style:font-name-asian", "style:language-asian",
+ "style:line-break", "fo:keep-with-next"
+ };
+
+
+ /*
+ * This code checks whether an attribute is one that we
+ * intentionally ignore.
+ *
+ * @param attribute The attribute to check.
+ *
+ * @return true if <code>attribute</code> can be ignored,
+ * otherwise false.
+ */
+ private boolean isIgnored(String attribute) {
+ for (int i = 0; i < ignored.length; i++) {
+ if (ignored[i].equals(attribute))
+ return true;
+ }
+ return false;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/ColumnRowInfo.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/ColumnRowInfo.java
new file mode 100644
index 000000000000..14c1dbfc8e77
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/ColumnRowInfo.java
@@ -0,0 +1,195 @@
+/*************************************************************************
+ *
+ * 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.sxc;
+
+/**
+ * This is a class to define a table-column structure. This can then be
+ * used by plugins to write or read their own column types.
+ *
+ * @author Martin Maher
+ */
+public class ColumnRowInfo {
+
+ final public static int COLUMN = 0x01;
+ final public static int ROW = 0x02;
+
+ final private static int DEFAULTROWSIZE_MIN = 250;
+ final private static int DEFAULTROWSIZE_MAX = 260;
+
+ private int type;
+ private int dimension = 0;
+ private int repeated = 1;
+ private boolean userDefined = true;
+ private Format fmt = new Format();
+
+ /**
+ * Constructor for a <code>ColumnRowInfo</code>
+ *
+ * @param dimension if it's a row the height, a column the width
+ * @param repeated
+ */
+ public ColumnRowInfo(int type) {
+
+ this.type = type;
+ }
+
+ /**
+ * Constructor for a <code>ColumnRowInfo</code>
+ *
+ * @param dimension if it's a row the height, a column the width
+ * @param repeated how many times it is repeated
+ * @param type whether Row or column record
+ */
+ public ColumnRowInfo(int dimension, int repeated, int type) {
+
+ this.dimension = dimension;
+ this.repeated = repeated;
+ this.type = type;
+ }
+
+ /**
+ * Constructor that includes userDefined field
+ *
+ * @param userDefined whether the record is manually set
+ */
+ public ColumnRowInfo(int dimension, int repeated, int type, boolean userDefined) {
+
+ this(dimension, repeated, type);
+ this.userDefined = userDefined;
+ }
+
+ /**
+ * sets the definition
+ *
+ * @param newDefinition sets the definition
+ */
+ public void setFormat(Format fmt) {
+
+ this.fmt = fmt;
+ }
+
+ /**
+ * returns Name of the definition
+ *
+ * @return the name which identifies the definition
+ */
+ public Format getFormat() {
+
+ return fmt;
+ }
+
+ /**
+ * returns Name of the definition
+ *
+ * @return the name which identifies the definition
+ */
+ public int getSize() {
+
+ return dimension;
+ }
+
+ /**
+ * sets the definition
+ *
+ * @param newDefinition sets the definition
+ */
+ public void setSize(int dimension) {
+
+ this.dimension = dimension;
+ }
+ /**
+ * Returns the definition itself
+ *
+ * @return the definition
+ */
+ public int getRepeated() {
+
+ return repeated;
+ }
+
+ /**
+ * Returns the base Cell address
+ *
+ * @return the base cell address
+ */
+ public void setRepeated(int repeated) {
+
+ this.repeated = repeated;
+ }
+
+ /**
+ * Returns the definition itself
+ *
+ * @return the definition
+ */
+ public boolean isRow() {
+
+ if(type==ROW)
+ return true;
+ else
+ return false;
+ }
+
+ /**
+ * Returns the base Cell address
+ *
+ * @return the base cell address
+ */
+ public boolean isColumn() {
+
+ if(type==COLUMN)
+ return true;
+ else
+ return false;
+ }
+
+ /**
+ * Test if the row height as been set manually
+ *
+ * @return true if user defined otherwise false
+ */
+ public boolean isUserDefined() {
+
+ return userDefined;
+ }
+
+ /**
+ * Test if the row height is default
+ *
+ * @return true if default otherwise false
+ */
+ public boolean isDefaultSize() {
+
+ if( type==ROW &&
+ dimension>DEFAULTROWSIZE_MIN &&
+ dimension<DEFAULTROWSIZE_MAX)
+ return true;
+ else
+ return false;
+ }
+}
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/ColumnStyle.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/ColumnStyle.java
new file mode 100644
index 000000000000..76c742b57496
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/ColumnStyle.java
@@ -0,0 +1,300 @@
+/*************************************************************************
+ *
+ * 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.sxc;
+
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Element;
+
+import org.openoffice.xmerge.converter.xml.Style;
+import org.openoffice.xmerge.converter.xml.StyleCatalog;
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.TwipsConverter;
+
+/**
+ * Represents a text <code>Style</code> in an OpenOffice document.
+ *
+ * @author Martin Maher
+ */
+public class ColumnStyle extends Style implements Cloneable {
+
+ private int colWidth = 0;
+ /**
+ * Constructor for use when going from DOM to client device format.
+ *
+ * @param Node The <i>style:style</i> <code>Node</code> containing
+ * the <code>Style</code>. (This <code>Node</code> is
+ * assumed have a <i>family</i> attribute of <i>text</i>).
+ * @param sc The <code>StyleCatalog</code>, which is used for
+ * looking up ancestor <code>Style</code> objects.
+ */
+ public ColumnStyle(Node node, StyleCatalog sc) {
+ super(node, sc);
+
+ // Run through the attributes of this node, saving
+ // the ones we're interested in.
+ NamedNodeMap attrNodes = node.getAttributes();
+ if (attrNodes != null) {
+ int len = attrNodes.getLength();
+ for (int i = 0; i < len; i++) {
+ Node attr = attrNodes.item(i);
+ handleAttribute(attr.getNodeName(), attr.getNodeValue());
+ }
+ }
+
+ // 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);
+ handleAttribute(attr.getNodeName(),
+ attr.getNodeValue());
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Constructor for use when going from client device format to DOM
+ *
+ * @param name Name of text <code>Style</code>. Can be null.
+ * @param family Family of text <code>Style</code> (usually
+ * <i>text</i>). Can be null.
+ * @param parent Name of parent text <code>Style</code>, or null
+ * for none.
+ * @param mask the width of this column
+ * @param sc The <code>StyleCatalog</code>, which is used for
+ * looking up ancestor <code>Style</code> objects.
+ */
+ public ColumnStyle(String name, String family, String parent,int colWidth, StyleCatalog sc) {
+ super(name, family, parent, sc);
+ this.colWidth = colWidth;
+ }
+
+ /**
+ * Returns the width of this column
+ *
+ * @return the <code>Format</code> object
+ */
+ public int getColWidth() {
+ return colWidth;
+ }
+
+ /**
+ * Sets the width of this column
+ *
+ * @return the <code>Format</code> object
+ */
+ public void setColWidth(int colWidth) {
+
+ this.colWidth = colWidth;
+ }
+
+ /**
+ * Parse a colwidth in the form "1.234cm" to twips
+ *
+ * @param value <code>String</code> specification to parse.
+ *
+ * @return The twips equivalent.
+ */
+ private int parseColWidth(String value) {
+
+ int width = 255; // Default value
+
+ if(value.indexOf("cm")!=-1) {
+ float widthCM = Float.parseFloat(value.substring(0,value.indexOf("c")));
+ width = TwipsConverter.cm2twips(widthCM);
+ } else if(value.indexOf("inch")!=-1) {
+ float widthInch = Float.parseFloat(value.substring(0,value.indexOf("i")));
+ width = TwipsConverter.inches2twips(widthInch);
+ }
+
+ return (width);
+ }
+
+
+ /**
+ * Set an attribute.
+ *
+ * @param attr The attribute to set.
+ * @param value The attribute value to set.
+ */
+ private void handleAttribute(String attr, String value) {
+
+ if (attr.equals("style:column-width")) {
+ colWidth = parseColWidth(value);
+ }
+ else {
+ Debug.log(Debug.INFO, "ColumnStyle Unhandled: " + attr + "=" + value);
+ }
+ }
+
+
+ /**
+ * Return a <code>Style</code> object corresponding to this one,
+ * but with all of the inherited information from parent
+ * <code>Style</code> objects filled in. The object returned will
+ * be a new object, not a reference to this object, even if it does
+ * not need any information added.
+ *
+ * @return The <code>StyleCatalog</code> in which to look up
+ * ancestors.
+ */
+ public Style getResolved() {
+ // Create a new object to return, which is a clone of this one.
+ ColumnStyle resolved = null;
+ try {
+ resolved = (ColumnStyle)this.clone();
+ } catch (Exception e) {
+ Debug.log(Debug.ERROR, "Can't clone", e);
+ }
+
+ // Look up the parentStyle. (If there is no style catalog
+ // specified, we can't do any lookups.)
+ ColumnStyle parentStyle = null;
+ if (sc != null) {
+ if (parent != null) {
+ parentStyle = (ColumnStyle)sc.lookup(parent, family, null,
+ this.getClass());
+ if (parentStyle == null)
+ Debug.log(Debug.ERROR, "parent style lookup of "
+ + parent + " failed!");
+ else
+ parentStyle = (ColumnStyle)parentStyle.getResolved();
+
+ } else if (!name.equals("DEFAULT_STYLE")) {
+ parentStyle = (ColumnStyle)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 = (ColumnStyle)parentStyle.getResolved();
+
+ if ((colWidth == 0) && (parentStyle.getColWidth() != 0))
+ resolved.setColWidth(parentStyle.getColWidth());
+ }
+ return resolved;
+ }
+
+
+ /**
+ * Create a new <code>Node</code> in the <code>Document</code>, and
+ * write this <code>Style</code> to it.
+ *
+ * @param parentDoc Parent <code>Document</code> of the
+ * <code>Node</code> to create.
+ * @param name Name to use for the new <code>Node</code> (e.g.
+ * <i>style:style</i>)
+ *
+ * @return 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> specifies as much or less
+ * than this <code>Style</code>, and nothing it specifies
+ * contradicts this <code>Style</code>.
+ *
+ * @param style The <code>Style</code> to check.
+ *
+ * @return true if <code>style</code> is a subset, false
+ * otherwise.
+ */
+ public boolean isSubset(Style style) {
+ if (style.getClass() != this.getClass())
+ return false;
+ ColumnStyle tStyle = (ColumnStyle)style;
+
+ if(colWidth!=tStyle.getColWidth())
+ return false;
+
+ return true;
+ }
+
+
+ /**
+ * Write this <code>Style</code> object's attributes to a
+ * <code>Node</code> in the <code>Document</code>.
+ *
+ * @param node The <code>Node</code> to add <code>Style</code>
+ * attributes.
+ */
+ public void writeAttributes(Element node) {
+
+ if(colWidth!=0) {
+ String width = TwipsConverter.twips2cm(colWidth) + "cm";
+ node.setAttribute("style:column-width", width);
+ }
+ }
+
+
+ private static String[] ignored = {
+ "fo:break-before", "fo:keep-with-next"
+ };
+
+
+ /*
+ * This code checks whether an attribute is one that we
+ * intentionally ignore.
+ *
+ * @param attribute The attribute to check.
+ *
+ * @return true if <code>attribute</code> can be ignored,
+ * otherwise false.
+ */
+ private boolean isIgnored(String attribute) {
+ for (int i = 0; i < ignored.length; i++) {
+ if (ignored[i].equals(attribute))
+ return true;
+ }
+ return false;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/DocumentMergerImpl.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/DocumentMergerImpl.java
new file mode 100644
index 000000000000..2fa5f22303b2
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/DocumentMergerImpl.java
@@ -0,0 +1,198 @@
+/*************************************************************************
+ *
+ * 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.sxc;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.DocumentMerger;
+import org.openoffice.xmerge.MergeException;
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+import org.openoffice.xmerge.merger.DiffAlgorithm;
+import org.openoffice.xmerge.merger.Difference;
+import org.openoffice.xmerge.merger.Iterator;
+import org.openoffice.xmerge.merger.NodeMergeAlgorithm;
+import org.openoffice.xmerge.merger.diff.IteratorRowCompare;
+import org.openoffice.xmerge.merger.diff.RowIterator;
+import org.openoffice.xmerge.merger.merge.SheetMerge;
+import org.openoffice.xmerge.merger.merge.PositionBaseRowMerge;
+import org.openoffice.xmerge.merger.MergeAlgorithm;
+import org.openoffice.xmerge.util.XmlUtil;
+import org.openoffice.xmerge.util.Debug;
+
+
+/**
+ * Generic small device implementation of <code>DocumentMerger</code> for
+ * the {@link
+ * org.openoffice.xmerge.converter.xml.sxc.SxcPluginFactory
+ * SxcPluginFactory}. Used with SXC <code>Document</code> objects.</p>
+ */
+public class DocumentMergerImpl implements DocumentMerger {
+
+ private ConverterCapabilities cc_;
+ private org.openoffice.xmerge.Document orig = null;
+
+ /**
+ * Constructor
+ *
+ * @param doc The original &quot;Office&quot; <code>Document</code>
+ * to merge.
+ * @param cc The <code>ConverterCapabilities</code>.
+ */
+ public DocumentMergerImpl(org.openoffice.xmerge.Document doc, ConverterCapabilities cc) {
+ cc_ = cc;
+ this.orig = doc;
+ }
+
+ public void merge(Document modifiedDoc) throws MergeException {
+
+ SxcDocument sdoc1 = (SxcDocument)orig;
+ SxcDocument sdoc2 = (SxcDocument)modifiedDoc;
+
+ org.w3c.dom.Document doc1 = sdoc1.getContentDOM();
+ org.w3c.dom.Document doc2 = sdoc2.getContentDOM();
+
+ Element elem1 = doc1.getDocumentElement();
+ Element elem2 = doc2.getDocumentElement();
+
+ // get table name
+ NodeList workSheetList1 =
+ elem1.getElementsByTagName(OfficeConstants.TAG_TABLE);
+ NodeList workSheetList2 =
+ elem2.getElementsByTagName(OfficeConstants.TAG_TABLE);
+
+ int numOfWorkSheet = workSheetList1.getLength();
+
+ for (int i=0; i < numOfWorkSheet; i++) {
+ Node workSheet = workSheetList1.item(i);
+
+ // try to match the workSheet
+ Node matchingWorkSheet = matchWorkSheet(workSheet, workSheetList2);
+
+ if (matchingWorkSheet != null) {
+
+ // need to put it into a row Iterator
+ // use a straight comparsion algorithm then do a merge on it
+ Iterator i1 = new RowIterator(cc_, workSheet);
+ Iterator i2 = new RowIterator(cc_, matchingWorkSheet);
+
+ // find out the diff
+ DiffAlgorithm diffAlgo = new IteratorRowCompare();
+
+ // find out the paragrah level diffs
+ Difference[] diffResult = diffAlgo.computeDiffs(i1, i2);
+
+ if (Debug.isFlagSet(Debug.INFO)) {
+ Debug.log(Debug.INFO, "Diff Result: ");
+
+ for (int j = 0; j < diffResult.length; j++) {
+ Debug.log(Debug.INFO, diffResult[j].debug());
+ }
+ }
+
+ // merge back the result
+ NodeMergeAlgorithm rowMerger = new PositionBaseRowMerge(cc_);
+ MergeAlgorithm merger = new SheetMerge(cc_, rowMerger);
+
+ Iterator result = null;
+
+ merger.applyDifference(i1, i2, diffResult);
+ }
+ }
+
+ numOfWorkSheet = workSheetList2.getLength();
+
+ // for those workSheet from target don't have a matching one
+ // in the original workSheet list, we add it
+
+ // find out the office body node first
+ NodeList officeBodyList =
+ elem1.getElementsByTagName(OfficeConstants.TAG_OFFICE_BODY);
+
+ Node officeBody = officeBodyList.item(0);
+
+ // for each WorkSheets, try to see whether we have it or not
+ for (int j=0; j < numOfWorkSheet; j++) {
+ Node workSheet= workSheetList2.item(j);
+
+ // try to match the workSheet
+ //
+ Node matchingWorkSheet = matchWorkSheet(workSheet, workSheetList1);
+
+ // add the new WorkSheet to the original document iff match not
+ // found
+ //
+ if (matchingWorkSheet == null) {
+ Node cloneNode = XmlUtil.deepClone(officeBody, workSheet);
+ officeBody.appendChild(cloneNode);
+ }
+ }
+ }
+
+ /**
+ * Try to find a WorkSheet from the modified WorkSheetList that
+ * has a matching table name from the original WorkSheet.
+ *
+ * @param orgSheet The original WorkSheet.
+ * @param modSheetList The modified WorkSheet.
+ *
+ * @return The Node in modSheetList that matches the orgSheet.
+ */
+ private Node matchWorkSheet(Node orgSheet, NodeList modSheetList) {
+
+ Node matchSheet = null;
+
+ String orgTableName = ((Element)orgSheet).getAttribute(
+ OfficeConstants.ATTRIBUTE_TABLE_NAME);
+
+ if (orgTableName == null)
+ return null;
+
+ int numOfWorkSheet = modSheetList.getLength();
+
+ String modTableName;
+
+ for (int i=0; i < numOfWorkSheet; i++) {
+ modTableName = ((Element)modSheetList.item(i)).getAttribute(
+ OfficeConstants.ATTRIBUTE_TABLE_NAME);
+ if (modTableName == null)
+ continue;
+
+ if (orgTableName.equals(modTableName)) {
+ matchSheet = modSheetList.item(i);
+ break;
+ }
+ }
+
+ return matchSheet;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/Format.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/Format.java
new file mode 100644
index 000000000000..2bb836a7303d
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/Format.java
@@ -0,0 +1,475 @@
+/*************************************************************************
+ *
+ * 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.sxc;
+
+import java.awt.Color;
+
+/**
+ * This class specifies the format for a given spreadsheet cell.
+ *
+ * @author Mark Murnane
+ * @author Martin Maher (Extended Style Support)
+ */
+public class Format implements Cloneable {
+
+ /** Horizontal Alignment Constants. */
+ final public static int RIGHT_ALIGN = 0x01;
+ final public static int CENTER_ALIGN = 0x02;
+ final public static int LEFT_ALIGN = 0x03;
+ final public static int JUST_ALIGN = 0x04;
+
+ /** Vertical Alignment Constants. */
+ final public static int TOP_ALIGN = 0x01;
+ final public static int MIDDLE_ALIGN = 0x02;
+ final public static int BOTTOM_ALIGN = 0x03;
+
+ /** Indicates <i>bold</i> text. */
+ final public static int BOLD = 0x01;
+ /** Indicates <i>italic</i> text. */
+ final public static int ITALIC = 0x02;
+ /** Indicates <i>underlined</i> text. */
+ final public static int UNDERLINE = 0x04;
+ /** Indicates <i>strike-through</i> in the text. */
+ final public static int STRIKETHRU = 0x08;
+ /** Indicates <i>superscripted</i> text. */
+ final public static int SUPERSCRIPT = 0x10;
+ /** Indicates <i>subscripted</i> text. */
+ final public static int SUBSCRIPT = 0x20;
+
+ final public static int LEFT_BORDER = 0x40;
+ final public static int RIGHT_BORDER = 0x80;
+ final public static int TOP_BORDER = 0x100;
+ final public static int BOTTOM_BORDER = 0x200;
+
+ final public static int WORD_WRAP = 0x400;
+
+ private int align;
+ private int vertAlign;
+ private String category;
+ private String value;
+ private String formatSpecifier;
+ private int decimalPlaces;
+
+ /** Font name. */
+ private String fontName;
+ /** Font size in points. */
+ protected int sizeInPoints;
+
+ private Color foreground, background;
+
+ /** Values of text attributes. */
+ protected int attributes = 0;
+ /** Bitwise mask of text attributes. */
+ protected int mask = 0;
+
+ /**
+ * Constructor for creating a new <code>Format</code>.
+ */
+ public Format() {
+ clearFormatting();
+ }
+
+ /**
+ * Constructor that creates a new <code>Format</code> object
+ * by setting all the format attributes.
+ *
+ */
+ public Format(int attributes, int fontSize, String fontName) {
+
+ this.attributes = attributes;
+ sizeInPoints = fontSize;
+ this.fontName = fontName;
+ }
+
+ /**
+ * Constructor for creating a new <code>Format</code> object
+ * based on an existing one.
+ *
+ * @param fmt <code>Format</code> to copy.
+ */
+ public Format(Format fmt) {
+ category = fmt.getCategory();
+ value = fmt.getValue();
+ formatSpecifier = fmt.getFormatSpecifier();
+ decimalPlaces = fmt.getDecimalPlaces();
+
+ attributes = fmt.attributes;
+ mask = fmt.mask;
+
+ fontName = fmt.getFontName();
+ align = fmt.getAlign();
+ vertAlign = fmt.getVertAlign();
+ foreground = fmt.getForeground();
+ background = fmt.getBackground();
+ sizeInPoints = fmt.sizeInPoints;
+ }
+
+
+ /**
+ * Reset this <code>Format</code> description.
+ */
+ public void clearFormatting() {
+ category = "";
+ value = "";
+ formatSpecifier = "";
+ decimalPlaces = 0;
+ attributes = 0;
+ mask = 0;
+ sizeInPoints = 10;
+ align = LEFT_ALIGN;
+ vertAlign = BOTTOM_ALIGN;
+ fontName = "";
+ foreground = null;
+ background = null;
+ }
+
+ /**
+ * Set one or more text attributes to <i>on</i>.
+ *
+ * @param flags Flag attributes to set <i>on</i>.
+ */
+ public void setAttribute(int flags, boolean toggle) {
+ mask |= flags;
+ if(toggle) {
+ attributes |= flags;
+ } else {
+ attributes &= ~flags;
+ }
+ }
+
+ /**
+ * Return true if the <code>attribute</code> is set to <i>on</i>
+ *
+ * @param attribute Attribute to check ({@link #BOLD},
+ * {@link #ITALIC}, etc.)
+ *
+ * @return true if <code>attribute</code> is set to <i>on</i>,
+ * otherwise false.
+ */
+ public boolean getAttribute(int attribute) {
+ if ((mask & attribute) == 0)
+ return false;
+ return (!((attributes & attribute) == 0));
+ }
+
+ /**
+ * Return true if text <code>attribute</code> is set in this
+ * <code>Style</code>.An attribute that is set may have a
+ * value of <i>on</i> or <i>off</i>.
+ *
+ * @param attribute The attribute to check ({@link #BOLD},
+ * {@link #ITALIC}, etc.).
+ *
+ * @return true if text <code>attribute</code> is set in this
+ * <code>Style</code>, false otherwise.
+ */
+ public boolean isSet(int attribute) {
+ return (!((mask & attribute) == 0));
+ }
+
+
+ /**
+ * Set the formatting category of this object, ie number, date,
+ * currency.The <code>OfficeConstants</code> class contains string
+ * constants for the category types.
+ *
+ * @see org.openoffice.xmerge.converter.xml.OfficeConstants
+ *
+ * @param newCategory The name of the category to be set.
+ */
+ public void setCategory(String newCategory) {
+ category = newCategory;
+ }
+
+ /**
+ * Return the formatting category of the object.
+ *
+ * @see org.openoffice.xmerge.converter.xml.OfficeConstants
+ *
+ * @return The formatting category of the object.
+ */
+ public String getCategory() {
+ return category;
+ }
+
+ /**
+ * In the case of Formula returns the value of the formula.
+ *
+ * @return The value of the formula
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * In the case of formula the contents are set as the formula string and
+ * the value of the formula is a formatting attribute.
+ *
+ * @param newValue the formuala value
+ */
+ public void setValue(String newValue) {
+ value = newValue;
+ }
+
+
+ /**
+ * Set the <code>Format</code> specifier for this category.
+ *
+ * @param formatString The new <code>Format</code> specifier.
+ */
+ public void setFormatSpecifier(String formatString) {
+ formatSpecifier = formatString;
+ }
+
+
+ /**
+ * Get the <code>Format</code> specifier for this category.
+ *
+ * @return <code>Format</code> specifier for this category.
+ */
+ public String getFormatSpecifier() {
+ return formatSpecifier;
+ }
+
+
+ /**
+ * Set the precision of the number to be displayed.
+ *
+ * @param precision The number of decimal places to display.
+ */
+ public void setDecimalPlaces(int precision) {
+ decimalPlaces = precision;
+ }
+
+
+ /**
+ * Get the number of decimal places displayed.
+ *
+ * @return Number of decimal places.
+ */
+ public int getDecimalPlaces() {
+ return decimalPlaces;
+ }
+
+
+ /**
+ * Set the font used for this cell.
+ *
+ * @param fontName The name of the font.
+ */
+ public void setFontName(String fontName) {
+ this.fontName = fontName;
+ }
+
+
+ /**
+ * Get the font used for this cell.
+ *
+ * @return The font name.
+ */
+ public String getFontName() {
+ return fontName;
+ }
+
+ /**
+ * Set the font used for this cell.
+ *
+ * @param fontName The name of the font.
+ */
+ public void setFontSize(int fontSize) {
+ sizeInPoints = fontSize;
+ }
+
+
+ /**
+ * Get the font used for this cell.
+ *
+ * @return The font name.
+ */
+ public int getFontSize() {
+ return sizeInPoints;
+ }
+
+ /**
+ * Set the alignmen used for this cell.
+ *
+ * @param fontName The name of the font.
+ */
+ public void setVertAlign(int vertAlign) {
+ this.vertAlign = vertAlign;
+ }
+
+
+ /**
+ * Get the alignment used for this cell.
+ *
+ * @return The font name.
+ */
+ public int getVertAlign() {
+ return vertAlign;
+ }
+
+ /**
+ * Set the alignmen used for this cell.
+ *
+ * @param fontName The name of the font.
+ */
+ public void setAlign(int align) {
+ this.align = align;
+ }
+
+
+ /**
+ * Get the alignment used for this cell.
+ *
+ * @return The font name.
+ */
+ public int getAlign() {
+ return align;
+ }
+ /**
+ * Set the Foreground <code>Color</code> for this cell.
+ *
+ * @param color A <code>Color</code> object representing the
+ * foreground color.
+ */
+ public void setForeground(Color c) {
+ if(c!=null)
+ foreground = new Color(c.getRGB());
+ }
+
+
+ /**
+ * Get the Foreground <code>Color</code> for this cell.
+ *
+ * @return Foreground <code>Color</code> value.
+ */
+ public Color getForeground() {
+ return foreground;
+ }
+
+
+ /**
+ * Set the Background <code>Color</code> for this cell
+ *
+ * @param color A <code>Color</code> object representing
+ * the background color.
+ */
+ public void setBackground(Color c) {
+ if(c!=null)
+ background = new Color(c.getRGB());
+ }
+
+
+ /**
+ * Get the Foreground <code>Color</code> for this cell
+ *
+ * @return Background <code>Color</code> value
+ */
+ public Color getBackground() {
+ return background;
+ }
+
+ /**
+ * Get the Foreground <code>Color</code> for this cell
+ *
+ * @return Background <code>Color</code> value
+ */
+ public String toString() {
+ return new String("Value : " + getValue() + " Category : " + getCategory());
+ }
+
+ /**
+ * Tests if the current <code>Format</code> object has default attribute
+ * values.
+ *
+ * @return true if it contains default value
+ */
+ public boolean isDefault() {
+
+ Format rhs = new Format();
+
+ if (rhs.attributes!= attributes)
+ return false;
+
+ if (foreground!=rhs.foreground)
+ return false;
+
+ if (background!=rhs.background)
+ return false;
+
+ if (rhs.align!= align)
+ return false;
+
+ if (rhs.vertAlign!= vertAlign)
+ return false;
+
+ return true;
+ }
+
+ /**
+ * Return true if <code>style</code> specifies as much or less
+ * than this <code>Style</code>, and nothing it specifies
+ * contradicts this <code>Style</code>.
+ *
+ * @param style The <code>Style</code> to check.
+ *
+ * @return true if <code>style</code> is a subset, false
+ * otherwise.
+ */
+ public boolean isSubset(Format rhs) {
+ if (rhs.getClass() != this.getClass())
+ return false;
+
+ if (rhs.attributes!= attributes)
+ return false;
+
+ if (rhs.sizeInPoints != 0) {
+ if (sizeInPoints != rhs.sizeInPoints)
+ return false;
+ }
+
+ if (fontName!=rhs.fontName)
+ return false;
+
+ if (foreground!=rhs.foreground)
+ return false;
+
+ if (background!=rhs.background)
+ return false;
+
+ if (rhs.align!= align)
+ return false;
+
+ if (rhs.vertAlign!= vertAlign)
+ return false;
+
+ return true;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/NameDefinition.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/NameDefinition.java
new file mode 100644
index 000000000000..de83543fd86e
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/NameDefinition.java
@@ -0,0 +1,215 @@
+/*************************************************************************
+ *
+ * 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.sxc;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.XmlUtil;
+
+/**
+ * This is a class to define a Name Definition structure. This can then be
+ * used by plugins to write or read their own definition types.
+ *
+ * @author Martin Maher
+ */
+public class NameDefinition implements OfficeConstants {
+
+ private String name; // name which identifies the definition
+ private String definition; // the definition itself
+ private String baseCellAddress; // the basecelladdress
+ private boolean rangeType = false; // true if definition of type range
+ private boolean expressionType = false; // true if definition of type expression
+
+ /**
+ * Default Constructor for a <code>NameDefinition</code>
+ *
+ */
+ public NameDefinition() {
+
+ }
+
+ /**
+ * Constructor that takes a <code>Node</code> to build a
+ * <code>NameDefinition</code>
+ *
+ * @param root XML Node to read from
+ */
+ public NameDefinition(Node root) {
+ readNode(root);
+ }
+
+ /**
+ * Default Constructor for a <code>NameDefinition</code>
+ *
+ */
+ public NameDefinition(String name, String definition, String
+ baseCellAddress, boolean rangeType, boolean expressionType ) {
+ this.name = name;
+ this.definition = definition;
+ this.baseCellAddress = baseCellAddress;
+ this.rangeType = rangeType;
+ this.expressionType = expressionType;
+ }
+
+ /**
+ * returns Name of the definition
+ *
+ * @return the name which identifies the definition
+ */
+ public String getName() {
+
+ return name;
+ }
+ /**
+ * sets the definition
+ *
+ * @param newDefinition sets the definition
+ */
+ public void setDefinition(String newDefinition) {
+
+ definition = newDefinition;
+ }
+ /**
+ * Returns the definition itself
+ *
+ * @return the definition
+ */
+ public String getDefinition() {
+
+ return definition;
+ }
+
+ /**
+ * Returns the base Cell address
+ *
+ * @return the base cell address
+ */
+ public String getBaseCellAddress() {
+
+ return baseCellAddress;
+ }
+
+ /**
+ * Tests if definition is of type expression
+ *
+ * @return whether or not this name definition is of type expression
+ */
+ public boolean isExpressionType() {
+ return expressionType;
+ }
+
+ /**
+ * Tests if definition is of type range
+ *
+ * @return whether or not this name definition is of type range
+ */
+ public boolean isRangeType() {
+ return rangeType;
+ }
+
+ /**
+ * Writes out a content.xml entry for this NameDefinition object
+ *
+ * @param settings a <code>Document</code> object representing the settings.xml
+ * @param root the root xml node to add to
+ */
+ public void writeNode(org.w3c.dom.Document doc, Node root) {
+
+ if(isRangeType()) {
+
+ Debug.log(Debug.TRACE, "Found Range Name : " + getName());
+ Element namedRangeElement = (Element) doc.createElement(TAG_TABLE_NAMED_RANGE);
+ namedRangeElement.setAttribute(ATTRIBUTE_TABLE_NAME, getName());
+ namedRangeElement.setAttribute(ATTRIBUTE_TABLE_BASE_CELL_ADDRESS, getBaseCellAddress());
+ namedRangeElement.setAttribute(ATTRIBUTE_TABLE_CELL_RANGE_ADDRESS, getDefinition());
+ root.appendChild(namedRangeElement);
+ } else if (isExpressionType()) {
+
+ Debug.log(Debug.TRACE, "Found Expression Name : " + getName());
+ Element namedExpressionElement = (Element) doc.createElement(TAG_TABLE_NAMED_EXPRESSION);
+ namedExpressionElement.setAttribute(ATTRIBUTE_TABLE_NAME, getName());
+ namedExpressionElement.setAttribute(ATTRIBUTE_TABLE_BASE_CELL_ADDRESS,getBaseCellAddress());
+ namedExpressionElement.setAttribute(ATTRIBUTE_TABLE_EXPRESSION, getDefinition());
+ root.appendChild(namedExpressionElement);
+ } else {
+
+ Debug.log(Debug.TRACE, "Unknown Name Definition : " + getName());
+ }
+ }
+
+ /**
+ * Reads document settings from xml and inits Settings variables
+ *
+ * @param root XML Node to read from
+ */
+ public void readNode(Node root) {
+
+ String nodeName = root.getNodeName();
+ NamedNodeMap cellAtt = root.getAttributes();
+
+ if (nodeName.equals(TAG_TABLE_NAMED_RANGE)) {
+
+ Node tableNameNode =
+ cellAtt.getNamedItem(ATTRIBUTE_TABLE_NAME);
+ Node tableBaseCellAddress =
+ cellAtt.getNamedItem(ATTRIBUTE_TABLE_BASE_CELL_ADDRESS);
+ Node tableCellRangeAddress =
+ cellAtt.getNamedItem(ATTRIBUTE_TABLE_CELL_RANGE_ADDRESS);
+ Debug.log(Debug.TRACE,"Named-range : " + tableNameNode.getNodeValue());
+ // Create a named-range name definition
+ name = tableNameNode.getNodeValue();
+ definition = tableCellRangeAddress.getNodeValue();
+ baseCellAddress = tableBaseCellAddress.getNodeValue();
+ expressionType = true;
+ rangeType = false;
+
+ } else if (nodeName.equals(TAG_TABLE_NAMED_EXPRESSION)) {
+
+ Node tableNameNode =
+ cellAtt.getNamedItem(ATTRIBUTE_TABLE_NAME);
+ Node tableBaseCellAddress =
+ cellAtt.getNamedItem(ATTRIBUTE_TABLE_BASE_CELL_ADDRESS);
+ Node tableExpression=
+ cellAtt.getNamedItem(ATTRIBUTE_TABLE_EXPRESSION);
+ Debug.log(Debug.TRACE,"Named-expression: " + tableNameNode.getNodeValue());
+ // Create a named-range name definition
+ name = tableNameNode.getNodeValue();
+ definition = tableExpression.getNodeValue();
+ baseCellAddress = tableBaseCellAddress.getNodeValue();
+ expressionType = false;
+ rangeType = true;
+ } else {
+ Debug.log(Debug.TRACE, "<OTHERS " + XmlUtil.getNodeInfo(root) + " />");
+ }
+ }
+
+}
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/RowStyle.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/RowStyle.java
new file mode 100644
index 000000000000..2b4ce04a13f0
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/RowStyle.java
@@ -0,0 +1,300 @@
+/*************************************************************************
+ *
+ * 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.sxc;
+
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Element;
+
+import org.openoffice.xmerge.converter.xml.Style;
+import org.openoffice.xmerge.converter.xml.StyleCatalog;
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.TwipsConverter;
+
+/**
+ * Represents a text <code>Style</code> in an OpenOffice document.
+ *
+ * @author Martin Maher
+ */
+public class RowStyle extends Style implements Cloneable {
+
+ private int rowHeight = 255;
+ /**
+ * Constructor for use when going from DOM to client device format.
+ *
+ * @param Node The <i>style:style</i> <code>Node</code> containing
+ * the <code>Style</code>. (This <code>Node</code> is
+ * assumed have a <i>family</i> attribute of <i>text</i>).
+ * @param sc The <code>StyleCatalog</code>, which is used for
+ * looking up ancestor <code>Style</code> objects.
+ */
+ public RowStyle(Node node, StyleCatalog sc) {
+ super(node, sc);
+
+ // Run through the attributes of this node, saving
+ // the ones we're interested in.
+ NamedNodeMap attrNodes = node.getAttributes();
+ if (attrNodes != null) {
+ int len = attrNodes.getLength();
+ for (int i = 0; i < len; i++) {
+ Node attr = attrNodes.item(i);
+ handleAttribute(attr.getNodeName(), attr.getNodeValue());
+ }
+ }
+
+ // 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);
+ handleAttribute(attr.getNodeName(),
+ attr.getNodeValue());
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Constructor for use when going from client device format to DOM
+ *
+ * @param name Name of text <code>Style</code>. Can be null.
+ * @param family Family of text <code>Style</code> (usually
+ * <i>text</i>). Can be null.
+ * @param parent Name of parent text <code>Style</code>, or null
+ * for none.
+ * @param mask The height of this row
+ * @param sc The <code>StyleCatalog</code>, which is used for
+ * looking up ancestor <code>Style</code> objects.
+ */
+ public RowStyle(String name, String family, String parent,int rowHeight, StyleCatalog sc) {
+ super(name, family, parent, sc);
+ this.rowHeight=rowHeight;
+ }
+
+ /**
+ * Returns the height of this row
+ *
+ * @return the <code>Format</code> object
+ */
+ public int getRowHeight() {
+ return rowHeight;
+ }
+
+ /**
+ * Sets the height of this row
+ *
+ * @return the <code>Format</code> object
+ */
+ public void setRowHeight(int RowHeight) {
+
+ this.rowHeight = rowHeight;
+ }
+ /**
+ * Parse a colheight in the form "1.234cm" to twips
+ *
+ * @param value <code>String</code> specification to parse.
+ *
+ * @return The twips equivalent.
+ */
+ private int parseRowHeight(String value) {
+
+ int height = 255; // Default value
+
+ if(value.indexOf("cm")!=-1) {
+ float heightCM = Float.parseFloat(value.substring(0,value.indexOf("c")));
+ height = TwipsConverter.cm2twips(heightCM);
+ } else if(value.indexOf("inch")!=-1) {
+ float heightInch = Float.parseFloat(value.substring(0,value.indexOf("i")));
+ height = TwipsConverter.inches2twips(heightInch);
+ }
+
+ return (height);
+
+ }
+
+
+ /**
+ * Set an attribute.
+ *
+ * @param attr The attribute to set.
+ * @param value The attribute value to set.
+ */
+ private void handleAttribute(String attr, String value) {
+
+ if (attr.equals("style:row-height")) {
+ rowHeight = parseRowHeight(value);
+ }
+ else {
+ Debug.log(Debug.INFO, "RowStyle Unhandled: " + attr + "=" + value);
+ }
+ }
+
+
+ /**
+ * Return a <code>Style</code> object corresponding to this one,
+ * but with all of the inherited information from parent
+ * <code>Style</code> objects filled in. The object returned will
+ * be a new object, not a reference to this object, even if it does
+ * not need any information added.
+ *
+ * @return The <code>StyleCatalog</code> in which to look up
+ * ancestors.
+ */
+ public Style getResolved() {
+ // Create a new object to return, which is a clone of this one.
+ RowStyle resolved = null;
+ try {
+ resolved = (RowStyle)this.clone();
+ } catch (Exception e) {
+ Debug.log(Debug.ERROR, "Can't clone", e);
+ }
+
+ // Look up the parentStyle. (If there is no style catalog
+ // specified, we can't do any lookups.)
+ RowStyle parentStyle = null;
+ if (sc != null) {
+ if (parent != null) {
+ parentStyle = (RowStyle)sc.lookup(parent, family, null,
+ this.getClass());
+ if (parentStyle == null)
+ Debug.log(Debug.ERROR, "parent style lookup of "
+ + parent + " failed!");
+ else
+ parentStyle = (RowStyle)parentStyle.getResolved();
+
+ } else if (!name.equals("DEFAULT_STYLE")) {
+ parentStyle = (RowStyle)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 = (RowStyle)parentStyle.getResolved();
+
+ if ((rowHeight == 0) && (parentStyle.getRowHeight() != 0))
+ resolved.setRowHeight(parentStyle.getRowHeight());
+ }
+ return resolved;
+ }
+
+
+ /**
+ * Create a new <code>Node</code> in the <code>Document</code>, and
+ * write this <code>Style</code> to it.
+ *
+ * @param parentDoc Parent <code>Document</code> of the
+ * <code>Node</code> to create.
+ * @param name Name to use for the new <code>Node</code> (e.g.
+ * <i>style:style</i>)
+ *
+ * @return 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> specifies as much or less
+ * than this <code>Style</code>, and nothing it specifies
+ * contradicts this <code>Style</code>.
+ *
+ * @param style The <code>Style</code> to check.
+ *
+ * @return true if <code>style</code> is a subset, false
+ * otherwise.
+ */
+ public boolean isSubset(Style style) {
+ if (style.getClass() != this.getClass())
+ return false;
+ RowStyle tStyle = (RowStyle)style;
+
+ if(rowHeight!=tStyle.getRowHeight())
+ return false;
+
+ return true;
+ }
+
+
+ /**
+ * Write this <code>Style</code> object's attributes to a
+ * <code>Node</code> in the <code>Document</code>.
+ *
+ * @param node The <code>Node</code> to add <code>Style</code>
+ * attributes.
+ */
+ public void writeAttributes(Element node) {
+
+ if(rowHeight!=0) {
+ String height = TwipsConverter.twips2cm(rowHeight) + "cm";
+ node.setAttribute("style:row-height", height);
+ }
+ }
+
+
+ private static String[] ignored = {
+ "fo:break-before", "fo:keep-with-next"
+ };
+
+
+ /*
+ * This code checks whether an attribute is one that we
+ * intentionally ignore.
+ *
+ * @param attribute The attribute to check.
+ *
+ * @return true if <code>attribute</code> can be ignored,
+ * otherwise false.
+ */
+ private boolean isIgnored(String attribute) {
+ for (int i = 0; i < ignored.length; i++) {
+ if (ignored[i].equals(attribute))
+ return true;
+ }
+ return false;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SheetSettings.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SheetSettings.java
new file mode 100644
index 000000000000..4258e1a5e035
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SheetSettings.java
@@ -0,0 +1,373 @@
+/*************************************************************************
+ *
+ * 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.sxc;
+
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+import java.awt.Point;
+
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+
+/**
+ * This is a class representing the different attributes for a worksheet
+ * contained in settings.xml.
+ *
+ * @author Martin Maher
+ */
+public class SheetSettings implements OfficeConstants {
+
+ /** A w3c <code>Document</code>. */
+ private org.w3c.dom.Document settings = null;
+
+ private String sheetName;
+ private int cursorX = 0;
+ private int cursorY = 0;
+ private int splitTypeX;
+ private int splitTypeY;
+ private int splitPointX = 0;
+ private int splitPointY = 0;
+ private int posLeft = 0;
+ private int posRight = 0;
+ private int posBottom = 0;
+ private int posTop = 0;
+ private int paneNumber = 2;
+
+ final public static int NONE = 0x00;
+ final public static int SPLIT = 0x01;
+ final public static int FREEZE = 0x02;
+
+
+ /**
+ * Default Constructor for a <code>ColumnRowInfo</code>
+ *
+ */
+ public SheetSettings() {
+ }
+
+ /**
+ * Constructor that takes a <code>Node</code> to build a <code>SheetSettings</code>
+ *
+ * @param root XML Node to read from
+ */
+ public SheetSettings(Node root) {
+ readNode(root);
+ }
+
+ /**
+ * Constructor for a <code>ColumnRowInfo</code>
+ *
+ * @param dimension if it's a row the height, a column the width
+ * @param repeated
+ */
+ public SheetSettings(String name) {
+ sheetName = name;
+ }
+
+ /**
+ * sets the position of the acitve cell
+ *
+ * @param activeCell the current curor position
+ */
+ public void setCursor(Point activeCell) {
+
+ cursorX = (int) activeCell.getX();
+ cursorY = (int) activeCell.getY();
+ }
+
+ /**
+ * Gets the position of the acitve cell
+ *
+ * @return The position as a <code>Point</code>
+ */
+ public Point getCursor() {
+
+ return (new Point(cursorX, cursorY));
+ }
+
+ /**
+ * Sets the position of the freeze
+ *
+ * @param splitPoint the point at where the split occurs
+ */
+ public void setFreeze(Point splitPoint) {
+
+ splitTypeX = FREEZE;
+ splitTypeY = FREEZE;
+ splitPointX = (int) splitPoint.getX();
+ splitPointY = (int) splitPoint.getY();
+ }
+
+ /**
+ * Sets the position of the split
+ *
+ * @param splitPoint the point at where the split occurs
+ */
+ public void setSplit(Point splitPoint) {
+
+ splitTypeX = SPLIT;
+ splitTypeY = SPLIT;
+ splitPointX = (int) splitPoint.getX();
+ splitPointY = (int) splitPoint.getY();
+ }
+
+ /**
+ * sets the position and type of the split
+ *
+ * @return The position as a <code>Point</code> where the split occurs
+ */
+ public Point getSplit() {
+
+ return (new Point(splitPointX, splitPointY));
+ }
+
+ /**
+ * sets the position and type of the split
+ *
+ * @return The position as a <code>Point</code> where the split occurs
+ */
+ public Point getSplitType() {
+
+ return (new Point(splitTypeX, splitTypeY));
+ }
+
+ /**
+ * Sets the top row visible in the lower pane and the leftmost column
+ * visibile in the right pane.
+ *
+ * @param top The top row visible in the lower pane
+ * @param left The leftmost column visibile in the right pane
+ */
+ public void setTopLeft(int top, int left) {
+
+ posLeft = left;
+ posTop = top;
+ }
+
+ /**
+ * Gets the the leftmost column visibile in the right pane.
+ *
+ * @return the 0-based index to the column
+ */
+ public int getLeft() {
+
+ return posLeft;
+ }
+ /**
+ * Sets the top row visible in the lower pane and the leftmost column
+ * visibile in the right pane.
+ *
+ * @param top The top row visible in the lower pane
+ * @param left The leftmost column visibile in the right pane
+ */
+ public int getTop() {
+
+ return posTop;
+ }
+
+ /**
+ * Gets the active Panel
+ * 0 - Bottom Right, 1 - Top Right
+ * 2 - Bottom Left, 3 - Top Left
+ *
+ * @return int representing the active panel
+ */
+ public int getPaneNumber() {
+
+ return paneNumber;
+ }
+
+ /**
+ * Sets the sheetname this settings object applies to
+ *
+ * @param sheetName the name of the worksheet
+ */
+ public void setSheetName(String sheetName) {
+
+ this.sheetName = sheetName;
+
+ }
+
+ /**
+ * Sets the active pane number
+ * 0 - Bottom Right, 1 - Top Right
+ * 2 - Bottom Left, 3 - Top Left
+ *
+ * @param paneNumber the pane number
+ */
+ public void setPaneNumber(int paneNumber) {
+
+ this.paneNumber = paneNumber;
+ }
+
+ /**
+ * Gets the name of the worksheet these <code>Settings</code> apply to
+ *
+ * @return the name of the worksheet
+ */
+ public String getSheetName() {
+
+ return sheetName;
+ }
+
+ /**
+ * Adds an XML entry for a particular setting
+ *
+ * @param root the root node at which to add the xml entry
+ * @param attriute the name of the attribute to add
+ * @param type the attribute type (int, short etc)
+ * @param value the value of the attribute
+ */
+ private void addConfigItem(Node root, String attribute, String type, String value) {
+
+ Element configItem = settings.createElement(TAG_CONFIG_ITEM);
+ configItem.setAttribute(ATTRIBUTE_CONFIG_NAME, attribute);
+ configItem.setAttribute(ATTRIBUTE_CONFIG_TYPE, type);
+
+ configItem.appendChild(settings.createTextNode(value));
+
+ root.appendChild(configItem);
+ }
+
+ /**
+ * Writes out a settings.xml entry for this SheetSettings object
+ *
+ * @param settings a <code>Document</code> object representing the settings.xml
+ * @param root the root xml node to add to
+ */
+ public void writeNode(org.w3c.dom.Document settings, Node root) {
+
+ this.settings = settings;
+ Element configItemMapEntry = (Element) settings.createElement(TAG_CONFIG_ITEM_MAP_ENTRY);
+ configItemMapEntry.setAttribute(ATTRIBUTE_CONFIG_NAME, getSheetName());
+ addConfigItem(configItemMapEntry, "CursorPositionX", "int", Integer.toString(cursorX));
+ addConfigItem(configItemMapEntry, "CursorPositionY", "int", Integer.toString(cursorY));
+
+ String splitMode = Integer.toString(splitTypeX);
+ if(splitPointX==0) {
+ splitMode = "0";
+ }
+ addConfigItem(configItemMapEntry, "HorizontalSplitMode", "short", splitMode);
+
+ splitMode = Integer.toString(splitTypeY);
+ if(splitPointY==0) {
+ splitMode = "0";
+ }
+ addConfigItem(configItemMapEntry, "VerticalSplitMode", "short", splitMode);
+
+ addConfigItem(configItemMapEntry, "HorizontalSplitPosition", "int", Integer.toString(splitPointX));
+ addConfigItem(configItemMapEntry, "VerticalSplitPosition", "int", Integer.toString(splitPointY));
+ addConfigItem(configItemMapEntry, "ActiveSplitRange", "short", Integer.toString(paneNumber));
+
+ addConfigItem(configItemMapEntry, "PositionLeft", "int", "0");
+ addConfigItem(configItemMapEntry, "PositionRight", "int", Integer.toString(posLeft));
+ addConfigItem(configItemMapEntry, "PositionTop", "int", "0");
+ addConfigItem(configItemMapEntry, "PositionBottom", "int", Integer.toString(posTop));
+ root.appendChild(configItemMapEntry);
+ }
+
+ /**
+ * Sets a variable based on a String value read from XML
+ *
+ * @param name xml name of the attribute to set
+ * @param value String value fo the attribute
+ */
+ public void addAttribute(String name, String value) {
+
+ if(name.equals("CursorPositionX")) {
+ cursorX = Integer.parseInt(value);
+ } else if(name.equals("CursorPositionY")) {
+ cursorY = Integer.parseInt(value);
+
+ } else if(name.equals("HorizontalSplitPosition")) {
+ splitPointX = Integer.parseInt(value);
+ } else if(name.equals("VerticalSplitPosition")) {
+ splitPointY = Integer.parseInt(value);
+ } else if(name.equals("ActiveSplitRange")) {
+ paneNumber = Integer.parseInt(value);
+
+ } else if(name.equals("PositionRight")) {
+ posLeft = Integer.parseInt(value);
+ } else if(name.equals("PositionBottom")) {
+ posTop = Integer.parseInt(value);
+
+ } else if(name.equals("HorizontalSplitMode")) {
+ splitTypeX = Integer.parseInt(value);
+ } else if(name.equals("VerticalSplitMode")) {
+ splitTypeY = Integer.parseInt(value);
+ }
+ }
+
+ /**
+ * Reads document settings from xml and inits SheetSettings variables
+ *
+ * @param root XML Node to read from
+ */
+ public void readNode(Node root) {
+
+ NamedNodeMap sheetAtt = root.getAttributes();
+
+ Node sheetNameNode = sheetAtt.getNamedItem(ATTRIBUTE_CONFIG_NAME);
+
+ sheetName = sheetNameNode.getNodeValue();
+
+ if (root.hasChildNodes()) {
+
+ NodeList nodeList = root.getChildNodes();
+ int len = nodeList.getLength();
+ for (int i = 0; i < len; i++) {
+ Node child = nodeList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String nodeName = child.getNodeName();
+
+ if (nodeName.equals(TAG_CONFIG_ITEM)) {
+
+ NamedNodeMap cellAtt = child.getAttributes();
+
+ Node configNameNode =
+ cellAtt.getNamedItem(ATTRIBUTE_CONFIG_NAME);
+
+ String name = configNameNode.getNodeValue();
+ NodeList nodeList2 = child.getChildNodes();
+ int len2 = nodeList2.getLength();
+ String s = "";
+ for (int j = 0; j < len2; j++) {
+ Node child2 = nodeList2.item(j);
+ if (child2.getNodeType() == Node.TEXT_NODE) {
+ s = child2.getNodeValue();
+ }
+ }
+ addAttribute(name, s);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SpreadsheetDecoder.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SpreadsheetDecoder.java
new file mode 100644
index 000000000000..169f54a65845
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SpreadsheetDecoder.java
@@ -0,0 +1,180 @@
+/*************************************************************************
+ *
+ * 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.sxc;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+import org.openoffice.xmerge.converter.xml.sxc.Format;
+import org.openoffice.xmerge.ConvertData;
+
+/**
+ * This class is a abstract class for encoding a &quot;Device&quot;
+ * <code>Document</code> format into an alternative spreadsheet format.
+ *
+ * @author Mark Murnane
+ */
+public abstract class SpreadsheetDecoder {
+
+ /**
+ * Constructor for creating new <code>SpreadsheetDecoder</code>.
+ */
+ public SpreadsheetDecoder(String name, String password) throws IOException {
+ }
+
+ /**
+ * Returns the total number of sheets in the WorkBook.
+ *
+ * @return The number of sheets in the WorkBook.
+ */
+ public abstract int getNumberOfSheets();
+
+ /**
+ * Returns an Enumeration to a Vector of <code>NameDefinition</code>.
+ *
+ * @return The Enumeration
+ */
+ public abstract Enumeration getNameDefinitions();
+
+ /**
+ * Returns an <code>BookSettings</code>
+ *
+ * @return The Enumeration
+ */
+ public abstract BookSettings getSettings();
+
+ /**
+ * Returns an Enumeration to a Vector of <code>ColumnRowInfo</code>.
+ *
+ * @return The Enumeration
+ */
+ public abstract Enumeration getColumnRowInfos();
+
+ /**
+ * Returns the number of populated rows in the current WorkSheet.
+ *
+ * @return the number of populated rows in the current WorkSheet.
+ */
+ public abstract int getNumberOfRows();
+
+
+ /**
+ * Returns the number of populated columns in the current WorkSheet.
+ *
+ * @return The number of populated columns in the current WorkSheet.
+ */
+ public abstract int getNumberOfColumns();
+
+
+ /**
+ * Returns the name of the current WorkSheet.
+ *
+ * @return Name of the current WorkSheet.
+ */
+ public abstract String getSheetName();
+
+
+ /**
+ * Returns the number of the active column.
+ *
+ * @return The number of the active column.
+ */
+ public abstract int getColNumber();
+
+
+ /**
+ * Returns the number of the active row.
+ *
+ * @return The number of the active row.
+ */
+ public abstract int getRowNumber();
+
+
+ /**
+ * Sets the active WorkSheet.
+ *
+ * @param sheetIndex The index of the sheet to be made active.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public abstract void setWorksheet(int sheetIndex) throws IOException;
+
+
+ /**
+ * Move on the next populated cell in the current WorkSheet.
+ *
+ * @return true if successful, false otherwise.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public abstract boolean goToNextCell() throws IOException;
+
+
+ /**
+ * Return the contents of the active cell.
+ *
+ * @return The cell contents.
+ */
+ public abstract String getCellContents();
+
+ /**
+ * Return the value of the active cell. Used in the case of Formula where
+ * the cell contents and the cell value are not the same thing.
+ *
+ * @return The cell value.
+ */
+ public abstract String getCellValue();
+
+ /**
+ * Return the data type of the active cell.
+ *
+ * @return The cell data type.
+ */
+ public abstract String getCellDataType();
+
+
+ /**
+ * Return a <code>Format</code> object describing the active cells
+ * formatting.
+ *
+ * @return <code>Format</code> object for the cell.
+ */
+ public abstract Format getCellFormat();
+
+
+ /**
+ * Add the contents of a <code>ConvertData</code> to the workbook.
+ *
+ * @param cd The <code>ConvertData</code> containing the
+ * content.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public abstract void addDeviceContent(ConvertData cd) throws IOException;
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SpreadsheetEncoder.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SpreadsheetEncoder.java
new file mode 100644
index 000000000000..fc965bcd88b1
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SpreadsheetEncoder.java
@@ -0,0 +1,129 @@
+/*************************************************************************
+ *
+ * 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.sxc;
+
+import java.io.IOException;
+import java.util.Vector;
+
+/**
+ * <p>This class is a abstract class for encoding an SXC into an
+ * alternative spreadsheet format.</p>
+ *
+ * <p>TODO - Add appropriate exceptions to each of the methods.</p>
+ *
+ * @author Mark Murnane
+ */
+public abstract class SpreadsheetEncoder {
+
+
+ /**
+ * Creates new SpreadsheetEncoder.
+ *
+ * @param name The name of the WorkBook to be created.
+ * @param password An optional password for the WorkBook.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public SpreadsheetEncoder(String name, String password) throws IOException { };
+
+
+ /**
+ * Create a new WorkSheet within the WorkBook.
+ *
+ * @param sheetName The name of the WorkSheet.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public abstract void createWorksheet(String sheetName) throws IOException;
+
+
+ /**
+ * Set a cell's formatting options via a separately create
+ * <code>Format</code> object.
+ *
+ * @param row The row number of the cell to be changed
+ * @param column The column number of the cell to be changed
+ * @param fmt Object containing formatting settings for this cell.
+ */
+ public abstract void setCellFormat(int row, int column, Format fmt);
+
+
+ /**
+ * Add a cell to the current WorkSheet.
+ *
+ * @param row The row number of the cell
+ * @param column The column number of the cell
+ * @param fmt The <code>Format</code> object describing the
+ * appearance of this cell.
+ * @param cellContents The text or formula of the cell's contents.
+ */
+ public abstract void addCell(int row, int column,
+ Format fmt, String cellContents) throws IOException;
+
+
+ /**
+ * Get the number of sheets in the WorkBook.
+ *
+ * @return The number of sheets in the WorkBook.
+ */
+ public abstract int getNumberOfSheets();
+
+
+ /**
+ * Get the names of the sheets in the WorkBook.
+ *
+ * @param sheet The required sheet.
+ */
+ public abstract String getSheetName(int sheet);
+
+
+ /**
+ * Set the width of the columns in the WorkBook.
+ *
+ * @param columnWidths An <code>IntArrayList</code> of column
+ * widths.
+ */
+ public abstract void setColumnRows(Vector columnRows) throws IOException;
+
+ /**
+ * Set the width of the columns in the WorkBook.
+ *
+ * @param columnWidths An <code>IntArrayList</code> of column
+ * widths.
+ */
+ public abstract void setNameDefinition(NameDefinition nd) throws IOException;
+
+ /**
+ * Set the width of the columns in the WorkBook.
+ *
+ * @param columnWidths An <code>IntArrayList</code> of column
+ * widths.
+ */
+ public abstract void addSettings(BookSettings s) throws IOException;
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcConstants.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcConstants.java
new file mode 100644
index 000000000000..32fd85fa071a
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcConstants.java
@@ -0,0 +1,49 @@
+/*************************************************************************
+ *
+ * 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.sxc;
+
+
+/**
+ * Interface defining constants for Sxc attributes.
+ *
+ * @author Martin Maher
+ */
+public interface SxcConstants {
+
+ /** Family name for column styles. */
+ public static final String COLUMN_STYLE_FAMILY = "table-column";
+
+ /** Family name for row styles. */
+ public static final String ROW_STYLE_FAMILY = "table-row";
+
+ /** Family name for table-cell styles. */
+ public static final String TABLE_CELL_STYLE_FAMILY = "table-cell";
+
+ /** Name of the default style. */
+ public static final String DEFAULT_STYLE = "Default";
+}
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocument.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocument.java
new file mode 100644
index 000000000000..5561ef3c9d9c
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocument.java
@@ -0,0 +1,92 @@
+/*************************************************************************
+ *
+ * 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.sxc;
+
+import org.openoffice.xmerge.converter.xml.OfficeDocument;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+
+/**
+ * This class is an implementation of <code>OfficeDocument</code> for
+ * the SXC format.
+ */
+public class SxcDocument extends OfficeDocument {
+
+ /**
+ * Constructor with arguments to set <code>name</code>.
+ *
+ * @param name The name of the <code>Document</code>
+ */
+ public SxcDocument(String name) {
+ super(name);
+ }
+
+
+ /**
+ * Constructor with arguments to set <code>name</code>, the
+ * <code>namespaceAware</code> flag, and the <code>validating</code>
+ * flag.
+ *
+ * @param name The name of the <code>Document</code>.
+ * @param namespaceAware The value of the <code>namespaceAware</code>
+ * flag.
+ * @param validating The value of the <code>validating</code> flag.
+ */
+ public SxcDocument(String name, boolean namespaceAware, boolean validating) {
+
+ super(name, namespaceAware, validating);
+ }
+
+ /**
+ * Returns the Office file extension for the SXC format.
+ *
+ * @return The Office file extension for the SXC format.
+ */
+ protected String getFileExtension() {
+ return OfficeConstants.SXC_FILE_EXTENSION;
+ }
+
+ /**
+ * Returns the Office attribute for the SXC format.
+ *
+ * @return The Office attribute for the SXC format.
+ */
+ protected String getOfficeClassAttribute() {
+ return OfficeConstants.SXC_TYPE;
+ }
+
+ /**
+ * Method to return the MIME type of the document.
+ *
+ * @return String The document's MIME type.
+ */
+ protected final String getDocumentMimeType() {
+ return OfficeConstants.SXC_MIME_TYPE;
+ }
+
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocumentDeserializer.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocumentDeserializer.java
new file mode 100644
index 000000000000..2eb507d09b7b
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocumentDeserializer.java
@@ -0,0 +1,792 @@
+/*************************************************************************
+ *
+ * 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.sxc;
+
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.ConvertException;
+import org.openoffice.xmerge.DocumentDeserializer;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+import org.openoffice.xmerge.converter.xml.sxc.SxcDocument;
+import org.openoffice.xmerge.converter.xml.sxc.BookSettings;
+import org.openoffice.xmerge.converter.xml.sxc.NameDefinition;
+import org.openoffice.xmerge.converter.xml.sxc.CellStyle;
+import org.openoffice.xmerge.converter.xml.Style;
+import org.openoffice.xmerge.converter.xml.StyleCatalog;
+import org.openoffice.xmerge.util.Debug;
+
+/**
+ * <p>General spreadsheet implementation of <code>DocumentDeserializer</code>
+ * for the {@link
+ * org.openoffice.xmerge.converter.xml.sxc.SxcPluginFactory
+ * SxcPluginFactory}. Used with SXC <code>Document</code> objects.</p>
+ *
+ * <p>The <code>deserialize</code> method uses a <code>DocDecoder</code>
+ * to read the device spreadsheet format into a <code>String</code>
+ * object, then it calls <code>buildDocument</code> to create a
+ * <code>SxcDocument</code> object from it.</p>
+ *
+ * @author Paul Rank
+ * @author Mark Murnane
+ * @author Martin Maher
+ */
+public abstract class SxcDocumentDeserializer implements OfficeConstants,
+ DocumentDeserializer {
+
+ /**
+ * A <code>SpreadsheetDecoder</code> object for decoding from
+ * device formats.
+ */
+ private SpreadsheetDecoder decoder = null;
+
+ /** A w3c <code>Document</code>. */
+ private org.w3c.dom.Document settings = null;
+
+ /** A w3c <code>Document</code>. */
+ private org.w3c.dom.Document doc = null;
+
+ /** An <code>ConvertData</code> object assigned to this object. */
+ private ConvertData cd = null;
+
+ /** A style catalog for the workbook */
+ private StyleCatalog styleCat = null;
+
+ private int textStyles = 1;
+ private int colStyles = 1;
+ private int rowStyles = 1;
+
+ /**
+ * Constructor.
+ *
+ * @param cd <code>ConvertData</code> consisting of a
+ * device content object.
+ */
+ public SxcDocumentDeserializer(ConvertData cd) {
+ this.cd = cd;
+ }
+
+
+ /**
+ * This abstract method will be implemented by concrete subclasses
+ * and will return an application-specific Decoder.
+ *
+ * @param workbook The WorkBook to read.
+ * @param password The WorkBook password.
+ *
+ * @return The appropriate <code>SpreadSheetDecoder</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public abstract SpreadsheetDecoder createDecoder(String workbook, String[] worksheetNames, String password)
+ throws IOException;
+
+
+ /**
+ * <p>This method will return the name of the WorkBook from the
+ * <code>ConvertData</code>. Allows for situations where the
+ * WorkBook name differs from the Device Content name.</p>
+ *
+ * <p>Implemented in the Deserializer as the Decoder's constructor requires
+ * a name.</p>
+ *
+ * @param cd The <code>ConvertData</code> containing the Device
+ * content.
+ *
+ * @return The WorkBook name.
+ */
+ protected abstract String getWorkbookName(ConvertData cd) throws IOException;
+
+
+ /**
+ * This method will return the name of the WorkSheet from the
+ * <code>ConvertData</code>.
+ *
+ * @param cd The <code>ConvertData</code> containing the Device
+ * content.
+ *
+ * @return The WorkSheet names.
+ */
+ protected abstract String[] getWorksheetNames(ConvertData cd) throws IOException;
+
+
+ /**
+ * <p>Method to convert a set of &quot;Device&quot;
+ * <code>Document</code> objects into a <code>SxcDocument</code>
+ * object and returns it as a <code>Document</code>.</p>
+ *
+ * <p>This method is not thread safe for performance reasons.
+ * This method should not be called from within two threads.
+ * It would be best to call this method only once per object
+ * instance.</p>
+ *
+ * @return document An <code>SxcDocument</code> consisting
+ * of the data converted from the input
+ * stream.
+ *
+ * @throws ConvertException If any conversion error occurs.
+ * @throws IOException If any I/O error occurs.
+ */
+ public Document deserialize() throws ConvertException,
+ IOException {
+
+ // Get the name of the WorkBook from the ConvertData.
+ String[] worksheetNames = getWorksheetNames(cd);
+ String workbookName = getWorkbookName(cd);
+
+ // Create a document
+ SxcDocument sxcDoc = new SxcDocument(workbookName);
+ sxcDoc.initContentDOM();
+ sxcDoc.initSettingsDOM();
+
+ // Default to an initial 5 entries in the catalog.
+ styleCat = new StyleCatalog(5);
+
+ doc = sxcDoc.getContentDOM();
+ settings = sxcDoc.getSettingsDOM();
+ initFontTable();
+ // Little fact for the curious reader: workbookName should
+ // be the name of the StarCalc file minus the file extension suffix.
+
+ // Create a Decoder to decode the DeviceContent to a spreadsheet document
+ // TODO - we aren't using a password in StarCalc, so we can
+ // use any value for password here. If StarCalc XML supports
+ // passwords in the future, we should try to get the correct
+ // password value here.
+ //
+ decoder = createDecoder(workbookName, worksheetNames, "password");
+
+ Debug.log(Debug.TRACE, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ Debug.log(Debug.TRACE, "<DEBUGLOG>");
+
+ decoder.addDeviceContent(cd);
+ decode();
+
+ Debug.log(Debug.TRACE, "</DEBUGLOG>");
+
+ return sxcDoc;
+ }
+
+ /**
+ * This initializes a font table so we can imclude some basic font
+ * support for spreadsheets.
+ *
+ */
+ private void initFontTable() {
+
+ String fontTable[]= new String[] { "Tahoma", "Tahoma", "swiss", "variable",
+ "Courier New", "&apos;Courier New&apos;", "modern", "fixed"};
+ // Traverse to the office:body element.
+ // There should only be one.
+ NodeList list = doc.getElementsByTagName(TAG_OFFICE_FONT_DECLS);
+ Node root = list.item(0);
+
+ for(int i=0;i<fontTable.length;) {
+
+ // Create an element node for the table
+ Element tableElement = (Element) doc.createElement(TAG_STYLE_FONT_DECL);
+
+ tableElement.setAttribute(ATTRIBUTE_STYLE_NAME, fontTable[i++]);
+ tableElement.setAttribute(ATTRIBUTE_FO_FONT_FAMILY, fontTable[i++]);
+ tableElement.setAttribute(ATTRIBUTE_FO_FONT_FAMILY_GENERIC, fontTable[i++]);
+ tableElement.setAttribute(ATTRIBUTE_STYLE_FONT_PITCH, fontTable[i++]);
+
+ root.appendChild(tableElement);
+ }
+
+ }
+
+ /**
+ * Outer level method used to decode a WorkBook
+ * into a <code>Document</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void decode() throws IOException {
+
+ // Get number of worksheets
+ int numSheets = decoder.getNumberOfSheets();
+ // #i33702# - check for an Empty InputStream.
+ if(numSheets == 0)
+ {
+ System.err.println("Error decoding invalid Input stream");
+ return;
+ }
+
+ // Traverse to the office:body element.
+ // There should only be one.
+ NodeList list = doc.getElementsByTagName(TAG_OFFICE_BODY);
+ Node node = list.item(0);
+
+ for (int i = 0; i < numSheets; i++) {
+
+ // Set the decoder to the correct worksheet
+ decoder.setWorksheet(i);
+
+ int len = list.getLength();
+
+ if (len > 0) {
+
+ // Process the spreadsheet
+ processTable(node);
+ }
+ }
+
+ // Add the Defined Name table if there is one
+ Enumeration nameDefinitionTable = decoder.getNameDefinitions();
+ if(nameDefinitionTable.hasMoreElements()) {
+ processNameDefinition(node, nameDefinitionTable);
+ }
+
+ // add settings
+ NodeList settingsList = settings.getElementsByTagName(TAG_OFFICE_SETTINGS);
+ Node settingsNode = settingsList.item(0);;
+ processSettings(settingsNode);
+
+ }
+
+
+
+ /**
+ * This method process the settings portion
+ * of the <code>Document</code>.
+ *
+ * @param root The root <code>Node</code> of the
+ * <code>Document</code> we are building. This
+ * <code>Node</code> should be a TAG_OFFICE_SETTINGS
+ * tag.
+ */
+ protected void processSettings(Node root) {
+
+ Element configItemSetEntry = (Element) settings.createElement(TAG_CONFIG_ITEM_SET);
+ configItemSetEntry.setAttribute(ATTRIBUTE_CONFIG_NAME, "view-settings");
+ Element configItemMapIndexed = (Element) settings.createElement(TAG_CONFIG_ITEM_MAP_INDEXED);
+ configItemMapIndexed.setAttribute(ATTRIBUTE_CONFIG_NAME, "Views");
+ Element configItemMapEntry = (Element) settings.createElement(TAG_CONFIG_ITEM_MAP_ENTRY);
+ BookSettings bs = (BookSettings) decoder.getSettings();
+ bs.writeNode(settings, configItemMapEntry);
+
+ configItemMapIndexed.appendChild(configItemMapEntry);
+ configItemSetEntry.appendChild(configItemMapIndexed);
+ root.appendChild(configItemSetEntry);
+ }
+
+ /**
+ * This method process a Name Definition Table and generates a portion
+ * of the <code>Document</code>.
+ *
+ * @param root The root <code>Node</code> of the
+ * <code>Document</code> we are building. This
+ * <code>Node</code> should be a TAG_OFFICE_BODY
+ * tag.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void processNameDefinition(Node root, Enumeration eNameDefinitions) throws IOException {
+
+ Debug.log(Debug.TRACE, "<NAMED-EXPRESSIONS>");
+
+ Element namedExpressionsElement = (Element) doc.createElement(TAG_NAMED_EXPRESSIONS);
+
+ while(eNameDefinitions.hasMoreElements()) {
+
+ NameDefinition tableEntry = (NameDefinition) eNameDefinitions.nextElement();
+ tableEntry.writeNode(doc, namedExpressionsElement);
+ }
+
+ root.appendChild(namedExpressionsElement);
+
+ Debug.log(Debug.TRACE, "</NAMED-EXPRESSIONS>");
+ }
+
+ /**
+ * This method process a WorkSheet and generates a portion
+ * of the <code>Document</code>. A spreadsheet is represented
+ * as a table Node in StarOffice XML format.
+ *
+ * @param root The root <code>Node</code> of the
+ * <code>Document</code> we are building. This
+ * <code>Node</code> should be a TAG_OFFICE_BODY
+ * tag.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void processTable(Node root) throws IOException {
+
+ Debug.log(Debug.TRACE, "<TABLE>");
+
+ // Create an element node for the table
+ Element tableElement = (Element) doc.createElement(TAG_TABLE);
+
+ // Get the sheet name
+ String sheetName = decoder.getSheetName();
+
+ // Set the table name attribute
+ tableElement.setAttribute(ATTRIBUTE_TABLE_NAME, sheetName);
+
+ // TODO - style currently hardcoded - get real value
+ // Set table style-name attribute
+ tableElement.setAttribute(ATTRIBUTE_TABLE_STYLE_NAME, "Default");
+
+ // Append the table element to the root node
+ root.appendChild(tableElement);
+
+ Debug.log(Debug.TRACE, "<SheetName>" + sheetName + "</SheetName>");
+
+ // add the various different table-columns
+ processColumns(tableElement);
+
+ // Get each cell and add to doc
+ processCells(tableElement);
+
+ Debug.log(Debug.TRACE, "</TABLE>");
+ }
+
+ /**
+ * <p>This method process the cells in a <code>Document</code>
+ * and generates a portion of the <code>Document</code>.</p>
+ *
+ * <p>This method assumes that records are sorted by
+ * row and then column.</p>
+ *
+ * @param root The <code>Node</code> of the <code>Document</code>
+ * we are building that we will append our cell
+ * <code>Node</code> objects. This <code>Node</code>
+ * should be a TAG_TABLE tag.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void processColumns(Node root) throws IOException {
+
+ for(Enumeration e = decoder.getColumnRowInfos();e.hasMoreElements();) {
+
+ ColumnRowInfo ci = (ColumnRowInfo) e.nextElement();
+ if(ci.isColumn()) {
+ ColumnStyle cStyle = new ColumnStyle("Default",SxcConstants.COLUMN_STYLE_FAMILY,
+ SxcConstants.DEFAULT_STYLE, ci.getSize(), null);
+
+ Style result[] = (Style[]) styleCat.getMatching(cStyle);
+ String styleName;
+ if(result.length==0) {
+
+ cStyle.setName("co" + colStyles++);
+ styleName = cStyle.getName();
+ Debug.log(Debug.TRACE,"No existing style found, adding " + styleName);
+ styleCat.add(cStyle);
+ } else {
+ ColumnStyle existingStyle = (ColumnStyle) result[0];
+ styleName = existingStyle.getName();
+ Debug.log(Debug.TRACE,"Existing style found : " + styleName);
+ }
+
+ // Create an element node for the new row
+ Element colElement = (Element) doc.createElement(TAG_TABLE_COLUMN);
+ colElement.setAttribute(ATTRIBUTE_TABLE_STYLE_NAME, styleName);
+ if(ci.getRepeated()!=1) {
+ String repeatStr = String.valueOf(ci.getRepeated());
+ colElement.setAttribute(ATTRIBUTE_TABLE_NUM_COLUMNS_REPEATED, repeatStr);
+ }
+ root.appendChild(colElement);
+ }
+ }
+ }
+
+ /**
+ * <p>This method process the cells in a <code>Document</code>
+ * and generates a portion of the <code>Document</code>.</p>
+ *
+ * <p>This method assumes that records are sorted by
+ * row and then column.</p>
+ *
+ * @param root The <code>Node</code> of the <code>Document</code>
+ * we are building that we will append our cell
+ * <code>Node</code> objects. This <code>Node</code>
+ * should be a TAG_TABLE tag.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void processCells(Node root) throws IOException {
+
+ // The current row element
+ Element rowElement = null;
+
+ // The current cell element
+ Element cellElement = null;
+
+ // The row number - we may not have any rows (empty sheet)
+ // so set to zero.
+ int row = 0;
+
+ // The column number - This is the expected column number of
+ // the next cell we are reading.
+ int col = 1;
+
+ // The number of columns in the spreadsheet
+ int lastColumn = decoder.getNumberOfColumns();
+
+ //
+ Node autoStylesNode = null;
+
+ // Loop over all cells in the spreadsheet
+ while (decoder.goToNextCell()) {
+
+ // Get the row number
+ int newRow = decoder.getRowNumber();
+
+ // Is the cell in a new row, or part of the current row?
+ if (newRow != row) {
+
+ // Make sure that all the cells in the previous row
+ // have been entered.
+ if (col <= lastColumn && rowElement != null) {
+ int numSkippedCells = lastColumn - col + 1;
+ addEmptyCells(numSkippedCells, rowElement);
+ }
+
+ // log an end row - if we already have a row
+ if (row != 0) {
+ Debug.log(Debug.TRACE, "</tr>");
+ }
+
+ // How far is the new row from the last row?
+ int deltaRows = newRow - row;
+
+ // Check if we have skipped any rows
+ if (deltaRows > 1) {
+ // Add in empty rows
+ addEmptyRows(deltaRows-1, root, lastColumn);
+ }
+
+ // Re-initialize column (since we are in a new row)
+ col = 1;
+
+ // Create an element node for the new row
+ rowElement = (Element) doc.createElement(TAG_TABLE_ROW);
+
+
+ for(Enumeration e = decoder.getColumnRowInfos();e.hasMoreElements();) {
+ ColumnRowInfo cri = (ColumnRowInfo) e.nextElement();
+ if(cri.isRow() && cri.getRepeated()==newRow-1) {
+ // We have the correct Row BIFFRecord for this row
+ RowStyle rStyle = new RowStyle("Default",SxcConstants.ROW_STYLE_FAMILY,
+ SxcConstants.DEFAULT_STYLE, cri.getSize(), null);
+
+ Style result[] = (Style[]) styleCat.getMatching(rStyle);
+ String styleName;
+ if(result.length==0) {
+
+ rStyle.setName("ro" + rowStyles++);
+ styleName = rStyle.getName();
+ Debug.log(Debug.TRACE,"No existing style found, adding " + styleName);
+ styleCat.add(rStyle);
+ } else {
+ RowStyle existingStyle = (RowStyle) result[0];
+ styleName = existingStyle.getName();
+ Debug.log(Debug.TRACE,"Existing style found : " + styleName);
+ }
+ rowElement.setAttribute(ATTRIBUTE_TABLE_STYLE_NAME, styleName);
+ // For now we will not use the repeat column attribute
+ }
+ }
+
+ // Append the row element to the root node
+ root.appendChild(rowElement);
+
+ // Update row number
+ row = newRow;
+
+ Debug.log(Debug.TRACE, "<tr>");
+ }
+
+ // Get the column number of the current cell
+ int newCol = decoder.getColNumber();
+
+ // Check to see if some columns were skipped
+ if (newCol != col) {
+
+ // How many columns have we skipped?
+ int numColsSkipped = newCol - col;
+
+ addEmptyCells(numColsSkipped, rowElement);
+
+ // Update the column number to account for the
+ // skipped cells
+ col = newCol;
+ }
+
+ // Lets start dealing with the cell data
+ Debug.log(Debug.TRACE, "<td>");
+
+ // Get the cell's contents
+ String cellContents = decoder.getCellContents();
+
+ // Get the type of the data in the cell
+ String cellType = decoder.getCellDataType();
+
+ // Get the cell format
+ Format fmt = decoder.getCellFormat();
+
+ // Create an element node for the cell
+ cellElement = (Element) doc.createElement(TAG_TABLE_CELL);
+
+ Node bodyNode = doc.getElementsByTagName(TAG_OFFICE_BODY).item(0);
+
+ // Not every document has an automatic style tag
+ autoStylesNode = doc.getElementsByTagName(
+ TAG_OFFICE_AUTOMATIC_STYLES).item(0);
+
+ if (autoStylesNode == null) {
+ autoStylesNode = doc.createElement(TAG_OFFICE_AUTOMATIC_STYLES);
+ doc.insertBefore(autoStylesNode, bodyNode);
+ }
+
+ CellStyle tStyle = new
+ CellStyle( "Default",SxcConstants.TABLE_CELL_STYLE_FAMILY,
+ SxcConstants.DEFAULT_STYLE, fmt, null);
+ String styleName;
+ Style result[] = (Style[]) styleCat.getMatching(tStyle);
+ if(result.length==0) {
+
+ tStyle.setName("ce" + textStyles++);
+ styleName = tStyle.getName();
+ Debug.log(Debug.TRACE,"No existing style found, adding " + styleName);
+ styleCat.add(tStyle);
+ } else {
+ CellStyle existingStyle = (CellStyle) result[0];
+ styleName = existingStyle.getName();
+ Debug.log(Debug.TRACE,"Existing style found : " + styleName);
+ }
+
+ cellElement.setAttribute(ATTRIBUTE_TABLE_STYLE_NAME, styleName);
+
+ // Store the cell data into the appropriate attributes
+ processCellData(cellElement, cellType, cellContents);
+
+ // Append the cell element to the row node
+ rowElement.appendChild(cellElement);
+
+ // Append the cellContents as a text node
+ Element textElement = (Element) doc.createElement(TAG_PARAGRAPH);
+ cellElement.appendChild(textElement);
+ textElement.appendChild(doc.createTextNode(cellContents));
+
+ Debug.log(Debug.TRACE, cellContents);
+ Debug.log(Debug.TRACE, "</td>");
+
+ // Increment to the column number of the next expected cell
+ col++;
+ }
+
+ // Make sure that the last row is padded correctly
+ if (col <= lastColumn && rowElement != null) {
+ int numSkippedCells = lastColumn - col + 1;
+ addEmptyCells(numSkippedCells, rowElement);
+ }
+
+ // Now write the style catalog to the document
+ if(autoStylesNode!=null) {
+ Debug.log(Debug.TRACE,"Well the autostyle node was found!!!");
+ NodeList nl = styleCat.writeNode(doc, "dummy").getChildNodes();
+ int nlLen = nl.getLength(); // nl.item reduces the length
+ for (int i = 0; i < nlLen; i++) {
+ autoStylesNode.appendChild(nl.item(0));
+ }
+ }
+
+ if (row != 0) {
+
+ // The sheet does have rows, so write out a /tr
+ Debug.log(Debug.TRACE, "</tr>");
+ }
+ }
+
+
+ /**
+ * This method will add empty rows to the <code>Document</code>.
+ * It is called when the conversion process encounters
+ * a row (or rows) that do not contain any data in its cells.
+ *
+ * @param numEmptyRows The number of empty rows that we
+ * need to add to the <code>Document</code>.
+ * @param root The <code>Node</code> of the
+ * <code>Document</code> we are building
+ * that we will append our empty row
+ * <code>Node</code> objects. This
+ * <code>Node</code> should be a TAG_TABLE
+ * tag.
+ * @param numEmptyCells The number of empty cells in the
+ * empty row.
+ */
+ protected void addEmptyRows(int numEmptyRows, Node root, int numEmptyCells) {
+
+ // Create an element node for the row
+ Element rowElement = (Element) doc.createElement(TAG_TABLE_ROW);
+
+ // TODO - style currently hardcoded - get real value
+ // Set row style-name attribute
+ rowElement.setAttribute(ATTRIBUTE_TABLE_STYLE_NAME, "Default");
+
+ // Set cell number-rows-repeated attribute
+ rowElement.setAttribute(ATTRIBUTE_TABLE_NUM_ROWS_REPEATED,
+ Integer.toString(numEmptyRows));
+
+ // Append the row element to the root node
+ root.appendChild(rowElement);
+
+ // Open Office requires the empty row to have an empty cell (or cells)
+ addEmptyCells(numEmptyCells, rowElement);
+
+ // Write empty rows to the log
+ for (int i = 0; i < numEmptyRows; i++) {
+ Debug.log(Debug.TRACE, "<tr />");
+ }
+
+ }
+
+
+ /**
+ * This method will add empty cells to the <code>Document</code>.
+ * It is called when the conversion process encounters a row
+ * that contains some cells without data.
+ *
+ * @param numColsSkipped The number of empty cells
+ * that we need to add to the
+ * current row.
+ * @param row The <code>Node</code> of the
+ * <code>Document</code> we
+ * are building that we will
+ * append our empty cell
+ * <code>Node</code> objects.
+ * This <code>Node</code> should
+ * be a TAG_TABLE_ROW tag.
+ */
+ protected void addEmptyCells(int numColsSkipped, Node row) {
+
+ // Create an empty cellElement
+ Element cellElement = (Element) doc.createElement(TAG_TABLE_CELL);
+
+ // TODO - style currently hardcoded - get real value
+ // Set cell style-name attribute
+ cellElement.setAttribute(ATTRIBUTE_TABLE_STYLE_NAME, "Default");
+
+ // If we skipped more than 1 cell, we must set the
+ // appropriate attribute
+ if (numColsSkipped > 1) {
+
+ // Set cell number-columns-repeated attribute
+ cellElement.setAttribute(ATTRIBUTE_TABLE_NUM_COLUMNS_REPEATED,
+ Integer.toString(numColsSkipped));
+ }
+
+ // Append the empty cell element to the row node
+ row.appendChild(cellElement);
+
+ // Write empty cells to the log
+ for (int i = 0; i < numColsSkipped; i++) {
+ Debug.log(Debug.TRACE, "<td />");
+ }
+ }
+
+
+ /**
+ * This method process the data in a cell and sets
+ * the appropriate attributes on the cell <code>Element</code>.
+ *
+ * @param cellElement A TAG_TABLE_CELL <code>Element</code>
+ * that we will be adding attributes to
+ * based on the type of data in the cell.
+ * @param type The type of data contained in the cell.
+ * @param contents The contents of the data contained in
+ * the cell.
+ */
+ protected void processCellData(Element cellElement, String type,
+ String contents) {
+
+ // Set cell value-type attribute
+ cellElement.setAttribute(ATTRIBUTE_TABLE_VALUE_TYPE, type);
+
+ // Does the cell contain a formula?
+ if (contents.startsWith("=")) {
+
+ cellElement.setAttribute(ATTRIBUTE_TABLE_FORMULA, contents);
+
+ cellElement.setAttribute(ATTRIBUTE_TABLE_VALUE, decoder.getCellValue());
+ // String data does not require any additional attributes
+ } else if (!type.equals(CELLTYPE_STRING)) {
+
+ if (type.equals(CELLTYPE_TIME)) {
+
+ // Data returned in StarOffice XML format, so store in
+ // attribute
+ cellElement.setAttribute(ATTRIBUTE_TABLE_TIME_VALUE,
+ contents);
+
+ } else if (type.equals(CELLTYPE_DATE)) {
+
+ // Data returned in StarOffice XML format, so store in
+ // attribute
+ cellElement.setAttribute(ATTRIBUTE_TABLE_DATE_VALUE,
+ contents);
+
+ } else if (type.equals(CELLTYPE_BOOLEAN)) {
+
+ // StarOffice XML format requires stored boolean value
+ // to be in lower case
+ cellElement.setAttribute(ATTRIBUTE_TABLE_BOOLEAN_VALUE,
+ contents.toLowerCase());
+
+ } else if (type.equals(CELLTYPE_CURRENCY)) {
+ // TODO - StarOffice XML format requires a correct style to
+ // display currencies correctly. Need to implement styles.
+ // TODO - USD is for US currencies. Need to pick up
+ // the correct currency location from the source file.
+ cellElement.setAttribute(ATTRIBUTE_TABLE_CURRENCY, "USD");
+
+ // Data comes stripped of currency symbols
+ cellElement.setAttribute(ATTRIBUTE_TABLE_VALUE, contents);
+
+ } else if (type.equals(CELLTYPE_PERCENT)) {
+ // Data comes stripped of percent signs
+ cellElement.setAttribute(ATTRIBUTE_TABLE_VALUE, contents);
+
+ } else {
+ // Remaining data types use table-value attribute
+
+ cellElement.setAttribute(ATTRIBUTE_TABLE_VALUE, contents);
+ }
+ }
+ }
+
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocumentSerializer.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocumentSerializer.java
new file mode 100644
index 000000000000..b0cfc09893bc
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocumentSerializer.java
@@ -0,0 +1,993 @@
+/*************************************************************************
+ *
+ * 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.sxc;
+
+import java.awt.Color;
+
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Element;
+
+import java.io.IOException;
+import java.util.Vector;
+import java.util.Enumeration;
+
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.ConvertException;
+import org.openoffice.xmerge.DocumentSerializer;
+
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+import org.openoffice.xmerge.converter.xml.sxc.SxcDocument;
+import org.openoffice.xmerge.converter.xml.sxc.CellStyle;
+import org.openoffice.xmerge.converter.xml.StyleCatalog;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.XmlUtil;
+
+/**
+ * <p>General spreadsheet implementation of <code>DocumentSerializer</code>
+ * for the {@link
+ * org.openoffice.xmerge.converter.xml.sxc.SxcPluginFactory
+ * SxcPluginFactory}. Used with SXC <code>Document</code> objects.</p>
+ *
+ * <p>The <code>serialize</code> method traverses the DOM
+ * <code>Document</code> from the given <code>Document</code> object.
+ * It uses a <code>DocEncoder</code> object for the actual conversion
+ * of contents to the device spreadsheet format.</p>
+ *
+ * @author Paul Rank
+ * @author Mark Murnane
+ */
+public abstract class SxcDocumentSerializer implements OfficeConstants,
+ DocumentSerializer {
+
+ /** The cell foreground <code>Color</code>. */
+ private Color foreground = Color.black;
+
+ /** The cell background <code>Color</code>. */
+ private Color background = Color.white;
+
+ /** The cell format. */
+ private long format = 0;
+
+ /** <code>Format</code> object describing the cell. */
+ private Format fmt = null;
+
+ /** The row number. */
+ private int rowID = 1;
+
+ /** The column number. */
+ private int colID = 1;
+
+ /** The number of times the current row is repeated. */
+ private int rowsRepeated = 1;
+
+ /** The number of times the current column is repeated. */
+ private int colsRepeated = 1;
+
+ /** The number of times the current column is repeated. */
+ private StyleCatalog styleCat = null;
+ /**
+ * An array of column widths of the current worksheet. Width is
+ * measured in number of characters.
+ */
+ private Vector ColumnRowList;
+
+ /** Width, in characters, of the current cell display data. */
+ private int displayWidth = 0;
+
+ /**
+ * A <code>SpreadsheetEncoder</code> object for encoding to
+ * appropriate format.
+ */
+ protected SpreadsheetEncoder encoder = null;
+
+ /** <code>SxcDocument</code> object that this converter processes. */
+ protected SxcDocument sxcDoc = null;
+
+
+ /**
+ * Constructor.
+ *
+ * @param document Input <code>SxcDocument</code>
+ * <code>Document</code>.
+ */
+ public SxcDocumentSerializer(Document document) {
+ fmt = new Format();
+ sxcDoc = (SxcDocument) document;
+ }
+
+
+ /**
+ * <p>Method to convert a DOM <code>Document</code> into
+ * &quot;Device&quot; <code>Document</code> objects.</p>
+ *
+ * <p>This method is not thread safe for performance reasons.
+ * This method should not be called from within two threads.
+ * It would be best to call this method only once per object
+ * instance.</p>
+ *
+ * @return <code>ConvertData</code> containing &quot;Device&quot;
+ * <code>Document</code> objects.
+ *
+ * @throws ConvertException If any conversion error occurs.
+ * @throws IOException If any I/O error occurs.
+ */
+ public abstract ConvertData serialize() throws ConvertException,
+ IOException;
+
+
+ /**
+ * This method traverses <i>office:settings</i> <code>Element</code>.
+ *
+ * @param node <i>office:settings</i> <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void traverseSettings(Node node) throws IOException {
+ if (node.hasChildNodes()) {
+
+ NodeList nodeList = node.getChildNodes();
+ int len = nodeList.getLength();
+ for (int i = 0; i < len; i++) {
+ Node child = nodeList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String nodeName = child.getNodeName();
+
+ if (nodeName.equals(TAG_CONFIG_ITEM_SET)) {
+
+ traverseSettings(child);
+
+ } else if (nodeName.equals(TAG_CONFIG_ITEM_MAP_INDEXED)) {
+
+ traverseSettings(child);
+
+ } else if (nodeName.equals(TAG_CONFIG_ITEM_MAP_ENTRY)) {
+
+ BookSettings bs = new BookSettings(child);
+ encoder.addSettings(bs);
+
+ } else {
+
+ Debug.log(Debug.TRACE, "<OTHERS " + XmlUtil.getNodeInfo(child) + " />");
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * Handles the loading of defined styles from the style.xml file as well
+ * as automatic styles from the content.xml file.
+ *
+ * Any change to a defined style, such as a short bold section, falls into
+ * the latter category.
+ */
+ protected void loadStyles(SxcDocument sxcDoc) {
+
+ styleCat = new StyleCatalog(25);
+ NodeList nl = null;
+ String families[] = new String[] { SxcConstants.COLUMN_STYLE_FAMILY,
+ SxcConstants.ROW_STYLE_FAMILY,
+ SxcConstants.TABLE_CELL_STYLE_FAMILY };
+ Class classes[] = new Class[] { ColumnStyle.class,
+ RowStyle.class,
+ CellStyle.class};
+ /*
+ * Process the content XML for any other style info.
+ */
+ org.w3c.dom.Document contentDom = sxcDoc.getContentDOM();
+ nl = contentDom.getElementsByTagName(TAG_OFFICE_AUTOMATIC_STYLES);
+ if (nl.getLength() != 0) {
+ styleCat.add(nl.item(0), families, classes, null, false);
+ }
+
+ org.w3c.dom.Document stylesDom = sxcDoc.getStyleDOM();
+ nl = stylesDom.getElementsByTagName(TAG_OFFICE_STYLES);
+ if (nl.getLength() != 0) {
+ styleCat.add(nl.item(0), families, classes, null, false);
+ }
+ }
+
+ /**
+ * This method traverses <i>office:body</i> <code>Element</code>.
+ *
+ * @param node <i>office:body</i> <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void traverseBody(Node node) throws IOException {
+
+ Debug.log(Debug.TRACE, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ Debug.log(Debug.TRACE, "<DEBUGLOG>");
+
+ if (node.hasChildNodes()) {
+
+ NodeList nodeList = node.getChildNodes();
+ int len = nodeList.getLength();
+
+ for (int i = 0; i < len; i++) {
+ Node searchNode = nodeList.item(i);
+ if (searchNode.getNodeType() == Node.ELEMENT_NODE) {
+
+ String nodeName = searchNode.getNodeName();
+
+ if (nodeName.equals(TAG_NAMED_EXPRESSIONS)) {
+
+ traverseNamedExpressions(searchNode);
+
+ } else {
+
+ Debug.log(Debug.TRACE, "Skipping " + XmlUtil.getNodeInfo(searchNode) + " />");
+ }
+ }
+ }
+
+ for (int i = 0; i < len; i++) {
+ Node child = nodeList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String nodeName = child.getNodeName();
+
+ if (nodeName.equals(TAG_TABLE)) {
+
+ traverseTable(child);
+
+ } else {
+
+ Debug.log(Debug.TRACE, "<OTHERS " + XmlUtil.getNodeInfo(child) + " />");
+ }
+ }
+ }
+ }
+
+ Debug.log(Debug.TRACE, "</DEBUGLOG>");
+ }
+
+
+ /**
+ * This method traverses the <i>table:table</i> element
+ * <code>Node</code>.
+ *
+ * @param node A <i>table:table</i> <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void traverseNamedExpressions(Node node) throws IOException {
+
+ Debug.log(Debug.TRACE, "<NAMED:EXPRESSIONS>");
+
+ NamedNodeMap att = node.getAttributes();
+
+ if (node.hasChildNodes()) {
+
+ NodeList nodeList = node.getChildNodes();
+ int len = nodeList.getLength();
+
+ for (int i = 0; i < len; i++) {
+ Node child = nodeList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ NameDefinition nd = new NameDefinition(child);
+ encoder.setNameDefinition(nd);
+ }
+ }
+ }
+
+ Debug.log(Debug.TRACE, "</NAMED:EXPRESSIONS>");
+ }
+
+ /**
+ * This method traverses the <i>table:table</i> element
+ * <code>Node</code>.
+ *
+ * @param node A <i>table:table</i> <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void traverseTable(Node node) throws IOException {
+
+ Debug.log(Debug.TRACE, "<TABLE>");
+
+ ColumnRowList = new Vector();
+
+ // Get table attributes
+ // TODO - extract style from attribute
+
+ NamedNodeMap att = node.getAttributes();
+
+ String tableName =
+ att.getNamedItem(ATTRIBUTE_TABLE_NAME).getNodeValue();
+
+ rowID = 1;
+
+ encoder.createWorksheet(tableName);
+
+ if (node.hasChildNodes()) {
+
+ NodeList nodeList = node.getChildNodes();
+ int len = nodeList.getLength();
+
+ for (int i = 0; i < len; i++) {
+ Node child = nodeList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String nodeName = child.getNodeName();
+
+ if (nodeName.equals(TAG_TABLE_ROW)) {
+ // TODO - handle all the possible rows
+ // spelled out in the entities
+
+ traverseTableRow(child);
+
+ } else if (nodeName.equals(TAG_TABLE_COLUMN)) {
+
+ traverseTableColumn(child);
+
+ } else if (nodeName.equals(TAG_TABLE_SCENARIO)) {
+
+ // TODO
+
+ } else {
+
+ Debug.log(Debug.TRACE, "<OTHERS " + XmlUtil.getNodeInfo(child) + " />");
+ }
+ }
+ }
+ }
+
+ // Add column width info to the current sheet
+ encoder.setColumnRows(ColumnRowList);
+
+ Debug.log(Debug.TRACE, "</TABLE>");
+ }
+
+ /**
+ * This method traverses the <i>table:table-row</i> element
+ * <code>Node</code>.
+ *
+ * @param node A <i>table:table-row</i> <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void traverseTableRow(Node node) throws IOException {
+
+ // Get the attributes of the row
+ NamedNodeMap cellAtt = node.getAttributes();
+
+ if (cellAtt != null) {
+
+ Node rowStyle =
+ cellAtt.getNamedItem(ATTRIBUTE_TABLE_STYLE_NAME);
+
+ Node tableNumRowRepeatingNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_NUM_ROWS_REPEATED);
+ int repeatedRows = 1;
+
+ if(tableNumRowRepeatingNode!=null) {
+ String repeatStr = tableNumRowRepeatingNode.getNodeValue();
+ Debug.log(Debug.TRACE, "traverseTableRow() repeated-rows : " + repeatStr);
+ repeatedRows = Integer.parseInt(repeatStr);
+ }
+
+ String styleName = new String("");
+
+ if ( rowStyle != null) {
+ styleName = rowStyle.getNodeValue();
+ }
+ if(styleName.equalsIgnoreCase("Default") || styleName.length()==0) {
+
+ Debug.log(Debug.TRACE, "No defined Row Style Attribute was found");
+
+ } else {
+
+ RowStyle rStyle = ( RowStyle)styleCat.lookup(styleName,
+ SxcConstants.ROW_STYLE_FAMILY, null,
+ RowStyle.class);
+
+ int rowHeight = rStyle.getRowHeight();
+
+ Debug.log(Debug.TRACE, "traverseTableRow() Row Height : " + rowHeight);
+ ColumnRowInfo ri = new ColumnRowInfo( rowHeight,
+ repeatedRows,
+ ColumnRowInfo.ROW,
+ rowHeight!=0);
+ ColumnRowList.add(ri);
+ }
+
+ // Get the attribute representing the number of rows repeated
+ Node rowsRepeatedNode =
+ cellAtt.getNamedItem(ATTRIBUTE_TABLE_NUM_ROWS_REPEATED);
+
+ // There is a number of rows repeated attribute:
+ if (rowsRepeatedNode != null) {
+
+ // Get the number of times the row is repeated
+ String rowsRepeatedString = rowsRepeatedNode.getNodeValue();
+
+ Integer rowsRepeatedInt = new Integer(rowsRepeatedString);
+
+ rowsRepeated = rowsRepeatedInt.intValue();
+
+ } else {
+
+ // The row is not repeated
+ rowsRepeated = 1;
+ }
+ }
+
+ Debug.log(Debug.TRACE, "<TR>");
+
+ if (node.hasChildNodes()) {
+
+ NodeList nodeList = node.getChildNodes();
+ int len = nodeList.getLength();
+
+ for (int i = 0; i < len; i++) {
+ Node child = nodeList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String nodeName = child.getNodeName();
+
+ if (nodeName.equals(TAG_TABLE_CELL)) {
+
+ traverseCell(child);
+
+ } else {
+
+ Debug.log(Debug.TRACE, "<OTHERS " + XmlUtil.getNodeInfo(child) + " />");
+ }
+ }
+ }
+ }
+
+ // Increase the row counter by the number of rows which are repeated
+ rowID += rowsRepeated;
+
+ // Re-initialize number of rows repeated before processing the next
+ // row data.
+ rowsRepeated = 1;
+
+ // When starting a new row, set the column counter back to the
+ // first column.
+ colID = 1;
+
+ // Re-initialize number of columns repeated before processing
+ // the next row data.
+ colsRepeated = 1;
+
+ Debug.log(Debug.TRACE, "</TR>");
+ }
+
+
+ /**
+ * This method traverses the <i>table:table-column</i>
+ * <code>Node</code>. Not yet implemented.
+ *
+ * @param node A <i>table:table-column</i> <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void traverseTableColumn(Node node) throws IOException {
+
+ Debug.log(Debug.TRACE, "traverseColumn() : ");
+ NamedNodeMap cellAtt = node.getAttributes();
+ Node tableStyleNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_STYLE_NAME);
+ Node tableNumColRepeatingNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_NUM_COLUMNS_REPEATED);
+ Node tableDefaultCellStyle = cellAtt.getNamedItem(ATTRIBUTE_DEFAULT_CELL_STYLE);
+
+ int repeatedColumns = 1;
+ int columnWidth = 0;
+ ColumnRowInfo col = new ColumnRowInfo(ColumnRowInfo.COLUMN);
+
+ if(tableNumColRepeatingNode!=null) {
+ Debug.log(Debug.TRACE, "traverseColumn() repeated-cols : " + tableNumColRepeatingNode.getNodeValue());
+ repeatedColumns = Integer.parseInt(tableNumColRepeatingNode.getNodeValue());
+ col.setRepeated(repeatedColumns);
+ }
+
+ String cellStyleName = new String("");
+
+ if(tableDefaultCellStyle!=null) {
+ cellStyleName = tableDefaultCellStyle.getNodeValue();
+
+ Debug.log(Debug.TRACE, "traverseColumn() default-cell-style : " + cellStyleName);
+ }
+
+ if(cellStyleName.equalsIgnoreCase("Default") || cellStyleName.length()==0) {
+
+ Debug.log(Debug.TRACE, "No default cell Style Attribute was found");
+
+ } else {
+
+ CellStyle cellStyle = (CellStyle)styleCat.lookup(cellStyleName,
+ SxcConstants.TABLE_CELL_STYLE_FAMILY, null,
+ CellStyle.class);
+ Format defaultFmt = new Format(cellStyle.getFormat());
+ col.setFormat(defaultFmt);
+ }
+
+ String styleName = new String("");
+
+ if(tableStyleNode!=null) {
+ styleName = tableStyleNode.getNodeValue();
+ }
+
+ if(styleName.equalsIgnoreCase("Default") || styleName.length()==0) {
+
+ Debug.log(Debug.TRACE, "No defined Style Attribute was found");
+
+ } else {
+
+ ColumnStyle cStyle = (ColumnStyle)styleCat.lookup(styleName,
+ SxcConstants.COLUMN_STYLE_FAMILY, null,
+ ColumnStyle.class);
+
+ columnWidth = cStyle.getColWidth();
+ col.setSize(columnWidth);
+ Debug.log(Debug.TRACE, "traverseColumn() Column Width : " + columnWidth);
+
+ }
+ ColumnRowList.add(col);
+ }
+
+ /**
+ * This method traverses a <i>table:table-cell</i> element
+ * <code>Node</code>.
+ *
+ * @param node a <i>table:table-cell</i> <code>Node</code>.
+ *
+ * @throws IOException if any I/O error occurs.
+ */
+ protected void traverseCell(Node node) throws IOException {
+
+ NamedNodeMap cellAtt = node.getAttributes();
+
+ int debug_i=0;
+ Node debug_attrib = null;
+ fmt.clearFormatting();
+ if (cellAtt == null || cellAtt.item(0) == null)
+ {
+ Debug.log(Debug.INFO, "No Cell Attributes\n");
+ // return;
+ }
+ else
+ {
+ while ((debug_attrib = cellAtt.item(debug_i++)) != null)
+ {
+ Debug.log(Debug.INFO, "Cell Attribute " + debug_i +
+ ": " + debug_attrib.getNodeName() + " : " +
+ debug_attrib.getNodeValue() + "\n");
+ }
+ }
+
+ // Get the type of data in the cell
+ Node tableValueTypeNode =
+ cellAtt.getNamedItem(ATTRIBUTE_TABLE_VALUE_TYPE);
+
+ // Get the number of columns this cell is repeated
+ Node colsRepeatedNode =
+ cellAtt.getNamedItem(ATTRIBUTE_TABLE_NUM_COLUMNS_REPEATED);
+
+ // Get the style type
+ Node tableStyleNode =
+ cellAtt.getNamedItem(ATTRIBUTE_TABLE_STYLE_NAME);
+
+ String styleName = new String("");
+
+ if(tableStyleNode!=null) {
+ styleName = tableStyleNode.getNodeValue();
+ }
+
+ if(styleName.equalsIgnoreCase("Default")) {
+
+ Debug.log(Debug.TRACE, "No defined Style Attribute was found");
+
+ } else if(styleName.length()!=0) {
+
+ CellStyle cStyle = (CellStyle)styleCat.lookup(styleName,
+ SxcConstants.TABLE_CELL_STYLE_FAMILY, null,
+ CellStyle.class);
+
+ Format definedFormat = cStyle.getFormat();
+ fmt = new Format(definedFormat);
+ }
+
+ // There is a number of cols repeated attribute
+ if (colsRepeatedNode != null) {
+
+ // Get the number of times the cell is repeated
+ String colsRepeatedString = colsRepeatedNode.getNodeValue();
+
+ Integer colsRepeatedInt = new Integer(colsRepeatedString);
+ colsRepeated = colsRepeatedInt.intValue();
+ } else {
+
+ // The cell is not repeated
+ colsRepeated = 1;
+ }
+
+
+ // if there is no style we need to check to see if there is a default
+ // cell style defined in the table-column's
+
+ if (fmt.isDefault() && styleName.length()==0) {
+ int index = 1;
+ for(Enumeration e = ColumnRowList.elements();e.hasMoreElements();) {
+ ColumnRowInfo cri = (ColumnRowInfo) e.nextElement();
+ if(cri.isColumn()) {
+ if(colID>=index && colID<(index+cri.getRepeated())) {
+ fmt = new Format(cri.getFormat());
+ }
+ index += cri.getRepeated();
+ }
+ }
+ }
+
+
+ // for (int j = 0; j < colsRepeated; j++) {
+
+
+ if (tableValueTypeNode != null) {
+
+ // Make sure we initialize to 0 the width of the current cell
+ displayWidth = 0;
+
+ String cellType =
+ tableValueTypeNode.getNodeValue();
+
+ if (cellType.equalsIgnoreCase(CELLTYPE_STRING)) {
+
+ // has text:p tag
+ fmt.setCategory(CELLTYPE_STRING);
+ Node tableStringValueNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_STRING_VALUE);
+ Debug.log(Debug.TRACE,"Cell Type String : " + tableStringValueNode);
+ if(tableStringValueNode != null) {
+ fmt.setValue(tableStringValueNode.getNodeValue());
+ }
+
+ } else if (cellType.equalsIgnoreCase(CELLTYPE_FLOAT)) {
+
+ // has table:value attribute
+ // has text:p tag
+
+ // Determine the number of decimal places StarCalc
+ // is displaying for this floating point output.
+ fmt.setCategory(CELLTYPE_FLOAT);
+ fmt.setDecimalPlaces(getDecimalPlaces(node));
+ Node tableValueNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_VALUE);
+ fmt.setValue(tableValueNode.getNodeValue());
+
+
+ } else if (cellType.equalsIgnoreCase(CELLTYPE_TIME)) {
+
+ // has table:time-value attribute
+ // has text:p tag - which is the value we convert
+
+ fmt.setCategory(CELLTYPE_TIME);
+ Node tableTimeNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_TIME_VALUE);
+ fmt.setValue(tableTimeNode.getNodeValue());
+
+ } else if (cellType.equalsIgnoreCase(CELLTYPE_DATE)) {
+
+ // has table:date-value attribute
+ // has text:p tag - which is the value we convert
+
+ fmt.setCategory(CELLTYPE_DATE);
+ Node tableDateNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_DATE_VALUE);
+ fmt.setValue(tableDateNode.getNodeValue());
+
+ } else if (cellType.equalsIgnoreCase(CELLTYPE_CURRENCY)) {
+
+ // has table:currency
+ // has table:value attribute
+ // has text:p tag
+
+ fmt.setCategory(CELLTYPE_CURRENCY);
+ fmt.setDecimalPlaces(getDecimalPlaces(node));
+ Node tableValueNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_VALUE);
+ fmt.setValue(tableValueNode.getNodeValue());
+
+ } else if (cellType.equalsIgnoreCase(CELLTYPE_BOOLEAN)) {
+
+ // has table:boolean-value attribute
+ // has text:p tag - which is the value we convert
+
+ fmt.setCategory(CELLTYPE_BOOLEAN);
+ Node tableBooleanNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_BOOLEAN_VALUE);
+ fmt.setValue(tableBooleanNode.getNodeValue());
+
+ } else if (cellType.equalsIgnoreCase(CELLTYPE_PERCENT)) {
+
+ // has table:value attribute
+ // has text:p tag
+
+ fmt.setCategory(CELLTYPE_PERCENT);
+ fmt.setDecimalPlaces(getDecimalPlaces(node));
+ Node tableValueNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_VALUE);
+ fmt.setValue(tableValueNode.getNodeValue());
+
+ } else {
+
+ Debug.log(Debug.TRACE,"No defined value type" + cellType);
+ // Should never get here
+
+ }
+ }
+
+ Node tableFormulaNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_FORMULA);
+
+ if(tableFormulaNode != null)
+ {
+ if(tableValueTypeNode == null) { // If there is no value-type Node we must assume string-value
+ fmt.setCategory(CELLTYPE_STRING);
+ Node tableStringValueNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_STRING_VALUE);
+ fmt.setValue(tableStringValueNode.getNodeValue());
+ }
+ String cellFormula = tableFormulaNode.getNodeValue();
+ addCell(cellFormula);
+ } else {
+
+ // Text node, Date node, or Time node
+ //
+ Debug.log(Debug.INFO,
+ "TextNode, DateNode, TimeNode or BooleanNode\n");
+ // This handles the case where we have style information but no content
+ if (node.hasChildNodes()) {
+ NodeList childList = node.getChildNodes();
+ int len = childList.getLength();
+
+ for (int i = 0; i < len; i++) {
+ Node child = childList.item(i);
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String childName = child.getNodeName();
+ if (childName.equals(TAG_PARAGRAPH)) {
+ traverseParagraph(child);
+ }
+ }
+ }
+ } else if(!fmt.isDefault()) {
+ addCell("");
+ }
+ }
+
+ // Clear out format for current cell after it is written
+ format = 0;
+
+ // Increase the column counter by the number of times the
+ // last cell was repeated.
+ colID += colsRepeated;
+
+ // Re-initialize the number of columns repeated before processing
+ // the next cell data.
+ colsRepeated = 1;
+
+ }
+
+
+ /**
+ * This method traverses the <i>text:p</i> element <code>Node</code>.
+ *
+ * @param node A <i>text:p</i> <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void traverseParagraph(Node node) throws IOException {
+
+ NamedNodeMap cellAtt = node.getAttributes();
+
+ int debug_i=0;
+ Node debug_attrib = null;
+ if (cellAtt == null || cellAtt.item(0) == null)
+ {
+ Debug.log(Debug.INFO, "No Paragraph Attributes\n");
+ }
+ else
+ {
+ while ((debug_attrib = cellAtt.item(debug_i++)) != null)
+ {
+ Debug.log(Debug.INFO, "Paragraph Attribute " + debug_i +
+ ": " + debug_attrib.getNodeName() + " : " +
+ debug_attrib.getNodeValue() + "\n");
+ }
+ }
+
+ if (node.hasChildNodes()) {
+
+ NodeList nodeList = node.getChildNodes();
+
+ int len = nodeList.getLength();
+
+ StringBuffer buffer = new StringBuffer();
+
+ for (int i = 0; i < len; i++) {
+
+ Node child = nodeList.item(i);
+
+ // TODO: need to handle space/tabs/newline nodes later
+ short nodeType = child.getNodeType();
+
+ switch (nodeType) {
+
+ case Node.TEXT_NODE:
+ buffer.append(child.getNodeValue());
+ break;
+
+ case Node.ENTITY_REFERENCE_NODE:
+
+ NodeList nodeList2 = child.getChildNodes();
+ int len2 = nodeList2.getLength();
+
+ for (int j = 0; j < len2; j++) {
+ Node child2 = nodeList2.item(j);
+
+ if (child2.getNodeType() == Node.TEXT_NODE) {
+ buffer.append(child2.getNodeValue());
+ }
+ }
+
+ break;
+ }
+ }
+
+ String s = buffer.toString();
+ // displayWidth = calculateContentWidth(s);
+ addCell(s);
+
+ }
+ }
+
+
+ /**
+ * This method will take the input cell value and add
+ * it to the spreadsheet <code>Document</code> we are currently
+ * encoding. This method correctly handles cells that are
+ * repeated in either the row, cell, or both directions.
+ *
+ * @param cellValue The contents of the cell we want to add
+ * to the spreadsheet <code>Document</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void addCell(String cellValue) throws IOException {
+
+ int col = colID;
+ int row = rowID;
+
+ for (int i = 0; i < rowsRepeated; i++) {
+
+ // Log the columns when there are rowsRepeated.
+ if (i > 0) {
+ Debug.log(Debug.TRACE, "</TR>");
+ Debug.log(Debug.TRACE, "<TR>");
+ }
+
+ col = colID;
+
+ for (int j = 0; j < colsRepeated; j++) {
+
+ Debug.log(Debug.TRACE, "<TD>");
+
+
+ // Add the cell data to the encoded spreadsheet document
+ encoder.addCell(row, col, fmt, cellValue);
+
+ Debug.log(Debug.TRACE, cellValue);
+ Debug.log(Debug.TRACE, "</TD>");
+
+ col++;
+ }
+
+ row++;
+
+ }
+
+ }
+
+
+
+ /**
+ * This method takes a <i>table:table-cell</i> <code>Node</code>
+ * and traverses down to the <i>text:p</i> tag. The value is
+ * extracted from the <i>text:p</i> tag and the number of decimal
+ * places is calculated.
+ *
+ * @param node A <i>table:table-cell</i> <code>Node</code>.
+ *
+ * @return The number of decimal places in the display
+ * string of the data in the input <code>Node</code>.
+ */
+ protected int getDecimalPlaces(Node node) {
+
+ int decimals = 0;
+
+ Element element = null;
+
+ // cast org.w3c.dom.Node to org.w3c.dom.Element
+ if (node instanceof Element) {
+ element = (Element) node;
+ } else {
+ return decimals;
+ }
+
+ // Traverse to the text:p element, there should only be one.
+ NodeList list = element.getElementsByTagName(TAG_PARAGRAPH);
+
+ if (list.getLength() != 1) {
+ return decimals;
+ }
+
+ Node paragraph = list.item(0);
+
+ if (paragraph.hasChildNodes()) {
+
+ NodeList nodeList = paragraph.getChildNodes();
+
+ int len = nodeList.getLength();
+
+ for (int j = 0; j < len; j++) {
+
+ Node child = nodeList.item(j);
+
+ if (child.getNodeType() == Node.TEXT_NODE) {
+
+ String s = child.getNodeValue();
+
+ // displayWidth = calculateContentWidth(s);
+
+ int k = s.lastIndexOf(".");
+ if (k > 0) {
+ s = s.substring(k+1);
+ decimals = s.length();
+ }
+ }
+ }
+ }
+
+ return decimals;
+ }
+
+ /*
+ * Utility method to retrieve a Node attribute.
+ */
+ private String getAttribute (Node node, String attribute) {
+ NamedNodeMap attrNodes = node.getAttributes();
+
+ if (attrNodes != null) {
+ Node attr = attrNodes.getNamedItem(attribute);
+ if (attr != null) {
+ return attr.getNodeValue();
+ }
+ }
+ return null;
+ }
+
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcPluginFactory.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcPluginFactory.java
new file mode 100644
index 000000000000..401bdff1f533
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcPluginFactory.java
@@ -0,0 +1,82 @@
+/*************************************************************************
+ *
+ * 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.sxc;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+import org.openoffice.xmerge.util.registry.ConverterInfo;
+import org.openoffice.xmerge.PluginFactory;
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.DocumentMergerFactory;
+
+
+/**
+ * General implementation of the <code>PluginFactory</code> interface
+ * for SXC <code>Document</code> objects.
+ *
+ * @see org.openoffice.xmerge.DocumentDeserializer
+ * @see org.openoffice.xmerge.DocumentMerger
+ * @see org.openoffice.xmerge.DocumentSerializer
+ */
+public abstract class SxcPluginFactory
+ extends PluginFactory implements DocumentMergerFactory {
+
+
+ /**
+ * Constructor that caches the <code>ConvertInfo</code> that
+ * corresponds to the registry information for this plug-in.
+ *
+ * @param ci <code>ConvertInfo</code> object.
+ */
+ public SxcPluginFactory(ConverterInfo ci) {
+ super(ci);
+ }
+
+
+ public Document createOfficeDocument(String name, InputStream is)
+ throws IOException {
+
+ // read zipped XML stream
+ //
+ SxcDocument doc = new SxcDocument(name);
+ doc.read(is);
+ return doc;
+ }
+
+ public Document createOfficeDocument(String name, InputStream is,boolean isZip)
+ throws IOException {
+
+ // read zipped XML stream
+ //
+ SxcDocument doc = new SxcDocument(name);
+ doc.read(is,isZip);
+ return doc;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/package.html b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/package.html
new file mode 100644
index 000000000000..d350ea262303
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/package.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!--
+ #*************************************************************************
+ #
+ 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.
+
+ #*************************************************************************
+ -->
+<html>
+<head>
+<title>org.openoffice.xmerge.converter.xml.sxc package</title>
+</head>
+
+<body bgcolor="white">
+<p>Provides base implementation of StarCalc XML conversion to and from
+different &quot;Device&quot; <code>Document</code> formats.</p>
+
+</body>
+</html>