All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.odftoolkit.odfdom.doc.table.OdfTable Maven / Gradle / Ivy

The newest version!
/************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
 * 
 * Copyright 2009 IBM. 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.odfdom.doc.table;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.odftoolkit.odfdom.pkg.OdfElement;
import org.odftoolkit.odfdom.pkg.OdfFileDom;
import org.odftoolkit.odfdom.pkg.OdfName;
import org.odftoolkit.odfdom.pkg.OdfXMLFactory;
import org.odftoolkit.odfdom.doc.OdfDocument;
import org.odftoolkit.odfdom.doc.OdfSpreadsheetDocument;
import org.odftoolkit.odfdom.doc.OdfDocument.OdfMediaType;
import org.odftoolkit.odfdom.dom.OdfDocumentNamespace;
import org.odftoolkit.odfdom.dom.attribute.table.TableAlignAttribute;
import org.odftoolkit.odfdom.dom.element.office.OfficeBodyElement;
import org.odftoolkit.odfdom.dom.element.style.StyleTableCellPropertiesElement;
import org.odftoolkit.odfdom.dom.element.style.StyleTableColumnPropertiesElement;
import org.odftoolkit.odfdom.dom.element.style.StyleTablePropertiesElement;
import org.odftoolkit.odfdom.dom.element.table.TableCoveredTableCellElement;
import org.odftoolkit.odfdom.dom.element.table.TableNamedRangeElement;
import org.odftoolkit.odfdom.dom.element.table.TableTableCellElement;
import org.odftoolkit.odfdom.dom.element.table.TableTableCellElementBase;
import org.odftoolkit.odfdom.dom.element.table.TableTableColumnElement;
import org.odftoolkit.odfdom.dom.element.table.TableTableElement;
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.text.TextHElement;
import org.odftoolkit.odfdom.dom.element.text.TextListElement;
import org.odftoolkit.odfdom.dom.element.text.TextPElement;
import org.odftoolkit.odfdom.dom.style.OdfStyleFamily;
import org.odftoolkit.odfdom.dom.style.props.OdfTableProperties;
import org.odftoolkit.odfdom.incubator.doc.office.OdfOfficeAutomaticStyles;
import org.odftoolkit.odfdom.incubator.doc.style.OdfStyle;
import org.odftoolkit.odfdom.type.PositiveLength;
import org.odftoolkit.odfdom.type.Length.Unit;
import org.w3c.dom.DOMException;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * OdfTable represents the table feature in ODF spreadsheet and text documents.
 * 

* OdfTable provides methods to get/add/delete/modify table column/row/cell. * */ public class OdfTable { TableTableElement mTableElement; protected OdfDocument mDocument; protected boolean mIsSpreadsheet; protected boolean mIsCellStyleInheritance = true; private static final int DEFAULT_ROW_COUNT = 2; private static final int DEFAULT_COLUMN_COUNT = 5; private static final double DEFAULT_TABLE_WIDTH = 6; private static final int DEFAULT_REL_TABLE_WIDTH = 65535; private static final String DEFAULT_TABLE_ALIGN = "margins"; // TODO: should save seperately for different dom tree static IdentityHashMap mTableRepository = new IdentityHashMap(); IdentityHashMap> mCellRepository = new IdentityHashMap>(); IdentityHashMap> mRowRepository = new IdentityHashMap>(); IdentityHashMap> mColumnRepository = new IdentityHashMap>(); private OdfTable(TableTableElement table) { mTableElement = table; mDocument = (OdfDocument) ((OdfFileDom)(table.getOwnerDocument())).getDocument(); if (mDocument instanceof OdfSpreadsheetDocument) mIsSpreadsheet = true; else mIsSpreadsheet = false; } /** * Get a table feature instance by an instance of TableTableElement. * * @param odfElement an instance of TableTableElement * @return an instance of OdfTable that can represent odfElement */ public synchronized static OdfTable getInstance(TableTableElement odfElement) { if (mTableRepository.containsKey(odfElement)) { return mTableRepository.get(odfElement); } else { OdfTable newTable = new OdfTable(odfElement); mTableRepository.put(odfElement, newTable); return newTable; } } OdfTableCell getCellInstance(TableTableCellElementBase cell, int repeatedColIndex, int repeatedRowIndex) { if (mCellRepository.containsKey(cell)) { Vector list = mCellRepository.get(cell); OdfTableCell fCell = null; for (int i = 0; i < list.size(); i++) { if (list.get(i).getOdfElement() == cell && list.get(i).mnRepeatedColIndex == repeatedColIndex && list.get(i).mnRepeatedRowIndex == repeatedRowIndex) { fCell = list.get(i); break; } } if (fCell == null) { fCell = new OdfTableCell(cell, repeatedColIndex, repeatedRowIndex); list.add(fCell); } return fCell; } else { OdfTableCell newCell = new OdfTableCell(cell, repeatedColIndex, repeatedRowIndex); Vector list = new Vector(); list.add(newCell); mCellRepository.put(cell, list); return newCell; } } OdfTableRow getRowInstance(TableTableRowElement row, int repeatedRowIndex) { if (mRowRepository.containsKey(row)) { Vector list = mRowRepository.get(row); if (list.size() <= repeatedRowIndex) { list.setSize(repeatedRowIndex + 1); } OdfTableRow fCell = list.get(repeatedRowIndex); if (fCell == null) { fCell = new OdfTableRow(row, repeatedRowIndex); list.set(repeatedRowIndex, fCell); } return fCell; } else { OdfTableRow newCell = new OdfTableRow(row, repeatedRowIndex); int size = (repeatedRowIndex > 7) ? (repeatedRowIndex + 1) : 8; Vector list = new Vector(size); list.setSize(repeatedRowIndex + 1); list.set(repeatedRowIndex, newCell); mRowRepository.put(row, list); return newCell; } } OdfTableColumn getColumnInstance(TableTableColumnElement col, int repeatedColIndex) { if (mColumnRepository.containsKey(col)) { Vector list = mColumnRepository.get(col); if (list.size() <= repeatedColIndex) { list.setSize(repeatedColIndex + 1); } OdfTableColumn fClm = list.get(repeatedColIndex); if (fClm == null) { fClm = new OdfTableColumn(col, repeatedColIndex); list.set(repeatedColIndex, fClm); } return fClm; } else { OdfTableColumn newCell = new OdfTableColumn(col, repeatedColIndex); int size = (repeatedColIndex > 7) ? (repeatedColIndex + 1) : 8; Vector list = new Vector(size); list.setSize(repeatedColIndex + 1); list.set(repeatedColIndex, newCell); mColumnRepository.put(col, list); return newCell; } } TableTableColumnElement getColumnElementByIndex(int colIndex) { int result = 0; TableTableColumnElement columnEle = null; for (Node n : new DomNodeList(mTableElement.getChildNodes())) { if (n instanceof TableTableHeaderColumnsElement) { TableTableHeaderColumnsElement headers = (TableTableHeaderColumnsElement) n; for (Node m : new DomNodeList(headers.getChildNodes())) { if (m instanceof TableTableColumnElement) { columnEle = (TableTableColumnElement) m; if (columnEle.getTableNumberColumnsRepeatedAttribute() == null) { result += 1; } else { result += columnEle.getTableNumberColumnsRepeatedAttribute(); } } if (result > colIndex) { break; } } } if (n instanceof TableTableColumnElement) { columnEle = (TableTableColumnElement) n; if (columnEle.getTableNumberColumnsRepeatedAttribute() == null) { result += 1; } else { result += columnEle.getTableNumberColumnsRepeatedAttribute(); } } if (result > colIndex) { break; } } return columnEle; } TableTableRowElement getRowElementByIndex(int rowIndex) { int result = 0; TableTableRowElement rowEle = null; for (Node n : new DomNodeList(mTableElement.getChildNodes())) { if (n instanceof TableTableHeaderRowsElement) { TableTableHeaderRowsElement headers = (TableTableHeaderRowsElement) n; for (Node m : new DomNodeList(headers.getChildNodes())) { if (m instanceof TableTableRowElement) { rowEle = (TableTableRowElement) m; result += rowEle.getTableNumberRowsRepeatedAttribute(); } if (result > rowIndex) { break; } } } if (n instanceof TableTableRowElement) { rowEle = (TableTableRowElement) n; result += ((TableTableRowElement) n).getTableNumberRowsRepeatedAttribute(); } if (result > rowIndex) { break; } } return rowEle; } /** * Get the width of the table (in Millimeter). *

* Throw an UnsupportedOperationException if the * table is one sheet of a spreadsheet document. * because the sheet doesn't have an attribute of table width. * * @return the width of the current table (in Millimeter). *

* An UnsupportedOperationException will be thrown if the table is in the spreadsheet document. */ public long getWidth() { if (!mIsSpreadsheet) { String sWidth = mTableElement.getProperty(OdfTableProperties.Width); if(sWidth == null){ int colCount = getColumnCount(); int tableWidth = 0; for(int i = 0; i * Throw an UnsupportedOperationException if the * table is part of a spreadsheet document that does not allow to change the table size, * because spreadsheet is not allow user to set the table size. * * @param width the width that need to set (in Millimeter). *

* An UnsupportedOperationException will be thrown if the table is in the spreadsheet document. */ public void setWidth(long width) { if (!mIsSpreadsheet) { String sWidthMM = String.valueOf(width) + Unit.MILLIMETER.abbr(); String sWidthIN = PositiveLength.mapToUnit(sWidthMM, Unit.INCH); mTableElement.setProperty(OdfTableProperties.Width, sWidthIN); //if the width is changed, we should also change the table:align properties if it is "margins" //otherwise the width seems not changed String alineStyle = mTableElement.getProperty(StyleTablePropertiesElement.Align); if (TableAlignAttribute.Value.MARGINS.toString().equals(alineStyle)) { mTableElement.setProperty(StyleTablePropertiesElement.Align, TableAlignAttribute.Value.LEFT.toString()); } } else { throw new UnsupportedOperationException(); } } static void setLeftTopBorderStyleProperties(OdfStyle style) { style.setProperty(StyleTableCellPropertiesElement.Padding, "0.0382in"); style.setProperty(StyleTableCellPropertiesElement.BorderLeft, "0.0007in solid #000000"); style.setProperty(StyleTableCellPropertiesElement.BorderRight, "none"); style.setProperty(StyleTableCellPropertiesElement.BorderTop, "0.0007in solid #000000"); style.setProperty(StyleTableCellPropertiesElement.BorderBottom, "0.0007in solid #000000"); } static void setRightTopBorderStyleProperties(OdfStyle style) { style.setProperty(StyleTableCellPropertiesElement.Padding, "0.0382in"); style.setProperty(StyleTableCellPropertiesElement.Border, "0.0007in solid #000000"); } static void setLeftBottomBorderStylesProperties(OdfStyle style) { style.setProperty(StyleTableCellPropertiesElement.Padding, "0.0382in"); style.setProperty(StyleTableCellPropertiesElement.BorderLeft, "0.0007in solid #000000"); style.setProperty(StyleTableCellPropertiesElement.BorderRight, "none"); style.setProperty(StyleTableCellPropertiesElement.BorderTop, "none"); style.setProperty(StyleTableCellPropertiesElement.BorderBottom, "0.0007in solid #000000"); } static void setRightBottomBorderStylesProperties(OdfStyle style) { style.setProperty(StyleTableCellPropertiesElement.Padding, "0.0382in"); style.setProperty(StyleTableCellPropertiesElement.Border, "0.0007in solid #000000"); style.setProperty(StyleTableCellPropertiesElement.BorderTop, "none"); style.setProperty(StyleTableCellPropertiesElement.BorderBottom, "0.0007in solid #000000"); } private static TableTableElement createTable(OdfDocument document, int numRows, int numCols, int headerRowNumber, int headerColumnNumber) throws Exception { boolean isSpreadsheet = document instanceof OdfSpreadsheetDocument; // check arguments if (numRows < 1 || numCols < 1 || headerRowNumber < 0 || headerColumnNumber < 0 || headerRowNumber > numRows || headerColumnNumber > numCols) { throw new IllegalArgumentException("Can not create table with the given parameters:\n" + "Rows " + numRows + ", Columns " + numCols + ", HeaderRows " + headerRowNumber + ", HeaderColumns " + headerColumnNumber); } OdfFileDom dom = document.getContentDom(); OdfOfficeAutomaticStyles styles = dom.getAutomaticStyles(); //1. create table element TableTableElement newTEle = (TableTableElement) OdfXMLFactory.newOdfElement(dom, OdfName.newName(OdfDocumentNamespace.TABLE, "table")); String tablename = getUniqueTableName(document); newTEle.setTableNameAttribute(tablename); //create style OdfStyle tableStyle = styles.newStyle(OdfStyleFamily.Table); String stylename = tableStyle.getStyleNameAttribute(); tableStyle.setProperty(StyleTablePropertiesElement.Width, DEFAULT_TABLE_WIDTH + "in"); tableStyle.setProperty(StyleTablePropertiesElement.Align, DEFAULT_TABLE_ALIGN); newTEle.setStyleName(stylename); // 2. create column elements // 2.0 create column style OdfStyle columnStyle = styles.newStyle(OdfStyleFamily.TableColumn); String columnStylename = columnStyle.getStyleNameAttribute(); columnStyle.setProperty(StyleTableColumnPropertiesElement.ColumnWidth, new DecimalFormat("000.0000").format(DEFAULT_TABLE_WIDTH / numCols) + "in"); columnStyle.setProperty(StyleTableColumnPropertiesElement.RelColumnWidth, Math.round(DEFAULT_REL_TABLE_WIDTH / numCols) + "*"); // 2.1 create header column elements if (headerColumnNumber > 0) { TableTableHeaderColumnsElement headercolumns = (TableTableHeaderColumnsElement) OdfXMLFactory.newOdfElement(dom, OdfName.newName(OdfDocumentNamespace.TABLE, "table-header-columns")); TableTableColumnElement headercolumn = (TableTableColumnElement) OdfXMLFactory.newOdfElement(dom, OdfName.newName(OdfDocumentNamespace.TABLE, "table-column")); headercolumn.setTableNumberColumnsRepeatedAttribute(headerColumnNumber); headercolumns.appendChild(headercolumn); newTEle.appendChild(headercolumns); headercolumn.setStyleName(columnStylename); } //2.2 create common column elements TableTableColumnElement columns = (TableTableColumnElement) OdfXMLFactory.newOdfElement(dom, OdfName.newName(OdfDocumentNamespace.TABLE, "table-column")); columns.setTableNumberColumnsRepeatedAttribute(numCols - headerColumnNumber); columns.setStyleName(columnStylename); newTEle.appendChild(columns); //3. create row elements //3.0 create 4 kinds of styles OdfStyle lefttopStyle=null,leftbottomStyle=null,righttopStyle=null,rightbottomStyle=null; if (!document.getMediaTypeString().equals(OdfMediaType.SPREADSHEET.getMediaTypeString())) { lefttopStyle = styles.newStyle(OdfStyleFamily.TableCell); setLeftTopBorderStyleProperties(lefttopStyle); leftbottomStyle = styles.newStyle(OdfStyleFamily.TableCell); setLeftBottomBorderStylesProperties(leftbottomStyle); righttopStyle = styles.newStyle(OdfStyleFamily.TableCell); setRightTopBorderStyleProperties(righttopStyle); rightbottomStyle = styles.newStyle(OdfStyleFamily.TableCell); setRightBottomBorderStylesProperties(rightbottomStyle); } //3.1 create header row elements if( headerRowNumber > 0) { TableTableHeaderRowsElement headerrows = (TableTableHeaderRowsElement) OdfXMLFactory.newOdfElement(dom, OdfName.newName(OdfDocumentNamespace.TABLE, "table-header-rows")); for (int i = 0; i < headerRowNumber; i++) { TableTableRowElement aRow = (TableTableRowElement) OdfXMLFactory.newOdfElement(dom, OdfName.newName(OdfDocumentNamespace.TABLE, "table-row")); for (int j = 0; j < numCols; j++) { TableTableCellElement aCell = (TableTableCellElement) OdfXMLFactory.newOdfElement(dom, OdfName.newName(OdfDocumentNamespace.TABLE, "table-cell")); TextPElement aParagraph = (TextPElement) OdfXMLFactory.newOdfElement(dom, OdfName.newName(OdfDocumentNamespace.TEXT, "p")); aCell.appendChild(aParagraph); if (!isSpreadsheet) { if ((j + 1 == numCols) && (i == 0)) { aCell.setStyleName(righttopStyle.getStyleNameAttribute()); } else if (i == 0) { aCell.setStyleName(lefttopStyle.getStyleNameAttribute()); } else if ((j + 1 == numCols) && (i > 0)) { aCell.setStyleName(rightbottomStyle.getStyleNameAttribute()); } else { aCell.setStyleName(leftbottomStyle.getStyleNameAttribute()); } } aRow.appendChild(aCell); } headerrows.appendChild(aRow); } newTEle.appendChild(headerrows); } //3.2 create common row elements for (int i = headerRowNumber; i < numRows; i++) { TableTableRowElement aRow = (TableTableRowElement) OdfXMLFactory.newOdfElement(dom, OdfName.newName(OdfDocumentNamespace.TABLE, "table-row")); for (int j = 0; j < numCols; j++) { TableTableCellElement aCell = (TableTableCellElement) OdfXMLFactory.newOdfElement(dom, OdfName.newName(OdfDocumentNamespace.TABLE, "table-cell")); TextPElement aParagraph = (TextPElement) OdfXMLFactory.newOdfElement(dom, OdfName.newName(OdfDocumentNamespace.TEXT, "p")); aCell.appendChild(aParagraph); if (!isSpreadsheet) { if ((j + 1 == numCols) && (i == 0)) { aCell.setStyleName(righttopStyle.getStyleNameAttribute()); } else if (i == 0) { aCell.setStyleName(lefttopStyle.getStyleNameAttribute()); } else if ((j + 1 == numCols) && (i > 0)) { aCell.setStyleName(rightbottomStyle.getStyleNameAttribute()); } else { aCell.setStyleName(leftbottomStyle.getStyleNameAttribute()); } } aRow.appendChild(aCell); } newTEle.appendChild(aRow); } return newTEle; } /** * Construct the OdfTable feature. * The default column count is 5. * The default row count is 2. *

* The table will be inserted at the end of the document. * An unique table name will be given, you may set a custom table name using the setTableName method. *

* If the document is a text document, cell borders will be created by default. * * @param document the ODF document that contains this feature * @return the created OdfTable feature instance */ public static OdfTable newTable(OdfDocument document) { try { TableTableElement newTEle = createTable(document, DEFAULT_ROW_COUNT, DEFAULT_COLUMN_COUNT, 0, 0); //4. append to the end of document OdfElement root = document.getContentDom().getRootElement(); OfficeBodyElement officeBody = OdfElement.findFirstChildNode(OfficeBodyElement.class, root); OdfElement typedContent = OdfElement.findFirstChildNode(OdfElement.class, officeBody); typedContent.appendChild(newTEle); return OdfTable.getInstance(newTEle); } catch (DOMException e) { Logger.getLogger(OdfTable.class.getName()).log(Level.SEVERE, e.getMessage(), e); } catch (Exception e) { Logger.getLogger(OdfTable.class.getName()).log(Level.SEVERE, e.getMessage(), e); } return null; } private static String getUniqueTableName(OdfDocument document) { List tableList = document.getTableList(); boolean notUnique = true; String tablename = "Table" + (tableList.size() + 1); while (notUnique) { notUnique = false; for (int i = 0; i < tableList.size(); i++) { if (tableList.get(i).getTableName().equalsIgnoreCase(tablename)) { notUnique = true; break; } } if (notUnique) { tablename = tablename + Math.round(Math.random() * 10); } } return tablename; } /** * Construct the OdfTable feature * with a specified row number and column number. *

* The table will be inserted at the end of the document. * An unique table name will be given, you may set a custom table name using the setTableName method. *

* If the document is a text document, cell borders will be created by default. * * @param document the ODF document that contains this feature * @param numRows the row number * @param numCols the column number * @return a new instance of OdfTable */ public static OdfTable newTable(OdfDocument document, int numRows, int numCols) { try { TableTableElement newTEle = createTable(document, numRows, numCols, 0, 0); //4. append to the end of document OdfElement root = document.getContentDom().getRootElement(); OfficeBodyElement officeBody = OdfElement.findFirstChildNode(OfficeBodyElement.class, root); OdfElement typedContent = OdfElement.findFirstChildNode(OdfElement.class, officeBody); typedContent.appendChild(newTEle); return OdfTable.getInstance(newTEle); } catch (Exception e) { Logger.getLogger(OdfTable.class.getName()).log(Level.SEVERE, e.getMessage(), e); } return null; } /** * Construct the OdfTable feature * with a specified row number, column number, header row number, header column number. *

* The table will be inserted at the end of the document. * An unique table name will be given, you may set a custom table name using the setTableName method. *

* If the document is a text document, cell borders will be created by default. * * @param document the ODF document that contains this feature * @param numRows the row number * @param numCols the column number * @param headerRowNumber the header row number * @param headerColumnNumber the header column number * @return a new instance of OdfTable * */ public static OdfTable newTable(OdfDocument document, int numRows, int numCols, int headerRowNumber, int headerColumnNumber) { try { TableTableElement newTEle = createTable(document, numRows, numCols, headerRowNumber, headerColumnNumber); //4. append to the end of document OdfElement root = document.getContentDom().getRootElement(); OfficeBodyElement officeBody = OdfElement.findFirstChildNode(OfficeBodyElement.class, root); OdfElement typedContent = OdfElement.findFirstChildNode(OdfElement.class, officeBody); typedContent.appendChild(newTEle); return OdfTable.getInstance(newTEle); } catch (DOMException e) { Logger.getLogger(OdfTable.class.getName()).log(Level.SEVERE, e.getMessage(), e); } catch (Exception e) { Logger.getLogger(OdfTable.class.getName()).log(Level.SEVERE, e.getMessage(), e); } return null; } /** * Construct the OdfTable feature * with a specified 2 dimension array as the data of this table. * The value type of each cell is float. *

* The table will be inserted at the end of the document. * An unique table name will be given, you may set a custom table name using the setTableName method. *

* If the document is a text document, cell borders will be created by default. * * @param document the ODF document that contains this feature * @param rowLabel set as the header row, it can be null if no header row needed * @param columnLabel set as the header column, it can be null if no header column needed * @param data the two dimension array of double as the data of this table * @return a new instance of OdfTable */ public static OdfTable newTable(OdfDocument document, String[] rowLabel, String[] columnLabel, double[][] data) { int rowNumber = DEFAULT_ROW_COUNT; int columnNumber = DEFAULT_COLUMN_COUNT; if (data != null) { rowNumber = data.length; columnNumber = data[0].length; } int rowHeaders = 0, columnHeaders = 0; if (rowLabel != null) { rowHeaders = 1; } if (columnLabel != null) { columnHeaders = 1; } try { TableTableElement newTEle = createTable(document, rowNumber + rowHeaders, columnNumber + columnHeaders, rowHeaders, columnHeaders); //4. append to the end of document OdfElement root = document.getContentDom().getRootElement(); OfficeBodyElement officeBody = OdfElement.findFirstChildNode(OfficeBodyElement.class, root); OdfElement typedContent = OdfElement.findFirstChildNode(OdfElement.class, officeBody); typedContent.appendChild(newTEle); OdfTable table = OdfTable.getInstance(newTEle); List rowList = table.getRowList(); for (int i = 0; i < rowNumber + rowHeaders; i++) { OdfTableRow row = rowList.get(i); for (int j = 0; j < columnNumber + columnHeaders; j++) { if ((i == 0) && (j == 0)) { continue; } OdfTableCell cell = row.getCellByIndex(j); if (i == 0 && columnLabel != null) //first row, should fill column labels { if (j <= columnLabel.length) { cell.setStringValue(columnLabel[j - 1]); } else { cell.setStringValue(""); } } else if (j == 0 && rowLabel != null) //first column, should fill row labels { if (i <= rowLabel.length) { cell.setStringValue(rowLabel[i - 1]); } else { cell.setStringValue(""); } } else {//data if ((data != null) && (i >= rowHeaders) && (j >= columnHeaders)) { cell.setDoubleValue(data[i - rowHeaders][j - columnHeaders]); } } } } return table; } catch (DOMException e) { Logger.getLogger(OdfTable.class.getName()).log(Level.SEVERE, e.getMessage(), e); } catch (Exception e) { Logger.getLogger(OdfTable.class.getName()).log(Level.SEVERE, e.getMessage(), e); } return null; } /** * Construct the OdfTable feature * with a specified 2 dimension array as the data of this table. * The value type of each cell is string. *

* The table will be inserted at the end of the document. * An unique table name will be given, you may set a custom table name using the setTableName method. *

* If the document is a text document, cell borders will be created by default. * * @param document the ODF document that contains this feature * @param rowLabel set as the header row, it can be null if no header row needed * @param columnLabel set as the header column, it can be null if no header column needed * @param data the two dimension array of string as the data of this table * @return a new instance of OdfTable */ public static OdfTable newTable(OdfDocument document, String[] rowLabel, String[] columnLabel, String[][] data) { int rowNumber = DEFAULT_ROW_COUNT; int columnNumber = DEFAULT_COLUMN_COUNT; if (data != null) { rowNumber = data.length; columnNumber = data[0].length; } int rowHeaders = 0, columnHeaders = 0; if (rowLabel != null) { rowHeaders = 1; } if (columnLabel != null) { columnHeaders = 1; } try { TableTableElement newTEle = createTable(document, rowNumber + rowHeaders, columnNumber + columnHeaders, rowHeaders, columnHeaders); //4. append to the end of document OdfElement root = document.getContentDom().getRootElement(); OfficeBodyElement officeBody = OdfElement.findFirstChildNode(OfficeBodyElement.class, root); OdfElement typedContent = OdfElement.findFirstChildNode(OdfElement.class, officeBody); typedContent.appendChild(newTEle); OdfTable table = OdfTable.getInstance(newTEle); List rowList = table.getRowList(); for (int i = 0; i < rowNumber + rowHeaders; i++) { OdfTableRow row = rowList.get(i); for (int j = 0; j < columnNumber + columnHeaders; j++) { if ((i == 0) && (j == 0)) { continue; } OdfTableCell cell = row.getCellByIndex(j); if (i == 0 && columnLabel != null) //first row, should fill column labels { if (j <= columnLabel.length) { cell.setStringValue(columnLabel[j - 1]); } else { cell.setStringValue(""); } } else if (j == 0 && rowLabel != null) //first column, should fill row labels { if (i <= rowLabel.length) { cell.setStringValue(rowLabel[i - 1]); } else { cell.setStringValue(""); } } else { if ((data != null) && (i >= rowHeaders) && (j >= columnHeaders)) { cell.setStringValue(data[i - rowHeaders][j - columnHeaders]); } } } } return table; } catch (DOMException e) { Logger.getLogger(OdfTable.class.getName()).log(Level.SEVERE, e.getMessage(), e); } catch (Exception e) { Logger.getLogger(OdfTable.class.getName()).log(Level.SEVERE, e.getMessage(), e); } return null; } /** * Get the row count of this table. * * @return total count of rows */ public int getRowCount() { int result = 0; for (Node n : new DomNodeList(mTableElement.getChildNodes())) { if (n instanceof TableTableHeaderRowsElement) { result += getHeaderRowCount((TableTableHeaderRowsElement) n); } if (n instanceof TableTableRowElement) { result += ((TableTableRowElement) n).getTableNumberRowsRepeatedAttribute(); } } return result; } /** * Get the column count of this table. * * @return total count of columns */ public int getColumnCount() { int result = 0; for (Node n : new DomNodeList(mTableElement.getChildNodes())) { if (n instanceof TableTableHeaderColumnsElement) { result += getHeaderColumnCount((TableTableHeaderColumnsElement) n); } if (n instanceof TableTableColumnElement) { result += getColumnInstance((TableTableColumnElement) n, 0).getColumnsRepeatedNumber(); } } return result; } /** * This method is invoked by appendRow. * When a table has no row, the first row is a default row. */ private TableTableRowElement createDefaultRow(int columnCount) { OdfFileDom dom = (OdfFileDom) mTableElement.getOwnerDocument(); //3. create row elements //3.0 create 4 kinds of styles OdfStyle lefttopStyle=null,righttopStyle=null; if (!mIsSpreadsheet) { lefttopStyle = mTableElement.getAutomaticStyles().newStyle(OdfStyleFamily.TableCell); setLeftTopBorderStyleProperties(lefttopStyle); righttopStyle = mTableElement.getAutomaticStyles().newStyle(OdfStyleFamily.TableCell); setRightTopBorderStyleProperties(righttopStyle); } //3.1 create header row elements TableTableRowElement aRow = (TableTableRowElement) OdfXMLFactory.newOdfElement(dom, OdfName.newName(OdfDocumentNamespace.TABLE, "table-row")); for (int j = 0; j < columnCount; j++) { TableTableCellElement aCell = (TableTableCellElement) OdfXMLFactory.newOdfElement(dom, OdfName.newName(OdfDocumentNamespace.TABLE, "table-cell")); TextPElement aParagraph = (TextPElement) OdfXMLFactory.newOdfElement(dom, OdfName.newName(OdfDocumentNamespace.TEXT, "p")); aCell.appendChild(aParagraph); if (!mIsSpreadsheet) { if (j + 1 == columnCount) { aCell.setStyleName(righttopStyle.getStyleNameAttribute()); } else { aCell.setStyleName(lefttopStyle.getStyleNameAttribute()); } } aRow.appendChild(aCell); } return aRow; } /** * Append a row to the end of the table. The style of new row is same with * the last row in the table. *

* Since ODFDOM 8.5 automatic table expansion is supported. Whenever a cell * outside the current table is addressed the table is instantly expanded. * Method getCellByPosition can randomly access any cell, no * matter it in or out of the table original range. * * @return a new appended row * @see #appendRows(int) * @see #getRowByIndex(int) * @see #getCellByPosition(int, int) * @see #getCellByPosition(String) */ public OdfTableRow appendRow() { int columnCount = getColumnCount(); List rowList = getRowList(); if (rowList.size() == 0) //no row, create a default row { TableTableRowElement newRow = createDefaultRow(columnCount); mTableElement.appendChild(newRow); return getRowInstance(newRow, 0); } else { OdfTableRow refRow = rowList.get(rowList.size() - 1); OdfTableRow newRow = insertRowBefore(refRow, null); return newRow; } } /** * Append a specific number of rows to the end of the table. The style of * new rows are same with the last row in the table. *

* Since ODFDOM 8.5 automatic table expansion is supported. Whenever a cell * outside the current table is addressed the table is instantly expanded. * Method getCellByPosition can randomly access any cell, no * matter it in or out of the table original range. * * @param rowCount is the number of rows to be appended. * @return a list of new appended rows * @see #appendRow() * @see #getRowByIndex(int) * @see #getCellByPosition(int, int) * @see #getCellByPosition(String) */ public List appendRows(int rowCount) { return appendRows(rowCount, false); } List appendRows(int rowCount, boolean isCleanStyle) { List resultList = new ArrayList(); if (rowCount <= 0) { return resultList; } OdfTableRow firstRow = appendRow(); resultList.add(firstRow); if (rowCount == 1) { return resultList; } List list = insertRowsBefore((getRowCount() - 1), (rowCount - 1)); resultList.addAll(list); if (isCleanStyle) { // clean style name for (OdfTableRow row : resultList) { for (int i = 0; i < row.getCellCount(); i++) { TableTableCellElement cellElement = (TableTableCellElement) (row .getCellByIndex(i).mCellElement); cellElement.removeAttributeNS(OdfDocumentNamespace.TABLE.getUri(), "style-name"); } } } return resultList; } /** * Append a column at the end of the table. The style of new column is * same with the last column in the table. *

* Since ODFDOM 8.5 automatic table expansion is supported. Whenever a cell * outside the current table is addressed the table is instantly expanded. * Method getCellByPosition can randomly access any cell, no * matter it in or out of the table original range. * * @return a new appended column * @see #appendColumns(int) * @see #getColumnByIndex(int) * @see #getCellByPosition(int, int) * @see #getCellByPosition(String) */ public OdfTableColumn appendColumn() { List columnList = getColumnList(); int columnCount = columnList.size(); TableTableColumnElement newColumn; OdfElement positonElement = getRowElementByIndex(0); if (positonElement.getParentNode() instanceof TableTableHeaderRowsElement) { positonElement = (OdfElement) positonElement.getParentNode(); } //Moved before column elements inserted //insert cells firstly //Or else, wrong column number will be gotten in updateCellRepository, which will cause a NPE. //insertCellBefore()->splitRepeatedRows()->updateRowRepository()->updateCellRepository() List rowList = getRowList(); for (int i = 0; i < rowList.size();) { OdfTableRow row1 = rowList.get(i); row1.insertCellBefore(row1.getCellByIndex(columnCount - 1), null); i = i + row1.getRowsRepeatedNumber(); } //insert columns secondly if (columnList.size() == 0) //no column, create a new column { OdfStyle columnStyle = mTableElement.getAutomaticStyles().newStyle(OdfStyleFamily.TableColumn); String columnStylename = columnStyle.getStyleNameAttribute(); columnStyle.setProperty(StyleTableColumnPropertiesElement.ColumnWidth, DEFAULT_TABLE_WIDTH + "in"); columnStyle.setProperty(StyleTableColumnPropertiesElement.RelColumnWidth, DEFAULT_REL_TABLE_WIDTH + "*"); newColumn = (TableTableColumnElement) OdfXMLFactory.newOdfElement((OdfFileDom) mTableElement.getOwnerDocument(), OdfName.newName(OdfDocumentNamespace.TABLE, "table-column")); newColumn.setStyleName(columnStylename); mTableElement.insertBefore(newColumn, positonElement); } else { //has column, append a same column as the last one. TableTableColumnElement refColumn = columnList.get(columnList.size() - 1).getOdfElement(); newColumn = (TableTableColumnElement) refColumn.cloneNode(true); newColumn.setTableNumberColumnsRepeatedAttribute(1);//chagne to remove attribute mTableElement.insertBefore(newColumn, positonElement); } return getColumnInstance(newColumn, 0); } /** * Append a specific number of columns to the right of the table. The style * of new columns are same with the rightmost column in the table. *

* Since ODFDOM 8.5 automatic table expansion is supported. Whenever a cell * outside the current table is addressed the table is instantly expanded. * Method getCellByPosition can randomly access any cell, no * matter it in or out of the table original range. * * @param columnCount is the number of columns to be appended. * @return a list of new appended columns * @see #appendColumn() * @see #getColumnByIndex(int) * @see #getCellByPosition(int, int) * @see #getCellByPosition(String) */ public List appendColumns(int columnCount) { return appendColumns(columnCount, false); } List appendColumns(int columnCount, boolean isCleanStyle) { List resultList = new ArrayList(); if (columnCount <= 0) { return resultList; } OdfTableColumn firstClm = appendColumn(); resultList.add(firstClm); if (columnCount == 1) { return resultList; } List list = insertColumnsBefore((getColumnCount() - 1), (columnCount - 1)); resultList.addAll(list); // clean style name if(isCleanStyle){ for (OdfTableColumn column : resultList) { for (int i = 0; i < column.getCellCount(); i++) { TableTableCellElement cellElement = (TableTableCellElement) (column .getCellByIndex(i).mCellElement); cellElement.removeAttributeNS(OdfDocumentNamespace.TABLE.getUri(), "style-name"); } } } return resultList; } /** * This method is to insert a numbers of row */ private List insertMultipleRowBefore(OdfTableRow refRow, OdfTableRow positionRow, int count) { List resultList = new ArrayList(); int j = 1; if (count <= 0) { return resultList; } OdfTableRow firstRow = insertRowBefore(refRow, positionRow); resultList.add(firstRow); if (count == 1) { return resultList; } TableTableRowElement rowEle = firstRow.getOdfElement(); for (int i = 0; i < getColumnCount();) { OdfTableCell refCell = refRow.getCellByIndex(i); if (!refCell.isCoveredElement()) { int coveredHeigth = refCell.getRowSpannedNumber(); if (coveredHeigth > 1) { refCell.setRowSpannedNumber(coveredHeigth + 1); } } i += refCell.getColumnsRepeatedNumber(); } firstRow.setRowsRepeatedNumber(count); while (j < count) { resultList.add(getRowInstance(rowEle, j)); j++; } return resultList; } private OdfTableRow insertRowBefore(OdfTableRow refRow, OdfTableRow positionRow) //only insert one Row { int columnCount = getColumnCount(); TableTableRowElement aRow = (TableTableRowElement) OdfXMLFactory.newOdfElement((OdfFileDom) mTableElement.getOwnerDocument(), OdfName.newName(OdfDocumentNamespace.TABLE, "table-row")); int coveredLength = 0, coveredHeigth = 0; for (int i = 0; i < columnCount;) { OdfTableCell refCell = refRow.getCellByIndex(i); if (!refCell.isCoveredElement()) //not cover element { TableTableCellElement aCellEle = (TableTableCellElement) refCell.getOdfElement(); coveredHeigth = aCellEle.getTableNumberRowsSpannedAttribute(); if (coveredHeigth == 1) { TableTableCellElement newCellEle = (TableTableCellElement) aCellEle.cloneNode(true); cleanCell(newCellEle); aRow.appendChild(newCellEle); } else { //cover more rows aCellEle.setTableNumberRowsSpannedAttribute(coveredHeigth + 1); TableCoveredTableCellElement newCellEle = (TableCoveredTableCellElement) OdfXMLFactory.newOdfElement( (OdfFileDom) mTableElement.getOwnerDocument(), OdfName.newName(OdfDocumentNamespace.TABLE, "covered-table-cell")); newCellEle.setTableNumberColumnsRepeatedAttribute(refCell.getColumnsRepeatedNumber()); aRow.appendChild(newCellEle); } coveredLength = aCellEle.getTableNumberColumnsSpannedAttribute() - refCell.getColumnsRepeatedNumber(); i = i + refCell.getColumnsRepeatedNumber(); } else { TableCoveredTableCellElement aCellEle = (TableCoveredTableCellElement) refCell.getOdfElement(); if (coveredLength >= 1) { TableCoveredTableCellElement newCellEle = (TableCoveredTableCellElement) aCellEle.cloneNode(true); aRow.appendChild(newCellEle); coveredLength -= newCellEle.getTableNumberColumnsRepeatedAttribute(); } else { TableTableCellElement coveredCell = (TableTableCellElement) refCell.getCoverCell().getOdfElement(); TableTableCellElement newCellEle = (TableTableCellElement) coveredCell.cloneNode(true); cleanCell(newCellEle); newCellEle.removeAttributeNS(OdfDocumentNamespace.TABLE.getUri(), "number-rows-spanned"); aRow.appendChild(newCellEle); coveredLength = coveredCell.getTableNumberColumnsSpannedAttribute() - refCell.getColumnsRepeatedNumber(); } i = i + refCell.getColumnsRepeatedNumber(); } } if (positionRow == null) { mTableElement.appendChild(aRow); } else { mTableElement.insertBefore(aRow, positionRow.getOdfElement()); } return getRowInstance(aRow, 0); } void cleanCell(TableTableCellElement newCellEle) { newCellEle.removeAttributeNS(OdfDocumentNamespace.OFFICE.getUri(), "value"); newCellEle.removeAttributeNS(OdfDocumentNamespace.OFFICE.getUri(), "date-value"); newCellEle.removeAttributeNS(OdfDocumentNamespace.OFFICE.getUri(), "time-value"); newCellEle.removeAttributeNS(OdfDocumentNamespace.OFFICE.getUri(), "boolean-value"); newCellEle.removeAttributeNS(OdfDocumentNamespace.OFFICE.getUri(), "string-value"); newCellEle.removeAttributeNS(OdfDocumentNamespace.TABLE.getUri(), "formula"); newCellEle.removeAttributeNS(OdfDocumentNamespace.OFFICE.getUri(), "value-type"); if(!isCellStyleInheritance()){ newCellEle.removeAttributeNS(OdfDocumentNamespace.TABLE.getUri(), "style-name"); } Node n = newCellEle.getFirstChild(); while (n != null) { Node m = n.getNextSibling(); if (n instanceof TextPElement || n instanceof TextHElement || n instanceof TextListElement) { newCellEle.removeChild(n); } n = m; } } /** * Return an instance of TableTableElement which represents this feature. * * @return an instance of TableTableElement */ public TableTableElement getOdfElement() { return mTableElement; } /** * Insert a specific number of columns before the column whose index is index. * * @param index is the index of the column to insert before. * @param columnCount is the number of columns to insert. * @return a list of new inserted columns */ public List insertColumnsBefore(int index, int columnCount) { OdfTableColumn refColumn, positionCol; ArrayList list = new ArrayList(); int columncount = getColumnCount(); if (index >= columncount) { throw new IndexOutOfBoundsException(); } if (index == 0) { int iRowCount = getRowCount(); for (int i = 0; i < iRowCount; i++) { OdfTableRow row = getRowByIndex(i); row.insertCellByIndex(index, columnCount); } refColumn = getColumnByIndex(index); positionCol = refColumn; TableTableColumnElement newColumnEle = (TableTableColumnElement) refColumn.getOdfElement().cloneNode(true); newColumnEle.setTableNumberColumnsRepeatedAttribute(new Integer(columnCount)); mTableElement.insertBefore(newColumnEle, positionCol.getOdfElement()); for (int i = 0; i < columnCount; i++) { list.add(getColumnInstance(newColumnEle, i)); } return list; } //1. insert the cell int iRowCount = getRowCount(); for (int i = iRowCount - 1; i >= 0;) { OdfTableRow row = getRowByIndex(i); OdfTableCell refCell = row.getCellByIndex(index - 1); OdfTableCell positionCell = null; positionCell = row.getCellByIndex(index); row.insertCellBefore(refCell, positionCell, columnCount); i = i - row.getRowsRepeatedNumber(); } refColumn = getColumnByIndex(index - 1); positionCol = getColumnByIndex(index); //2. insert a if (refColumn.getOdfElement() == positionCol.getOdfElement()) { TableTableColumnElement column = refColumn.getOdfElement(); int repeatedCount = getColumnInstance(column, 0).getColumnsRepeatedNumber(); getColumnInstance(column, 0).setColumnsRepeatedNumber((repeatedCount + columnCount)); TableTableColumnElement columnEle = positionCol.getOdfElement(); OdfTableColumn startCol = getColumnInstance(positionCol.getOdfElement(), 0); for (int i = repeatedCount + columnCount - 1; i >= columnCount + (index - startCol.getColumnIndex()); i--) { updateColumnRepository(columnEle, i - columnCount, columnEle, i); } for (int i = 0; i < columnCount; i++) { list.add(getColumnInstance(column, refColumn.mnRepeatedIndex + 1 + i)); } } else { TableTableColumnElement newColumnEle = (TableTableColumnElement) refColumn.getOdfElement().cloneNode(true); newColumnEle.setTableNumberColumnsRepeatedAttribute(new Integer(columnCount)); mTableElement.insertBefore(newColumnEle, positionCol.getOdfElement()); for (int i = 0; i < columnCount; i++) { list.add(getColumnInstance(newColumnEle, i)); } } return list; } /** * Remove a specific number of columns, starting from the column at index. * * @param startIndex * is the index of the first column to delete. * @param deleteColCount * is the number of columns to delete. */ public void removeColumnsByIndex(int startIndex, int deleteColCount) { //0. verify the index if(deleteColCount <= 0) { return; } if(startIndex < 0) { throw new IllegalArgumentException("startIndex of the deleted columns should not be negative"); } int colCount = getColumnCount(); if (startIndex >= colCount) { throw new IndexOutOfBoundsException("Start column index is out of bound"); } if (startIndex + deleteColCount >= colCount) { deleteColCount = colCount - startIndex; } //1. remove cell for (int i = 0; i < getRowCount(); i++) { OdfTableRow aRow = getRowByIndex(i); aRow.removeCellByIndex(startIndex, deleteColCount); } //2. remove column OdfTableColumn firstColumn; for (int i = 0; i < deleteColCount; i++) { firstColumn = getColumnByIndex(startIndex); int repeatedAttr = firstColumn.getColumnsRepeatedNumber(); if (repeatedAttr == 1) { TableTableColumnElement columnEle = OdfElement.findNextChildNode(TableTableColumnElement.class, firstColumn.getOdfElement()); mTableElement.removeChild(firstColumn.getOdfElement()); if (i < (deleteColCount - 1)) { firstColumn = this.getColumnInstance(columnEle, 0); } } else { if (repeatedAttr > firstColumn.mnRepeatedIndex) { firstColumn.setColumnsRepeatedNumber(repeatedAttr - 1); OdfTableColumn startCol = this.getColumnInstance(firstColumn.getOdfElement(), 0); updateColumnRepository(firstColumn.getOdfElement(), startIndex - startCol.getColumnIndex(), null, 0); } } } } private void reviseStyleFromTopRowToMediumRow(OdfTableRow oldTopRow) { if (mIsSpreadsheet) return; int length = getColumnCount(); for (int i = 0; i < length;) { OdfTableCell cell = oldTopRow.getCellByIndex(i); if (cell.isCoveredElement()) { i = i + cell.getColumnsRepeatedNumber(); continue; } OdfStyle styleEle = cell.getCellStyleElementForWrite(); if (i < length - 1) { setLeftBottomBorderStylesProperties(styleEle); } else { setRightBottomBorderStylesProperties(styleEle); } i = i + cell.getColumnsRepeatedNumber(); } } private void reviseStyleFromMediumRowToTopRow(OdfTableRow newTopRow) { if (mIsSpreadsheet) { return; } int length = getColumnCount(); for (int i = 0; i < length;) { OdfTableCell cell = newTopRow.getCellByIndex(i); if (cell.isCoveredElement()) { i = i + cell.getColumnsRepeatedNumber(); continue; } OdfStyle styleEle = cell.getCellStyleElementForWrite(); if (i < length - 1) { setLeftTopBorderStyleProperties(styleEle); } else { setRightTopBorderStyleProperties(styleEle); } i = i + cell.getColumnsRepeatedNumber(); } } /** * Insert a specific number of rows before the row at index. * * @param index is the index of the row to insert before. * @param rowCount is the number of rows to insert. * @return a list of new inserted rows */ public List insertRowsBefore(int index, int rowCount) { if (index >= getRowCount()) { throw new IndexOutOfBoundsException(); } ArrayList list = new ArrayList(); if (index == 0) { OdfTableRow refRow = getRowByIndex(index); OdfTableRow positionRow = refRow; //add first row OdfTableRow newFirstRow = insertRowBefore(refRow, positionRow); reviseStyleFromTopRowToMediumRow(refRow); list.add(newFirstRow); List rowList = insertMultipleRowBefore(refRow, refRow, rowCount - 1); for (int i = 0; i < rowList.size(); i++) { list.add(rowList.get(i)); } return list; } OdfTableRow refRow = getRowByIndex(index - 1); OdfTableRow positionRow = getRowByIndex(index); //1. insert a if (refRow.getOdfElement() == positionRow.getOdfElement()) { TableTableRowElement row = refRow.getOdfElement(); int repeatedCount = refRow.getRowsRepeatedNumber(); refRow.setRowsRepeatedNumber(repeatedCount + rowCount); TableTableRowElement rowEle = positionRow.getOdfElement(); OdfTableRow startRow = getRowInstance(positionRow.getOdfElement(), 0); for (int i = repeatedCount + rowCount - 1; i >= rowCount + (index - startRow.getRowIndex()); i--) { updateRowRepository(rowEle, i - rowCount, rowEle, i); } for (int i = 0; i < rowCount; i++) { list.add(getRowInstance(row, refRow.mnRepeatedIndex + 1 + i)); } } else { List newRowList = insertMultipleRowBefore(refRow, positionRow, rowCount); if (index - 1 == 0) { //correct styles reviseStyleFromTopRowToMediumRow(newRowList.get(0)); } for (int i = 0; i < newRowList.size(); i++) { list.add(newRowList.get(i)); } } return list; } /** * Return a list of columns in the current table. * * @return a list of table columns */ public List getColumnList() { ArrayList list = new ArrayList(); TableTableColumnElement colEle = null; for (Node n : new DomNodeList(mTableElement.getChildNodes())) { if (n instanceof TableTableHeaderColumnsElement) { TableTableHeaderColumnsElement headers = (TableTableHeaderColumnsElement) n; for (Node m : new DomNodeList(headers.getChildNodes())) { if (m instanceof TableTableColumnElement) { colEle = (TableTableColumnElement) m; for (int i = 0; i < getColumnInstance(colEle, 0).getColumnsRepeatedNumber(); i++) { list.add(getColumnInstance(colEle, i)); } } } } if (n instanceof TableTableColumnElement) { colEle = (TableTableColumnElement) n; for (int i = 0; i < getColumnInstance(colEle, 0).getColumnsRepeatedNumber(); i++) { list.add(getColumnInstance(colEle, i)); } } } return list; } /** * Return a list of table rows in the current table. * * @return a list of table rows */ public List getRowList() { ArrayList list = new ArrayList(); TableTableRowElement rowEle = null; for (Node n : new DomNodeList(mTableElement.getChildNodes())) { if (n instanceof TableTableHeaderRowsElement) { TableTableHeaderRowsElement headers = (TableTableHeaderRowsElement) n; for (Node m : new DomNodeList(headers.getChildNodes())) { if (m instanceof TableTableRowElement) { rowEle = (TableTableRowElement) m; for (int i = 0; i < rowEle.getTableNumberRowsRepeatedAttribute(); i++) { list.add(getRowInstance(rowEle, i)); } } } } if (n instanceof TableTableRowElement) { rowEle = (TableTableRowElement) n; for (int i = 0; i < rowEle.getTableNumberRowsRepeatedAttribute(); i++) { list.add(getRowInstance(rowEle, i)); } } } return list; } /** * Get the column at the specified index. The table will be automatically * expanded, when the given index is outside of the original table. * * @param index * the zero-based index of the column. * @return the column at the specified index */ public OdfTableColumn getColumnByIndex(int index) { if (index < 0) { throw new IllegalArgumentException( "index should be nonnegative integer."); } // expand column as needed. int lastIndex = getColumnCount() - 1; if (index > lastIndex) { appendColumns(index - lastIndex); } int result = 0; OdfTableColumn col = null; // TableTableColumnElement colEle=null; for (Node n : new DomNodeList(mTableElement.getChildNodes())) { if (n instanceof TableTableHeaderColumnsElement) { col = getHeaderColumnByIndex( (TableTableHeaderColumnsElement) n, index); if (col != null) { return col; } result += getHeaderColumnCount((TableTableHeaderColumnsElement) n); } if (n instanceof TableTableColumnElement) { col = getColumnInstance((TableTableColumnElement) n, 0); result += col.getColumnsRepeatedNumber(); } if ((result > index) && (col != null)) { return getColumnInstance(col.getOdfElement(), index - (result - col.getColumnsRepeatedNumber())); } } return null; } private OdfTableRow getHeaderRowByIndex(TableTableHeaderRowsElement headers, int nIndex) { int result = 0; OdfTableRow row = null; for (Node n : new DomNodeList(headers.getChildNodes())) { if (n instanceof TableTableRowElement) { row = getRowInstance((TableTableRowElement) n, 0); result += row.getRowsRepeatedNumber(); } if ((result > nIndex) && (row != null)) { return getRowInstance(row.getOdfElement(), nIndex - (result - row.getRowsRepeatedNumber())); } } return null; } private OdfTableColumn getHeaderColumnByIndex(TableTableHeaderColumnsElement headers, int nIndex) { int result = 0; OdfTableColumn col = null; for (Node n : new DomNodeList(headers.getChildNodes())) { if (n instanceof TableTableColumnElement) { col = getColumnInstance((TableTableColumnElement) n, 0); result += col.getColumnsRepeatedNumber(); } if (result > nIndex) { return getColumnInstance(col.getOdfElement(), nIndex - (result - col.getColumnsRepeatedNumber())); } } return null; } /** * Get the row at the specified index. The table will be automatically * expanded, when the given index is outside of the original table. * * @param index * the zero-based index of the row. * @return the row at the specified index */ public OdfTableRow getRowByIndex(int index) { if (index < 0) { throw new IllegalArgumentException( "index should be nonnegative integer."); } // expand row as needed. int lastIndex = getRowCount() - 1; if (index > lastIndex) { appendRows(index - lastIndex); } int result = 0; OdfTableRow row = null; for (Node n : new DomNodeList(mTableElement.getChildNodes())) { if (n instanceof TableTableHeaderRowsElement) { row = getHeaderRowByIndex((TableTableHeaderRowsElement) n, index); if (row != null) { return row; } result += getHeaderRowCount((TableTableHeaderRowsElement) n); } if (n instanceof TableTableRowElement) { row = getRowInstance((TableTableRowElement) n, 0); result += row.getRowsRepeatedNumber(); } if (result > index) { return getRowInstance(row.getOdfElement(), index - (result - row.getRowsRepeatedNumber())); } } return null; } /** * Remove the specific number of rows, starting from the row at index. * * @param startIndex is the zero-based index of the first row to delete. * @param deleteRowCount is the number of rows to delete. */ public void removeRowsByIndex(int startIndex, int deleteRowCount) { boolean deleted = false; //0. verify the index if(deleteRowCount <= 0) { return; } if(startIndex < 0) { throw new IllegalArgumentException("startIndex of the deleted rows should not be negative"); } int rowCount = getRowCount(); if (startIndex >= rowCount) { throw new IndexOutOfBoundsException("Start index out of bound"); } if (startIndex + deleteRowCount >= rowCount) { deleteRowCount = rowCount - startIndex; } //1. remove row OdfTableRow firstRow = getRowByIndex(startIndex); for (int i = startIndex; i < startIndex + deleteRowCount; i++) { int repeatedAttr = firstRow.getRowsRepeatedNumber(); if (repeatedAttr == 1) { TableTableRowElement rowEle = OdfElement.findNextChildNode(TableTableRowElement.class, firstRow.getOdfElement()); firstRow.removeAllCellsRelationship(); firstRow.getOdfElement().getParentNode().removeChild(firstRow.getOdfElement()); updateRowRepository(firstRow.getOdfElement(), firstRow.mnRepeatedIndex, null, 0); if (i < (startIndex + deleteRowCount - 1)) { firstRow = this.getRowInstance(rowEle, 0); } deleted = true; } else { if (repeatedAttr > firstRow.mnRepeatedIndex) { firstRow.setRowsRepeatedNumber(repeatedAttr - 1); OdfTableRow startRow = this.getRowInstance(firstRow.getOdfElement(), 0); updateRowRepository(firstRow.getOdfElement(), i - startRow.getRowIndex(), null, 0); } } } //2. if mediumRow becomes as top row, revise style if (deleted && startIndex == 0) { OdfTableRow aRow = getRowByIndex(0); reviseStyleFromMediumRowToTopRow(aRow); } } /** * Remove this table from the document */ public void remove() { mTableElement.getParentNode().removeChild(mTableElement); } private int getHeaderRowCount(TableTableHeaderRowsElement headers) { int result = 0; if (headers != null) { for (Node n : new DomNodeList(headers.getChildNodes())) { if (n instanceof TableTableRowElement) { result += ((TableTableRowElement) n).getTableNumberRowsRepeatedAttribute(); } } } return result; } /** * Return the number of header rows in this table. * * @return the number of header rows. */ public int getHeaderRowCount() { TableTableHeaderRowsElement headers = OdfElement.findFirstChildNode(TableTableHeaderRowsElement.class, mTableElement); return getHeaderRowCount(headers); } private int getHeaderColumnCount(TableTableHeaderColumnsElement headers) { int result = 0; if (headers != null) { for (Node n : new DomNodeList(headers.getChildNodes())) { if (n instanceof TableTableColumnElement) { result += getColumnInstance(((TableTableColumnElement) n), 0).getColumnsRepeatedNumber(); } } } return result; } /** * Return the number of header columns in the table. * * @return the number of header columns. */ public int getHeaderColumnCount() { TableTableHeaderColumnsElement headers = OdfElement.findFirstChildNode(TableTableHeaderColumnsElement.class, mTableElement); return getHeaderColumnCount(headers); } /** * Return the table name. * * @return the table name */ public String getTableName() { return mTableElement.getTableNameAttribute(); } /** * Set the table name. * * @param tableName the table name * @throws IllegalArgumentException if the tableName is duplicate with one of tables in the current document */ public void setTableName(String tableName) { //check if the table name is already exist List tableList = mDocument.getTableList(); for(int i=0;i * The default setting is inherited. In this condition, the style of new * column is same with the previous column before the inserted position, * while the style of new row is same with the last row before the inserted * position. *

* This feature setting will influence appendRow(), * appendColumn(), appendRows(), * appendColumns(), insertRowsBefore() and * insertColumnsBefore(). *

* For getCellByPosition(), * getCellRangeByPosition(), getCellRangeByName(), * getRowByIndex() and getColumnByIndex(), if need * automatically expand cells, it will return empty cell(s) without any * style settings. So inheritance setting have no effect on them. * * @return true if cell style is inherited when a new cell is added to the * table. * * @see #setCellStyleInheritance(boolean) * @see #appendColumn() * @see #appendColumns(int) * @see #appendRow() * @see #appendRows(int) * @see #insertColumnsBefore(int, int) * @see #insertRowsBefore(int, int) * @see #getCellByPosition(int, int) * @see #getCellByPosition(String) * @see #getCellRangeByPosition(int, int, int, int) * @see #getCellRangeByPosition(String, String) * @see #getCellRangeByName(String) * @see #getColumnByIndex(int) * @see #getRowByIndex(int) */ protected boolean isCellStyleInheritance() { return mIsCellStyleInheritance; } /** * This method allows users to set whether cell style is inherited or not * when a new cell is added to the table. Of course, the default setting is * inherited. In this condition, the style of new column is same with the * previous column before the inserted position, while the style of new row * is same with the last row before the inserted position. *

* This feature setting will influence appendRow(), * appendColumn(), appendRows(), * appendColumns(), insertRowsBefore() and * insertColumnsBefore(). *

* For getCellByPosition(), * getCellRangeByPosition(), getCellRangeByName(), * getRowByIndex() and getColumnByIndex(), if need * automatically expand cells, it will return empty cell(s) without any * style settings. So inheritance setting have no effect on them. * * @param isEnabled * ifisEnabled is true, cell style will be inherited * by new cell. * * @see #isCellStyleInheritance() * @see #appendColumn() * @see #appendColumns(int) * @see #appendRow() * @see #appendRows(int) * @see #insertColumnsBefore(int, int) * @see #insertRowsBefore(int, int) * @see #getCellByPosition(int, int) * @see #getCellByPosition(String) * @see #getCellRangeByPosition(int, int, int, int) * @see #getCellRangeByPosition(String, String) * @see #getCellRangeByName(String) * @see #getColumnByIndex(int) * @see #getRowByIndex(int) */ protected void setCellStyleInheritance(boolean isEnabled) { mIsCellStyleInheritance=isEnabled; } //////////////////////////////////////////////////////////////////////////////////////////// /** * Return a range of cells within the specified range. The table will be * automatically expanded as need. * * @param startCol * the column index of the first cell inside the range. * @param startRow * the row index of the first cell inside the range. * @param endCol * the column index of the last cell inside the range. * @param endRow * the row index of the last cell inside the range. * @return the specified cell range. */ public OdfTableCellRange getCellRangeByPosition(int startCol, int startRow, int endCol, int endRow) { // test whether cell position is out of table range and expand table // automatically. getCellByPosition(startCol, startRow); getCellByPosition(endCol, endRow); return new OdfTableCellRange(this, startCol, startRow, endCol, endRow); } /** * Return a range of cells within the specified range. The range is * specified by the cell address of the first cell and the cell address of * the last cell. The table will be automatically expanded as need. *

* The cell address is constructed with a table name, a dot (.), an * alphabetic value representing the column, and a numeric value * representing the row. The table name can be omitted. For example: * "$Sheet1.A1", "Sheet1.A1" and "A1" are all valid cell address. * * @param startAddress * the cell address of the first cell inside the range. * @param endAddress * the cell address of the last cell inside the range. * @return the specified cell range. */ public OdfTableCellRange getCellRangeByPosition(String startAddress, String endAddress) { return getCellRangeByPosition(getColIndexFromCellAddress(startAddress), getRowIndexFromCellAddress(startAddress), getColIndexFromCellAddress(endAddress), getRowIndexFromCellAddress(endAddress)); } /** * Return a range of cells by a specified name. *

* After you get a cell range with getCellRangeByPosition, * you can assign a name to this cell range with the method setCellRangeName in class OdfTableCellRange. * Then you will get a named range which can be represented by name. * This method can be used to get a named range. * * @param name the name of the specified named range * @return the specified cell range. */ public OdfTableCellRange getCellRangeByName(String name) { NodeList nameRanges; try { nameRanges = mTableElement.getOwnerDocument().getElementsByTagNameNS(OdfDocumentNamespace.TABLE.getUri(), "named-range"); for (int i = 0; i < nameRanges.getLength(); i++) { TableNamedRangeElement nameRange = (TableNamedRangeElement) nameRanges.item(i); if (nameRange.getTableNameAttribute().equals(name)) { String cellRange = nameRange.getTableCellRangeAddressAttribute(); String[] addresses = cellRange.split(":"); return getCellRangeByPosition(addresses[0], addresses[1]); } } } catch (Exception e) { Logger.getLogger(OdfTable.class.getName()).log(Level.SEVERE, e.getMessage(), e); } return null; } /** * Return a single cell that is positioned at the specified column and row. * The table will be automatically expanded as need. * * @param colIndex the column index of the cell. * @param rowIndex the row index of the cell. * @return the cell at the specified position */ public OdfTableCell getCellByPosition(int colIndex, int rowIndex) { if (colIndex < 0 || rowIndex < 0) { throw new IllegalArgumentException( "colIndex and rowIndex should be nonnegative integer."); } // expand row as needed. int lastRowIndex = getRowCount() - 1; if (rowIndex > lastRowIndex) { //need clean cell style. appendRows((rowIndex - lastRowIndex), true); } // expand column as needed. int lastColumnIndex = getColumnCount() - 1; if (colIndex > lastColumnIndex) { //need clean cell style. appendColumns((colIndex - lastColumnIndex), true); } OdfTableRow row = getRowByIndex(rowIndex); return row.getCellByIndex(colIndex); } //return array of string contain 3 member //1. sheet table name //2. alphabetic represent the column //3. string represent the row number String[] splitCellAddress(String cellAddress) { String[] returnArray = new String[3]; //seperate column and row from cell range StringTokenizer stDot = new StringTokenizer(cellAddress, "."); //get sheet table name and the cell address String cell = ""; if (stDot.countTokens() >= 2) { StringTokenizer stDollar = new StringTokenizer(stDot.nextToken(), "$"); returnArray[0] = stDollar.nextToken(); cell = stDot.nextToken(); } else { returnArray[0] = getTableName(); cell = stDot.nextToken(); } //get the column/row number from the cell address StringTokenizer stDollar = new StringTokenizer(cell, "$"); if (stDollar.countTokens() >= 2) { returnArray[1] = stDollar.nextToken(); returnArray[2] = stDollar.nextToken(); } else { cell = stDollar.nextToken(); for (int i = 0; i < cell.length(); i++) { if (!Character.isLetter(cell.charAt(i))) { returnArray[1] = cell.substring(0, i); returnArray[2] = cell.substring(i); break; } } } return returnArray; } /** * Return a single cell that is positioned at the specified cell address. * The table can be automatically expanded as need. *

* The cell address is constructed with a table name, a dot (.), * an alphabetic value representing the column, and a numeric value representing the row. * The table name can be omitted. For example: "$Sheet1.A1", "Sheet1.A1" and "A1" are all * valid cell address. * * @param address the cell address of the cell. * @return the cell at the specified position. */ public OdfTableCell getCellByPosition(String address) { return getCellByPosition(getColIndexFromCellAddress(address), getRowIndexFromCellAddress(address)); } //TODO: can put these two method to type.CellAddress int getColIndexFromCellAddress(String cellAddress) { String[] returnArray = splitCellAddress(cellAddress); String colNum = returnArray[1]; int colIndex = 0; for (int i = 0; i < colNum.length(); i++) { colIndex = 26 * colIndex; colIndex += (colNum.charAt(i) - 'A') + 1; } return (colIndex - 1); } int getRowIndexFromCellAddress(String cellAddress) { String[] returnArray = splitCellAddress(cellAddress); return Integer.parseInt(returnArray[2]) - 1; } String getAbsoluteCellAddress(int colIndex, int rowIndex) { int remainder = 0; int multiple = colIndex; String cellRange = ""; while (multiple != 0) { multiple = colIndex / 26; remainder = colIndex % 26; char c; if (multiple == 0) { c = (char) ('A' + remainder); } else { c = (char) ('A' + multiple - 1); } cellRange = cellRange + String.valueOf(c); colIndex = remainder; } cellRange = "$" + cellRange + "$" + (rowIndex + 1); return cellRange; } //the parameter is the column/row index in the ownerTable,rather than in the cell range //if the position is a covered cell, then get the owner cell for it OdfTableCell getOwnerCellByPosition(List coverList, int nCol, int nRow) { CellCoverInfo info; if (!isCoveredCellInOwnerTable(coverList, nCol, nRow)) { OdfTableCell cell = getCellByPosition(nCol, nRow); return cell; } else { for (int m = 0; m < coverList.size(); m++) { info = coverList.get(m); if (((nCol > info.nStartCol) && (nCol <= info.nEndCol) && (nRow == info.nStartRow) && (nRow == info.nEndRow)) || ((nCol == info.nStartCol) && (nCol == info.nEndCol) && (nRow > info.nStartRow) && (nRow <= info.nEndRow)) || ((nCol > info.nStartCol) && (nCol <= info.nEndCol) && (nRow > info.nStartRow) && (nRow <= info.nEndRow))) { OdfTableCell cell = getCellByPosition(info.nStartCol, info.nStartRow); return cell; } } } return null; } //the parameter is the column/row index in the ownerTable,rather than in the cell range boolean isCoveredCellInOwnerTable(List coverList, int nCol, int nRow) { CellCoverInfo info; for (int m = 0; m < coverList.size(); m++) { info = coverList.get(m); if (((nCol > info.nStartCol) && (nCol <= info.nEndCol) && (nRow == info.nStartRow) && (nRow == info.nEndRow)) || ((nCol == info.nStartCol) && (nCol == info.nEndCol) && (nRow > info.nStartRow) && (nRow <= info.nEndRow)) || ((nCol > info.nStartCol) && (nCol <= info.nEndCol) && (nRow > info.nStartRow) && (nRow <= info.nEndRow))) //covered cell { return true; } } return false; } List getCellCoverInfos(int nStartCol, int nStartRow, int nEndCol, int nEndRow) { List coverList = new ArrayList(); int nColSpan, nRowSpan; for (int i = nStartCol; i < nEndCol + 1; i++) { for (int j = nStartRow; j < nEndRow + 1; j++) { OdfTableCell cell = getCellByPosition(i, j); if (cell != null) { nColSpan = cell.getColumnSpannedNumber(); nRowSpan = cell.getRowSpannedNumber(); if ((nColSpan > 1) || (nRowSpan > 1)) { coverList.add(new CellCoverInfo(i, j, nColSpan, nRowSpan)); } } } } return coverList; } //the odfelement of the FTableColumn changed, so we should update the repository here void updateColumnRepository(TableTableColumnElement oldElement, int oldRepeatIndex, TableTableColumnElement newElement, int newRepeatIndex) { if (mColumnRepository.containsKey(oldElement)) { Vector oldList = mColumnRepository.get(oldElement); if (oldRepeatIndex < oldList.size()) { if (oldElement != newElement) { //the new column replace the old column OdfTableColumn oldColumn = oldList.get(oldRepeatIndex); if (oldColumn != null) { //update the mnRepeateIndex of the column which locate after the removed column for (int i = oldRepeatIndex + 1; i < oldList.size(); i++) { OdfTableColumn column = oldList.get(i); if (column != null) { column.mnRepeatedIndex = i - 1; } } oldList.remove(oldColumn); //oldList.add(oldRepeatIndex, null); if (newElement != null) { oldColumn.maColumnElement = newElement; oldColumn.mnRepeatedIndex = newRepeatIndex; int size = (newRepeatIndex > 7) ? (newRepeatIndex + 1) : 8; Vector list = new Vector(size); list.setSize(newRepeatIndex + 1); list.set(newRepeatIndex, oldColumn); mColumnRepository.put(newElement, list); } else { oldColumn.maColumnElement = null; } } } else { //the new column element is equal to the old column element, just change the repeatIndex OdfTableColumn oldColumn = oldList.get(oldRepeatIndex); if (oldColumn != null) { oldList.remove(oldColumn); oldList.add(oldRepeatIndex, null); oldColumn.mnRepeatedIndex = newRepeatIndex; if (newRepeatIndex >= oldList.size()) { oldList.setSize(newRepeatIndex + 1); } oldList.set(newRepeatIndex, oldColumn); } else { getColumnInstance(newElement, newRepeatIndex); } } } } } //the odfelement of the FTableRow changed, so we should update the repository here void updateRowRepository(TableTableRowElement oldElement, int oldRepeatIndex, TableTableRowElement newElement, int newRepeatIndex) { if (mRowRepository.containsKey(oldElement)) { Vector oldList = mRowRepository.get(oldElement); if (oldRepeatIndex < oldList.size()) { if (oldElement != newElement) { //the new row replace the old row OdfTableRow oldRow = oldList.get(oldRepeatIndex); Vector updateCellList = new Vector(); if (oldRow != null) { //update the mnRepeateIndex of the row which locate after the removed row for (int i = oldRepeatIndex + 1; i < oldList.size(); i++) { OdfTableRow row = oldList.get(i); if (row != null) { //update the cell in this row, int colNum = getColumnCount(); for (int j = 0; j < colNum; j++) { OdfTableCell cell = row.getCellByIndex(j); updateCellList.add(cell); } row.mnRepeatedIndex = i - 1; } } oldList.remove(oldRow); if (newElement != null) { //update the cell in this row int colNum = getColumnCount(); OdfTableCell[] oldCells = new OdfTableCell[colNum]; for (int j = 0; j < colNum; j++) { oldCells[j] = oldRow.getCellByIndex(j); } /// oldRow.maRowElement = newElement; oldRow.mnRepeatedIndex = newRepeatIndex; int size = (newRepeatIndex > 7) ? (newRepeatIndex + 1) : 8; Vector list = new Vector(size); list.setSize(newRepeatIndex + 1); list.set(newRepeatIndex, oldRow); mRowRepository.put(newElement, list); //update the cell in this row OdfTableCell[] newCells = new OdfTableCell[colNum]; for (int j = 0; j < colNum; j++) { newCells[j] = oldRow.getCellByIndex(j); } for (int j = 0; j < colNum; j++) { this.updateCellRepository(oldCells[j].getOdfElement(), oldCells[j].mnRepeatedColIndex, oldCells[j].mnRepeatedRowIndex, newCells[j].getOdfElement(), newCells[j].mnRepeatedColIndex, newCells[j].mnRepeatedRowIndex); } //update the mnRepeatedRowIndex of the cell which locate after the removed row for (int j = 0; j < updateCellList.size(); j++) { OdfTableCell cell = updateCellList.get(j); if (cell.mnRepeatedRowIndex > oldRepeatIndex) { cell.mnRepeatedRowIndex--; } } } else { oldRow.maRowElement = null; } } } else { //the new row element is equal to the old row element, just change the repeatIndex OdfTableRow oldRow = oldList.get(oldRepeatIndex); if (oldRow != null) { oldList.remove(oldRow); oldList.add(oldRepeatIndex, null); oldRow.mnRepeatedIndex = newRepeatIndex; if (newRepeatIndex >= oldList.size()) { oldList.setSize(newRepeatIndex + 1); } oldList.set(newRepeatIndex, oldRow); } else { getRowInstance(newElement, newRepeatIndex); } } } } } //the odfelement of the FTableCell changed, so we should update the repository here void updateCellRepository(TableTableCellElementBase oldElement, int oldRepeatColIndex, int oldRepeatRowIndex, TableTableCellElementBase newElement, int newRepeatColIndex, int newRepeatRowIndex) { if (mCellRepository.containsKey(oldElement)) { OdfTableCell oldCell = null; Vector oldList = mCellRepository.get(oldElement); for (int i = 0; i < oldList.size(); i++) { if (oldList.get(i).getOdfElement() == oldElement && oldList.get(i).mnRepeatedColIndex == oldRepeatColIndex && oldList.get(i).mnRepeatedRowIndex == oldRepeatRowIndex) { oldCell = oldList.get(i); break; } } if (oldElement != newElement) { //the new cell replace the old cell if (oldCell != null) { //update the mnRepeateRowIndex & mnRepeateColIndex of the cell which locate after the removed cell for (int i = 0; i < oldList.size(); i++) { OdfTableCell cell = oldList.get(i); if (cell != null && (cell.getOdfElement() == oldElement)) { if ((cell.mnRepeatedRowIndex == oldRepeatRowIndex) && (cell.mnRepeatedColIndex > oldRepeatColIndex)) { cell.mnRepeatedColIndex--; } } } oldList.remove(oldCell); if (oldList.size() == 0) { mCellRepository.remove(oldElement); } if (newElement != null) { oldCell.mCellElement = newElement; oldCell.mnRepeatedColIndex = newRepeatColIndex; oldCell.mnRepeatedRowIndex = newRepeatRowIndex; Vector list; if (mCellRepository.containsKey(newElement)) { list = mCellRepository.get(newElement); boolean bReplaced = false; for (int i = 0; i < list.size(); i++) { OdfTableCell cell = list.get(i); if (cell != null && (cell.getOdfElement() == newElement)) { if ((cell.mnRepeatedColIndex == newRepeatColIndex) && (cell.mnRepeatedRowIndex == newRepeatRowIndex)) { list.remove(i); list.add(i, oldCell); bReplaced = true; break; } } } if (!bReplaced) { list.add(oldCell); } } else { list = new Vector(); list.add(oldCell); mCellRepository.put(newElement, list); } } else { oldCell.mCellElement = null; oldCell.mnRepeatedColIndex = 0; oldCell.mnRepeatedRowIndex = 0; } } } else { //the new cell element is equal to the old cell element, just change the repeatIndex if (oldCell != null) { oldCell.mnRepeatedColIndex = newRepeatColIndex; oldCell.mnRepeatedRowIndex = newRepeatRowIndex; } else { getCellInstance(newElement, newRepeatColIndex, newRepeatRowIndex); } } } } void updateRepositoryWhenCellElementChanged(int startRow, int endRow, int startClm, int endClm, TableTableCellElement newCellEle) { for (int i = startRow; i < endRow; i++) { for (int j = startClm; j < endClm; j++) { OdfTableCell cell = getCellByPosition(j, i); updateCellRepository(cell.getOdfElement(), cell.mnRepeatedColIndex, cell.mnRepeatedRowIndex, newCellEle, cell.mnRepeatedColIndex, cell.mnRepeatedRowIndex); } } } } /** * Record the Cell Cover Info in this cell range. *

* Sometimes the covered cell is not tagged as element. * */ class CellCoverInfo { int nStartCol; int nStartRow; int nEndCol; int nEndRow; CellCoverInfo(int nSC, int nSR, int nColumnSpan, int nRowSpan) { nStartCol = nSC; nStartRow = nSR; nEndCol = nSC + nColumnSpan - 1; nEndRow = nSR + nRowSpan - 1; } }