diff options
Diffstat (limited to 'xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc')
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 "Office" <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 "Device" + * <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 "Device" + * <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", "'Courier New'", "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 + * "Device" <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 "Device" + * <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 "Device" <code>Document</code> formats.</p> + +</body> +</html> |