Package org.odftoolkit.odfdom.doc.table

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

/************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* Copyright 2009 IBM. All rights reserved.
*
* Use is subject to license terms.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0. You can also
* obtain a copy of the License at http://odftoolkit.org/docs/license.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*
************************************************************************/
package org.odftoolkit.odfdom.doc.table;

import java.util.ArrayList;
import java.util.Arrays;
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.pkg.OdfXMLFactory;
import org.odftoolkit.odfdom.doc.OdfDocument;
import org.odftoolkit.odfdom.doc.OdfSpreadsheetDocument;
import org.odftoolkit.odfdom.dom.OdfDocumentNamespace;
import org.odftoolkit.odfdom.dom.attribute.office.OfficeValueTypeAttribute;
import org.odftoolkit.odfdom.dom.element.table.TableCoveredTableCellElement;
import org.odftoolkit.odfdom.dom.element.table.TableNamedExpressionsElement;
import org.odftoolkit.odfdom.dom.element.table.TableNamedRangeElement;
import org.odftoolkit.odfdom.dom.element.table.TableTableCellElement;

/**
* OdfTableCellRange represent a rang of cells that are adjacent with each other
* <p>
* OdfTableCellRange provides methods to get/set/modify the properties of cell range.
*/
public class OdfTableCellRange {

  private int mnStartRow;
  private int mnStartColumn;
  private int mnEndRow;
  private int mnEndColumn;
  private String msCellRangeName;
  private OdfTable maOwnerTable;
  private boolean mbSpreadsheet;

  /**
   * Construct the instance of OdfTableCellRange.
   * @param table
   *           is the container table of this cell range.
   * @param startColumn
   *           is the column index of the first cell in this cell range.
   * @param startRow
   *           is the row index of the first cell in this cell range.
   * @param endColumn
   *           is the column index of the last cell in this cell range.
   * @param endRow
   *           is the row index of the last cell in this cell range.
   */
  OdfTableCellRange(OdfTable table, int startColumn, int startRow, int endColumn, int endRow) {
    maOwnerTable = table;

    OdfDocument doc = (OdfDocument) ((OdfFileDom) maOwnerTable.getOdfElement().getOwnerDocument()).getDocument();
    if (doc instanceof OdfSpreadsheetDocument) {
      mbSpreadsheet = true;
    }

    //the first cell is the covered cell, then the cell range should be enlarged
    //so that it can contains the complete cell
    //get the cell cover info
    mnStartColumn = startColumn;
    mnStartRow = startRow;
    mnEndColumn = endColumn;
    mnEndRow = endRow;
    List<CellCoverInfo> coverList = maOwnerTable.getCellCoverInfos(0, 0, maOwnerTable.getColumnCount() - 1, maOwnerTable.getRowCount() - 1);
    OdfTableCell cell;// = maOwnerTable.getOwnerCellByPosition(coverList, nStartColumn, nStartRow);
    for (int i = startColumn; i <= endColumn; i++) {
      cell = maOwnerTable.getOwnerCellByPosition(coverList, i, startRow);
      int rowIndex = cell.getRowIndex();
      int colIndex = cell.getColumnIndex();
      mnStartColumn = Math.min(mnStartColumn, colIndex);
      mnStartRow = Math.min(mnStartRow, rowIndex);
      mnEndColumn = Math.max(mnEndColumn, colIndex + cell.getColumnSpannedNumber() - 1);
      mnEndRow = Math.max(mnEndRow, rowIndex + cell.getRowSpannedNumber() - 1);
    }

    for (int i = startColumn; i <= endColumn; i++) {
      cell = maOwnerTable.getOwnerCellByPosition(coverList, i, endRow);
      int rowIndex = cell.getRowIndex();
      int colIndex = cell.getColumnIndex();
      mnStartColumn = Math.min(mnStartColumn, colIndex);
      mnStartRow = Math.min(mnStartRow, rowIndex);
      mnEndColumn = Math.max(mnEndColumn, colIndex + cell.getColumnSpannedNumber() - 1);
      mnEndRow = Math.max(mnEndRow, rowIndex + cell.getRowSpannedNumber() - 1);
    }

    for (int i = startRow + 1; i < endRow; i++) {
      cell = maOwnerTable.getOwnerCellByPosition(coverList, startColumn, i);
      int rowIndex = cell.getRowIndex();
      int colIndex = cell.getColumnIndex();
      mnStartColumn = Math.min(mnStartColumn, colIndex);
      mnStartRow = Math.min(mnStartRow, rowIndex);
      mnEndColumn = Math.max(mnEndColumn, colIndex + cell.getColumnSpannedNumber() - 1);
      mnEndRow = Math.max(mnEndRow, rowIndex + cell.getRowSpannedNumber() - 1);
    }

    for (int i = startRow + 1; i < endRow; i++) {
      cell = maOwnerTable.getOwnerCellByPosition(coverList, endColumn, i);
      int rowIndex = cell.getRowIndex();
      int colIndex = cell.getColumnIndex();
      mnStartColumn = Math.min(mnStartColumn, colIndex);
      mnStartRow = Math.min(mnStartRow, rowIndex);
      mnEndColumn = Math.max(mnEndColumn, colIndex + cell.getColumnSpannedNumber() - 1);
      mnEndRow = Math.max(mnEndRow, rowIndex + cell.getRowSpannedNumber() - 1);
    }
  }

