org.odftoolkit.odfdom.doc.table.OdfTableRow 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.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
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.dom.OdfContentDom;
import org.odftoolkit.odfdom.dom.OdfDocumentNamespace;
import org.odftoolkit.odfdom.dom.element.table.TableCoveredTableCellElement;
import org.odftoolkit.odfdom.dom.element.table.TableTableCellElement;
import org.odftoolkit.odfdom.dom.element.table.TableTableCellElementBase;
import org.odftoolkit.odfdom.dom.element.table.TableTableElement;
import org.odftoolkit.odfdom.dom.element.table.TableTableHeaderRowsElement;
import org.odftoolkit.odfdom.dom.element.table.TableTableRowElement;
import org.odftoolkit.odfdom.dom.element.table.TableTableRowGroupElement;
import org.odftoolkit.odfdom.dom.element.table.TableTableRowsElement;
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.OdfTableRowProperties;
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.Node;
/**
* OdfTableRow represents table row feature in ODF document.
*
* OdfTableRow provides methods to get table cells that belong to this table row.
*/
public class OdfTableRow {
//boolean mbVisible;
TableTableRowElement maRowElement;
int mnRepeatedIndex;
int mRowsRepeatedNumber = -1;
private static final String DEFAULT_HEIGHT = "0.30in";
private OdfDocument mDocument;
/**
* Construct the OdfTableRow
feature.
* @param rowElement the row element represent this row
* @param repeatedIndex the index in the repeated rows
*/
OdfTableRow(TableTableRowElement rowElement, int repeatedIndex) {
maRowElement = rowElement;
mnRepeatedIndex = repeatedIndex;
mDocument = (OdfDocument) ((OdfFileDom) maRowElement.getOwnerDocument()).getDocument();
}
/**
* Get the OdfTableRow
instance from the TableTableRowElement
instance.
*
* Each TableTableRowElement
instance has a one-to-one relationship to a OdfTableRow
instance.
*
* @param rowElement the row element that need to get the corresponding OdfTableRow
instance
* @return the OdfTableRow
instance represent the specified row element
*/
public static OdfTableRow getInstance(TableTableRowElement rowElement) {
TableTableElement tableElement = null;
Node node = rowElement.getParentNode();
while (node != null) {
if (node instanceof TableTableElement) {
tableElement = (TableTableElement) node;
}
node = node.getParentNode();
}
OdfTable table = null;
if (tableElement != null) {
table = OdfTable.getInstance(tableElement);
} else {
throw new IllegalArgumentException("the rowElement is not in the table dom tree");
}
OdfTableRow row = table.getRowInstance(rowElement, 0);
if (row.getRowsRepeatedNumber() > 1) {
Logger.getLogger(OdfTableRow.class.getName()).log(Level.WARNING, "the row has the repeated row number, and puzzled about get which repeated index of the row,"
+ "here just return the first row of the repeated rows.");
}
return row;
}
/**
* Get the TableTableElement
who contains this row.
*
* @return the table element that contains the row.
*/
private TableTableElement getTableElement() {
Node node = maRowElement.getParentNode();
while (node != null) {
if (node instanceof TableTableElement) {
return (TableTableElement) node;
}
node = node.getParentNode();
}
return null;
}
/**
* Get owner table of the current row.
* @return the parent table of this row
*/
public OdfTable getTable() {
TableTableElement tableElement = getTableElement();
if (tableElement != null) {
return OdfTable.getInstance(tableElement);
}
return null;
}
/**
* Return the height of the row (in Millimeter).
*
* Return the minimal height, if the row height is not set,
* @return the height of the current row (in Millimeter).
*/
public long getHeight() {
String sHeight = maRowElement.getProperty(OdfTableRowProperties.RowHeight);
if (sHeight == null) {
sHeight = maRowElement.getProperty(OdfTableRowProperties.MinRowHeight);
}
if (sHeight == null) {
sHeight = DEFAULT_HEIGHT;
}
return PositiveLength.parseLong(sHeight, Unit.MILLIMETER);
}
/**
* Set the height/minimal height of the row (in Millimeter) according to the second parameter.
* @param height
* the height/minimal height that will be set to the row (in Millimeter).
* @param isMinHeight
* if it is true, the row can fit the height to the text, vice versa.
*/
public void setHeight(long height, boolean isMinHeight) {
String sHeightMM = String.valueOf(height) + Unit.MILLIMETER.abbr();
String sHeightIN = PositiveLength.mapToUnit(sHeightMM, Unit.INCH);
splitRepeatedRows();
maRowElement.removeAttributeNS(OdfDocumentNamespace.TABLE.getUri(), "style-name");
maRowElement.setProperty(OdfTableRowProperties.RowHeight, sHeightIN);
}
//if one of the repeated row want to change something
//then this repeated row have to split to repeated number rows
//the maRowElement/mnRepeatedIndex should also be updated according to the original index in the repeated column
void splitRepeatedRows() {
int repeateNum = getRowsRepeatedNumber();
if (repeateNum > 1) {
OdfTable table = getTable();
TableTableElement tableEle = table.getOdfElement();
//change this repeated row to several single rows
TableTableRowElement ownerRowElement = null;
int repeatedRowIndex = mnRepeatedIndex;
Node refElement = maRowElement;
Node oldRowElement = maRowElement;
for (int i = repeateNum - 1; i >= 0; i--) {
TableTableRowElement newRow = (TableTableRowElement) maRowElement.cloneNode(true);
newRow.removeAttributeNS(OdfDocumentNamespace.TABLE.getUri(), "number-rows-repeated");
tableEle.insertBefore(newRow, refElement);
refElement = newRow;
if (repeatedRowIndex == i) {
ownerRowElement = newRow;
} else {
table.updateRowRepository(maRowElement, i, newRow, 0);
}
}
if (ownerRowElement != null) {
table.updateRowRepository(maRowElement, mnRepeatedIndex, ownerRowElement, 0);
}
tableEle.removeChild(oldRowElement);
mRowsRepeatedNumber = -1;
}
}
/**
* Return if the row always keeps its optimal height.
* @return
* true if the row always keeps its optimal height;
* vice versa
*/
public boolean isOptimalHeight() {
return Boolean.parseBoolean(maRowElement.getProperty(OdfTableRowProperties.UseOptimalRowHeight));
}
/**
* Set if the row always keeps its optimal height.
* @param isUseOptimalHeight
* the flag that indicate row should keep its optimal height or not
*/
public void setUseOptimalHeight(boolean isUseOptimalHeight) {
maRowElement.setProperty(OdfTableRowProperties.UseOptimalRowHeight, String.valueOf(isUseOptimalHeight));
}
/**
* Return an instance of TableTableRowElement
which represents this feature.
* @return an instance of TableTableRowElement
*/
public TableTableRowElement getOdfElement() {
return maRowElement;
}
/**
* Get a cell with a specific index. The table will be automatically
* expanded, when the given index is outside of the original table.
*
* @param index
* the cell index in this row
* @return the cell object in the given cell index
*/
public OdfTableCell getCellByIndex(int index) {
OdfTable table = getTable();
if (index < 0) {
throw new IllegalArgumentException("index should be nonnegative integer.");
}
// expand column as needed.
int lastColumnIndex = table.getColumnCount() - 1;
if (index > lastColumnIndex) {
//need clean cell style.
table.appendColumns((index - lastColumnIndex), true);
}
for (Node n : new DomNodeList(maRowElement.getChildNodes())) {
if (n instanceof TableTableCellElementBase) {
if (index == 0) {
return table.getCellInstance((TableTableCellElementBase) n,
0, mnRepeatedIndex);
} else {
int nextIndex = index
- ((TableTableCellElementBase) n).getTableNumberColumnsRepeatedAttribute().intValue();
if (nextIndex < 0) {
OdfTableCell cell = table.getCellInstance(
(TableTableCellElementBase) n, index,
mnRepeatedIndex);
return cell;
} else {
index = nextIndex;
}
}
}
}
return null;
}
/**
* Return the count of real cells in this row.
* The cells covered by top cells are not counted.
*
* Please note it might not equal to the column count of the owner table,
* because some of them are the covered cells.
* @return the cell count
*/
public int getCellCount() {
OdfTable table = getTable();
Set realCells = new HashSet();
List coverList = table.getCellCoverInfos(0, 0, table.getColumnCount() - 1, table.getRowCount() - 1);
int rowIndex = getRowIndex();
for (int i = 0; i < table.getColumnCount(); i++) {
OdfTableCell cell = table.getOwnerCellByPosition(coverList, i, rowIndex);
realCells.add(cell);
}
return realCells.size();
}
/**
* Return the previous row of the current row.
*
* @return the previous row before this row in the owner table
*/
public OdfTableRow getPreviousRow() {
OdfTable table = getTable();
//the row has repeated row number > 1
if (getRowsRepeatedNumber() > 1) {
if (mnRepeatedIndex > 0) {
return table.getRowInstance(maRowElement, mnRepeatedIndex - 1);
}
}
//the row has repeated row number > 1 && the index is 0
//or the row has repeated row num = 1
Node aPrevNode = maRowElement.getPreviousSibling();
Node aCurNode = maRowElement;
TableTableRowElement lastRow;
while (true) {
if (aPrevNode == null) {
//does not have previous sibling, then get the parent
//because aCurNode might be the child element of table-header-rows, table-rows, table-row-group
Node parentNode = aCurNode.getParentNode();
//if the parent is table, then it means that this row is the first row in this table
//it has no previous row
if (parentNode instanceof TableTableElement) {
return null;
}
aPrevNode = parentNode.getPreviousSibling();
}
//else the previous node might be table-header-rows, table-rows, table-row-group
if (aPrevNode != null) {
try {
if (aPrevNode instanceof TableTableRowElement) {
return table.getRowInstance((TableTableRowElement) aPrevNode,
((TableTableRowElement) aPrevNode).getTableNumberRowsRepeatedAttribute().intValue() - 1);
} else if (aPrevNode instanceof TableTableRowsElement
|| aPrevNode instanceof TableTableHeaderRowsElement
|| aPrevNode instanceof TableTableRowGroupElement) {
XPath xpath = ((OdfContentDom) aPrevNode.getOwnerDocument()).getXPath();
synchronized (mDocument) {
lastRow = (TableTableRowElement) xpath.evaluate(".//table:table-row[last()]", aPrevNode, XPathConstants.NODE);
}
if (lastRow != null) {
return table.getRowInstance(lastRow, lastRow.getTableNumberRowsRepeatedAttribute().intValue() - 1);
}
} else {
aCurNode = aPrevNode;
aPrevNode = aPrevNode.getPreviousSibling();
}
} catch (XPathExpressionException e) {
Logger.getLogger(OdfTableRow.class.getName()).log(Level.SEVERE, e.getMessage(), e);
}
}
}
}
/**
* Return the next row of the current row.
*
* @return the next row after this row in the owner table
*/
public OdfTableRow getNextRow() {
OdfTable table = getTable();
//the row has repeated row number > 1
if (getRowsRepeatedNumber() > 1) {
if (mnRepeatedIndex < (getRowsRepeatedNumber() - 1)) {
return table.getRowInstance(maRowElement, mnRepeatedIndex + 1);
}
}
Node aNextNode = maRowElement.getNextSibling();
Node aCurNode = maRowElement;
TableTableRowElement firstRow;
while (true) {
if (aNextNode == null) {
//does not have next sibling, then get the parent
//because aCurNode might be the child element of table-header-rows, table-rows, table-row-group
Node parentNode = aCurNode.getParentNode();
//if the parent is table, then it means that this row is the last row in this table
//it has no next row
if (parentNode instanceof TableTableElement) {
return null;
}
aNextNode = parentNode.getNextSibling();
}
//else the next node might be table-header-rows, table-rows, table-row-group
if (aNextNode != null) {
try {
if (aNextNode instanceof TableTableRowElement) {
return table.getRowInstance((TableTableRowElement) aNextNode, 0);
} else if (aNextNode instanceof TableTableRowsElement
|| aNextNode instanceof TableTableHeaderRowsElement
|| aNextNode instanceof TableTableRowGroupElement) {
XPath xpath = ((OdfContentDom) aNextNode.getOwnerDocument()).getXPath();
synchronized (mDocument) {
firstRow = (TableTableRowElement) xpath.evaluate(".//table:table-row[first()]", aNextNode, XPathConstants.NODE);
}
if (firstRow != null) {
return table.getRowInstance(firstRow, 0);
}
} else {
aCurNode = aNextNode;
aNextNode = aNextNode.getNextSibling();
}
} catch (XPathExpressionException e) {
Logger.getLogger(OdfTableRow.class.getName()).log(Level.SEVERE, e.getMessage(), e);
}
}
}
}
/**
* Set the default cell style to this row.
*
* The style should already exist in this document.
* @param style
* the cell style of the document
*/
public void setDefaultCellStyle(OdfStyle style) {
splitRepeatedRows();
OdfStyle defaultStyle = getDefaultCellStyle();
if (defaultStyle != null) {
defaultStyle.removeStyleUser(maRowElement);
}
if (style != null) {
style.addStyleUser(maRowElement);
maRowElement.setTableDefaultCellStyleNameAttribute(
style.getStyleNameAttribute());
}
}
/**
* Get the default cell style of this row.
*
* @return the default cell style of this row
*/
public OdfStyle getDefaultCellStyle() {
String styleName = maRowElement.getTableDefaultCellStyleNameAttribute();
OdfStyle style = maRowElement.getAutomaticStyles().getStyle(
styleName, OdfStyleFamily.TableCell);
if (style == null) {
style = mDocument.getDocumentStyles().getStyle(styleName, OdfStyleFamily.TableCell);
}
return style;
}
/**
* Return the index of this row in the owner table.
*
* @return the index of the row
*/
public int getRowIndex() {
int result = 0;
TableTableElement mTableElement = getTableElement();
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;
if (rowEle == getOdfElement()) {
return result + mnRepeatedIndex;
}
result += rowEle.getTableNumberRowsRepeatedAttribute();
}
}
}
if (n instanceof TableTableRowElement) {
rowEle = (TableTableRowElement) n;
if (rowEle == getOdfElement()) {
break;
}
result += ((TableTableRowElement) n).getTableNumberRowsRepeatedAttribute();
}
}
return result + mnRepeatedIndex;
}
//insert count number of cell from index
//this is called after insertColumn has been called by OdfTable
void insertCellByIndex(int index, int count) {
splitRepeatedRows();
//all insert the real cell
OdfTable table = getTable();
List coverList = table.getCellCoverInfos(0, 0, table.getColumnCount() - 1, table.getRowCount() - 1);
int rowIndex = getRowIndex();
OdfTableCell preCell;
if (index == 0) {
preCell = table.getOwnerCellByPosition(coverList, 0, rowIndex);
} else {
preCell = table.getOwnerCellByPosition(coverList, index - 1, rowIndex);
}
OdfTableCell nextCell = getCellByIndex(index);
if (nextCell == null) {
nextCell = getCellByIndex(getCellCount() - 1);
}
for (int i = index + count; i > index; i--) {
TableTableCellElement newCell = (TableTableCellElement) OdfXMLFactory.newOdfElement((OdfFileDom) maRowElement.getOwnerDocument() ,
OdfName.newName(OdfDocumentNamespace.TABLE, "table-cell"));
newCell.setTableStyleNameAttribute(preCell.getStyleName());
maRowElement.insertBefore(newCell, nextCell.getOdfElement());
}
}
//note: we have to use this method to modify the row repeated number
//in order to update mnRepeatedIndex of the each row
void setRowsRepeatedNumber(int num) {
mRowsRepeatedNumber = num;
//update the mnRepeatedIndex for the ever repeated row
maRowElement.setTableNumberRowsRepeatedAttribute(Integer.valueOf(num));
}
int getRowsRepeatedNumber() {
if (mRowsRepeatedNumber < 0) {
Integer count = maRowElement.getTableNumberRowsRepeatedAttribute();
if (count == null) {
mRowsRepeatedNumber = 1;
} else {
mRowsRepeatedNumber = count.intValue();
}
}
return mRowsRepeatedNumber;
}
/****************************
* Moved from OdfTable
*
*/
private void insertCellElementBefore(OdfElement parentEle, TableTableCellElementBase positionEle, TableTableCellElementBase cellEle, int count) {
if (positionEle == null) {
parentEle.appendChild(cellEle);
for (int i = 1; i < count; i++) {
parentEle.appendChild(cellEle.cloneNode(true));
}
} else {
parentEle.insertBefore(cellEle, positionEle);
for (int i = 1; i < count; i++) {
parentEle.insertBefore(cellEle.cloneNode(true), positionEle);
}
}
}
void insertCellBefore(OdfTableCell refCell, OdfTableCell positionCell, int count) {
splitRepeatedRows();
OdfTable ownerTable = getTable();
if (positionCell == null) {
if (refCell.isCoveredElement()) {
TableTableCellElement coverCellEle = (TableTableCellElement) refCell.getCoverCell().getOdfElement();
TableTableCellElement newCellEle = (TableTableCellElement) coverCellEle.cloneNode(true);
cleanCell(newCellEle);
insertCellElementBefore(getOdfElement(), null, newCellEle, count);
} else {
TableTableCellElement endCellEle = (TableTableCellElement) refCell.getOdfElement().cloneNode(true);
cleanCell(endCellEle);
getOdfElement().appendChild(endCellEle);
reviseStyleFromLastColumnToMedium(refCell);
if (count > 1) {
TableTableCellElement newCellEle = (TableTableCellElement) refCell.getOdfElement().cloneNode(true);
cleanCell(newCellEle);
insertCellElementBefore(getOdfElement(), endCellEle, newCellEle, count - 1);
}
}
} else {
TableTableCellElement coverRefCellEle = null;
TableTableCellElement coverPosCellEle = null;
OdfTableCell coverRefCell = null;
if (refCell.isCoveredElement()) { //get ref cover cell
coverRefCell = refCell.getCoverCell();
coverRefCellEle = (TableTableCellElement) coverRefCell.getOdfElement();
}
if (positionCell.isCoveredElement()) //get position cover cell
{
coverPosCellEle = (TableTableCellElement) positionCell.getCoverCell().getOdfElement();
}
if ((coverRefCellEle != null && coverRefCellEle == coverPosCellEle) //is cover cell and have the same cover cell
|| (coverPosCellEle != null && refCell.getOdfElement() == coverPosCellEle)) //position cell is cover cell and refer cell covers position cell
{
if (coverRefCellEle == null) {
coverRefCellEle = (TableTableCellElement) refCell.getOdfElement();
coverRefCell = refCell;
}
TableCoveredTableCellElement newCellEle = (TableCoveredTableCellElement) OdfXMLFactory.newOdfElement(
(OdfFileDom) ownerTable.getOdfElement().getOwnerDocument(),
OdfName.newName(OdfDocumentNamespace.TABLE, "covered-table-cell"));
insertCellElementBefore(getOdfElement(), positionCell.getOdfElement(), newCellEle, count);
if (refCell.getRowIndex() == coverRefCell.getRowIndex()) //the first cover line
{
coverRefCell.setColumnSpannedNumber(coverRefCell.getColumnSpannedNumber() + count);
}
} else if (coverRefCellEle != null) //is cover cell
{
if (refCell.getRowIndex() == coverRefCell.getRowIndex()) { //the first cover line
TableTableCellElement newCellEle = (TableTableCellElement) coverRefCellEle.cloneNode(true);
cleanCell(newCellEle);
insertCellElementBefore(getOdfElement(), positionCell.getOdfElement(), newCellEle, count);
} else { //the second and other cover line
TableCoveredTableCellElement newCellEle = (TableCoveredTableCellElement) refCell.getOdfElement().cloneNode(true);
newCellEle.removeAttributeNS(OdfDocumentNamespace.TABLE.getUri(), "number-columns-repeated");
insertCellElementBefore(getOdfElement(), positionCell.getOdfElement(), newCellEle, count);
}
} else if ((refCell.getOdfElement() == positionCell.getOdfElement())
&& (refCell.getColumnsRepeatedNumber() > 1)) //repeated number
{
int repeatNum = refCell.getColumnsRepeatedNumber();
//update the cell that after the ref cell
for (int i = repeatNum - 1; i > refCell.mnRepeatedColIndex; i--) {
ownerTable.updateCellRepository(refCell.getOdfElement(), i, refCell.mnRepeatedRowIndex,
refCell.getOdfElement(), i + count, refCell.mnRepeatedRowIndex);
}
refCell.getOdfElement().setTableNumberColumnsRepeatedAttribute(repeatNum + count);
} else {
TableTableCellElement newCellEle = (TableTableCellElement) refCell.getOdfElement().cloneNode(true);
cleanCell(newCellEle);
insertCellElementBefore(getOdfElement(), positionCell.getOdfElement(), newCellEle, count);
}
}
}
/**
* This method is to insert a cell same as refCell before positionCell.
*
* This method is invoked by appendColumn and insertColumnBefore.
*/
OdfTableCell insertCellBefore(OdfTableCell refCell, OdfTableCell positionCell) {
splitRepeatedRows();
OdfTableCell newCell = null;
OdfTable ownerTable = getTable();
if (positionCell == null) {
if (refCell.isCoveredElement()) {
TableTableCellElement coverCellEle = (TableTableCellElement) refCell.getCoverCell().getOdfElement();
TableTableCellElement newCellEle = (TableTableCellElement) coverCellEle.cloneNode(true);
cleanCell(newCellEle);
getOdfElement().appendChild(newCellEle);
newCell = ownerTable.getCellInstance(newCellEle, 0, 0);
} else {
TableTableCellElement newCellEle = (TableTableCellElement) refCell.getOdfElement().cloneNode(true);
cleanCell(newCellEle);
getOdfElement().appendChild(newCellEle);
newCell = ownerTable.getCellInstance(newCellEle, 0, 0);
reviseStyleFromLastColumnToMedium(refCell);
}
} else {
TableTableCellElement coverRefCellEle = null;
TableTableCellElement coverPosCellEle = null;
OdfTableCell coverRefCell = null;
if (refCell.isCoveredElement()) { //get ref cover cell
coverRefCell = refCell.getCoverCell();
coverRefCellEle = (TableTableCellElement) coverRefCell.getOdfElement();
}
if (positionCell.isCoveredElement()) //get position cover cell
{
coverPosCellEle = (TableTableCellElement) positionCell.getCoverCell().getOdfElement();
}
if ((coverRefCellEle != null && coverRefCellEle == coverPosCellEle) //is cover cell and have the same cover cell
|| (coverPosCellEle != null && refCell.getOdfElement() == coverPosCellEle)) //position cell is cover cell and refer cell covers position cell
{
if (coverRefCellEle == null) {
coverRefCellEle = (TableTableCellElement) refCell.getOdfElement();
coverRefCell = refCell;
}
TableCoveredTableCellElement newCellEle = (TableCoveredTableCellElement) OdfXMLFactory.newOdfElement(
(OdfFileDom) ownerTable.getOdfElement().getOwnerDocument(),
OdfName.newName(OdfDocumentNamespace.TABLE, "covered-table-cell"));
getOdfElement().insertBefore(newCellEle, positionCell.getOdfElement());
if (refCell.getRowIndex() == coverRefCell.getRowIndex()) //the first cover line
{
coverRefCell.setColumnSpannedNumber(coverRefCell.getColumnSpannedNumber() + 1);
}
newCell = ownerTable.getCellInstance(newCellEle, 0, 0);
} else if (coverRefCellEle != null) //is cover cell
{
if (refCell.getRowIndex() == coverRefCell.getRowIndex()) { //the first cover line
TableTableCellElement newCellEle = (TableTableCellElement) coverRefCellEle.cloneNode(true);
cleanCell(newCellEle);
getOdfElement().insertBefore(newCellEle, positionCell.getOdfElement());
newCell = ownerTable.getCellInstance(newCellEle, 0, 0);
} else { //the second and other cover line
TableCoveredTableCellElement newCellEle = (TableCoveredTableCellElement) refCell.getOdfElement().cloneNode(true);
newCellEle.removeAttributeNS(OdfDocumentNamespace.TABLE.getUri(), "number-columns-repeated");
getOdfElement().insertBefore(newCellEle, positionCell.getOdfElement());
newCell = ownerTable.getCellInstance(newCellEle, 0, 0);
}
} else if ((refCell.getOdfElement() == positionCell.getOdfElement())
&& (refCell.getColumnsRepeatedNumber() > 1)) //repeated number
{
int repeatNum = refCell.getColumnsRepeatedNumber();
//update the cell that after the ref cell
for (int i = repeatNum - 1; i > refCell.mnRepeatedColIndex; i--) {
ownerTable.updateCellRepository(refCell.getOdfElement(), i, refCell.mnRepeatedRowIndex,
refCell.getOdfElement(), i + 1, refCell.mnRepeatedRowIndex);
}
refCell.getOdfElement().setTableNumberColumnsRepeatedAttribute(repeatNum + 1);
newCell = ownerTable.getCellInstance(refCell.getOdfElement(), refCell.mnRepeatedColIndex + 1, refCell.mnRepeatedRowIndex);
} else {
TableTableCellElement newCellEle = (TableTableCellElement) refCell.getOdfElement().cloneNode(true);
cleanCell(newCellEle);
getOdfElement().insertBefore(newCellEle, positionCell.getOdfElement());
newCell = ownerTable.getCellInstance(newCellEle, 0, 0);
}
}
return newCell;
}
private 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.TABLE.getUri(), "number-columns-repeated");
newCellEle.removeAttributeNS(OdfDocumentNamespace.TABLE.getUri(), "number-columns-spanned");
if(!getTable().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;
}
}
private void reviseStyleFromLastColumnToMedium(OdfTableCell oldLastCell) {
if (getTable().mIsSpreadsheet) return;
OdfStyle styleEle = oldLastCell.getCellStyleElementForWrite();
if (styleEle != null) {
if (oldLastCell.getRowIndex() == 0) {
OdfTable.setLeftTopBorderStyleProperties(styleEle);
} else {
OdfTable.setLeftBottomBorderStylesProperties(styleEle);
}
}
}
private void reviseStyleFromMediumColumnToLast(OdfTableCell newLastCell) {
if (getTable().mIsSpreadsheet) return;
OdfStyle styleEle = newLastCell.getCellStyleElementForWrite();
if (styleEle != null) {
if (newLastCell.getRowIndex() == 0) {
OdfTable.setRightTopBorderStyleProperties(styleEle);
} else {
OdfTable.setRightBottomBorderStylesProperties(styleEle);
}
}
}
/**
* This method is invoked by removeColumnByIndex
* So we don't need to care about
* the covered and spanned cell in a same column
*/
void removeCellByIndex(int nStart, int nCount) {
splitRepeatedRows();
OdfTableCell startCell = getCellByIndex(nStart);
OdfTableCell coverCell = null;
if (startCell.isCoveredElement()) {
coverCell = startCell.getCoverCellInSameRow();
}
int index = nStart;
for (int i = 0; i < nCount; i++) {
OdfTableCell cell = getCellByIndex(index);
cell.splitRepeatedCells();
if (cell.isCoveredElement() && coverCell != null) {
coverCell.setColumnSpannedNumber(coverCell.getColumnSpannedNumber() - cell.getColumnsRepeatedNumber());
maRowElement.removeChild(cell.getOdfElement());
i += cell.getColumnsRepeatedNumber() - 1;
} else if (cell.isCoveredElement()) {
maRowElement.removeChild(cell.getOdfElement());
i += cell.getColumnsRepeatedNumber() - 1;
} else if (!cell.isCoveredElement()) {
if (i + cell.getColumnSpannedNumber() <= nCount) {
maRowElement.removeChild(cell.getOdfElement());
i += cell.getColumnSpannedNumber() - 1;
} else {
removeCellByIndex(index + 1, nCount - i);
}
}
}
int clmnum = getTable().getColumnCount();
if (nStart + nCount >= clmnum) {
OdfTableCell cell = getCellByIndex(nStart - 1);
reviseStyleFromMediumColumnToLast(cell);
}
}
void removeAllCellsRelationship() {
OdfTable table = getTable();
for (int i = 0; i < table.getColumnCount();) {
OdfTableCell cell = getCellByIndex(i);
if (cell.isCoveredElement()) //cell is a cover cell
{
OdfTableCell coverCell = cell.getCoverCellInSameColumn();
if (coverCell != null) {
coverCell.setRowSpannedNumber(coverCell.getRowSpannedNumber() - getRowsRepeatedNumber());
}
getOdfElement().removeChild(cell.getOdfElement());
} else {
if (cell.getRowSpannedNumber() > 1) //cell is not a cover cell, and it span more rows
{
//split the cell under this cell to a single cell
OdfTableRow nextRow = table.getRowByIndex(getRowIndex() + 1);
if (nextRow.getRowsRepeatedNumber() > 1) {
nextRow.splitRepeatedRows();
}
OdfTableCell coveredCell = table.getCellByPosition(cell.getColumnIndex(), getRowIndex() + 1);
if (coveredCell.getColumnsRepeatedNumber() > 1) {
coveredCell.splitRepeatedCells();
coveredCell = table.getCellByPosition(cell.getColumnIndex(), getRowIndex() + 1);
}
//create a new cell
TableTableCellElement newCellEle = (TableTableCellElement) cell.getOdfElement().cloneNode(true);
newCellEle.setTableNumberRowsSpannedAttribute(cell.getRowSpannedNumber() - getRowsRepeatedNumber());
//update repository
int startRow = coveredCell.getRowIndex();
int endRow = coveredCell.getRowIndex() + newCellEle.getTableNumberRowsSpannedAttribute();
int startClm = coveredCell.getColumnIndex();
int endClm = coveredCell.getColumnIndex() + newCellEle.getTableNumberColumnsSpannedAttribute() * newCellEle.getTableNumberColumnsRepeatedAttribute();
coveredCell.getOdfElement().getParentNode().replaceChild(newCellEle, coveredCell.getOdfElement());
table.updateRepositoryWhenCellElementChanged(startRow, endRow, startClm, endClm, newCellEle);
}
}
i += cell.getColumnSpannedNumber();
}
}
}