Package org.odftoolkit.odfdom.doc.table

Source Code of org.odftoolkit.odfdom.doc.table.OdfTableCell

/************************************************************************
*
* 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.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
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.doc.OdfDocument;
import org.odftoolkit.odfdom.dom.OdfDocumentNamespace;
import org.odftoolkit.odfdom.dom.attribute.fo.FoTextAlignAttribute;
import org.odftoolkit.odfdom.dom.attribute.fo.FoWrapOptionAttribute;
import org.odftoolkit.odfdom.dom.attribute.office.OfficeValueTypeAttribute;
import org.odftoolkit.odfdom.dom.element.OdfStyleBase;
import org.odftoolkit.odfdom.dom.element.number.NumberCurrencySymbolElement;
import org.odftoolkit.odfdom.dom.element.number.NumberNumberElement;
import org.odftoolkit.odfdom.dom.element.number.NumberTextElement;
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.TableTableColumnElement;
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.OdfStylePropertiesSet;
import org.odftoolkit.odfdom.dom.style.props.OdfStyleProperty;
import org.odftoolkit.odfdom.incubator.doc.number.OdfNumberCurrencyStyle;
import org.odftoolkit.odfdom.incubator.doc.number.OdfNumberDateStyle;
import org.odftoolkit.odfdom.incubator.doc.number.OdfNumberPercentageStyle;
import org.odftoolkit.odfdom.incubator.doc.number.OdfNumberStyle;
import org.odftoolkit.odfdom.incubator.doc.number.OdfNumberTimeStyle;
import org.odftoolkit.odfdom.incubator.doc.office.OdfOfficeAutomaticStyles;
import org.odftoolkit.odfdom.incubator.doc.style.OdfStyle;
import org.odftoolkit.odfdom.incubator.doc.text.OdfTextParagraph;
import org.odftoolkit.odfdom.incubator.doc.text.OdfWhitespaceProcessor;
import org.odftoolkit.odfdom.type.Color;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

/**
* OdfTableCell represents table cell feature in ODF document.
* <p>
* OdfTable provides methods to get/set/modify the cell content and cell properties.
*
*/
public class OdfTableCell {

  TableTableCellElementBase mOdfElement;
  int mnRepeatedColIndex;
  int mnRepeatedRowIndex;
  OdfTable mOwnerTable;
  String msFormatString;
  /**
   * The default date format of table cell.
   */
  private static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
  /**
   * The default time format of table cell.
   */
  private static final String DEFAULT_TIME_FORMAT = "'PT'HH'H'mm'M'ss'S'";
  /**
   * The default cell back color of table cell.
   */
  private static final String DEFAULT_BACKGROUND_COLOR = "#FFFFFF";
  /**
   * The default column spanned number.
   */
  private static final int DEFAULT_COLUMN_SPANNED_NUMBER = 1;
  /**
   * The default row spanned number.
   */
  private static final int DEFAULT_ROW_SPANNED_NUMBER = 1;
  /**
   * The default columns repeated number.
   */
  private static final int DEFAULT_COLUMNS_REPEATED_NUMBER = 1;
  TableTableCellElementBase mCellElement;
  OdfDocument mDocument;

  OdfTableCell(TableTableCellElementBase odfElement, int repeatedColIndex, int repeatedRowIndex) {
    mCellElement = odfElement;
    mnRepeatedColIndex = repeatedColIndex;
    mnRepeatedRowIndex = repeatedRowIndex;
    mOwnerTable = getTable();
    mDocument = ((OdfDocument) ((OdfFileDom) mCellElement.getOwnerDocument()).getDocument());
  }

  /**
   * Get the <code>OdfTableCell</code> instance from the <code>TableTableCellElementBase</code> instance.
   * <p>
   * Each <code>TableTableCellElementBase</code> instance has a one-to-one relationship to the a <code>OdfTableCell</code> instance.
   *
   * @param cellElement  the cell element that need to get the corresponding <code>OdfTableCell</code> instance
   * @return the <code>OdfTableCell</code> instance that represents a specified cell element
   */
  public static OdfTableCell getInstance(TableTableCellElementBase cellElement) {
    TableTableElement tableElement = null;
    Node node = cellElement.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 cellElement is not in the table dom tree");
    }