  /**
   * construct the empty cellRange
   */
  OdfTableCellRange() {
  }

  /**
   * Merge the current cell range to one cell
   */
  public void merge() {
    OdfTableCell firstCell = maOwnerTable.getCellByPosition(mnStartColumn, mnStartRow);

    //note: after merge, the cell row/column count might  be changed
    int rowCount = maOwnerTable.getRowCount();
    int colCount = maOwnerTable.getColumnCount();
    //if the cell range is the whole table, then merge it to a big cell
    //as to the spreadsheet document, it should still keep the original cell count,
    //rather than merge to a big cell.
    if (rowCount == (mnEndRow - mnStartRow + 1)
        && colCount == (mnEndColumn - mnStartColumn + 1)
        && !mbSpreadsheet) {
      if (firstCell.getOdfElement() instanceof TableTableCellElement) {
        TableTableCellElement firstCellElement = (TableTableCellElement) (firstCell.getOdfElement());
        firstCellElement.removeAttributeNS(OdfDocumentNamespace.TABLE.getUri(), "number-columns-spanned");
        firstCellElement.removeAttributeNS(OdfDocumentNamespace.TABLE.getUri(), "number-rows-spanned");
        firstCellElement.setOfficeValueTypeAttribute(OfficeValueTypeAttribute.Value.STRING.toString());
      }
      //just copy the text of the other cells to this first cell
      for (int i = mnStartRow; i < mnEndRow + 1; i++) {
        for (int j = mnStartColumn; j < mnEndColumn + 1; j++) {
          OdfTableCell cellBase = maOwnerTable.getCellByPosition(j, i);
          if (j != mnStartColumn || i != mnStartRow) {
            //copy the content of this cell to the first cell
            firstCell.appendContentFrom(cellBase);
          }
        }
      }
      maOwnerTable.removeRowsByIndex(1, maOwnerTable.getRowCount() - 1);
      maOwnerTable.removeColumnsByIndex(1, maOwnerTable.getColumnCount() - 1);
      OdfTableColumn firstColumn = maOwnerTable.getColumnByIndex(0);
      firstColumn.setWidth(maOwnerTable.getWidth());
      mnEndRow = mnStartRow;
      mnEndColumn = mnStartColumn;
      return;
    } //if the cell range covered all the table row, and the merged column > 1
    //the merged column can be removed
    else if (rowCount == (mnEndRow - mnStartRow + 1)
        && colCount > (mnEndColumn - mnStartColumn + 1)
        && (mnEndColumn - mnStartColumn) > 0) {
      //the first cell, set the span attribute
      if (firstCell.getOdfElement() instanceof TableTableCellElement) {
        TableTableCellElement firstCellElement = (TableTableCellElement) (firstCell.getOdfElement());
        firstCellElement.removeAttributeNS(OdfDocumentNamespace.TABLE.getUri(), "number-columns-spanned");
        firstCellElement.setTableNumberRowsSpannedAttribute(Integer.valueOf(mnEndRow - mnStartRow + 1));
        firstCellElement.setOfficeValueTypeAttribute(OfficeValueTypeAttribute.Value.STRING.toString());
      }
      //the other cell, copy the content to first cell
      //if it is also in the first column of the cell range, set to the covered cell
      //other cell not in the first column will be removed when remove the column
      for (int i = mnStartRow; i < mnEndRow + 1; i++) {
        for (int j = mnStartColumn; j < mnEndColumn + 1; j++) {
          OdfTableCell cellBase = maOwnerTable.getCellByPosition(j, i);
          if (j != mnStartColumn || i != mnStartRow) {
            //append content to first cell
            firstCell.appendContentFrom(cellBase);
            //change the cell in the first column of cell range to covered cell
            if ((j == mnStartColumn) && (cellBase.getOdfElement() instanceof TableTableCellElement)) {
              //change the normal cell to be the covered cell
              TableTableCellElement firstColumnCell = (TableTableCellElement) cellBase.getOdfElement();
              TableCoveredTableCellElement coveredCell = (TableCoveredTableCellElement) OdfXMLFactory.newOdfElement(
                  (OdfFileDom) firstColumnCell.getOwnerDocument(),
                  OdfName.newName(OdfDocumentNamespace.TABLE, "covered-table-cell"));
              OdfTableRow parentRow = cellBase.getTableRow();
              parentRow.getOdfElement().insertBefore(coveredCell, firstColumnCell);
              parentRow.getOdfElement().removeChild(firstColumnCell);
            }
          }
        }
      }
      List<Long> widthList = getCellRangeWidthList();
      long nCellRangeWidth = widthList.get(widthList.size() - 1).longValue() - widthList.get(0).longValue();
      maOwnerTable.removeColumnsByIndex(mnStartColumn + 1, mnEndColumn - mnStartColumn);
      OdfTableColumn firstColumn = maOwnerTable.getColumnByIndex(mnStartColumn);
      firstColumn.setWidth(nCellRangeWidth);
      mnEndColumn = mnStartColumn;
      return;
    } //if the cell range covered all the table column, the merged row can be removed
    else if (rowCount > (mnEndRow - mnStartRow + 1)
        && colCount == (mnEndColumn - mnStartColumn + 1)
        && (mnEndRow - mnStartRow) > 0) {
      //the first cell, set the span attribute
      if (firstCell.getOdfElement() instanceof TableTableCellElement) {
        TableTableCellElement firstCellElement = (TableTableCellElement) (firstCell.getOdfElement());
        firstCellElement.removeAttributeNS(OdfDocumentNamespace.TABLE.getUri(), "number-rows-spanned");
        firstCellElement.setTableNumberColumnsSpannedAttribute(Integer.valueOf(mnEndColumn - mnStartColumn + 1));
        firstCellElement.setOfficeValueTypeAttribute(OfficeValueTypeAttribute.Value.STRING.toString());
      }
      //the other cell, copy the content to first cell
      //if it is also in the first row of the cell range, set to the covered cell
      //other cell not in the first row will be removed when remove the row
      for (int i = mnStartRow; i < mnEndRow + 1; i++) {
        for (int j = mnStartColumn; j < mnEndColumn + 1; j++) {
          OdfTableCell cellBase = maOwnerTable.getCellByPosition(j, i);
          if (j != mnStartColumn || i != mnStartRow) {
            //append content to first cell
            firstCell.appendContentFrom(cellBase);
            //change the cell in the first row of cell range to covered cell
            if ((i == mnStartRow) && (cellBase.getOdfElement() instanceof TableTableCellElement)) {
              //change the normal cell to be the covered cell
              TableTableCellElement firstRowCell = (TableTableCellElement) cellBase.getOdfElement();
              TableCoveredTableCellElement coveredCell = (TableCoveredTableCellElement) OdfXMLFactory.newOdfElement(
                  (OdfFileDom) firstRowCell.getOwnerDocument(),
                  OdfName.newName(OdfDocumentNamespace.TABLE, "covered-table-cell"));
              OdfTableRow parentRow = cellBase.getTableRow();
              parentRow.getOdfElement().insertBefore(coveredCell, firstRowCell);
              parentRow.getOdfElement().removeChild(firstRowCell);
            }
          }
        }
      }
      maOwnerTable.removeRowsByIndex(mnStartRow + 1, mnEndRow - mnStartRow);
      mnEndRow = mnStartRow;
      return;
    } //don't remove any row/column
    else {
      //first keep the column and row count in this cell range
      //the first cell, set the span attribute
      if (firstCell.getOdfElement() instanceof TableTableCellElement) {
        TableTableCellElement firstCellElement = (TableTableCellElement) (firstCell.getOdfElement());
        firstCellElement.setTableNumberColumnsSpannedAttribute(Integer.valueOf(mnEndColumn - mnStartColumn + 1));
        firstCellElement.setTableNumberRowsSpannedAttribute(Integer.valueOf(mnEndRow - mnStartRow + 1));
        firstCellElement.setOfficeValueTypeAttribute(OfficeValueTypeAttribute.Value.STRING.toString());
      }
      //the other cell, set to the covered cell
      for (int i = mnStartRow; i < mnEndRow + 1; i++) {
        for (int j = mnStartColumn; j < mnEndColumn + 1; j++) {
          OdfTableCell cellBase = maOwnerTable.getCellByPosition(j, i);
          if (j != mnStartColumn || i != mnStartRow) {
            if (cellBase.getOdfElement() instanceof TableTableCellElement) {
              //change the normal cell to be the covered cell
              TableTableCellElement cell = (TableTableCellElement) cellBase.getOdfElement();
              TableCoveredTableCellElement coveredCell = (TableCoveredTableCellElement) OdfXMLFactory.newOdfElement(
                  (OdfFileDom) cell.getOwnerDocument(),
                  OdfName.newName(OdfDocumentNamespace.TABLE, "covered-table-cell"));

              OdfTableRow parentRow = cellBase.getTableRow();
              parentRow.getOdfElement().insertBefore(coveredCell, cell);
              //copy the content of this cell to the first cell
              firstCell.appendContentFrom(cellBase);
              cellBase.removeContent();
              //set the table column repeated attribute
              int repeatedNum = cell.getTableNumberColumnsRepeatedAttribute().intValue();
              int num = (mnEndColumn - j + 1) - repeatedNum;
              if (num >= 0) {
                coveredCell.setTableNumberColumnsRepeatedAttribute(Integer.valueOf(repeatedNum));
                parentRow.getOdfElement().removeChild(cell);
              } else {
                coveredCell.setTableNumberColumnsRepeatedAttribute(new Integer(mnEndColumn - j + 1));
                cell.setTableNumberColumnsRepeatedAttribute(Integer.valueOf(-num));
              }

            } else if (cellBase.getOdfElement() instanceof TableCoveredTableCellElement) {
              try {
                //copy the content of this cell to the first cell
                firstCell.appendContentFrom(cellBase);
                cellBase.removeContent();
              } catch (Exception e) {
                Logger.getLogger(OdfTableCellRange.class.getName()).log(Level.SEVERE, e.getMessage(), e);
              }
            }
          }
        }
      }
    }
  }

