org.odftoolkit.odfdom.doc.table.OdfTable Maven / Gradle / Ivy
/************************************************************************
*
* 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;
}
}