    OdfTableCell cell = table.getCellInstance(cellElement, 0, 0);
    int colRepeatedNum = cell.getColumnsRepeatedNumber();
    int rowRepeatedNum = cell.getTableRow().getRowsRepeatedNumber();
    if (colRepeatedNum > 1 && rowRepeatedNum > 1) {
      if (colRepeatedNum > 1) {
        Logger.getLogger(OdfTableCell.class.getName()).log(Level.WARNING, "the cell has the repeated column number, and puzzled about get which repeated column index of the cell,");
      }
      if (rowRepeatedNum > 1) {
        Logger.getLogger(OdfTableCell.class.getName()).log(Level.WARNING, "the row contains the current cell has the repeated row number, and puzzled about get which repeated row index of the cell,");
      }
      Logger.getLogger(OdfTableCell.class.getName()).log(Level.WARNING, "here just return the first cell that the repeated column index is 0 and repeated row index is 0, too.");
    }
    return cell;
  }

  /**
   * Return the horizontal alignment setting of this cell.
   * <p>
   * The returned value can be "center", "end", "justify", "left", "right", or "start".
   * If no horizontal alignment is set, null will be returned.
   *
   * @return the horizontal alignment setting.
   */
  public String getHorizontalAlignment() {
    OdfStyleBase styleElement = getCellStyleElement();
    if (styleElement != null) {
      OdfStyleProperty property = OdfStyleProperty.get(OdfStylePropertiesSet.ParagraphProperties,
          OdfName.newName(OdfDocumentNamespace.FO, "text-align"));
      return styleElement.getProperty(property);
    }
    return null;
  }

  /**
   * Set the horizontal alignment setting of this cell.
   * <p>
   * The parameter can be "center", "end", "justify", "left", "right", or "start".
   * Actually, "left" will be interpreted as "start", while "right" will be interpreted as "end".
   * If argument is null, the explicit horizontal alignment setting is removed.
   *
   * @param horizontalAlignment  the horizontal alignment setting.
   */
  public void setHorizontalAlignment(String horizontalAlignment) {
    if (FoTextAlignAttribute.Value.LEFT.toString().equalsIgnoreCase(horizontalAlignment)) {
      horizontalAlignment = FoTextAlignAttribute.Value.START.toString();
    }
    if (FoTextAlignAttribute.Value.RIGHT.toString().equalsIgnoreCase(horizontalAlignment)) {
      horizontalAlignment = FoTextAlignAttribute.Value.END.toString();
    }
    splitRepeatedCells();
    OdfStyleBase styleElement = getCellStyleElementForWrite();
    if (styleElement != null) {
      OdfStyleProperty property = OdfStyleProperty.get(OdfStylePropertiesSet.ParagraphProperties, OdfName.newName(
          OdfDocumentNamespace.FO, "text-align"));
      if (horizontalAlignment != null) {
        styleElement.setProperty(property, horizontalAlignment);
      } else {
        styleElement.removeProperty(property);
      }
    }
  }

  /**
   * Return the vertical alignment setting of this cell.
   * <p>
   * The returned value can be "auto", "automatic", "baseline", "bottom", "middle", or "top".
   *
   * @return the vertical alignment setting of this cell.
   */
  public String getVerticalAlignment() {
    OdfStyleBase styleElement = getCellStyleElement();
    if (styleElement != null) {
      OdfStyleProperty property = OdfStyleProperty.get(OdfStylePropertiesSet.TableCellProperties,
          OdfName.newName(OdfDocumentNamespace.STYLE, "vertical-align"));
      return styleElement.getProperty(property);
    }
    return null;
  }

  /**
   * Set the vertical alignment setting of this cell.
   * <p>
   * The parameter can be "auto", "automatic", "baseline", "bottom", "middle", or "top".
   * If argument is null, the explicit vertical alignment setting is removed.
   *
   * @param verticalAlignment  the vertical alignment setting.
   */
  public void setVerticalAlignment(String verticalAlignment) {
    splitRepeatedCells();
    OdfStyleBase styleElement = getCellStyleElementForWrite();
    if (styleElement != null) {
      OdfStyleProperty property = OdfStyleProperty.get(OdfStylePropertiesSet.TableCellProperties, OdfName.newName(
          OdfDocumentNamespace.STYLE, "vertical-align"));
      if (verticalAlignment != null) {
        styleElement.setProperty(property, verticalAlignment);
      } else {
        styleElement.removeProperty(property);
      }
    }
  }

  /**
   * Return the wrap option of this cell.
   * @return true if the cell content can be wrapped;
   * <p>
   * false if the cell content cannot be wrapped.
   */
  public boolean isTextWrapped() {
    OdfStyleBase styleElement = getCellStyleElement();
    if (styleElement != null) {
      OdfStyleProperty property = OdfStyleProperty.get(OdfStylePropertiesSet.TableCellProperties,
          OdfName.newName(OdfDocumentNamespace.FO, "wrap-option"));
      String wrapped = styleElement.getProperty(property);
      if ((wrapped != null) && (wrapped.equals(FoWrapOptionAttribute.Value.WRAP.toString()))) {
        return true;
      }
    }
    return false;
  }

  /**
   * Set the wrap option of this cell.
   * @param isTextWrapped  whether the cell content can be wrapped or not
   */
  public void setTextWrapped(boolean isTextWrapped) {
    splitRepeatedCells();
    OdfStyleBase styleElement = getCellStyleElementForWrite();
    if (styleElement != null) {
      OdfStyleProperty property = OdfStyleProperty.get(OdfStylePropertiesSet.TableCellProperties,
          OdfName.newName(OdfDocumentNamespace.FO, "wrap-option"));
      if (isTextWrapped) {
        styleElement.setProperty(property, FoWrapOptionAttribute.Value.WRAP.toString());
      } else {
        styleElement.setProperty(property, FoWrapOptionAttribute.Value.NO_WRAP.toString());
      }
    }
  }

  private TableTableRowElement findRowInTableHeaderRows(TableTableHeaderRowsElement headers, TableTableRowElement tr, int[] indexs) {
    int result = 0;
    for (Node m : new DomNodeList(headers.getChildNodes())) {
      if (m == tr) {
        indexs[0] = result;
        return tr;
      }
      if (m instanceof TableTableRowElement) {
        result += ((TableTableRowElement) m).getTableNumberRowsRepeatedAttribute().intValue();
      }
    }
    indexs[0] = result;
    return null;
  }

  private TableTableRowElement findRowInTableRows(TableTableRowsElement rows, TableTableRowElement tr, int[] indexs) {
    int result = 0;
    for (Node m : new DomNodeList(rows.getChildNodes())) {
      if (m == tr) {
        indexs[0] = result;
        return tr;
      }
      if (m instanceof TableTableRowElement) {
        result += ((TableTableRowElement) m).getTableNumberRowsRepeatedAttribute().intValue();
      }
    }
    indexs[0] = result;
    return null;
  }

  private TableTableRowElement findRowInTableRowGroup(OdfElement group, TableTableRowElement tr, int[] indexs) {
    int result = 0;
    int[] resultIndexs = new int[1];

    if (!(group instanceof TableTableRowGroupElement) && !(group instanceof TableTableElement)) {
      indexs[0] = 0;
      return null;
    }

    for (Node m : new DomNodeList(group.getChildNodes())) {
      if (m instanceof TableTableHeaderRowsElement) {
        TableTableHeaderRowsElement headers = (TableTableHeaderRowsElement) m;
        TableTableRowElement returnEle = findRowInTableHeaderRows(headers, tr, resultIndexs);
        result += resultIndexs[0];
        if (returnEle != null) {//find
          indexs[0] = result;
          return returnEle;
        }
      } else if (m instanceof TableTableRowGroupElement) {
        TableTableRowGroupElement aGroup = (TableTableRowGroupElement) m;
        TableTableRowElement returnEle = findRowInTableRowGroup(aGroup, tr, resultIndexs);
        result += resultIndexs[0];
        if (returnEle != null) {//find
          indexs[0] = result;
          return returnEle;
        }
      } else if (m instanceof TableTableRowsElement) {
        TableTableRowsElement rows = (TableTableRowsElement) m;
        TableTableRowElement returnEle = findRowInTableRows(rows, tr, resultIndexs);
        result += resultIndexs[0];
        if (returnEle != null) {//find
          indexs[0] = result;
          return returnEle;
        }
      } else if (m instanceof TableTableRowElement) {
        if (m == tr) { //find
          indexs[0] = result;
          return tr;
        }
        result += ((TableTableRowElement) m).getTableNumberRowsRepeatedAttribute().intValue();
      }
    }
    indexs[0] = result;
    return null;
  }

  /**
   * Get the index of the table row which contains this cell.
   * @return the index of the row containing this cell
   */
  public int getRowIndex() {
    TableTableElement table = getTableElement();
    TableTableRowElement tr = getTableRowElement();
    int[] indexs = new int[1];

    TableTableRowElement returnEle = findRowInTableRowGroup(table, tr, indexs);
    if (returnEle != null) {
      return (indexs[0] + mnRepeatedRowIndex);
    } else {
      return -1;
    }
  }

  /**
   * Get an instance of table feature which contains this cell.
   * @return the table containing this cell
   */
  public OdfTable getTable() {
    TableTableElement tableElement = getTableElement();
    if (tableElement != null) {
      return OdfTable.getInstance(tableElement);
    }
    return null;
  }

  /**
   * Get the index of the table column which contains this cell.
   * @return the index of the column containing this cell
   */
  public int getColumnIndex() {
    TableTableRowElement tr = (TableTableRowElement) mCellElement.getParentNode();
    int result = 0;
    for (Node n : new DomNodeList(tr.getChildNodes())) {
      if (n == mCellElement) {
        return result + mnRepeatedColIndex;
      }
      if (n instanceof TableTableCellElementBase) {
        result += ((TableTableCellElementBase) n).getTableNumberColumnsRepeatedAttribute().intValue();
      }
    }
    return result;
  }

  /**
   * Get the instance of table column feature which contains this cell.
   * @return the instance of table column feature which contains the cell.
   */
  public OdfTableColumn getTableColumn() {
    OdfTable table = getTable();
    int index = getColumnIndex();
    return table.getColumnByIndex(index);
  }

  TableTableColumnElement getTableColumnElement() {
    //return OdfTableCellBaseImpl.getTableColumn((OdfTableCellBase) mCellElement);
    TableTableElement tableElement = getTableElement();
    int columnindex = getColumnIndex();
    OdfTable fTable = OdfTable.getInstance(tableElement);
    return fTable.getColumnElementByIndex(columnindex);
  }

  /**
   * Get the instance of table row feature which contains this cell.
   * @return the instance of table row feature which contains the cell.
   */
  public OdfTableRow getTableRow() {
    OdfTable table = getTable();
    int index = getRowIndex();
    return table.getRowByIndex(index);
  }

  private TableTableRowElement getTableRowElement() {
    Node node = mCellElement.getParentNode();
    if (node instanceof TableTableRowElement) {
      return (TableTableRowElement) node;
    }
    return null;
  }

  /**
   * Get the table object who contains this cell.
   * @return the table object who contains the cell.
   */
  private TableTableElement getTableElement() {
    Node node = mCellElement.getParentNode();
    while (node != null) {
      if (node instanceof TableTableElement) {
        return (TableTableElement) node;
      }
      node = node.getParentNode();
    }
    return null;
  }

  /**
   * Get the cell that covers this cell.
   * <p>
   * If the cell is a covered cell, the owner cell will be returned;
   * if the cell is a real cell , the cell itself will be returned.
   * @return the cell that covers the current cell
   */
  public OdfTableCell getOwnerTableCell() {
    OdfTable ownerTable = getTable();
    List<CellCoverInfo> coverList = ownerTable.getCellCoverInfos(0, 0, ownerTable.getColumnCount() - 1, ownerTable.getRowCount() - 1);
    return ownerTable.getOwnerCellByPosition(coverList, getColumnIndex(), getRowIndex());
  }

  /**
   * Get the instance of <code>TableTableCellElementBase</code> which represents this cell.
   * @return the instance of <code>TableTableCellElementBase</code>
   */
  public TableTableCellElementBase getOdfElement() {
    return mCellElement;
  }

  /**
   * Return the currency code of this cell, for example, "USD", "EUR", "CNY", and etc.
   * <p>
   * If the value type is not "currency", an IllegalArgumentException will be thrown.
   *
   * @return the currency code
   * <p>
   * @throws IllegalArgumentException  an IllegalArgumentException will be thrown if the value type is not "currency".
   */
  public String getCurrencyCode() {
    if (mCellElement.getOfficeValueTypeAttribute().equals(OfficeValueTypeAttribute.Value.CURRENCY.toString())) {
      return mCellElement.getOfficeCurrencyAttribute();
    } else {
      throw new IllegalArgumentException();
    }
  }

  /**
   * Set the currency code of this cell, for example, "USD", "EUR", "CNY", and etc.
   *
   * @param currency  the currency code that need to be set.
   * @throws IllegalArgumentException  If input <code>currency</code> is null, an IllegalArgumentException will be thrown.
   */
  public void setCurrencyCode(String currency) {
    if (currency == null) {
      throw new IllegalArgumentException(
          "Currency code of cell should not be null.");
    }
    splitRepeatedCells();
    if (mCellElement.getOfficeValueTypeAttribute().equals(OfficeValueTypeAttribute.Value.CURRENCY.toString())) {
      mCellElement.setOfficeCurrencyAttribute(currency);
    } else {
      throw new IllegalArgumentException();
    }
  }

  private void setTypeAttr(OfficeValueTypeAttribute.Value type) {
    mCellElement.setOfficeValueTypeAttribute(type.toString());
  }

  /**
   * Set the value type of this cell.
   * The parameter can be "boolean", "currency", "date", "float", "percentage", "string" or "time".
   * <p>
   * If the parameter <code>type</code> is not a valid cell type, an IllegalArgumentException will be thrown.
   *
   * @param type  the type that need to be set
   * If input type is null, an IllegalArgumentException will be thrown.
   */
  public void setValueType(String type) {
    if (type == null) {
      throw new IllegalArgumentException("type shouldn't be null.");
    }
    String sType = type.toLowerCase();
    OfficeValueTypeAttribute.Value value = OfficeValueTypeAttribute.Value.enumValueOf(sType);
    if (value == null) {
      throw new IllegalArgumentException("the value type of cell is not valid");
    }

    mCellElement.setOfficeValueTypeAttribute(sType);
  }

  /**
   * Get the value type of this cell.
   * The returned value can be "boolean", "currency", "date", "float", "percentage", "string" or "time".
   * If no value type is set, null will be returned.
   *
   * @return the type of the cell
   */
  public String getValueType() {
    return mCellElement.getOfficeValueTypeAttribute();
  }

  private OfficeValueTypeAttribute.Value getTypeAttr() {
    String type = mCellElement.getOfficeValueTypeAttribute();
    return OfficeValueTypeAttribute.Value.enumValueOf(type);
  }

  /**
   * Get the double value of this cell as Double object.
   * <p>
   * Throw IllegalArgumentException if the cell type is not "float".
   *
   * @return the double value of this cell as a Double object. If the cell value is empty, null will be returned.
   * <p>
   * An IllegalArgumentException will be thrown if the cell type is not "float".
   */
  public Double getDoubleValue() {
    if (getTypeAttr() == OfficeValueTypeAttribute.Value.FLOAT) {
      return mCellElement.getOfficeValueAttribute();
    } else {
      throw new IllegalArgumentException();
    }
  }

  /**
   * Get the currency value of this cell as Double object.
   * <p>
   * Throw IllegalArgumentException if the cell type is not "currency".
   *
   * @return the currency value of this cell as a Double object. If the cell value is empty, null will be returned.
   * @throws IllegalArgumentException  an IllegalArgumentException will be thrown if the cell type is not "currency".
   */
  public Double getCurrencyValue() {
    if (getTypeAttr() == OfficeValueTypeAttribute.Value.CURRENCY) {
      return mCellElement.getOfficeValueAttribute();
    } else {
      throw new IllegalArgumentException();
    }
  }

  /**
   * Get the symbol of currency.
   * @return the currency symbol
   * @throws IllegalArgumentException  an IllegalArgumentException will be thrown if the value type is not "currency".
   */
  public String getCurrencySymbol() {
    if (getTypeAttr() != OfficeValueTypeAttribute.Value.CURRENCY) {
      throw new IllegalArgumentException();
    }

    OdfStyle style = getCellStyleElement();
    if (style != null) {
      String dataStyleName = style.getOdfAttributeValue(OdfName.newName(OdfDocumentNamespace.STYLE, "data-style-name"));
      OdfNumberCurrencyStyle dataStyle = mCellElement.getAutomaticStyles().getCurrencyStyle(dataStyleName);
      if (dataStyle == null) {
        dataStyle = mDocument.getDocumentStyles().getCurrencyStyle(dataStyleName);
      }
      if ((dataStyle != null) && (dataStyle.getCurrencySymbolElement() != null)) {
        return dataStyle.getCurrencySymbolElement().getTextContent();
      }
    }
    return null;
  }

  /**
   * Set the value and currency of the cell, and set the value type as "currency".
   * If<code>value</value> is null, the cell value will be removed.
   *
   * @param value  the value that will be set
   * @param currency  the currency that will be set.
   * @throws IllegalArgumentException  If input currency is null, an IllegalArgumentException will be thrown.
   */
  public void setCurrencyValue(Double value, String currency) {
    if (currency == null) {
      throw new IllegalArgumentException("currency shouldn't be null.");
    }
    splitRepeatedCells();
    setTypeAttr(OfficeValueTypeAttribute.Value.CURRENCY);
    mCellElement.setOfficeValueAttribute(value);
    mCellElement.setOfficeCurrencyAttribute(currency);
  }

  /**
   * Get the cell percentage value as Double object.
   * <p>
   * Throw IllegalArgumentException if the cell type is not "percentage".
   *
   * @return the percentage value of this cell as a Double object. If the cell value is empty, null will be returned.
   * @throws IllegalArgumentException  an IllegalArgumentException will be thrown if the cell type is not "percentage".
   */
  public Double getPercentageValue() {
    if (getTypeAttr() == OfficeValueTypeAttribute.Value.PERCENTAGE) {
      return mCellElement.getOfficeValueAttribute();
    } else {
      throw new IllegalArgumentException();
    }
  }

  /**
   * Set the cell value as a percentage value and set the value type as percentage too.
   * If<code>value</value> is null, the cell value will be removed.
   *
   * @param value  the value that will be set
   */
  public void setPercentageValue(Double value) {
    splitRepeatedCells();
    setTypeAttr(OfficeValueTypeAttribute.Value.PERCENTAGE);
    mCellElement.setOfficeValueAttribute(value);
  }

  /**
   * Get the text displayed in this cell.
   *
   * @return the text displayed in this cell
   */
  public String getDisplayText() {
    //TODO: This function doesn't work well if a cell contains a list.
    //Refer to testGetSetTextValue();
    OdfWhitespaceProcessor textProcessor = new OdfWhitespaceProcessor();
    return textProcessor.getText(mCellElement);
  }

  /**
   * Set the text displayed in this cell.
   * <p>
   * Please note the displayed text in ODF viewer might be different with the value set by this method,
   * because the displayed text in ODF viewer is calculated and set by editor.
   *
   * @param content  the displayed text.
   * If content is null, it will display the empty string instead.
   */
  public void setDisplayText(String content) {
    if (content == null) {
      content = "";
    }
    removeContent();

    OdfWhitespaceProcessor textProcessor = new OdfWhitespaceProcessor();
    OdfTextParagraph para = new OdfTextParagraph((OdfFileDom) mCellElement.getOwnerDocument());
    textProcessor.append(para, content);

    mCellElement.appendChild(para);
  }

  /**
   * Set the text displayed in this cell, with a specified style name.
   * <p>
   * Please note the displayed text in ODF viewer might be different with the value set by this method,
   * because the displayed text in ODF viewer are calculated and set by editor.
   *
   * @param content    the displayed text. If content is null, it will display the empty string instead.
   * @param stylename  the style name. If stylename is null, the content will use the default paragraph style.
   */
  public void setDisplayText(String content, String stylename) {
    if (content == null) {
      content = "";
    }
    removeContent();

    OdfWhitespaceProcessor textProcessor = new OdfWhitespaceProcessor();
    OdfTextParagraph para = new OdfTextParagraph((OdfFileDom) mCellElement.getOwnerDocument());
    if ((stylename != null) && (stylename.length() > 0)) {
      para.setStyleName(stylename);
    }
    textProcessor.append(para, content);

    mCellElement.appendChild(para);
  }

  /**
   * Set the cell value as a double and set the value type to be "float".
   *
   * @param value  the double value that will be set. If<code>value</value> is null, the cell value will be removed.
   */
  public void setDoubleValue(Double value) {
    splitRepeatedCells();
    setTypeAttr(OfficeValueTypeAttribute.Value.FLOAT);
    mCellElement.setOfficeValueAttribute(value);
    setDisplayText(value + "");
  }

  /**
   * Get the cell boolean value as Boolean object.
   * <p>
   * Throw IllegalArgumentException if the cell type is not "boolean".
   *
   * @return the Boolean value of cell. If the cell value is empty, null will be returned.
   * @throws IllegalArgumentException  an IllegalArgumentException will be thrown if the cell type is not "boolean".
   */
  public Boolean getBooleanValue() {
    if (getTypeAttr() == OfficeValueTypeAttribute.Value.BOOLEAN) {
      return mCellElement.getOfficeBooleanValueAttribute();
    } else {
      throw new IllegalArgumentException();
    }
  }

  /**
   * Set the cell value as a boolean and set the value type to be boolean. If<code>value</value> is null, the cell value will be removed.
   *
   * @param value  the value of boolean type
   */
  public void setBooleanValue(Boolean value) {
    splitRepeatedCells();
    setTypeAttr(OfficeValueTypeAttribute.Value.BOOLEAN);
    mCellElement.setOfficeBooleanValueAttribute(value);
    setDisplayText(value + "");
  }

  /**
   * Get the cell date value as Calendar.
   * <p>
   * Throw IllegalArgumentException if the cell type is not "date".
   *
   * @return the Calendar value of cell
   * @throws IllegalArgumentException  an IllegalArgumentException will be thrown, if the cell type is not "date".
   */
  public Calendar getDateValue() {
    if (getTypeAttr() == OfficeValueTypeAttribute.Value.DATE) {
      String dateStr = mCellElement.getOfficeDateValueAttribute();
      if (dateStr == null) {
        return null;
      }
      Date date = parseString(dateStr, DEFAULT_DATE_FORMAT);
      Calendar calender = Calendar.getInstance();
      calender.setTime(date);
      return calender;
    } else {
      throw new IllegalArgumentException();
    }
  }

  /**
   * Set the cell value as a date, and set the value type to be "date".
   *
   * @param date  the value of {@link java.util.Calendar java.util.Calendar} type.
   */
  public void setDateValue(Calendar date) {
    if (date == null) {
      throw new IllegalArgumentException("date shouldn't be null.");
    }
    splitRepeatedCells();
    setTypeAttr(OfficeValueTypeAttribute.Value.DATE);
    SimpleDateFormat simpleFormat = new SimpleDateFormat(DEFAULT_DATE_FORMAT);
    String svalue = simpleFormat.format(date.getTime());
    mCellElement.setOfficeDateValueAttribute(svalue);
    setDisplayText(svalue);
  }

  /**
   * Set the cell value as a string, and set the value type to be string.
   *
   * @param str  the value of string type.
   * If input string is null, an empty string will be set.
   */
  public void setStringValue(String str) {
    if (str == null) {
      str = "";
    }
    splitRepeatedCells();
    setTypeAttr(OfficeValueTypeAttribute.Value.STRING);
    mCellElement.setOfficeStringValueAttribute(str);
    setDisplayText(str);
  }

  //Note: if you want to change the cell
  //splitRepeatedCells must be called first in order to
  //1. update parent row if the row is the repeated rows.
  //2. update the cell itself if the cell is the column repeated cells.
  void splitRepeatedCells() {
    OdfTable table = getTable();
    //1.if the parent row is the repeated row
    //the repeated row has to be separated
    //after this the cell element and repeated index will be updated
    //according to the new parent row
    OdfTableRow row = getTableRow();
    int colIndex = getColumnIndex();
    if (row.getRowsRepeatedNumber() > 1) {
      row.splitRepeatedRows();
      OdfTableCell cell = row.getCellByIndex(colIndex);
      mCellElement = cell.getOdfElement();
      mnRepeatedColIndex = cell.mnRepeatedColIndex;
      mnRepeatedRowIndex = cell.mnRepeatedRowIndex;
    }

    //2.if the cell is the column repeated cell
    //this repeated cell has to be separated
    int repeateNum = getColumnsRepeatedNumber();
    if (repeateNum > 1) {
      //change this repeated column to several single columns
      TableTableCellElementBase ownerCellElement = null;
      int repeatedColIndex = mnRepeatedColIndex;
      Node refElement = mCellElement;
      for (int i = repeateNum - 1; i >= 0; i--) {
        TableTableCellElementBase newCell = (TableTableCellElementBase) mCellElement.cloneNode(true);
        newCell.removeAttributeNS(OdfDocumentNamespace.TABLE.getUri(), "number-columns-repeated");
        row.getOdfElement().insertBefore(newCell, refElement);
        refElement = newCell;
        if (repeatedColIndex == i) {
          ownerCellElement = newCell;
        } else {
          table.updateCellRepository(mCellElement, i, mnRepeatedRowIndex, newCell, 0, mnRepeatedRowIndex);
        }
      }
      //remove this column element
      row.getOdfElement().removeChild(mCellElement);

      if (ownerCellElement != null) {
        table.updateCellRepository(mCellElement, mnRepeatedColIndex, mnRepeatedRowIndex, ownerCellElement, 0, mnRepeatedRowIndex);
        mCellElement = ownerCellElement;
        mnRepeatedColIndex = 0;
      }
    }
  }

  /**
   * Get the cell value as a string.
   * <p>
   * If the cell type is not string, the display text will be returned.
   *
   * @return the string value of this cell, or the display text
   */
  public String getStringValue() {
    return getDisplayText();
  }

  /**
   * Get the cell value as {@link java.util.Calendar java.util.Calendar}.
   * <p>
   * Throw exception if the cell type is not "time".
   *
   * @return the Calendar value of cell
   * @throws IllegalArgumentException  an IllegalArgumentException will be thrown if the cell type is not time.
   */
  public Calendar getTimeValue() {
    if (getTypeAttr() == OfficeValueTypeAttribute.Value.TIME) {
      String timeStr = mCellElement.getOfficeTimeValueAttribute();
      Date date = parseString(timeStr, DEFAULT_TIME_FORMAT);
      Calendar calender = Calendar.getInstance();
      calender.setTime(date);
      calender.clear(Calendar.YEAR);
      calender.clear(Calendar.MONTH);
      calender.clear(Calendar.DAY_OF_MONTH);
      return calender;
    } else {
      throw new IllegalArgumentException();
    }
  }

  /**
   * Set the cell value as a time and set the value type to be "time" too.
   *
   * @param time  the value of {@link java.util.Calendar java.util.Calendar} type.
   * @throws IllegalArgumentException   If input time is null, an IllegalArgumentException exception will be thrown.
   */
  public void setTimeValue(Calendar time) {
    if (time == null) {
      throw new IllegalArgumentException("time shouldn't be null.");
    }
    splitRepeatedCells();
    setTypeAttr(OfficeValueTypeAttribute.Value.TIME);
    SimpleDateFormat simpleFormat = new SimpleDateFormat(DEFAULT_TIME_FORMAT);
    String svalue = simpleFormat.format(time.getTime());
    mCellElement.setOfficeTimeValueAttribute(svalue);
    setDisplayText(svalue);
  }

  private Date parseString(String value, String format) {
    SimpleDateFormat simpleFormat = new SimpleDateFormat(format);
    Date simpleDate = null;
    try {
      simpleDate = simpleFormat.parse(value);
    } catch (ParseException e) {
      Logger.getLogger(OdfTableCell.class.getName()).log(Level.SEVERE, e.getMessage(), e);
      return null;
    }
    return simpleDate;
  }

  /**
   * Get the background color of this cell.
   * <p>
   * If no background color is set, default background color "#FFFFFF" will be returned.
   *
   * @return the background color of this cell
   */
  public Color getCellBackgroundColor() {
    Color color = Color.WHITE;
    OdfStyleBase styleElement = getCellStyleElement();
    if (styleElement != null) {
      OdfStyleProperty bkColorProperty = OdfStyleProperty.get(OdfStylePropertiesSet.TableCellProperties,
          OdfName.newName(OdfDocumentNamespace.FO, "background-color"));
      String property = styleElement.getProperty(bkColorProperty);
      if (property != null) {
        try {
          color = new Color(property);
        } catch (Exception e) {
          // use default background color White
          color = Color.WHITE;
          Logger.getLogger(OdfTableCell.class.getName()).log(Level.WARNING, e.getMessage());
        }
      }
    }
    return color;
  }

  /**
   * Get the background color string of this cell.
   * <p>
   * If no background color is set, default background color "#FFFFFF" will be returned.
   *
   * @return the background color of this cell
   */
  public String getCellBackgroundColorString() {
    String color = DEFAULT_BACKGROUND_COLOR;
    OdfStyleBase styleElement = getCellStyleElement();
    if (styleElement != null) {
      OdfStyleProperty bkColorProperty = OdfStyleProperty.get(OdfStylePropertiesSet.TableCellProperties,
          OdfName.newName(OdfDocumentNamespace.FO, "background-color"));
      String property = styleElement.getProperty(bkColorProperty);
      if (Color.isValid(property)) {
        color = property;
      }
    }
    return color;
  }

  /**
   * Set the background color of this cell.
   *
   * @param cellBackgroundColor
   *            the background color that need to set.
   *            If <code>cellBackgroundColor</code> is null, default background color <code>Color.WHITE</code> will be set.
   */
  public void setCellBackgroundColor(Color cellBackgroundColor) {
    if (cellBackgroundColor == null) {
      cellBackgroundColor = Color.WHITE;
    }
    splitRepeatedCells();
    OdfStyleBase styleElement = getCellStyleElementForWrite();
    if (styleElement != null) {
      OdfStyleProperty bkColorProperty = OdfStyleProperty.get(OdfStylePropertiesSet.TableCellProperties,
          OdfName.newName(OdfDocumentNamespace.FO, "background-color"));
      styleElement.setProperty(bkColorProperty, cellBackgroundColor.toString());
    }
  }

  /**
   * Set the background color of this cell using string. The string must be a valid argument for
   * constructing {@link org.odftoolkit.odfdom.type.Color <code>org.odftoolkit.odfdom.type.Color</code>}.
   *
   * @param cellBackgroundColor
   *            the background color that need to set.
   *            If cellBackgroundColor is null, default background color #FFFFFF will be set.
   * @see org.odftoolkit.odfdom.type.Color
   */
  public void setCellBackgroundColor(String cellBackgroundColor) {
    if (!Color.isValid(cellBackgroundColor)) {
      Logger.getLogger(OdfTableCell.class.getName()).log(Level.WARNING, "Parameter is invalid for datatype Color, default background color #FFFFFF will be set.");
      cellBackgroundColor = DEFAULT_BACKGROUND_COLOR;
    }
    splitRepeatedCells();
    OdfStyleBase styleElement = getCellStyleElementForWrite();
    if (styleElement != null) {
      OdfStyleProperty bkColorProperty = OdfStyleProperty.get(OdfStylePropertiesSet.TableCellProperties,
          OdfName.newName(OdfDocumentNamespace.FO, "background-color"));
      styleElement.setProperty(bkColorProperty, cellBackgroundColor);
    }
  }

  /**
   * Get the column spanned number of this cell.
   *
   * @return the column spanned number
   */
  int getColumnSpannedNumber() {
    if (mCellElement instanceof TableCoveredTableCellElement) {
      return 1;
    }
    Integer value = ((TableTableCellElement) mCellElement).getTableNumberColumnsSpannedAttribute();
    if (value != null) {
      return value.intValue();
    }
    return DEFAULT_COLUMN_SPANNED_NUMBER;
  }

  /**
   * Get the column repeated number of this cell.
   *
   * @return the column repeated number
   */
  int getColumnsRepeatedNumber() {
    Integer value = mCellElement.getTableNumberColumnsRepeatedAttribute();
    if (value != null) {
      return value.intValue();
    }
    return DEFAULT_COLUMNS_REPEATED_NUMBER;
  }

  /**
   * Get the row spanned number of this cell.
   *
   * @return the row spanned number
   */
  int getRowSpannedNumber() {
    if (mCellElement instanceof TableCoveredTableCellElement) {
      return 1;
    }
    Integer value = ((TableTableCellElement) mCellElement).getTableNumberRowsSpannedAttribute();
    if (value != null) {
      return value.intValue();
    }
    return DEFAULT_ROW_SPANNED_NUMBER;
  }

  /**
   * Set the column spanned number.
   *
   * @param spannedNum
   *            the column spanned number to be set. If spannedNum is less than 1,
   *            default column spanned number 1 will be
   *            set.
   */
  void setColumnSpannedNumber(int spannedNum) {
    if (spannedNum < 1) {
      spannedNum = DEFAULT_COLUMN_SPANNED_NUMBER;
    }
    splitRepeatedCells();
    if (mCellElement instanceof TableTableCellElement) {
      ((TableTableCellElement) mCellElement).setTableNumberColumnsSpannedAttribute(new Integer(spannedNum));
    } else {
      throw new IllegalArgumentException();
    }
  }

  /**
   * Set the column repeated number.
   *
   * @param repeatedNum
   *            the column repeated number that need to be set. If repeatedNum
   *            is less than 1, default columns repeated number 1 will be set.
   */
  void setColumnsRepeatedNumber(int repeatedNum) {
    if (repeatedNum < 1) {
      repeatedNum = DEFAULT_COLUMNS_REPEATED_NUMBER;
    }
    mCellElement.setTableNumberColumnsRepeatedAttribute(new Integer(repeatedNum));
  }

  /**
   * Set the row spanned number.
   *
   * @param spannedNum  row spanned number that need to be set
   *            the row spanned number that need to be set. If spannedNum is
   *            less than 1, default row spanned number 1 will be
   *            set.
   */
  void setRowSpannedNumber(int spannedNum) {
    if (spannedNum < 1) {
      spannedNum = DEFAULT_ROW_SPANNED_NUMBER;
    }
    splitRepeatedCells();
    if (mCellElement instanceof TableTableCellElement) {
      ((TableTableCellElement) mCellElement).setTableNumberRowsSpannedAttribute(new Integer(spannedNum));
    } else {
      throw new IllegalArgumentException();
    }
  }

  /**
   * Judge if the ODF DOM element of this cell is the covered cell element.
   *
   * @return true if the ODFDOM element is TableCoveredTableCellElement
   */
  boolean isCoveredElement() {
    if (mCellElement instanceof TableCoveredTableCellElement) {
      return true;
    }
    return false;
  }

  /**
   * Get the style name of this cell.
   *
   * @return the name of the style
   */
  public String getStyleName() {
    OdfStyle style = getCellStyleElement();
    if (style == null) {
      return "";
    }
    return style.getStyleNameAttribute();
  }

  /**
   * Set a formula to the cell.
   * <p>
   * Please note, the parameter <code>formula</code> will not be checked and interpreted;
   * the cell value will not be calculated.
   * It's just simply set as a formula attribute. See {@odf.attribute table:formula}
   *
   * @param formula  the formula that need to be set.
   * @throws IllegalArgumentException  if formula is null, an IllegalArgumentException will be thrown.
   */
  public void setFormula(String formula) {
    if (formula == null) {
      throw new IllegalArgumentException("formula shouldn't be null.");
    }
    splitRepeatedCells();
    mCellElement.setTableFormulaAttribute(formula);
  }

  /**
   * Get the formula string of the cell.
   *
   * @return the formula representation of the cell
   * <p>
   * If the cell does not contain a formula, null will be returned.
   *
   */
  public String getFormula() {
    return mCellElement.getTableFormulaAttribute();
  }