  //vector store the x coordinate of each column which reference to the left start point of owner table
  //the returned value is all measured with "mm" unit
  private List<Long> getCellRangeWidthList() {
    List<Long> list = new ArrayList<Long>();
    Long length = Long.valueOf(0);
    for (int i = 0; i < maOwnerTable.getColumnCount() - 1; i++) {
      OdfTableColumn col = maOwnerTable.getColumnByIndex(i);
      int repeateNum = col.getColumnsRepeatedNumber();
      if (repeateNum == 1) {
        if (isColumnInCellRange(i)) {
          list.add(length);
        }
        length = Long.valueOf(length.longValue() + col.getWidth());
      } else {
        for (int j = 0; j < repeateNum; j++) {
          if (isColumnInCellRange(i + j)) {
            list.add(length);
            length = Long.valueOf(length.longValue() + col.getWidth());
          }
        }
        i += repeateNum - 1;
      }
    }
    //x coordinate of last column right point
    list.add(length);
    return list;
  }

  //vector store the x coordinate of each will split column start point
  List<Long> getVeticalSplitCellRangeWidthList(int splitNum) {
    //get each cell in the cell range(the cell here means the real cell, not the covered cell)
    List<CellCoverInfo> coverList = maOwnerTable.getCellCoverInfos(mnStartColumn, mnStartRow, mnEndColumn, mnEndRow);
    //then get the real(uncovered) cell x coordinate
    List<Long> tmpList = new ArrayList<Long>();
    List<Long> widthList = getCellRangeWidthList();
    for (int i = mnStartColumn; i < mnEndColumn + 1; i++) {
      for (int j = mnStartRow; j < mnEndRow + 1; j++) {
        if (maOwnerTable.isCoveredCellInOwnerTable(coverList, i, j)) {
          continue;
        } else {
          //the real cell, record the x coordinate of the left point
          Long width = widthList.get(i - mnStartColumn);
          if (!tmpList.contains(width)) {
            tmpList.add(width);
          }
        }
      }
    }

    //last, reorder the tmpVector and split it to splitNum between each item
    Long[] widthArray = (Long[]) tmpList.toArray();
    Arrays.sort(widthArray);
    List<Long> rtnValues = new ArrayList<Long>();
    Long colWidth;
    long unitWidth;
    rtnValues.add(widthArray[0]);
    for (int i = 1; i < widthArray.length; i++) {
      colWidth = Long.valueOf(widthArray[i].longValue() - widthArray[i - 1].longValue());
      unitWidth = colWidth.longValue() / splitNum;
      for (int j = 1; j < splitNum; j++) {
        long eachWidth = unitWidth * j + widthArray[i - 1].longValue();
        rtnValues.add(Long.valueOf(eachWidth));
      }
      rtnValues.add(widthArray[i]);
    }
    return rtnValues;
  }

