OdfTableRow.java
/**
* **********************************************************************
*
* <p>Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License. You may obtain a
* copy of the License at
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>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.
*
* <p>**********************************************************************
*/
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.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.pkg.OdfElement;
import org.odftoolkit.odfdom.pkg.OdfFileDom;
import org.odftoolkit.odfdom.pkg.OdfName;
import org.odftoolkit.odfdom.pkg.OdfXMLFactory;
import org.odftoolkit.odfdom.type.Length.Unit;
import org.odftoolkit.odfdom.type.PositiveLength;
import org.w3c.dom.Node;
/**
* OdfTableRow represents table row feature in ODF document.
*
* <p>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 <code>OdfTableRow</code> 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 <code>OdfTableRow</code> instance from the <code>TableTableRowElement</code> instance.
*
* <p>Each <code>TableTableRowElement</code> instance has a one-to-one relationship to a <code>
* OdfTableRow</code> instance.
*
* @param rowElement the row element that need to get the corresponding <code>OdfTableRow</code>
* instance
* @return the <code>OdfTableRow</code> 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 <code>TableTableElement</code> 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).
*
* <p>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.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 <code>TableTableRowElement</code> which represents this feature.
*
* @return an instance of <code>TableTableRowElement</code>
*/
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.
*
* <p>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<OdfTableCell> realCells = new HashSet<OdfTableCell>();
List<CellCoverInfo> 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.
*
* <p>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.getOrCreateAutomaticStyles().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<CellCoverInfo> 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.
*
* <p>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);
if (cell != null) {
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()) {
int columnSpan = cell.getColumnSpannedNumber();
if (i + columnSpan <= nCount) {
maRowElement.removeChild(cell.getOdfElement());
i += columnSpan - 1;
} else {
cell.setColumnSpannedNumber(columnSpan - 1);
OdfElement nextCell = OdfElement.getNextSiblingElement(cell.mCellElement);
// Recently some office application do not use <table:covered-table-cell> elements any
// longer
if (nextCell instanceof TableCoveredTableCellElement) {
// only delete the next child if the next IS a <table:covered-table-cell> element
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();
}
}
}