//  /**
//   * get the error value of the cell
//   * if the formula can not be calculated, an error will be set
//   * @return
//   *       return 0 if the cell has no error
//   *       return the error value of the cell if the formula result can not be calculated
//   *       such as divided by 0
//   */
//  public long getError()
//  {
//    return 0;
//  }
  /**
   * Set the currency symbol and overall format of a currency cell.
   * <p>
   * Please note the overall format includes the symbol character, for example: $#,##0.00.
   * <p>
   * This function only works for currency.
   * @param currencySymbol  the currency symbol
   * @param format      overall format
   * @throws IllegalArgumentException  if input currencySymbol or format is null, an IllegalArgumentException will be thrown.
   */
  public void setCurrencyFormat(String currencySymbol, String format) {
    if (currencySymbol == null) {
      throw new IllegalArgumentException(
          "currencySymbol shouldn't be null.");
    }
    if (format == null) {
      throw new IllegalArgumentException("format shouldn't be null.");
    }
    splitRepeatedCells();
    String type = mCellElement.getOfficeValueTypeAttribute();
    OfficeValueTypeAttribute.Value typeValue = null;
    msFormatString = format;
    if (type != null) {
      typeValue = OfficeValueTypeAttribute.Value.enumValueOf(type);
    }

    if (typeValue != OfficeValueTypeAttribute.Value.CURRENCY) {
      throw new IllegalArgumentException();
    }

    OdfNumberCurrencyStyle currencyStyle = new OdfNumberCurrencyStyle(
        (OdfFileDom) mCellElement.getOwnerDocument(),
        currencySymbol,
        format,
        getUniqueCurrencyStyleName());
    mCellElement.getAutomaticStyles().appendChild(currencyStyle);
    setDataDisplayStyleName(currencyStyle.getStyleNameAttribute());
    Double value = getCurrencyValue();

    //set display text
    if (value != null) {
      setDisplayText(formatCurrency(currencyStyle, value.doubleValue()));
    }
  }

  //This method doesn't handle style:map element.
  private String formatCurrency(OdfNumberCurrencyStyle currencyStyle, double value) {
    String valuestr = "";
    for (Node m : new DomNodeList(currencyStyle.getChildNodes())) {
      if (m instanceof NumberCurrencySymbolElement) {
        valuestr += m.getTextContent();
      } else if (m instanceof NumberNumberElement) {
        String numberformat = currencyStyle.getNumberFormat();
        valuestr += (new DecimalFormat(numberformat)).format(value);
      } else if (m instanceof NumberTextElement) {
        String textcontent = m.getTextContent();
        if (textcontent == null || textcontent.length() == 0) {
          textcontent = " ";
        }
        valuestr += textcontent;
      }
    }
    return valuestr;
  }

  /**
   * Set the format string of the cell.
   * <p>
   * This function only works for float, date, time and percentage, otherwise an
   * {@link java.lang.IllegalArgumentException} will be thrown.
   * <p>
   * For value type float and percentage, the <code>formatStr</code> must follow the encoding
   * rule of {@link java.text.DecimalFormat <code>java.text.DecimalFormat</code>}.
   * For value type date and time, the <code>formatStr</code> must follow the encoding
   * rule of {@link java.text.SimpleDateFormat <code>java.text.SimpleDateFormat</code>}.
   * <p>
   * Refer to {@link org.odftoolkit.odfdom.doc.table.OdfTableCell#setCurrencyFormat <code>setCurrencyFormat</code>} to set the format of currency.
   * <p>
   * If the cell value type is not set, the method will try to give it a value type, according
   * to common ordination. The adapt order is: percentage-> time-> date-> float.
   * <blockquote>
   * <table border=0 cellspacing=3 cellpadding=0 summary="Chart showing ValueType, Distinguish Symbol
   * and Distinguish Priority.">
   *     <tr bgcolor="#ccccff">
   *          <th align=left>ValueType
   *          <th align=left>Distinguish Symbol
   *          <th align=left>Distinguish Priority
   *     <tr valign=top>
   *          <td>percentage
   *          <td>%
   *          <td>1
   *     <tr valign=top>
   *          <td>time
   *          <td>H, k, m, s, S
   *          <td>2
   *     <tr valign=top>
   *          <td>date
   *          <td>y, M, w, W, D, d, F, E, K, h
   *          <td>3
   *     <tr valign=top>
   *          <td>float
   *          <td>#, 0
   *          <td>4
   * </table>
   * </blockquote>
   * The adapt result may be inaccurate, so you'd better set value type before call this method.
   * If adaptive failed, an {@link java.lang.UnsupportedOperationException} will be thrown.
   * <p>
   * @param formatStr  the cell need be formatted as this specified format string.
   * @throws IllegalArgumentException if <code>formatStr</code> is null or the cell value type is supported.
   * @throws UnsupportedOperationException if the adaptive failed, when cell value type is not set.
   * @see java.text.SimpleDateFormat
   * @see java.text.DecimalFormat
   */
  public void setFormatString(String formatStr) {
    if (formatStr == null) {
      throw new IllegalArgumentException("formatStr shouldn't be null.");
    }
    String type = getValueType();
    if (type == null) {
      if (formatStr.contains("%")) {
        setValueType("percentage");
      } else if (formatStr.contains("H") || formatStr.contains("k")
          || formatStr.contains("m") || formatStr.contains("s")
          || formatStr.contains("S")) {
        setValueType("time");
      } else if (formatStr.contains("y") || formatStr.contains("M")
          || formatStr.contains("w") || formatStr.contains("W")
          || formatStr.contains("D") || formatStr.contains("d")
          || formatStr.contains("F") || formatStr.contains("E")
          || formatStr.contains("K") || formatStr.contains("h")) {
        setValueType("date");
      } else if (formatStr.contains("#") || formatStr.contains("0")) {
        setValueType("float");
      } else {
        throw new UnsupportedOperationException("format string: "
            + formatStr
            + " can't be adapted to a possible value type.");
      }
      type = getValueType();
    }
    setCellFormatString(formatStr, type);
  }

  private void setCellFormatString(String formatStr, String type) {
    OfficeValueTypeAttribute.Value typeValue = null;
    msFormatString = formatStr;
    splitRepeatedCells();
    typeValue = OfficeValueTypeAttribute.Value.enumValueOf(type);
    if (typeValue == OfficeValueTypeAttribute.Value.FLOAT) {
      OdfNumberStyle numberStyle = new OdfNumberStyle(
          (OdfFileDom) mCellElement.getOwnerDocument(),
          formatStr,
          getUniqueNumberStyleName());
      mCellElement.getAutomaticStyles().appendChild(numberStyle);
      setDataDisplayStyleName(numberStyle.getStyleNameAttribute());
      Double value = getDoubleValue();
      if (value != null) {
        setDisplayText((new DecimalFormat(formatStr)).format(value.doubleValue()));
      }
    } else if (typeValue == OfficeValueTypeAttribute.Value.DATE) {
      OdfNumberDateStyle dateStyle = new OdfNumberDateStyle(
          (OdfFileDom) mCellElement.getOwnerDocument(),
          formatStr,
          getUniqueDateStyleName(), null);
      mCellElement.getAutomaticStyles().appendChild(dateStyle);
      setDataDisplayStyleName(dateStyle.getStyleNameAttribute());
      String dateStr = mCellElement.getOfficeDateValueAttribute();
      if (dateStr != null) {
        Calendar date = getDateValue();
        setDisplayText((new SimpleDateFormat(formatStr)).format(date.getTime()));
      }
    } else if (typeValue == OfficeValueTypeAttribute.Value.TIME) {
      OdfNumberTimeStyle timeStyle = new OdfNumberTimeStyle(
          (OdfFileDom) mCellElement.getOwnerDocument(), formatStr,
          getUniqueDateStyleName());
      mCellElement.getAutomaticStyles().appendChild(timeStyle);
      setDataDisplayStyleName(timeStyle.getStyleNameAttribute());
      String timeStr = mCellElement.getOfficeTimeValueAttribute();
      if (timeStr != null) {
        Calendar time = getTimeValue();
        setDisplayText((new SimpleDateFormat(formatStr)).format(time.getTime()));
      }
    } else if (typeValue == OfficeValueTypeAttribute.Value.PERCENTAGE) {
      OdfNumberPercentageStyle dateStyle = new OdfNumberPercentageStyle(
          (OdfFileDom) mCellElement.getOwnerDocument(),
          formatStr,
          getUniquePercentageStyleName());
      mCellElement.getAutomaticStyles().appendChild(dateStyle);
      setDataDisplayStyleName(dateStyle.getStyleNameAttribute());
      Double value = getPercentageValue();
      if (value != null) {
        setDisplayText((new DecimalFormat(formatStr)).format(value.doubleValue()));
      }
    } else {
      throw new IllegalArgumentException("This function doesn't support " + typeValue + " cell.");
    }
  }

  private void setDataDisplayStyleName(String name) {
    OdfStyleBase styleElement = getCellStyleElementForWrite();
    if (styleElement != null) {
      styleElement.setOdfAttributeValue(OdfName.newName(OdfDocumentNamespace.STYLE, "data-style-name"), name);
    }
  }

  protected OdfStyle getCellStyleElement() {
    String styleName = mCellElement.getStyleName();
    if (styleName == null || (styleName.equals(""))) {  //search in row
      OdfTableRow aRow = getTableRow();
      styleName = aRow.getOdfElement().getTableDefaultCellStyleNameAttribute();
    }
    if (styleName == null || (styleName.equals(""))) {  //search in column
      OdfTableColumn aColumn = getTableColumn();
      styleName = aColumn.getOdfElement().getTableDefaultCellStyleNameAttribute();
    }
    if (styleName == null || (styleName.equals(""))) {
      return null;
    }

    OdfStyle styleElement = mCellElement.getAutomaticStyles().getStyle(styleName, mCellElement.getStyleFamily());

    if (styleElement == null) {
      styleElement = mDocument.getDocumentStyles().getStyle(styleName,
          OdfStyleFamily.TableCell);
    }

    if (styleElement == null) {
      styleElement = mCellElement.getDocumentStyle();
    }

    if (styleElement == null) {
      OdfStyle newStyle = mCellElement.getAutomaticStyles().newStyle(
          OdfStyleFamily.TableCell);
      String newname = newStyle.getStyleNameAttribute();
      mCellElement.setStyleName(newname);
      newStyle.addStyleUser(mCellElement);
      return newStyle;
    }

    return styleElement;
  }

  protected OdfStyle getCellStyleElementForWrite() {
    boolean copy = false;
    String styleName = mCellElement.getStyleName();
    if (styleName == null || (styleName.equals(""))) {  //search in row
      OdfTableRow aRow = getTableRow();
      styleName = aRow.getOdfElement().getTableDefaultCellStyleNameAttribute();
      copy = true;
    }
    if (styleName == null || (styleName.equals(""))) {  //search in column
      OdfTableColumn aColumn = getTableColumn();
      styleName = aColumn.getOdfElement().getTableDefaultCellStyleNameAttribute();
      copy = true;
    }
    if (styleName == null || (styleName.equals(""))) {
      return null;
    }

    OdfOfficeAutomaticStyles styles = mCellElement.getAutomaticStyles();
    OdfStyle styleElement = styles.getStyle(styleName, mCellElement.getStyleFamily());

    if (styleElement == null) {
      styleElement = mDocument.getDocumentStyles().getStyle(styleName, OdfStyleFamily.TableCell);
    }

    if (styleElement == null) {
      styleElement = mCellElement.getDocumentStyle();
    }

    if (styleElement.getStyleUserCount() > 1 || copy) //if this style are used by many users,
    //should create a new one.
    {
      OdfStyle newStyle = mCellElement.getAutomaticStyles().newStyle(OdfStyleFamily.TableCell);
      newStyle.setProperties(styleElement.getStylePropertiesDeep());
      //copy attributes
      NamedNodeMap attributes = styleElement.getAttributes();
      for (int i = 0; i < attributes.getLength(); i++) {
        Node attr = attributes.item(i);
        if (!attr.getNodeName().equals("style:name")) {
          newStyle.setAttributeNS(attr.getNamespaceURI(), attr.getNodeName(), attr.getNodeValue());
        }
      }//end of copying attributes
      //mCellElement.getAutomaticStyles().appendChild(newStyle);
      String newname = newStyle.getStyleNameAttribute();
      mCellElement.setStyleName(newname);
      return newStyle;
    }
    return styleElement;
  }

  private String getDataDisplayStyleName() {
    String datadisplayStylename = null;
    OdfStyleBase styleElement = getCellStyleElement();
    if (styleElement != null) {
      datadisplayStylename = styleElement.getOdfAttributeValue(OdfName.newName(OdfDocumentNamespace.STYLE, "data-style-name"));
    }

    return datadisplayStylename;
  }

  private String getUniqueNumberStyleName() {
    String unique_name;
    OdfOfficeAutomaticStyles styles = mCellElement.getAutomaticStyles();
    do {
      unique_name = String.format("n%06x", (int) (Math.random() * 0xffffff));
    } while (styles.getNumberStyle(unique_name) != null);
    return unique_name;
  }

  private String getUniqueDateStyleName() {
    String unique_name;
    OdfOfficeAutomaticStyles styles = mCellElement.getAutomaticStyles();
    do {
      unique_name = String.format("d%06x", (int) (Math.random() * 0xffffff));
    } while (styles.getDateStyle(unique_name) != null);
    return unique_name;
  }

  private String getUniquePercentageStyleName() {
    String unique_name;
    OdfOfficeAutomaticStyles styles = mCellElement.getAutomaticStyles();
    do {
      unique_name = String.format("p%06x", (int) (Math.random() * 0xffffff));
    } while (styles.getPercentageStyle(unique_name) != null);
    return unique_name;
  }

//    private String getUniqueCellStyleName() {
//      String unique_name;
//    OdfOfficeAutomaticStyles styles = mCellElement.getAutomaticStyles();
//      do {
//      unique_name = String.format("a%06x", (int) (Math.random() * 0xffffff));
//    } while (styles.getStyle(unique_name, OdfStyleFamily.TableCell) != null);
//      return unique_name;
//    } 
  private String getUniqueCurrencyStyleName() {
    String unique_name;
    OdfOfficeAutomaticStyles styles = mCellElement.getAutomaticStyles();
    do {
      unique_name = String.format("c%06x", (int) (Math.random() * 0xffffff));
    } while (styles.getCurrencyStyle(unique_name) != null);
    return unique_name;
  }

  /**
   * Get the format string of the cell.
   *
   * @return the format string of the cell
   */
  public String getFormatString() {
    String type = mCellElement.getOfficeValueTypeAttribute();
    OfficeValueTypeAttribute.Value typeValue = null;
    if (type != null) {
      typeValue = OfficeValueTypeAttribute.Value.enumValueOf(type);
    }

    if (typeValue == OfficeValueTypeAttribute.Value.FLOAT) {
      String name = getDataDisplayStyleName();
      OdfNumberStyle style = mCellElement.getAutomaticStyles().getNumberStyle(name);
      if (style == null) {
        style = mDocument.getDocumentStyles().getNumberStyle(name);
      }
      if (style != null) {
        return style.getFormat();
      }
    } else if (typeValue == OfficeValueTypeAttribute.Value.DATE) {
      String name = getDataDisplayStyleName();
      OdfNumberDateStyle style = mCellElement.getAutomaticStyles().getDateStyle(name);
      if (style == null) {
        style = mDocument.getDocumentStyles().getDateStyle(name);
      }
      if (style != null) {
        return style.getFormat();
      }
    } else if (typeValue == OfficeValueTypeAttribute.Value.CURRENCY) {
      String name = getCurrencyDisplayStyleName();
      OdfNumberCurrencyStyle dataStyle = mCellElement.getAutomaticStyles().getCurrencyStyle(name);
      if (dataStyle == null) {
        dataStyle = mDocument.getDocumentStyles().getCurrencyStyle(name);
      }
      if (dataStyle != null) {
        return dataStyle.getFormat();
      }
    } else if (typeValue == OfficeValueTypeAttribute.Value.PERCENTAGE) {
      String name = getDataDisplayStyleName();
      OdfNumberPercentageStyle style = mCellElement.getAutomaticStyles().getPercentageStyle(name);
      if (style == null) {
        style = mDocument.getDocumentStyles().getPercentageStyle(name);
      }
      if (style != null) {
        return style.getFormat();
      }
    }
    return null;
  }

  private String getCurrencyDisplayStyleName() {
    String name = getDataDisplayStyleName();
    OdfNumberCurrencyStyle dataStyle = mCellElement.getAutomaticStyles().getCurrencyStyle(name);
    if (dataStyle == null) {
      dataStyle = mDocument.getDocumentStyles().getCurrencyStyle(name);
    }

    if (dataStyle != null) {
      return dataStyle.getConditionStyleName(getCurrencyValue());
    }
    return null;
  }

  /**
   * Remove all the text content of cell.
   */
  public void removeTextContent() {
    splitRepeatedCells();
    //delete text:p child element
    Node node = mCellElement.getFirstChild();
    while (node != null) {
      Node nextNode = node.getNextSibling();
      if (node instanceof TextPElement
          || node instanceof TextHElement
          || node instanceof TextListElement) {
        mCellElement.removeChild(node);
      }
      node = nextNode;
    }
  }

  /**
   * Remove all the content of the cell.
   */
  public void removeContent() {
    splitRepeatedCells();
    Node node = mCellElement.getFirstChild();
    while (node != null) {
      Node nextNode = node.getNextSibling();
      mCellElement.removeChild(node);
      node = nextNode;
    }
  }

  /**
   * Append the content of another cell.
   *
   * @param fromCell  another cell whose content will be appended to this cell
   */
  void appendContentFrom(OdfTableCell fromCell) {
    splitRepeatedCells();
    OdfWhitespaceProcessor textProcess = new OdfWhitespaceProcessor();
    TableTableCellElementBase cell = fromCell.getOdfElement();
    Node node = cell.getFirstChild();
    while (node != null) {
      if (node instanceof OdfTextParagraph) {
        if (!textProcess.getText(node).equals("")) {
          mCellElement.appendChild(node.cloneNode(true));
        }
      } else {
        mCellElement.appendChild(node.cloneNode(true));
      }
      node = node.getNextSibling();
    }
  }

  /*****************************************
   * Moved from OdfTable
   *
   *******************************************/
  /**
   * This method is invoked by insertCellBefore and insertRowBefore
   * When it is needed to clone a cell and the cell is a cover cell,
   * for some instance, we need to find the cell who covers this cell.
   * So this method is to get the cell who covers this cell
   */
  OdfTableCell getCoverCell() {
    int startRowi = getRowIndex();
    int startColumni = getColumnIndex();

    for (int i = startRowi; i >= 0; i--) {
      OdfTableRow aRow = mOwnerTable.getRowByIndex(i);
      for (int j = startColumni; j >= 0; j--) {
        if (i == startRowi && j == startColumni) {
          continue;
        }
        OdfTableCell cell = aRow.getCellByIndex(j);
        if (cell.getOdfElement() instanceof TableTableCellElement) {
          TableTableCellElement cellEle = (TableTableCellElement) cell.getOdfElement();
          if ((cellEle.getTableNumberColumnsSpannedAttribute() + j > startColumni)
              && (cellEle.getTableNumberRowsSpannedAttribute() + i > startRowi)) {
            return mOwnerTable.getCellInstance(cellEle, 0, 0);
          }
        }
      }
    }
    return null;
  }

  /**
   * This method is invoked by getCoverCell.
   * It's to get the cell in a same row who covers this cell.
   *
   * @return the cell in a same row who covers this cell
   * <p>
   *         Null if there is no cell who covers this cell
   */
  OdfTableCell getCoverCellInSameRow() {
    int startRowi = getRowIndex();
    int startColumni = getColumnIndex();

    for (int j = startColumni - 1; j >= 0; j--) {
      OdfTableCell cell = mOwnerTable.getCellByPosition(j, startRowi);
      if (cell.getOdfElement() instanceof TableCoveredTableCellElement) {
        continue;
      }

      int oldSpanN = cell.getColumnSpannedNumber();
      if (oldSpanN + j > startColumni) {
        //cell.setColumnSpannedNumber(oldSpanN-1);
        return cell;
      }
      return null;
    }
    return null;
  }

  /**
   * This method is invoked by getCoverCell
   */
  OdfTableCell getCoverCellInSameColumn() {
    int startRowi = getRowIndex();
    int startColumni = getColumnIndex();

    for (int i = startRowi - 1; i >= 0; i--) {
      OdfTableCell cell = mOwnerTable.getCellByPosition(startColumni, i);
      if (cell.getOdfElement() instanceof TableCoveredTableCellElement) {
        continue;
      }

      int oldSpanN = cell.getRowSpannedNumber();
      if (oldSpanN + i > startRowi) {
        //cell.setRowSpannedNumber(oldSpanN-1);
        return cell;
      }
      return null;
    }
    return null;
  }
}
TOP

Related Classes of org.odftoolkit.odfdom.doc.table.OdfTableCell

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.