  /**
   * Get the name of the named cell range.
   *
   * @return the name of the cell range
   */
  public String getCellRangeName() {
    return msCellRangeName;
  }

  /**
   * Set the name of the current cell range.
   *
   * @param cellRangeName  the name that need to set
   */
  public void setCellRangeName(String cellRangeName) {
    try {
      OdfElement contentRoot = maOwnerTable.mDocument.getContentRoot();
      //create name range element
      OdfFileDom contentDom = ((OdfFileDom) maOwnerTable.getOdfElement().getOwnerDocument());
      TableNamedExpressionsElement nameExpress = (TableNamedExpressionsElement) OdfXMLFactory.newOdfElement(
          contentDom,
          OdfName.newName(OdfDocumentNamespace.TABLE, "named-expressions"));
      String startCellRange = "$" + maOwnerTable.getTableName() + "." + maOwnerTable.getAbsoluteCellAddress(mnStartColumn, mnStartRow);
      String endCellRange = "$" + maOwnerTable.getTableName() + "." + maOwnerTable.getAbsoluteCellAddress(mnEndColumn, mnEndRow);
      TableNamedRangeElement nameRange = (TableNamedRangeElement) nameExpress.newTableNamedRangeElement(startCellRange + ":" + endCellRange, cellRangeName);
      nameRange.setTableBaseCellAddressAttribute(endCellRange);
      contentRoot.appendChild(nameExpress);
      msCellRangeName = cellRangeName;
    } catch (Exception ex) {
      Logger.getLogger(OdfTableCellRange.class.getName()).log(Level.SEVERE, null, ex);
    }

  }

  /**
   * Get the <code>OdfTable</code> instance who contains this cell range.
   * @return the table that contains the cell range.
   */
  public OdfTable getTable() {
    return maOwnerTable;
  }

  /**
   * Get the number of rows in this cell range.
   * @return rows number in the cell range
   */
  public int getRowNumber() {
    return (mnEndRow - mnStartRow + 1);
  }

  /**
   * Get the number of columns in this cell range.
   * @return columns number in the cell range
   */
  public int getColumnNumber() {
    return (mnEndColumn - mnStartColumn + 1);
  }

  /**
   * Returns a single cell that is positioned at specified column and row.
   * @param clmIndex  the column index of the cell inside the range.
   * @param rowIndex  the row index of the cell inside the range.
   * @return
   *         the cell at the specified position relative to the start position of the cell range
   * @throws IndexOutOfBoundsException if the column/row index is bigger than the column/row count
   */
  public OdfTableCell getCellByPosition(int clmIndex, int rowIndex) throws IndexOutOfBoundsException {
    return maOwnerTable.getCellByPosition(mnStartColumn + clmIndex, mnStartRow + rowIndex);
  }

  /**
   * Check if the given column in is this cell range.
   * @param colIndex 
   *           the given column index
   * @return true if the given column index is in the current cell range
   *
   */
  private boolean isColumnInCellRange(int colIndex) {
    if (colIndex < mnStartColumn || colIndex > mnEndColumn) {
      return false;
    } else {
      return true;
    }
  }

  /**
   * Returns a single cell that is positioned at specified cell address.
   *
   * @param address
   *         the cell address of the cell inside the range.
   * @return
   *         the cell at the specified cell address relative to the start position of the cell range
   */
  public OdfTableCell getCellByPosition(String address) {
    //if the address also contain the table name,  but the table is not the maOwnerTable
    //what should do? get the table then getcellByPosition?
    return getCellByPosition(maOwnerTable.getColIndexFromCellAddress(address), maOwnerTable.getRowIndexFromCellAddress(address));
  }
}
TOP

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

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.