All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.odftoolkit.simple.table.CellRange Maven / Gradle / Ivy

The newest version!
/* 
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

 http://www.apache.org/licenses/LICENSE-2.0

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.simple.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.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;
import org.odftoolkit.odfdom.dom.element.table.TableTableRowElement;
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.simple.Document;
import org.odftoolkit.simple.SpreadsheetDocument;

/**
 * CellRange represent a rang of cells that are adjacent with each other
 * 

* CellRange provides methods to get/set/modify the properties of cell range. */ public class CellRange { private int mnStartRow; private int mnStartColumn; private int mnEndRow; private int mnEndColumn; private String msCellRangeName; private Table maOwnerTable; private boolean mbSpreadsheet; /** * Construct the instance of CellRange. * @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. */ CellRange(Table table, int startColumn, int startRow, int endColumn, int endRow) { maOwnerTable = table; Document doc = (Document) ((OdfFileDom) maOwnerTable.getOdfElement().getOwnerDocument()).getDocument(); if (doc instanceof SpreadsheetDocument) { 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 coverList = maOwnerTable.getCellCoverInfos(0, 0, endColumn, endRow); Cell 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 */ CellRange() { } /** * Merge the current cell range to one cell */ public void merge() { Cell 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++) { Cell 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); Column 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++) { Cell 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")); Row parentRow = cellBase.getTableRow(); parentRow.getOdfElement().insertBefore(coveredCell, firstColumnCell); parentRow.getOdfElement().removeChild(firstColumnCell); } } } } List widthList = getCellRangeWidthList(); double nCellRangeWidth = widthList.get(widthList.size() - 1) - widthList.get(0); maOwnerTable.removeColumnsByIndex(mnStartColumn + 1, mnEndColumn - mnStartColumn); Column 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++) { Cell 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")); Row 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) { //first cell number columns repeated attribute may > 1. firstCell.splitRepeatedCells(); TableTableCellElement firstCellElement = (TableTableCellElement) (firstCell.getOdfElement()); firstCellElement.setTableNumberColumnsSpannedAttribute(mnEndColumn - mnStartColumn + 1); firstCellElement.setTableNumberRowsSpannedAttribute(mnEndRow - mnStartRow + 1); } //the other cell, set to the covered cell for (int i = mnStartRow; i < mnEndRow + 1; i++) { for (int j = mnStartColumn; j < mnEndColumn + 1; j++) { Cell 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")); TableTableRowElement parentRowEle = cellBase.getTableRow().getOdfElement(); parentRowEle.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(); int num = (mnEndColumn - j + 1) - repeatedNum; if (num >= 0) { if(repeatedNum > 1){ coveredCell.setTableNumberColumnsRepeatedAttribute(repeatedNum); } parentRowEle.removeChild(cell); } else { int tableNumberColumnsRepeatedValue = mnEndColumn - j + 1; if(tableNumberColumnsRepeatedValue > 1){ coveredCell.setTableNumberColumnsRepeatedAttribute(tableNumberColumnsRepeatedValue); } cell.setTableNumberColumnsRepeatedAttribute(-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(CellRange.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 getCellRangeWidthList() { List list = new ArrayList(); Double length = Double.valueOf(0.0); for (int i = 0; i < maOwnerTable.getColumnCount() - 1; i++) { Column col = maOwnerTable.getColumnByIndex(i); int repeateNum = col.getColumnsRepeatedNumber(); if (repeateNum == 1) { if (isColumnInCellRange(i)) { list.add(length); } length = Double.valueOf(length + col.getWidth()); } else { for (int j = 0; j < repeateNum; j++) { if (isColumnInCellRange(i + j)) { list.add(length); length = Double.valueOf(length + 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 getVeticalSplitCellRangeWidthList(int splitNum) { //get each cell in the cell range(the cell here means the real cell, not the covered cell) List coverList = maOwnerTable.getCellCoverInfos(mnStartColumn, mnStartRow, mnEndColumn, mnEndRow); //then get the real(uncovered) cell x coordinate List tmpList = new ArrayList(); List 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 Double width = widthList.get(i - mnStartColumn); if (!tmpList.contains(width)) { tmpList.add(width); } } } } //last, reorder the tmpVector and split it to splitNum between each item Double[] widthArray = (Double[]) tmpList.toArray(); Arrays.sort(widthArray); List rtnValues = new ArrayList(); double colWidth; double unitWidth; rtnValues.add(widthArray[0]); for (int i = 1; i < widthArray.length; i++) { colWidth = Double.valueOf(widthArray[i] - widthArray[i - 1]); unitWidth = colWidth / splitNum; for (int j = 1; j < splitNum; j++) { double eachWidth = unitWidth * j + widthArray[i - 1]; rtnValues.add(Double.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(CellRange.class.getName()).log(Level.SEVERE, null, ex); } } /** * Get the Table instance who contains this cell range. * @return the table that contains the cell range. */ public Table 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 Cell 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 Cell 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)); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy