#ODFTOOLKIT-388# fixed by Raimund Hoelle - Test hangs when iterating over a spreadsheet created with LibreOffice 4.0.0
git-svn-id: https://svn.apache.org/repos/asf/incubator/odf/trunk@1715398 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/simple/src/main/java/org/odftoolkit/simple/SpreadsheetDocument.java b/simple/src/main/java/org/odftoolkit/simple/SpreadsheetDocument.java
index 12b96b9..550c3a2 100644
--- a/simple/src/main/java/org/odftoolkit/simple/SpreadsheetDocument.java
+++ b/simple/src/main/java/org/odftoolkit/simple/SpreadsheetDocument.java
@@ -1,666 +1,639 @@
-/************************************************************************
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
- *
- * Copyright 2008, 2010 Oracle and/or its affiliates. All rights reserved.
- *
- * Use is subject to license terms.
- *
- * Licensed 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. You can also
- * obtain a copy of the License at http://odftoolkit.org/docs/license.txt
- *
- * 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.odftoolkit.simple;
-
-import java.awt.Rectangle;
-import java.io.File;
-import java.io.InputStream;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.xml.xpath.XPathConstants;
-
-import org.odftoolkit.odfdom.dom.OdfContentDom;
-import org.odftoolkit.odfdom.dom.element.draw.DrawFrameElement;
-import org.odftoolkit.odfdom.dom.element.office.OfficeSpreadsheetElement;
-import org.odftoolkit.odfdom.dom.element.table.TableTableCellElement;
-import org.odftoolkit.odfdom.dom.element.table.TableTableElement;
-import org.odftoolkit.odfdom.pkg.MediaType;
-import org.odftoolkit.odfdom.pkg.OdfElement;
-import org.odftoolkit.odfdom.pkg.OdfPackage;
-import org.odftoolkit.odfdom.type.CellRangeAddressList;
-import org.odftoolkit.simple.chart.AbstractChartContainer;
-import org.odftoolkit.simple.chart.Chart;
-import org.odftoolkit.simple.chart.ChartContainer;
-import org.odftoolkit.simple.chart.DataSet;
-import org.odftoolkit.simple.table.Cell;
-import org.odftoolkit.simple.table.Table;
-import org.odftoolkit.simple.table.TableContainer;
-import org.w3c.dom.Node;
-
-/**
- * This class represents an empty ODF spreadsheet document.
- *
- */
-public class SpreadsheetDocument extends Document implements ChartContainer {
-
- private static final String EMPTY_SPREADSHEET_DOCUMENT_PATH = "/OdfSpreadsheetDocument.ods";
- static final Resource EMPTY_SPREADSHEET_DOCUMENT_RESOURCE = new Resource(EMPTY_SPREADSHEET_DOCUMENT_PATH);
- private ChartContainerImpl chartContainerImpl;
- /**
- * This enum contains all possible media types of SpreadsheetDocument
- * documents.
- */
- public enum OdfMediaType implements MediaType {
-
- SPREADSHEET(Document.OdfMediaType.SPREADSHEET), SPREADSHEET_TEMPLATE(Document.OdfMediaType.SPREADSHEET_TEMPLATE);
- private final Document.OdfMediaType mMediaType;
-
- OdfMediaType(Document.OdfMediaType mediaType) {
- this.mMediaType = mediaType;
- }
-
- /**
- * @return the mediatype of this document
- */
- public String getMediaTypeString() {
- return mMediaType.getMediaTypeString();
- }
-
- /**
- * @return the ODF filesuffix of this document
- */
- public String getSuffix() {
- return mMediaType.getSuffix();
- }
-
- /**
- *
- * @param mediaType
- * string defining an ODF document
- * @return the according OdfMediatype encapuslating the given string and
- * the suffix
- */
- public static Document.OdfMediaType getOdfMediaType(String mediaType) {
- return Document.OdfMediaType.getOdfMediaType(mediaType);
- }
- }
-
- /**
- * Creates an empty spreadsheet document.
- *
- * @return ODF spreadsheet document based on a default template*
- * @throws java.lang.Exception
- * - if the document could not be created
- */
- public static SpreadsheetDocument newSpreadsheetDocument() throws Exception {
- return (SpreadsheetDocument) Document.loadTemplate(EMPTY_SPREADSHEET_DOCUMENT_RESOURCE,
- Document.OdfMediaType.SPREADSHEET);
- }
-
- /**
- * Creates an empty spreadsheet template.
- *
- * @return ODF spreadsheet template based on a default
- * @throws java.lang.Exception
- * - if the template could not be created
- */
- public static SpreadsheetDocument newSpreadsheetTemplateDocument() throws Exception {
- SpreadsheetDocument doc = (SpreadsheetDocument) Document.loadTemplate(EMPTY_SPREADSHEET_DOCUMENT_RESOURCE,
- Document.OdfMediaType.SPREADSHEET_TEMPLATE);
- doc.changeMode(OdfMediaType.SPREADSHEET_TEMPLATE);
- return doc;
- }
-
- /**
- * To avoid data duplication a new document is only created, if not already
- * opened. A document is cached by this constructor using the internalpath
- * as key.
- */
- protected SpreadsheetDocument(OdfPackage pkg, String internalPath, SpreadsheetDocument.OdfMediaType odfMediaType) {
- super(pkg, internalPath, odfMediaType.mMediaType);
- }
-
- /**
- * Creates an SpreadsheetDocument from the OpenDocument provided by a
- * resource Stream.
- *
- * <p>
- * Since an InputStream does not provide the arbitrary (non sequentiell)
- * read access needed by SpreadsheetDocument, the InputStream is cached.
- * This usually takes more time compared to the other createInternalDocument
- * methods. An advantage of caching is that there are no problems
- * overwriting an input file.
- * </p>
- *
- * <p>
- * If the resource stream is not a ODF spreadsheet document,
- * ClassCastException might be thrown.
- * </p>
- *
- * @param inputStream
- * - the InputStream of the ODF spreadsheet document.
- * @return the spreadsheet document created from the given InputStream
- * @throws java.lang.Exception
- * - if the document could not be created.
- */
- public static SpreadsheetDocument loadDocument(InputStream inputStream) throws Exception {
- return (SpreadsheetDocument) Document.loadDocument(inputStream);
- }
-
- /**
- * Loads an SpreadsheetDocument from the provided path.
- *
- * <p>
- * SpreadsheetDocument relies on the file being available for read access
- * over the whole lifecycle of SpreadsheetDocument.
- * </p>
- *
- * <p>
- * If the resource stream is not a ODF spreadsheet document,
- * ClassCastException might be thrown.
- * </p>
- *
- * @param documentPath
- * - the path from where the document can be loaded
- * @return the spreadsheet document from the given path or NULL if the media
- * type is not supported by SIMPLE.
- * @throws java.lang.Exception
- * - if the document could not be created.
- */
- public static SpreadsheetDocument loadDocument(String documentPath) throws Exception {
- return (SpreadsheetDocument) Document.loadDocument(documentPath);
- }
-
- /**
- * Creates an SpreadsheetDocument from the OpenDocument provided by a File.
- *
- * <p>
- * SpreadsheetDocument relies on the file being available for read access
- * over the whole lifecycle of SpreadsheetDocument.
- * </p>
- *
- * <p>
- * If the resource stream is not a ODF spreadsheet document,
- * ClassCastException might be thrown.
- * </p>
- *
- * @param file
- * - a file representing the ODF spreadsheet document.
- * @return the spreadsheet document created from the given File
- * @throws java.lang.Exception
- * - if the document could not be created.
- */
- public static SpreadsheetDocument loadDocument(File file) throws Exception {
- return (SpreadsheetDocument) Document.loadDocument(file);
- }
-
- /**
- * Get the content root of a spreadsheet document.
- *
- * @return content root, representing the office:spreadsheet tag
- * @throws Exception
- * if the file DOM could not be created.
- */
- @Override
- public OfficeSpreadsheetElement getContentRoot() throws Exception {
- return super.getContentRoot(OfficeSpreadsheetElement.class);
- }
-
- /**
- * Changes the document to the given mediatype. This method can only be used
- * to convert a document to a related mediatype, e.g. template.
- *
- * @param mediaType
- * the related ODF mimetype
- */
- public void changeMode(OdfMediaType mediaType) {
- setOdfMediaType(mediaType.mMediaType);
- }
-
- /**
- * Retrieves sheet by index.
- *
- * @param index
- * the index of the retrieved sheet, which starts from 0. If the
- * index value is out of range (index >= sheet count or index <
- * 0), this method would return <code>null</code>.
- * @since 0.6
- */
- public Table getSheetByIndex(int index) {
- if (index < 0) {
- return null;
- }
- int count = 0;
- try {
- OfficeSpreadsheetElement spreadsheetElement = getContentRoot();
- Node child = spreadsheetElement.getFirstChild();
- while ((child != null) && (count <= index)) {
- if (child instanceof TableTableElement) {
- if (count == index) {
- return getTableBuilder().getTableInstance((TableTableElement) child);
- } else {
- count++;
- }
- }
- child = child.getNextSibling();
- }
- } catch (Exception e) {
- Logger.getLogger(SpreadsheetDocument.class.getName()).log(Level.SEVERE, null, e);
- }
- return null;
- }
-
- /**
- * Retrieves sheet by name.
- *
- * @param name
- * the name of the retrieved sheet.
- * @since 0.6
- */
- public Table getSheetByName(String name) {
- return getTableByName(name);
- }
-
-
- /**
- * Adds a new blank sheet with the specified <code>name</code> to this
- * document.
- *
- * @param name
- * the name of the new sheet.
- * @return added sheet.
- * @since 0.6
- */
- public Table appendSheet(String name) {
- Table newTable = addTable();
- newTable.setTableName(name);
- return newTable;
- }
-
- /**
- * Adds a new sheet with data from existing table.
- * <p>
- * NOTE: This method copies data from existing table, including linked
- * resources and styles, if the source table is not in the target document.
- * If these data has dependencies to other data of the source document, the
- * data dependencies will not be copied. For example, document A has two
- * sheets, "Sheet1" and "Sheet2". In "Sheet2", there is a cell with formula,
- * "=sum(Sheet1.A1:Sheet1.A10)". After copy the data of "Sheet2" to the new
- * sheet in document B, the result of this formula would be different or
- * even invalid in document B.
- *
- * @param refTable
- * the reference table, which is the data source of the new
- * sheet.
- * @param name
- * the name of the new sheet.
- * @return added sheet.
- * @since 0.6
- */
- public Table appendSheet(Table refTable, String name) {
- TableTableElement refTableElement = refTable.getOdfElement();
- try {
- OdfContentDom contentDom = getContentDom();
- TableTableElement newTableEle = (TableTableElement) (refTableElement.cloneNode(true));
- // not in a same document
- if (refTableElement.getOwnerDocument() != contentDom) {
- Document ownerDocument = refTable.getOwnerDocument();
- copyLinkedRefInBatch(newTableEle, ownerDocument);
- copyForeignStyleRef(newTableEle, ownerDocument);
- newTableEle = (TableTableElement) cloneForeignElement(newTableEle, contentDom, true);
- }
- updateNames(newTableEle);
- updateXMLIds(newTableEle);
- getTableContainerElement().appendChild(newTableEle);
- Table tableInstance = getTableBuilder().getTableInstance(newTableEle);
- tableInstance.setTableName(name);
- return tableInstance;
- } catch (Exception e) {
- Logger.getLogger(SpreadsheetDocument.class.getName()).log(Level.SEVERE, null, e);
- }
- return null;
- }
-
- /**
- * Inserts a new blank sheet before the reference index.
- *
- * @param before
- * the reference index, which starts from 0. If the index value
- * is out of range (index >= sheet count or index < 0), this
- * method would return <code>null</code>.
- * @return inserted sheet.
- * @since 0.6
- */
- public Table insertSheet(int before) {
- if (before < 0) {
- return null;
- }
- int count = 0;
- try {
- OfficeSpreadsheetElement spreadsheetElement = getContentRoot();
- Node child = spreadsheetElement.getFirstChild();
- while ((child != null) && (count <= before)) {
- if (child instanceof TableTableElement) {
- if (count == before) {
- Table table = getTableBuilder().newTable();
- getContentRoot().insertBefore(table.getOdfElement(), child);
- return table;
- } else {
- count++;
- }
- }
- child = child.getNextSibling();
- }
- } catch (Exception e) {
- Logger.getLogger(SpreadsheetDocument.class.getName()).log(Level.SEVERE, null, e);
- }
- return null;
- }
-
- /**
- * Inserts a new sheet with data from existing table.
- *
- * <p>
- * NOTE: This method copies data from existing table, including linked
- * resources and styles, if the source table is not in the target document.
- * If these data has dependencies to other data of the source document, the
- * data dependencies will not be copied. For example, document A has two
- * sheets, "Sheet1" and "Sheet2". In "Sheet2", there is a cell with formula,
- * "=sum(Sheet1.A1:Sheet1.A10)". After copy the data of "Sheet2" to the new
- * sheet in document B, the result of this formula would be different or
- * even invalid in document B.
- *
- * @param refTable
- * the reference table, which is the data source of the new
- * sheet.
- * @param before
- * the reference index, which starts from 0 and new sheet would
- * be inserted before it. If the index value is out of range
- * (index >= sheet count or index < 0), this method would return
- * <code>null</code>.
- * @return inserted sheet.
- * @since 0.6
- */
- public Table insertSheet(Table refTable, int before) {
- if (before < 0) {
- return null;
- }
- int count = 0;
- try {
- OfficeSpreadsheetElement spreadsheetElement = getContentRoot();
- Node child = spreadsheetElement.getFirstChild();
- while ((child != null) && (count <= before)) {
- if (child instanceof TableTableElement) {
- if (count == before) {
- TableTableElement refTableElement = refTable.getOdfElement();
- try {
- OdfContentDom contentDom = getContentDom();
- TableTableElement newTableEle = (TableTableElement) (refTableElement.cloneNode(true));
- //foreign node not in a same document
- if (refTableElement.getOwnerDocument() != contentDom) {
- Document ownerDocument = refTable.getOwnerDocument();
- copyLinkedRefInBatch(newTableEle, ownerDocument);
- copyForeignStyleRef(newTableEle, ownerDocument);
- newTableEle = (TableTableElement) cloneForeignElement(newTableEle, contentDom, true);
- }
- updateNames(newTableEle);
- updateXMLIds(newTableEle);
- newTableEle.setTableNameAttribute(getUniqueSheetName(this));
- getContentRoot().insertBefore(newTableEle, child);
- return getTableBuilder().getTableInstance(newTableEle);
- } catch (Exception e) {
- Logger.getLogger(SpreadsheetDocument.class.getName()).log(Level.SEVERE, null, e);
- }
- } else {
- count++;
- }
- }
- child = child.getNextSibling();
- }
- } catch (Exception e) {
- Logger.getLogger(SpreadsheetDocument.class.getName()).log(Level.SEVERE, null, e);
- }
- return null;
- }
-
- /**
- * Removes the sheet in the specified <code>index</code>.
- *
- * @param index
- * the index of the removed sheet, which starts from 0. If the
- * index value is out of range (index >= sheet count or index <
- * 0), this method would do nothing.
- * @since 0.6
- */
- public void removeSheet(int index) {
- if (index < 0) {
- return;
- }
- int count = 0;
- try {
- OfficeSpreadsheetElement spreadsheetElement = getContentRoot();
- Node child = spreadsheetElement.getFirstChild();
- while ((child != null) && (count <= index)) {
- if (child instanceof TableTableElement) {
- if (count == index) {
- spreadsheetElement.removeChild(child);
- return;
- } else {
- count++;
- }
- }
- child = child.getNextSibling();
- }
- } catch (Exception e) {
- Logger.getLogger(SpreadsheetDocument.class.getName()).log(Level.SEVERE, null, e);
- }
- }
-
- /**
- * Returns the sheet count of this document.
- *
- * @return the sheet count of this document.
- * @since 0.6
- */
- public int getSheetCount() {
- int count = 0;
- try {
- OfficeSpreadsheetElement spreadsheetElement = getContentRoot();
- Node child = spreadsheetElement.getFirstChild();
- while (child != null) {
- if (child instanceof TableTableElement) {
- count++;
- }
- child = child.getNextSibling();
- }
- } catch (Exception e) {
- Logger.getLogger(SpreadsheetDocument.class.getName()).log(Level.SEVERE, null, e);
- }
- return count;
- }
-
- public OdfElement getTableContainerElement() {
- return getTableContainerImpl().getTableContainerElement();
- }
-
- /**
- * Creates a new Chart for this spreadsheet document.
- *
- * @param title
- * chart title.
- * @param dataset
- * chart data set.
- * @param rect
- * chart rectangle.
- * @return the created chart.
- *
- * @since 0.6
- */
- public Chart createChart(String title, DataSet dataset, Rectangle rect) {
- return getChartContainerImpl().createChart(title, dataset, rect);
- }
-
- /**
- * Creates a new Chart for this spreadsheet document.
- *
- * @param title
- * chart title.
- * @param document
- * the data source spreadsheet document.
- * @param cellRangeAddr
- * the cell range address list which is used as chart data set.
- * @param firstRowAsLabel
- * whether uses first row as label.
- * @param firstColumnAsLabel
- * whether uses first column as label.
- * @param rowAsDataSeries
- * whether uses data as series.
- * @param rect
- * chart rectangle.
- * @return the created chart.
- *
- * @since 0.6
- */
- public Chart createChart(String title, SpreadsheetDocument document, CellRangeAddressList cellRangeAddr, boolean firstRowAsLabel,
- boolean firstColumnAsLabel, boolean rowAsDataSeries, Rectangle rect) {
- return getChartContainerImpl().createChart(title, document, cellRangeAddr, firstRowAsLabel, firstColumnAsLabel,
- rowAsDataSeries, rect);
- }
-
- /**
- * Creates a new Chart for this spreadsheet document.
- *
- * @param title
- * chart rectangle.
- * @param labels
- * label strings
- * @param legends
- * legend strings
- * @param data
- * chart data set.
- * @param rect
- * chart rectangle.
- * @return the created chart.
- *
- * @since 0.6
- */
- public Chart createChart(String title, String[] labels, String[] legends, double[][] data, Rectangle rect) {
- return getChartContainerImpl().createChart(title, labels, legends, data, rect);
- }
-
- /**
- * Creates a new Chart for this spreadsheet document.
- *
- * @param title
- * chart rectangle.
- * @param document
- * the data source spreadsheet document.
- * @param cellRangeAddr
- * the cell range list to be used as chart data.
- * @param firstRowAsLabel
- * whether use first row as label.
- * @param firstColumnAsLabel
- * whether use first column as label.
- * @param rowAsDataSeries
- * whether use row as data series.
- * @param rect
- * chart rectangle.
- * @param cell
- * the position cell where the new chart is inserted.
- * @return the created chart.
- *
- * @since 0.6
- */
- public Chart createChart(String title, SpreadsheetDocument document, CellRangeAddressList cellRangeAddr, boolean firstRowAsLabel,
- boolean firstColumnAsLabel, boolean rowAsDataSeries, Rectangle rect, Cell cell) {
- return getChartContainerImpl().createChart(title, document, cellRangeAddr, firstRowAsLabel, firstColumnAsLabel,
- rowAsDataSeries, rect, cell);
- }
-
- public void deleteChartById(String chartId) {
- getChartContainerImpl().deleteChartById(chartId);
- }
-
- public void deleteChartByTitle(String title) {
- getChartContainerImpl().deleteChartByTitle(title);
- }
-
- public Chart getChartById(String chartId) {
- return getChartContainerImpl().getChartById(chartId);
- }
-
- public List<Chart> getChartByTitle(String title) {
- return getChartContainerImpl().getChartByTitle(title);
- }
-
- public int getChartCount() {
- return getChartContainerImpl().getChartCount();
- }
-
- private static String getUniqueSheetName(TableContainer container) {
- List<Table> tableList = container.getTableList();
- boolean notUnique = true;
- String tablename = "Sheet" + (tableList.size() + 1);
- while (notUnique) {
- notUnique = false;
- for (int i = 0; i < tableList.size(); i++) {
- if (tableList.get(i).getTableName() != null) {
- if (tableList.get(i).getTableName().equalsIgnoreCase(tablename)) {
- notUnique = true;
- break;
- }
- }
- }
- if (notUnique) {
- tablename = tablename + Math.round(Math.random() * 10);
- }
- }
- return tablename;
- }
-
- private ChartContainerImpl getChartContainerImpl() {
- if (chartContainerImpl == null) {
- chartContainerImpl = new ChartContainerImpl(this);
- }
- return chartContainerImpl;
- }
-
- private class ChartContainerImpl extends AbstractChartContainer {
- SpreadsheetDocument sdoc;
- DrawFrameElement drawFrame;
- protected ChartContainerImpl(Document doc) {
- super(doc);
- sdoc = (SpreadsheetDocument) doc;
- }
-
- protected DrawFrameElement getChartFrame() throws Exception {
- OdfContentDom contentDom2 = sdoc.getContentDom();
- DrawFrameElement drawFrame = contentDom2.newOdfElement(DrawFrameElement.class);
- TableTableCellElement lastCell = (TableTableCellElement) contentDom2.getXPath().evaluate(
- "//table:table-cell[last()]", contentDom2, XPathConstants.NODE);
- lastCell.appendChild(drawFrame);
- drawFrame.removeAttribute("text:anchor-type");
- this.drawFrame = drawFrame;
- return drawFrame;
- }
-
- private Chart createChart(String title, SpreadsheetDocument document, CellRangeAddressList cellRangeAddr, boolean firstRowAsLabel,
- boolean firstColumnAsLabel, boolean rowAsDataSeries, Rectangle rect, Cell cell) {
- Chart chart = getChartContainerImpl().createChart(title, document, cellRangeAddr, firstRowAsLabel, firstColumnAsLabel,
- rowAsDataSeries, rect);
- cell.getOdfElement().appendChild(this.drawFrame);
- return chart;
- }
- }
-}
+/**
+ * **********************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
+ *
+ * Copyright 2008, 2010 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Use is subject to license terms.
+ *
+ * Licensed 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. You can also
+ * obtain a copy of the License at http://odftoolkit.org/docs/license.txt
+ *
+ * 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.odftoolkit.simple;
+
+import java.awt.Rectangle;
+import java.io.File;
+import java.io.InputStream;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.xml.xpath.XPathConstants;
+import org.odftoolkit.odfdom.dom.OdfContentDom;
+import org.odftoolkit.odfdom.dom.element.draw.DrawFrameElement;
+import org.odftoolkit.odfdom.dom.element.office.OfficeSpreadsheetElement;
+import org.odftoolkit.odfdom.dom.element.table.TableTableCellElement;
+import org.odftoolkit.odfdom.dom.element.table.TableTableElement;
+import org.odftoolkit.odfdom.pkg.MediaType;
+import org.odftoolkit.odfdom.pkg.OdfElement;
+import org.odftoolkit.odfdom.pkg.OdfPackage;
+import org.odftoolkit.odfdom.type.CellRangeAddressList;
+import org.odftoolkit.simple.chart.AbstractChartContainer;
+import org.odftoolkit.simple.chart.Chart;
+import org.odftoolkit.simple.chart.ChartContainer;
+import org.odftoolkit.simple.chart.DataSet;
+import org.odftoolkit.simple.table.Cell;
+import org.odftoolkit.simple.table.RepeatedNumberUtils;
+import org.odftoolkit.simple.table.Table;
+import org.odftoolkit.simple.table.TableContainer;
+import org.w3c.dom.Node;
+
+/**
+ * This class represents an empty ODF spreadsheet document.
+ *
+ */
+public class SpreadsheetDocument extends Document implements ChartContainer {
+
+ private static final String EMPTY_SPREADSHEET_DOCUMENT_PATH = "/OdfSpreadsheetDocument.ods";
+ static final Resource EMPTY_SPREADSHEET_DOCUMENT_RESOURCE = new Resource(EMPTY_SPREADSHEET_DOCUMENT_PATH);
+ private ChartContainerImpl chartContainerImpl;
+
+ /**
+ * This enum contains all possible media types of SpreadsheetDocument
+ * documents.
+ */
+ public enum OdfMediaType implements MediaType {
+
+ SPREADSHEET(Document.OdfMediaType.SPREADSHEET), SPREADSHEET_TEMPLATE(Document.OdfMediaType.SPREADSHEET_TEMPLATE);
+ private final Document.OdfMediaType mMediaType;
+
+ OdfMediaType(Document.OdfMediaType mediaType) {
+ this.mMediaType = mediaType;
+ }
+
+ /**
+ * @return the mediatype of this document
+ */
+ public String getMediaTypeString() {
+ return mMediaType.getMediaTypeString();
+ }
+
+ /**
+ * @return the ODF filesuffix of this document
+ */
+ public String getSuffix() {
+ return mMediaType.getSuffix();
+ }
+
+ /**
+ *
+ * @param mediaType string defining an ODF document
+ * @return the according OdfMediatype encapuslating the given string and
+ * the suffix
+ */
+ public static Document.OdfMediaType getOdfMediaType(String mediaType) {
+ return Document.OdfMediaType.getOdfMediaType(mediaType);
+ }
+ }
+
+ /**
+ * Creates an empty spreadsheet document.
+ *
+ * @return ODF spreadsheet document based on a default template
+ *
+ * @throws java.lang.Exception - if the document could not be created
+ */
+ public static SpreadsheetDocument newSpreadsheetDocument() throws Exception {
+ return (SpreadsheetDocument) Document.loadTemplate(EMPTY_SPREADSHEET_DOCUMENT_RESOURCE,
+ Document.OdfMediaType.SPREADSHEET);
+ }
+
+ /**
+ * Creates an empty spreadsheet template.
+ *
+ * @return ODF spreadsheet template based on a default
+ * @throws java.lang.Exception - if the template could not be created
+ */
+ public static SpreadsheetDocument newSpreadsheetTemplateDocument() throws Exception {
+ SpreadsheetDocument doc = (SpreadsheetDocument) Document.loadTemplate(EMPTY_SPREADSHEET_DOCUMENT_RESOURCE,
+ Document.OdfMediaType.SPREADSHEET_TEMPLATE);
+ doc.changeMode(OdfMediaType.SPREADSHEET_TEMPLATE);
+ return doc;
+ }
+
+ /**
+ * To avoid data duplication a new document is only created, if not already
+ * opened. A document is cached by this constructor using the internalpath
+ * as key.
+ */
+ protected SpreadsheetDocument(OdfPackage pkg, String internalPath, SpreadsheetDocument.OdfMediaType odfMediaType) {
+ super(pkg, internalPath, odfMediaType.mMediaType);
+ }
+
+ /**
+ * Creates an SpreadsheetDocument from the OpenDocument provided by a
+ * resource Stream.
+ *
+ * <p>
+ * Since an InputStream does not provide the arbitrary (non sequentiell)
+ * read access needed by SpreadsheetDocument, the InputStream is cached.
+ * This usually takes more time compared to the other createInternalDocument
+ * methods. An advantage of caching is that there are no problems
+ * overwriting an input file.
+ * </p>
+ *
+ * <p>
+ * If the resource stream is not a ODF spreadsheet document,
+ * ClassCastException might be thrown.
+ * </p>
+ *
+ * @param inputStream - the InputStream of the ODF spreadsheet document.
+ * @return the spreadsheet document created from the given InputStream
+ * @throws java.lang.Exception - if the document could not be created.
+ */
+ public static SpreadsheetDocument loadDocument(InputStream inputStream) throws Exception {
+ SpreadsheetDocument document = (SpreadsheetDocument) Document.loadDocument(inputStream);
+ removeDummyCellsFromDocument(document);
+ return document;
+ }
+
+ /**
+ * Loads an SpreadsheetDocument from the provided path.
+ *
+ * <p>
+ * SpreadsheetDocument relies on the file being available for read access
+ * over the whole lifecycle of SpreadsheetDocument.
+ * </p>
+ *
+ * <p>
+ * If the resource stream is not a ODF spreadsheet document,
+ * ClassCastException might be thrown.
+ * </p>
+ *
+ * @param documentPath - the path from where the document can be loaded
+ * @return the spreadsheet document from the given path or NULL if the media
+ * type is not supported by SIMPLE.
+ * @throws java.lang.Exception - if the document could not be created.
+ */
+ public static SpreadsheetDocument loadDocument(String documentPath) throws Exception {
+ SpreadsheetDocument document = (SpreadsheetDocument) Document.loadDocument(documentPath);
+ removeDummyCellsFromDocument(document);
+ return document;
+ }
+
+ /**
+ * Creates an SpreadsheetDocument from the OpenDocument provided by a File.
+ *
+ * <p>
+ * SpreadsheetDocument relies on the file being available for read access
+ * over the whole lifecycle of SpreadsheetDocument.
+ * </p>
+ *
+ * <p>
+ * If the resource stream is not a ODF spreadsheet document,
+ * ClassCastException might be thrown.
+ * </p>
+ *
+ * @param file - a file representing the ODF spreadsheet document.
+ * @return the spreadsheet document created from the given File
+ * @throws java.lang.Exception - if the document could not be created.
+ */
+ public static SpreadsheetDocument loadDocument(File file) throws Exception {
+ SpreadsheetDocument document = (SpreadsheetDocument) Document.loadDocument(file);
+ removeDummyCellsFromDocument(document);
+ return document;
+ }
+
+ /**
+ * Get the content root of a spreadsheet document.
+ *
+ * @return content root, representing the office:spreadsheet tag
+ * @throws Exception if the file DOM could not be created.
+ */
+ @Override
+ public OfficeSpreadsheetElement getContentRoot() throws Exception {
+ return super.getContentRoot(OfficeSpreadsheetElement.class);
+ }
+
+ /**
+ * Changes the document to the given mediatype. This method can only be used
+ * to convert a document to a related mediatype, e.g. template.
+ *
+ * @param mediaType the related ODF mimetype
+ */
+ public void changeMode(OdfMediaType mediaType) {
+ setOdfMediaType(mediaType.mMediaType);
+ }
+
+ /**
+ * Retrieves sheet by index.
+ *
+ * @param index the index of the retrieved sheet, which starts from 0. If
+ * the index value is out of range (index >= sheet count or index < 0), this
+ * method would return <code>null</code>. @since 0.6
+ */
+ public Table getSheetByIndex(int index) {
+ if (index < 0) {
+ return null;
+ }
+ int count = 0;
+ try {
+ OfficeSpreadsheetElement spreadsheetElement = getContentRoot();
+ Node child = spreadsheetElement.getFirstChild();
+ while ((child != null) && (count <= index)) {
+ if (child instanceof TableTableElement) {
+ if (count == index) {
+ return getTableBuilder().getTableInstance((TableTableElement) child);
+ } else {
+ count++;
+ }
+ }
+ child = child.getNextSibling();
+ }
+ } catch (Exception e) {
+ Logger.getLogger(SpreadsheetDocument.class.getName()).log(Level.SEVERE, null, e);
+ }
+ return null;
+ }
+
+ /**
+ * Retrieves sheet by name.
+ *
+ * @param name the name of the retrieved sheet.
+ * @since 0.6
+ */
+ public Table getSheetByName(String name) {
+ return getTableByName(name);
+ }
+
+ /**
+ * Adds a new blank sheet with the specified <code>name</code> to this
+ * document.
+ *
+ * @param name the name of the new sheet.
+ * @return added sheet.
+ * @since 0.6
+ */
+ public Table appendSheet(String name) {
+ Table newTable = addTable();
+ newTable.setTableName(name);
+ return newTable;
+ }
+
+ /**
+ * Adds a new sheet with data from existing table.
+ * <p>
+ * NOTE: This method copies data from existing table, including linked
+ * resources and styles, if the source table is not in the target document.
+ * If these data has dependencies to other data of the source document, the
+ * data dependencies will not be copied. For example, document A has two
+ * sheets, "Sheet1" and "Sheet2". In "Sheet2", there is a cell with formula,
+ * "=sum(Sheet1.A1:Sheet1.A10)". After copy the data of "Sheet2" to the new
+ * sheet in document B, the result of this formula would be different or
+ * even invalid in document B.
+ *
+ * @param refTable the reference table, which is the data source of the new
+ * sheet.
+ * @param name the name of the new sheet.
+ * @return added sheet.
+ * @since 0.6
+ */
+ public Table appendSheet(Table refTable, String name) {
+ TableTableElement refTableElement = refTable.getOdfElement();
+ try {
+ OdfContentDom contentDom = getContentDom();
+ TableTableElement newTableEle = (TableTableElement) (refTableElement.cloneNode(true));
+ // not in a same document
+ if (refTableElement.getOwnerDocument() != contentDom) {
+ Document ownerDocument = refTable.getOwnerDocument();
+ copyLinkedRefInBatch(newTableEle, ownerDocument);
+ copyForeignStyleRef(newTableEle, ownerDocument);
+ newTableEle = (TableTableElement) cloneForeignElement(newTableEle, contentDom, true);
+ }
+ updateNames(newTableEle);
+ updateXMLIds(newTableEle);
+ getTableContainerElement().appendChild(newTableEle);
+ Table tableInstance = getTableBuilder().getTableInstance(newTableEle);
+ tableInstance.setTableName(name);
+ return tableInstance;
+ } catch (Exception e) {
+ Logger.getLogger(SpreadsheetDocument.class.getName()).log(Level.SEVERE, null, e);
+ }
+ return null;
+ }
+
+ /**
+ * Inserts a new blank sheet before the reference index.
+ *
+ * @param before the reference index, which starts from 0. If the index
+ * value is out of range (index >= sheet count or index < 0), this method
+ * would return <code>null</code>. @return inserted sheet. @since 0.6
+ */
+ public Table insertSheet(int before) {
+ if (before < 0) {
+ return null;
+ }
+ int count = 0;
+ try {
+ OfficeSpreadsheetElement spreadsheetElement = getContentRoot();
+ Node child = spreadsheetElement.getFirstChild();
+ while ((child != null) && (count <= before)) {
+ if (child instanceof TableTableElement) {
+ if (count == before) {
+ Table table = getTableBuilder().newTable();
+ getContentRoot().insertBefore(table.getOdfElement(), child);
+ return table;
+ } else {
+ count++;
+ }
+ }
+ child = child.getNextSibling();
+ }
+ } catch (Exception e) {
+ Logger.getLogger(SpreadsheetDocument.class.getName()).log(Level.SEVERE, null, e);
+ }
+ return null;
+ }
+
+ /**
+ * Inserts a new sheet with data from existing table.
+ *
+ * <p>
+ * NOTE: This method copies data from existing table, including linked
+ * resources and styles, if the source table is not in the target document.
+ * If these data has dependencies to other data of the source document, the
+ * data dependencies will not be copied. For example, document A has two
+ * sheets, "Sheet1" and "Sheet2". In "Sheet2", there is a cell with formula,
+ * "=sum(Sheet1.A1:Sheet1.A10)". After copy the data of "Sheet2" to the new
+ * sheet in document B, the result of this formula would be different or
+ * even invalid in document B.
+ *
+ * @param refTable the reference table, which is the data source of the new
+ * sheet.
+ * @param before the reference index, which starts from 0 and new sheet
+ * would be inserted before it. If the index value is out of range (index >=
+ * sheet count or index < 0), this method would return <code>null</code>.
+ * @return inserted sheet.
+ * @since 0.6
+ */
+ public Table insertSheet(Table refTable, int before) {
+ if (before < 0) {
+ return null;
+ }
+ int count = 0;
+ try {
+ OfficeSpreadsheetElement spreadsheetElement = getContentRoot();
+ Node child = spreadsheetElement.getFirstChild();
+ while ((child != null) && (count <= before)) {
+ if (child instanceof TableTableElement) {
+ if (count == before) {
+ TableTableElement refTableElement = refTable.getOdfElement();
+ try {
+ OdfContentDom contentDom = getContentDom();
+ TableTableElement newTableEle = (TableTableElement) (refTableElement.cloneNode(true));
+ //foreign node not in a same document
+ if (refTableElement.getOwnerDocument() != contentDom) {
+ Document ownerDocument = refTable.getOwnerDocument();
+ copyLinkedRefInBatch(newTableEle, ownerDocument);
+ copyForeignStyleRef(newTableEle, ownerDocument);
+ newTableEle = (TableTableElement) cloneForeignElement(newTableEle, contentDom, true);
+ }
+ updateNames(newTableEle);
+ updateXMLIds(newTableEle);
+ newTableEle.setTableNameAttribute(getUniqueSheetName(this));
+ getContentRoot().insertBefore(newTableEle, child);
+ return getTableBuilder().getTableInstance(newTableEle);
+ } catch (Exception e) {
+ Logger.getLogger(SpreadsheetDocument.class.getName()).log(Level.SEVERE, null, e);
+ }
+ } else {
+ count++;
+ }
+ }
+ child = child.getNextSibling();
+ }
+ } catch (Exception e) {
+ Logger.getLogger(SpreadsheetDocument.class.getName()).log(Level.SEVERE, null, e);
+ }
+ return null;
+ }
+
+ /**
+ * Removes the sheet in the specified <code>index</code>.
+ *
+ * @param index the index of the removed sheet, which starts from 0. If the
+ * index value is out of range (index >= sheet count or index < 0), this
+ * method would do nothing. @since 0.6
+ */
+ public void removeSheet(int index) {
+ if (index < 0) {
+ return;
+ }
+ int count = 0;
+ try {
+ OfficeSpreadsheetElement spreadsheetElement = getContentRoot();
+ Node child = spreadsheetElement.getFirstChild();
+ while ((child != null) && (count <= index)) {
+ if (child instanceof TableTableElement) {
+ if (count == index) {
+ spreadsheetElement.removeChild(child);
+ return;
+ } else {
+ count++;
+ }
+ }
+ child = child.getNextSibling();
+ }
+ } catch (Exception e) {
+ Logger.getLogger(SpreadsheetDocument.class.getName()).log(Level.SEVERE, null, e);
+ }
+ }
+
+ /**
+ * Returns the sheet count of this document.
+ *
+ * @return the sheet count of this document.
+ * @since 0.6
+ */
+ public int getSheetCount() {
+ int count = 0;
+ try {
+ OfficeSpreadsheetElement spreadsheetElement = getContentRoot();
+ Node child = spreadsheetElement.getFirstChild();
+ while (child != null) {
+ if (child instanceof TableTableElement) {
+ count++;
+ }
+ child = child.getNextSibling();
+ }
+ } catch (Exception e) {
+ Logger.getLogger(SpreadsheetDocument.class.getName()).log(Level.SEVERE, null, e);
+ }
+ return count;
+ }
+
+ public OdfElement getTableContainerElement() {
+ return getTableContainerImpl().getTableContainerElement();
+ }
+
+ /**
+ * Creates a new Chart for this spreadsheet document.
+ *
+ * @param title chart title.
+ * @param dataset chart data set.
+ * @param rect chart rectangle.
+ * @return the created chart.
+ *
+ * @since 0.6
+ */
+ public Chart createChart(String title, DataSet dataset, Rectangle rect) {
+ return getChartContainerImpl().createChart(title, dataset, rect);
+ }
+
+ /**
+ * Creates a new Chart for this spreadsheet document.
+ *
+ * @param title chart title.
+ * @param document the data source spreadsheet document.
+ * @param cellRangeAddr the cell range address list which is used as chart
+ * data set.
+ * @param firstRowAsLabel whether uses first row as label.
+ * @param firstColumnAsLabel whether uses first column as label.
+ * @param rowAsDataSeries whether uses data as series.
+ * @param rect chart rectangle.
+ * @return the created chart.
+ *
+ * @since 0.6
+ */
+ public Chart createChart(String title, SpreadsheetDocument document, CellRangeAddressList cellRangeAddr, boolean firstRowAsLabel,
+ boolean firstColumnAsLabel, boolean rowAsDataSeries, Rectangle rect) {
+ return getChartContainerImpl().createChart(title, document, cellRangeAddr, firstRowAsLabel, firstColumnAsLabel,
+ rowAsDataSeries, rect);
+ }
+
+ /**
+ * Creates a new Chart for this spreadsheet document.
+ *
+ * @param title chart rectangle.
+ * @param labels label strings
+ * @param legends legend strings
+ * @param data chart data set.
+ * @param rect chart rectangle.
+ * @return the created chart.
+ *
+ * @since 0.6
+ */
+ public Chart createChart(String title, String[] labels, String[] legends, double[][] data, Rectangle rect) {
+ return getChartContainerImpl().createChart(title, labels, legends, data, rect);
+ }
+
+ /**
+ * Creates a new Chart for this spreadsheet document.
+ *
+ * @param title chart rectangle.
+ * @param document the data source spreadsheet document.
+ * @param cellRangeAddr the cell range list to be used as chart data.
+ * @param firstRowAsLabel whether use first row as label.
+ * @param firstColumnAsLabel whether use first column as label.
+ * @param rowAsDataSeries whether use row as data series.
+ * @param rect chart rectangle.
+ * @param cell the position cell where the new chart is inserted.
+ * @return the created chart.
+ *
+ * @since 0.6
+ */
+ public Chart createChart(String title, SpreadsheetDocument document, CellRangeAddressList cellRangeAddr, boolean firstRowAsLabel,
+ boolean firstColumnAsLabel, boolean rowAsDataSeries, Rectangle rect, Cell cell) {
+ return getChartContainerImpl().createChart(title, document, cellRangeAddr, firstRowAsLabel, firstColumnAsLabel,
+ rowAsDataSeries, rect, cell);
+ }
+
+ public void deleteChartById(String chartId) {
+ getChartContainerImpl().deleteChartById(chartId);
+ }
+
+ public void deleteChartByTitle(String title) {
+ getChartContainerImpl().deleteChartByTitle(title);
+ }
+
+ public Chart getChartById(String chartId) {
+ return getChartContainerImpl().getChartById(chartId);
+ }
+
+ public List<Chart> getChartByTitle(String title) {
+ return getChartContainerImpl().getChartByTitle(title);
+ }
+
+ public int getChartCount() {
+ return getChartContainerImpl().getChartCount();
+ }
+
+ private static String getUniqueSheetName(TableContainer container) {
+ List<Table> tableList = container.getTableList();
+ boolean notUnique = true;
+ String tablename = "Sheet" + (tableList.size() + 1);
+ while (notUnique) {
+ notUnique = false;
+ for (int i = 0; i < tableList.size(); i++) {
+ if (tableList.get(i).getTableName() != null) {
+ if (tableList.get(i).getTableName().equalsIgnoreCase(tablename)) {
+ notUnique = true;
+ break;
+ }
+ }
+ }
+ if (notUnique) {
+ tablename = tablename + Math.round(Math.random() * 10);
+ }
+ }
+ return tablename;
+ }
+
+ private ChartContainerImpl getChartContainerImpl() {
+ if (chartContainerImpl == null) {
+ chartContainerImpl = new ChartContainerImpl(this);
+ }
+ return chartContainerImpl;
+ }
+
+ private class ChartContainerImpl extends AbstractChartContainer {
+
+ SpreadsheetDocument sdoc;
+ DrawFrameElement drawFrame;
+
+ protected ChartContainerImpl(Document doc) {
+ super(doc);
+ sdoc = (SpreadsheetDocument) doc;
+ }
+
+ protected DrawFrameElement getChartFrame() throws Exception {
+ OdfContentDom contentDom2 = sdoc.getContentDom();
+ DrawFrameElement drawFrame = contentDom2.newOdfElement(DrawFrameElement.class);
+ TableTableCellElement lastCell = (TableTableCellElement) contentDom2.getXPath().evaluate(
+ "//table:table-cell[last()]", contentDom2, XPathConstants.NODE);
+ lastCell.appendChild(drawFrame);
+ drawFrame.removeAttribute("text:anchor-type");
+ this.drawFrame = drawFrame;
+ return drawFrame;
+ }
+
+ private Chart createChart(String title, SpreadsheetDocument document, CellRangeAddressList cellRangeAddr, boolean firstRowAsLabel,
+ boolean firstColumnAsLabel, boolean rowAsDataSeries, Rectangle rect, Cell cell) {
+ Chart chart = getChartContainerImpl().createChart(title, document, cellRangeAddr, firstRowAsLabel, firstColumnAsLabel,
+ rowAsDataSeries, rect);
+ cell.getOdfElement().appendChild(this.drawFrame);
+ return chart;
+ }
+ }
+
+ /**
+ * @see RepeatedNumberUtils#removeDummyCellsFromTable(Table)
+ */
+ private static void removeDummyCellsFromDocument(SpreadsheetDocument document) {
+ int sheetCount = document.getSheetCount();
+ for (int n = 0; n < sheetCount; n++) {
+ RepeatedNumberUtils.removeDummyCellsFromTable(document.getSheetByIndex(n));
+ }
+ }
+}
diff --git a/simple/src/main/java/org/odftoolkit/simple/table/RepeatedNumberUtils.java b/simple/src/main/java/org/odftoolkit/simple/table/RepeatedNumberUtils.java
new file mode 100644
index 0000000..4f6ea2d
--- /dev/null
+++ b/simple/src/main/java/org/odftoolkit/simple/table/RepeatedNumberUtils.java
@@ -0,0 +1,248 @@
+/*
+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.odftoolkit.simple.table;
+
+import org.odftoolkit.odfdom.dom.element.table.TableTableCellElement;
+import org.odftoolkit.odfdom.dom.element.table.TableTableColumnElement;
+import org.odftoolkit.odfdom.dom.element.table.TableTableColumnsElement;
+import org.odftoolkit.odfdom.dom.element.table.TableTableHeaderColumnsElement;
+import org.odftoolkit.odfdom.dom.element.table.TableTableHeaderRowsElement;
+import org.odftoolkit.odfdom.dom.element.table.TableTableRowElement;
+import org.odftoolkit.odfdom.dom.element.table.TableTableRowsElement;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Node;
+
+/**
+ * Utility functions to evaluate the "repeated-number"-Attributes of rows,
+ * columns and cells.
+ *
+ * @author raimund
+ */
+public class RepeatedNumberUtils {
+
+ private static final int LIBRE_OFFICE_WORKAROUND_COLCOUNT = 1024;
+ private static final int LIBRE_OFFICE_WORKAROUND_ROWCOUNT = 1048576;
+ private static final int MS_EXCEL_BINARY_WORKAROUND_ROWCOUNT = 32768;
+
+ /**
+ * Remove unused columns and rows from the end of a table.
+ * <p>
+ * This is a workaround for bug ODFTOOLKIT-388. LibreOffice adds two dummy
+ * rows with "number-rows-repeated" attribute to "blow up" the sheet to
+ * {@value #LIBRE_OFFICE_WORKAROUND_ROWCOUNT} rows as needed by MS Excel
+ * 2010.
+ * <p>
+ * Files converted from MS Excel binary format (*.xls) contain a similar
+ * dummy row to "blow up" the sheet up to
+ * {@value #MS_EXCEL_BINARY_WORKAROUND_ROWCOUNT} rows.
+ * <p>
+ * Same is done for columns - one dummy column is added to get a whole
+ * column count of {@value #LIBRE_OFFICE_WORKAROUND_COLCOUNT}.
+ *
+ * @param table Table to clean.
+ */
+ public static void removeDummyCellsFromTable(Table table) {
+ // First analyze columns and rows; e. g. count them
+ int wholeColumnCount = 0;
+ int wholeRowCount = 0;
+ int maxCellCount = 0;
+ TableTableColumnElement lastColumnNode = null;
+ TableTableRowElement msExcelDummyRow = null;
+ for (Node node : new DomNodeList(table.getOdfElement().getChildNodes())) {
+ // TODO: how about <table:table-column-group>
+ if (node instanceof TableTableHeaderColumnsElement) {
+ wholeColumnCount += _getHeaderColumnCount((TableTableHeaderColumnsElement) node);
+ lastColumnNode = null;
+
+ } else if (node instanceof TableTableColumnsElement) {
+ wholeColumnCount += _getColumnsCount((TableTableColumnsElement) node);
+ lastColumnNode = null;
+
+ } else if (node instanceof TableTableColumnElement) {
+ wholeColumnCount += _getNumberColumnsRepeated((TableTableColumnElement) node);
+ lastColumnNode = (TableTableColumnElement) node;
+ }
+
+ if (node instanceof TableTableHeaderRowsElement) {
+ wholeRowCount += _getHeaderRowCount((TableTableHeaderRowsElement) node);
+ int n = _getCellCountOfRowWithoutDummies(node);
+ maxCellCount = n > maxCellCount ? n : maxCellCount;
+
+ } else if (node instanceof TableTableRowElement) {
+ wholeRowCount += _getNumberRowsRepeated((TableTableRowElement) node);
+ if (wholeRowCount == MS_EXCEL_BINARY_WORKAROUND_ROWCOUNT) {
+ msExcelDummyRow = (TableTableRowElement) node;
+ }
+ int n = _getCellCountOfRowWithoutDummies(node);
+ maxCellCount = n > maxCellCount ? n : maxCellCount;
+
+ } else if (node instanceof TableTableRowsElement) {
+ for (Node nodeChild : new DomNodeList(node.getChildNodes())) {
+ if (nodeChild instanceof TableTableRowElement) {
+ wholeRowCount += _getNumberRowsRepeated((TableTableRowElement) nodeChild);
+ int n = _getCellCountOfRowWithoutDummies(node);
+ maxCellCount = n > maxCellCount ? n : maxCellCount;
+ }
+ }
+ }
+ }
+
+ // Removing the dummy rows at end if needed
+ if (wholeRowCount == LIBRE_OFFICE_WORKAROUND_ROWCOUNT) {
+ boolean done = false;
+ for (int nodeIndex = table.getOdfElement().getChildNodes().getLength() - 1; !done && nodeIndex > 0; nodeIndex--) {
+ Node node = table.getOdfElement().getChildNodes().item(nodeIndex);
+ if (node instanceof TableTableHeaderRowsElement || node instanceof TableTableRowsElement) {
+ done = true;
+
+ } else if (node instanceof TableTableRowElement) {
+ if (_isEmptyDummyRow((TableTableRowElement) node)) {
+ table.getOdfElement().removeChild(node);
+ } else {
+ done = true;
+ }
+ }
+ }
+ }
+
+ // Workaround for files converted from MS Excel
+ if (msExcelDummyRow != null && msExcelDummyRow == table.getOdfElement().getLastChild()) {
+ try {
+ table.getOdfElement().removeChild(msExcelDummyRow);
+ } catch (DOMException e) {
+ // Row may be already removed by code above - just ignore that
+ }
+ }
+
+ // Removing the dummy columns at end if needed.
+ // Warning, we must retain at least one column for each cell,
+ // so it may be needed to just reduce the number-columns-repeated
+ // instead of deleting the cell.
+ if (wholeColumnCount == LIBRE_OFFICE_WORKAROUND_COLCOUNT && lastColumnNode != null) {
+ int n = _getNumberColumnsRepeated(lastColumnNode);
+ if (n > 1) {
+ int realColumnCount = wholeColumnCount - n;
+ if (realColumnCount < maxCellCount) {
+ lastColumnNode.setTableNumberColumnsRepeatedAttribute(maxCellCount - realColumnCount);
+ } else {
+ table.getOdfElement().removeChild(lastColumnNode);
+ }
+ }
+ }
+ }
+
+ private static int _getCellCountOfRowWithoutDummies(Node row) {
+ int cellCount = 0;
+ Node lastCell = row.getLastChild();
+ for (Node node : new DomNodeList(row.getChildNodes())) {
+ if (node instanceof TableTableCellElement) {
+ TableTableCellElement cell = (TableTableCellElement) node;
+
+ Integer repCnt = cell.getTableNumberColumnsRepeatedAttribute();
+ if (repCnt == null) {
+ repCnt = 1;
+ }
+ Integer spanned = cell.getTableNumberColumnsSpannedAttribute();
+ if (spanned == null || spanned == 0) {
+ spanned = 1;
+ }
+
+ if (node != lastCell || repCnt == 1 || spanned != 1) {
+ cellCount += repCnt * spanned;
+ }
+ }
+ }
+ return cellCount;
+ }
+
+ private static int _getNumberRowsRepeated(TableTableRowElement rowElement) {
+ int numberRowsRepeated = 0;
+
+ if (rowElement != null) {
+ Integer repCnt = rowElement.getTableNumberRowsRepeatedAttribute();
+ if (repCnt == null) {
+ numberRowsRepeated = 1;
+ } else {
+ numberRowsRepeated = repCnt;
+ }
+ }
+
+ return numberRowsRepeated;
+ }
+
+ static int _getNumberColumnsRepeated(TableTableColumnElement columnElement) {
+ int numberColumnsRepeated = 0;
+
+ if (columnElement != null) {
+ Integer repCnt = columnElement.getTableNumberColumnsRepeatedAttribute();
+ if (repCnt == null) {
+ numberColumnsRepeated = 1;
+ } else {
+ numberColumnsRepeated = repCnt;
+ }
+ }
+
+ return numberColumnsRepeated;
+ }
+
+ private static int _getHeaderColumnCount(TableTableHeaderColumnsElement headers) {
+ int result = 0;
+ if (headers != null) {
+ for (Node n : new DomNodeList(headers.getChildNodes())) {
+ result += _getNumberColumnsRepeated((TableTableColumnElement) n);
+ }
+ }
+ return result;
+ }
+
+ private static int _getColumnsCount(TableTableColumnsElement columns) {
+ int result = 0;
+ if (columns != null) {
+ for (Node n : new DomNodeList(columns.getChildNodes())) {
+ result += _getNumberColumnsRepeated((TableTableColumnElement) n);
+ }
+ }
+ return result;
+ }
+
+ private static int _getHeaderRowCount(TableTableHeaderRowsElement headers) {
+ int result = 0;
+ if (headers != null) {
+ for (Node n : new DomNodeList(headers.getChildNodes())) {
+ if (n instanceof TableTableRowElement) {
+ result += _getNumberRowsRepeated((TableTableRowElement) n);
+ }
+ }
+ }
+ return result;
+ }
+
+ private static boolean _isEmptyDummyRow(TableTableRowElement row) {
+ boolean dummyRow = true;
+ for (Node child = row.getChildNodes().item(0); dummyRow && child != null; child = child.getNextSibling()) {
+ if (child instanceof TableTableCellElement) {
+ dummyRow = child.getChildNodes().getLength() == 0;
+ } else {
+ dummyRow = false;
+ }
+ }
+
+ return dummyRow;
+ }
+}
diff --git a/simple/src/test/java/org/odftoolkit/simple/SpreadsheetDocumentTest.java b/simple/src/test/java/org/odftoolkit/simple/SpreadsheetDocumentTest.java
index 6f7a244..5f460a1 100644
--- a/simple/src/test/java/org/odftoolkit/simple/SpreadsheetDocumentTest.java
+++ b/simple/src/test/java/org/odftoolkit/simple/SpreadsheetDocumentTest.java
@@ -1,259 +1,284 @@
-/*
-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.odftoolkit.simple;
-
-import java.awt.Rectangle;
-import java.io.File;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import junit.framework.Assert;
-
-import org.junit.Test;
-import org.odftoolkit.simple.Document.OdfMediaType;
-import org.odftoolkit.simple.chart.Chart;
-import org.odftoolkit.simple.chart.ChartType;
-import org.odftoolkit.simple.chart.DataSet;
-import org.odftoolkit.simple.table.Column;
-import org.odftoolkit.simple.table.Table;
-import org.odftoolkit.simple.utils.ResourceUtilities;
-
-public class SpreadsheetDocumentTest {
- private static final Logger LOG = Logger.getLogger(SpreadsheetDocumentTest.class.getName());
- private static final String TEST_FILE = "spreadsheetTestTemplate.ots";
-
- @Test
- public void testGetMediaTypeString() throws Exception{
-
- try {
- String spreadDocPath = ResourceUtilities.getAbsolutePath(TEST_FILE);
- SpreadsheetDocument spreadDoc = SpreadsheetDocument.loadDocument(spreadDocPath);
- Assert.assertNotNull(spreadDoc);
- OdfMediaType odfMediaType = spreadDoc.getOdfMediaType();
- Assert.assertEquals(Document.OdfMediaType.SPREADSHEET_TEMPLATE, odfMediaType);
- } catch (Exception e) {
- LOG.log(Level.SEVERE, e.getMessage(), e);
- Assert.fail(e.getMessage());
- }
-
- }
-
- @Test
- public void testGetSuffix() throws Exception{
- try {
- String spreadDocPath = ResourceUtilities.getAbsolutePath(TEST_FILE);
- SpreadsheetDocument spreadDoc = SpreadsheetDocument.loadDocument(spreadDocPath);
- Assert.assertNotNull(spreadDoc);
- OdfMediaType odfMediaType = spreadDoc.getOdfMediaType();
- String suffix = odfMediaType.getSuffix();
- Assert.assertEquals("ots", suffix);
- } catch (Exception e) {
- LOG.log(Level.SEVERE, e.getMessage(), e);
- Assert.fail(e.getMessage());
- }
- }
-
- @Test
- public void testGetOdfMediaType() throws Exception{
-
- try {
- String spreadDocPath = ResourceUtilities.getAbsolutePath(TEST_FILE);
- SpreadsheetDocument spreadDoc = SpreadsheetDocument.loadDocument(spreadDocPath);
- Assert.assertNotNull(spreadDoc);
- Document.OdfMediaType odfMediaType = SpreadsheetDocument.OdfMediaType.getOdfMediaType(spreadDoc.getMediaTypeString());
- Assert.assertEquals("ots", odfMediaType.getSuffix());
- } catch (Exception e) {
- LOG.log(Level.SEVERE, e.getMessage(), e);
- Assert.fail(e.getMessage());
- }
- }
-
- @Test
- public void testLoadDocument() throws Exception{
- try {
- String filePath = ResourceUtilities.getAbsolutePath(TEST_FILE);
- SpreadsheetDocument spreadDoc = SpreadsheetDocument.loadDocument(filePath);
- Assert.assertNotNull(spreadDoc);
- Assert.assertEquals(Document.OdfMediaType.SPREADSHEET_TEMPLATE, spreadDoc.getOdfMediaType());
- } catch (Exception e) {
- LOG.log(Level.SEVERE, e.getMessage(), e);
- Assert.fail(e.getMessage());
- }
- }
-
- @Test
- public void testLoadDocumentFile() throws Exception{
-
- try {
- String filePath = ResourceUtilities.getAbsolutePath(TEST_FILE);
- File fileDoc = new File(filePath);
- SpreadsheetDocument spreadDoc = SpreadsheetDocument.loadDocument(fileDoc);;
- Assert.assertNotNull(spreadDoc);
- Assert.assertEquals(Document.OdfMediaType.SPREADSHEET_TEMPLATE, spreadDoc.getOdfMediaType());
- } catch (Exception e) {
- LOG.log(Level.SEVERE, e.getMessage(), e);
- Assert.fail(e.getMessage());
- }
-
- }
-
- @Test
- public void testCreateChart() throws Exception{
- try {
- SpreadsheetDocument spDocument = SpreadsheetDocument.loadDocument(ResourceUtilities.getAbsolutePath(TEST_FILE));
- String title = "XXXTitle";
- String[] lables = new String[]{"spring","summer","autumn","autumn"};
- String[] legends = new String[]{"hello1","hello2","hello3"};
- double[][] data = new double[][]{{1.2,2.22,3},{2,3,4},{3,4,5},{4,5,6}};
- DataSet dataset = new DataSet(lables, legends, data);
- Rectangle rect = new Rectangle();
- rect.x = 367;
- rect.y = 389;
- rect.width = 379;
- rect.height = 424;
- Chart spChart = spDocument.createChart(title, dataset, rect);
- Assert.assertNotNull(spChart);
- spChart.setChartType(ChartType.AREA);
- //save
- spDocument.save(ResourceUtilities.getTestOutput("Chart_"+TEST_FILE));
-
- Assert.assertEquals(dataset, spChart.getChartData());
- Assert.assertEquals("XXXTitle", spChart.getChartTitle());
- Assert.assertEquals(ChartType.AREA, spChart.getChartType());
-
- LOG.log(Level.INFO,"spChart--> " + spChart);
-
- } catch (Exception e) {
- LOG.log(Level.SEVERE, e.getMessage(), e);
- Assert.fail(e.getMessage());
- }
- }
-
- @Test
- public void testGetSheetByIndex() throws Exception{
- File file = new File(ResourceUtilities.getAbsolutePath("TestSpreadsheetTable.ods"));
- SpreadsheetDocument spDocument = SpreadsheetDocument.loadDocument(file);
- //index < 0 , Not expected, table ==null
- Table tablenull = spDocument.getSheetByIndex(-1);
- Assert.assertTrue((tablenull == null));
- //index > 0
- //index = 0
- Table tableSheet0 = spDocument.getSheetByIndex(0);
- Assert.assertTrue((tableSheet0 != null));
- Assert.assertEquals("Sheet1", tableSheet0.getTableName());
- Assert.assertEquals(29, tableSheet0.getColumnCount());
- //index = 1
- Table tableSheet1 = spDocument.getSheetByIndex(1);
- Assert.assertTrue((tableSheet1 != null));
- Assert.assertEquals("Sheet2", tableSheet1.getTableName());
- Assert.assertEquals(1, tableSheet1.getColumnCount());
- }
-
- @Test
- public void testInsertSheet() throws Exception{
- File file = new File(ResourceUtilities.getAbsolutePath(TEST_FILE));
- SpreadsheetDocument spDocument = SpreadsheetDocument.loadDocument(file);
- //index <0 , Not expected
- Table table = spDocument.insertSheet(-1);
- Assert.assertNull(table);
- //index >= sheet count
- Table tableb = spDocument.insertSheet(11);
- Assert.assertNull(tableb);
-
- //index is within the law
- Table tab = spDocument.getSheetByName("tabellDemo2");
- if(tab != null){
- for(int i=0;i<spDocument.getSheetCount();i++){
- if(tab.equals(spDocument.getSheetByIndex(i)))
- spDocument.removeSheet(i);
- }
- }
- Table tablea = spDocument.insertSheet(0);
- Column col = tablea.appendColumn();
- col.setWidth(12.99);
- Column col2 = tablea.appendColumn();
- col.setWidth(12.);
- tablea.setTableName("tabellDemo2");
- Assert.assertEquals("tabellDemo2", tablea.getTableName());
- spDocument.save(ResourceUtilities.getAbsolutePath(TEST_FILE));
-
- }
-
- @Test
- public void testRemoveSheet() throws Exception{
- File file = new File(ResourceUtilities.getAbsolutePath(TEST_FILE));
- SpreadsheetDocument spDocument = SpreadsheetDocument.loadDocument(file);
- //index <0 , Not expected
- Table table = spDocument.insertSheet(-1);
- Assert.assertNull(table);
- //index >= sheet count
- Table tableb = spDocument.insertSheet(11);
- Assert.assertNull(tableb);
-
- //index is within the law
- Table tab = spDocument.getSheetByName("tabellDemo2");
- if(tab != null){
- for(int i=0;i<spDocument.getSheetCount();i++){
- if(tab.equals(spDocument.getSheetByIndex(i)))
- spDocument.removeSheet(i);
- }
- }
- Table tablea = spDocument.insertSheet(0);
- Column col = tablea.appendColumn();
- col.setWidth(12.99);
- Column col2 = tablea.appendColumn();
- col.setWidth(12.);
- tablea.setTableName("tabellDemo2");
- Assert.assertEquals("tabellDemo2", tablea.getTableName());
- spDocument.removeSheet(0);
- Table tablem = spDocument.getSheetByIndex(0);
- Assert.assertNotSame(tablea, tablem);
-
- spDocument.save(ResourceUtilities.getAbsolutePath(TEST_FILE));
- }
-
- @Test
- public void testGetSheetByIndex2() throws Exception{
- File file = new File(ResourceUtilities.getAbsolutePath(TEST_FILE));
- SpreadsheetDocument spDocument = SpreadsheetDocument.loadDocument(file);
- //index <0 , Not expected
- Table table = spDocument.insertSheet(-1);
- Assert.assertNull(table);
- //index >= sheet count
- Table tableb = spDocument.insertSheet(11);
- Assert.assertNull(tableb);
-
- //index is within the law
- Table tab = spDocument.getSheetByName("tabellDemo1");
- if(tab != null)
- tab.remove();
-
- Table taba = spDocument.getSheetByName("Tabelle1");
- Table tablea = spDocument.insertSheet(taba,0);
- tablea.setTableName("tabellDemo1");
- Assert.assertEquals("tabellDemo1", tablea.getTableName());
- Table tablem = spDocument.getSheetByIndex(0);
- Assert.assertEquals(tablea, tablem);
-
- spDocument.save(ResourceUtilities.getAbsolutePath(TEST_FILE));
-
- }
-
-}
+/*
+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.odftoolkit.simple;
+
+import java.awt.Rectangle;
+import java.io.File;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+import org.odftoolkit.simple.Document.OdfMediaType;
+import org.odftoolkit.simple.chart.Chart;
+import org.odftoolkit.simple.chart.ChartType;
+import org.odftoolkit.simple.chart.DataSet;
+import org.odftoolkit.simple.table.Column;
+import org.odftoolkit.simple.table.Table;
+import org.odftoolkit.simple.utils.ResourceUtilities;
+
+public class SpreadsheetDocumentTest {
+ private static final Logger LOG = Logger.getLogger(SpreadsheetDocumentTest.class.getName());
+ private static final String TEST_FILE = "spreadsheetTestTemplate.ots";
+
+ @Test
+ public void testGetMediaTypeString() throws Exception{
+
+ try {
+ String spreadDocPath = ResourceUtilities.getAbsolutePath(TEST_FILE);
+ SpreadsheetDocument spreadDoc = SpreadsheetDocument.loadDocument(spreadDocPath);
+ Assert.assertNotNull(spreadDoc);
+ OdfMediaType odfMediaType = spreadDoc.getOdfMediaType();
+ Assert.assertEquals(Document.OdfMediaType.SPREADSHEET_TEMPLATE, odfMediaType);
+ } catch (Exception e) {
+ LOG.log(Level.SEVERE, e.getMessage(), e);
+ Assert.fail(e.getMessage());
+ }
+
+ }
+
+ @Test
+ public void testGetSuffix() throws Exception{
+ try {
+ String spreadDocPath = ResourceUtilities.getAbsolutePath(TEST_FILE);
+ SpreadsheetDocument spreadDoc = SpreadsheetDocument.loadDocument(spreadDocPath);
+ Assert.assertNotNull(spreadDoc);
+ OdfMediaType odfMediaType = spreadDoc.getOdfMediaType();
+ String suffix = odfMediaType.getSuffix();
+ Assert.assertEquals("ots", suffix);
+ } catch (Exception e) {
+ LOG.log(Level.SEVERE, e.getMessage(), e);
+ Assert.fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testGetOdfMediaType() throws Exception{
+
+ try {
+ String spreadDocPath = ResourceUtilities.getAbsolutePath(TEST_FILE);
+ SpreadsheetDocument spreadDoc = SpreadsheetDocument.loadDocument(spreadDocPath);
+ Assert.assertNotNull(spreadDoc);
+ Document.OdfMediaType odfMediaType = SpreadsheetDocument.OdfMediaType.getOdfMediaType(spreadDoc.getMediaTypeString());
+ Assert.assertEquals("ots", odfMediaType.getSuffix());
+ } catch (Exception e) {
+ LOG.log(Level.SEVERE, e.getMessage(), e);
+ Assert.fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testLoadDocument() throws Exception{
+ try {
+ String filePath = ResourceUtilities.getAbsolutePath(TEST_FILE);
+ SpreadsheetDocument spreadDoc = SpreadsheetDocument.loadDocument(filePath);
+ Assert.assertNotNull(spreadDoc);
+ Assert.assertEquals(Document.OdfMediaType.SPREADSHEET_TEMPLATE, spreadDoc.getOdfMediaType());
+ } catch (Exception e) {
+ LOG.log(Level.SEVERE, e.getMessage(), e);
+ Assert.fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testLoadDocumentFile() throws Exception{
+
+ try {
+ String filePath = ResourceUtilities.getAbsolutePath(TEST_FILE);
+ File fileDoc = new File(filePath);
+ SpreadsheetDocument spreadDoc = SpreadsheetDocument.loadDocument(fileDoc);;
+ Assert.assertNotNull(spreadDoc);
+ Assert.assertEquals(Document.OdfMediaType.SPREADSHEET_TEMPLATE, spreadDoc.getOdfMediaType());
+ } catch (Exception e) {
+ LOG.log(Level.SEVERE, e.getMessage(), e);
+ Assert.fail(e.getMessage());
+ }
+
+ }
+
+ @Test
+ public void testLoadDocumentFileWithExcelDummyRows0() {
+ testLoadDocumentFileWithExcelDummyRows("ExcelDummyRowProblem_rows0.ods", 0);
+ }
+
+ @Test
+ public void testLoadDocumentFileWithExcelDummyRows1() {
+ testLoadDocumentFileWithExcelDummyRows("ExcelDummyRowProblem_rows1.ods", 1);
+ }
+
+ private void testLoadDocumentFileWithExcelDummyRows(String file, int rowCount) {
+ try {
+ String filePath = ResourceUtilities.getAbsolutePath(file);
+ File fileDoc = new File(filePath);
+ SpreadsheetDocument spreadDoc = SpreadsheetDocument.loadDocument(fileDoc);
+ Assert.assertNotNull(spreadDoc);
+ Table table = spreadDoc.getSheetByIndex(0);
+ Assert.assertNotNull(table);
+ Assert.assertEquals(rowCount, table.getRowCount());
+ } catch (Exception e) {
+ LOG.log(Level.SEVERE, e.getMessage(), e);
+ Assert.fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testCreateChart() throws Exception{
+ try {
+ SpreadsheetDocument spDocument = SpreadsheetDocument.loadDocument(ResourceUtilities.getAbsolutePath(TEST_FILE));
+ String title = "XXXTitle";
+ String[] lables = new String[]{"spring","summer","autumn","autumn"};
+ String[] legends = new String[]{"hello1","hello2","hello3"};
+ double[][] data = new double[][]{{1.2,2.22,3},{2,3,4},{3,4,5},{4,5,6}};
+ DataSet dataset = new DataSet(lables, legends, data);
+ Rectangle rect = new Rectangle();
+ rect.x = 367;
+ rect.y = 389;
+ rect.width = 379;
+ rect.height = 424;
+ Chart spChart = spDocument.createChart(title, dataset, rect);
+ Assert.assertNotNull(spChart);
+ spChart.setChartType(ChartType.AREA);
+ //save
+ spDocument.save(ResourceUtilities.getTestOutput("Chart_"+TEST_FILE));
+
+ Assert.assertEquals(dataset, spChart.getChartData());
+ Assert.assertEquals("XXXTitle", spChart.getChartTitle());
+ Assert.assertEquals(ChartType.AREA, spChart.getChartType());
+
+ LOG.log(Level.INFO,"spChart--> " + spChart);
+
+ } catch (Exception e) {
+ LOG.log(Level.SEVERE, e.getMessage(), e);
+ Assert.fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testGetSheetByIndex() throws Exception{
+ File file = new File(ResourceUtilities.getAbsolutePath("TestSpreadsheetTable.ods"));
+ SpreadsheetDocument spDocument = SpreadsheetDocument.loadDocument(file);
+ //index < 0 , Not expected, table ==null
+ Table tablenull = spDocument.getSheetByIndex(-1);
+ Assert.assertTrue((tablenull == null));
+ //index > 0
+ //index = 0
+ Table tableSheet0 = spDocument.getSheetByIndex(0);
+ Assert.assertTrue((tableSheet0 != null));
+ Assert.assertEquals("Sheet1", tableSheet0.getTableName());
+ Assert.assertEquals(29, tableSheet0.getColumnCount());
+ //index = 1
+ Table tableSheet1 = spDocument.getSheetByIndex(1);
+ Assert.assertTrue((tableSheet1 != null));
+ Assert.assertEquals("Sheet2", tableSheet1.getTableName());
+ Assert.assertEquals(1, tableSheet1.getColumnCount());
+ }
+
+ @Test
+ public void testInsertSheet() throws Exception{
+ File file = new File(ResourceUtilities.getAbsolutePath(TEST_FILE));
+ SpreadsheetDocument spDocument = SpreadsheetDocument.loadDocument(file);
+ //index <0 , Not expected
+ Table table = spDocument.insertSheet(-1);
+ Assert.assertNull(table);
+ //index >= sheet count
+ Table tableb = spDocument.insertSheet(11);
+ Assert.assertNull(tableb);
+
+ //index is within the law
+ Table tab = spDocument.getSheetByName("tabellDemo2");
+ if(tab != null){
+ for(int i=0;i<spDocument.getSheetCount();i++){
+ if(tab.equals(spDocument.getSheetByIndex(i)))
+ spDocument.removeSheet(i);
+ }
+ }
+ Table tablea = spDocument.insertSheet(0);
+ Column col = tablea.appendColumn();
+ col.setWidth(12.99);
+ Column col2 = tablea.appendColumn();
+ col.setWidth(12.);
+ tablea.setTableName("tabellDemo2");
+ Assert.assertEquals("tabellDemo2", tablea.getTableName());
+ spDocument.save(ResourceUtilities.getAbsolutePath(TEST_FILE));
+
+ }
+
+ @Test
+ public void testRemoveSheet() throws Exception{
+ File file = new File(ResourceUtilities.getAbsolutePath(TEST_FILE));
+ SpreadsheetDocument spDocument = SpreadsheetDocument.loadDocument(file);
+ //index <0 , Not expected
+ Table table = spDocument.insertSheet(-1);
+ Assert.assertNull(table);
+ //index >= sheet count
+ Table tableb = spDocument.insertSheet(11);
+ Assert.assertNull(tableb);
+
+ //index is within the law
+ Table tab = spDocument.getSheetByName("tabellDemo2");
+ if(tab != null){
+ for(int i=0;i<spDocument.getSheetCount();i++){
+ if(tab.equals(spDocument.getSheetByIndex(i)))
+ spDocument.removeSheet(i);
+ }
+ }
+ Table tablea = spDocument.insertSheet(0);
+ Column col = tablea.appendColumn();
+ col.setWidth(12.99);
+ Column col2 = tablea.appendColumn();
+ col.setWidth(12.);
+ tablea.setTableName("tabellDemo2");
+ Assert.assertEquals("tabellDemo2", tablea.getTableName());
+ spDocument.removeSheet(0);
+ Table tablem = spDocument.getSheetByIndex(0);
+ Assert.assertNotSame(tablea, tablem);
+
+ spDocument.save(ResourceUtilities.getAbsolutePath(TEST_FILE));
+ }
+
+ @Test
+ public void testGetSheetByIndex2() throws Exception{
+ File file = new File(ResourceUtilities.getAbsolutePath(TEST_FILE));
+ SpreadsheetDocument spDocument = SpreadsheetDocument.loadDocument(file);
+ //index <0 , Not expected
+ Table table = spDocument.insertSheet(-1);
+ Assert.assertNull(table);
+ //index >= sheet count
+ Table tableb = spDocument.insertSheet(11);
+ Assert.assertNull(tableb);
+
+ //index is within the law
+ Table tab = spDocument.getSheetByName("tabellDemo1");
+ if(tab != null)
+ tab.remove();
+
+ Table taba = spDocument.getSheetByName("Tabelle1");
+ Table tablea = spDocument.insertSheet(taba,0);
+ tablea.setTableName("tabellDemo1");
+ Assert.assertEquals("tabellDemo1", tablea.getTableName());
+ Table tablem = spDocument.getSheetByIndex(0);
+ Assert.assertEquals(tablea, tablem);
+
+ spDocument.save(ResourceUtilities.getAbsolutePath(TEST_FILE));
+
+ }
+
+}
diff --git a/simple/src/test/resources/ExcelDummyRowProblem_rows0.ods b/simple/src/test/resources/ExcelDummyRowProblem_rows0.ods
new file mode 100644
index 0000000..b3add5c
--- /dev/null
+++ b/simple/src/test/resources/ExcelDummyRowProblem_rows0.ods
Binary files differ
diff --git a/simple/src/test/resources/ExcelDummyRowProblem_rows1.ods b/simple/src/test/resources/ExcelDummyRowProblem_rows1.ods
new file mode 100644
index 0000000..8c27b32
--- /dev/null
+++ b/simple/src/test/resources/ExcelDummyRowProblem_rows1.ods
Binary files differ