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

org.odftoolkit.odfdom.doc.table.OdfTableCellRange Maven / Gradle / Ivy

Go to download

ODFDOM is an OpenDocument Format (ODF) framework. Its purpose is to provide an easy common way to create, access and manipulate ODF files, without requiring detailed knowledge of the ODF specification. It is designed to provide the ODF developer community with an easy lightwork programming API portable to any object-oriented language. The current reference implementation is written in Java.

There is a newer version: 1.0.0-BETA1
Show 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.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.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; import org.odftoolkit.odfdom.pkg.OdfElement; import org.odftoolkit.odfdom.pkg.OdfFileDom; import org.odftoolkit.odfdom.pkg.OdfName; import org.odftoolkit.odfdom.pkg.OdfXMLFactory; /** * OdfTableCellRange represent a rang of cells that are adjacent with each other * *

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 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 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 getCellRangeWidthList() { List list = new ArrayList(); 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 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 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 rtnValues = new ArrayList(); 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 OdfTable 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)); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy