| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| package org.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; |
| } |
| |
| } |
| |