123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- /*
- * 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.
- */
-
- /* $Id$ */
-
- package org.apache.fop.render.rtf.rtflib.rtfdoc;
-
- /*
- * This file is part of the RTF library of the FOP project, which was originally
- * created by Bertrand Delacretaz <bdelacretaz@codeconsult.ch> and by other
- * contributors to the jfor project (www.jfor.org), who agreed to donate jfor to
- * the FOP project.
- */
-
- import java.io.IOException;
- import java.io.Writer;
- import java.util.Collections;
- import java.util.LinkedList;
- import java.util.List;
-
-
- /**
- * <p>Used to add extra table rows after a row that contains a nested table:</p>
- * <ul>
- * <li> created by RtfTableRow before generating RTF code
- * <li> an RtfTableCell that contains a nested table can ask this to put
- * some of its children in extra rows that after the current row
- * <li> once RtfTableRow is done rendering its children, it renders this,
- * causing extra rows to be generated, with content that can come
- * from several RtfTableCells
- * </ul>
- *
- * <p>See org.apache.fop.rtf.rtflib.testdocs.NestedTable for an example of
- * usage.</p>
- *
- * <p>This work was authored by Bertrand Delacretaz (bdelacretaz@codeconsult.ch).</p>
- */
-
- public class RtfExtraRowSet extends RtfContainer {
- // TODO what is idnum?
- static final int DEFAULT_IDNUM = 0;
-
- /** Parent table context
- * (added by Boris Poudérous on july 2002 in order to process nested tables)
- */
- private ITableColumnsInfo parentITableColumnsInfo;
-
- /** While a top-level RtfTableRow is being rendered, we build a list of
- * RtfTableCells that must be rendered in extra rows.
- * This holds a cell with positioning information
- */
- private final List cells = new LinkedList();
- private static class PositionedCell
- implements Comparable {
- private final RtfTableCell cell;
- private final int xOffset;
- private final int rowIndex;
-
- PositionedCell(RtfTableCell c, int index, int offset) {
- cell = c;
- xOffset = offset;
- rowIndex = index;
- }
-
- /** debugging dump */
- public String toString() {
- return "PositionedCell: row " + rowIndex + ", offset " + xOffset;
- }
-
- /** cells need to be sorted by row index and then by x offset */
- public int compareTo(Object o) {
- int result = 0;
- if (o == null) {
- result = 1;
- } else if (!(o instanceof PositionedCell)) {
- result = 1;
- } else {
- final PositionedCell pc = (PositionedCell)o;
- if (this.rowIndex < pc.rowIndex) {
- result = -1;
- } else if (this.rowIndex > pc.rowIndex) {
- result = 1;
- } else if (this.xOffset < pc.xOffset) {
- result = -1;
- } else if (this.xOffset > pc.xOffset) {
- result = 1;
- }
- }
-
- return result;
- }
-
- public int hashCode() {
- int hc = super.hashCode();
- hc ^= (hc * 11) + xOffset;
- hc ^= (hc * 19) + rowIndex;
- return hc;
- }
-
- public boolean equals(Object o) {
- if (o instanceof PositionedCell) {
- PositionedCell pc = (PositionedCell) o;
- return (pc.rowIndex == rowIndex) && (pc.xOffset == xOffset);
- } else {
- return false;
- }
- }
- }
-
- /** our maximum row index */
- private int maxRowIndex;
-
- /** an RtfExtraRowSet has no parent, it is only used temporary during
- * generation of RTF for an RtfTableRow
- */
- RtfExtraRowSet(Writer w)
- throws IOException {
- super(null, w);
- }
-
- /** Add all cells of given Table to this set for later rendering in extra rows
- * @return index of extra row to use for elements that follow this table in the same cell
- * @param rowIndex index of first extra row to create to hold cells of tbl
- * @param xOffset horizontal position of left edge of first column of tbl
- */
- int addTable(RtfTable tbl, int rowIndex, int xOffset) {
- // process all rows of the table
- for (Object o : tbl.getChildren()) {
- final RtfElement e = (RtfElement) o;
- if (e instanceof RtfTableRow) {
- addRow((RtfTableRow) e, rowIndex, xOffset);
- rowIndex++;
- maxRowIndex = Math.max(rowIndex, maxRowIndex);
- }
- }
- return rowIndex;
- }
-
- /** add all cells of given row to this set */
- private void addRow(RtfTableRow row, int rowIndex, int xOffset) {
- for (Object o : row.getChildren()) {
- final RtfElement e = (RtfElement) o;
- if (e instanceof RtfTableCell) {
- final RtfTableCell c = (RtfTableCell) e;
- cells.add(new PositionedCell(c, rowIndex, xOffset));
- xOffset += c.getCellWidth();
- }
- }
- }
-
- /** create an extra cell to hold content that comes after a nested table in a cell
- * Modified by Boris Poudérous in order to permit the extra cell to have
- * the attributes of its parent cell
- */
- RtfTableCell createExtraCell(int rowIndex, int xOffset, int cellWidth,
- RtfAttributes parentCellAttributes)
- throws IOException {
- final RtfTableCell c = new RtfTableCell(null, writer, cellWidth,
- parentCellAttributes, DEFAULT_IDNUM);
- cells.add(new PositionedCell(c, rowIndex, xOffset));
- return c;
- }
-
- /**
- * render extra RtfTableRows containing all the extra RtfTableCells that we
- * contain
- * @throws IOException for I/O problems
- */
- protected void writeRtfContent() throws IOException {
- // sort cells by rowIndex and xOffset
- Collections.sort(cells);
-
- // process all extra cells by rendering them into extra rows
- List rowCells = null;
- int rowIndex = -1;
- for (Object cell : cells) {
- final PositionedCell pc = (PositionedCell) cell;
- if (pc.rowIndex != rowIndex) {
- // starting a new row, render previous one
- if (rowCells != null) {
- writeRow(rowCells);
- }
- rowIndex = pc.rowIndex;
- rowCells = new LinkedList();
- }
- rowCells.add(pc);
- }
-
- // render last row
- if (rowCells != null) {
- writeRow(rowCells);
- }
- }
-
- /** write one RtfTableRow containing given PositionedCells */
- private void writeRow(List cells)
- throws IOException {
- if (allCellsEmpty(cells)) {
- return;
- }
-
- final RtfTableRow row = new RtfTableRow(null, writer, DEFAULT_IDNUM);
- int cellIndex = 0;
-
- // Get the context of the table that holds the nested table
- ITableColumnsInfo parentITableColumnsInfo = getParentITableColumnsInfo();
- parentITableColumnsInfo.selectFirstColumn();
-
- // X offset of the current empty cell to add
- float xOffset = 0;
- float xOffsetOfLastPositionedCell = 0;
-
- for (Object cell : cells) {
- final PositionedCell pc = (PositionedCell) cell;
-
- // if first cell is not at offset 0, add placeholder cell
- // TODO should be merged with the cell that is above it
- if (cellIndex == 0 && pc.xOffset > 0) {
- /**
- * Added by Boris Poudérous
- */
- // Add empty cells merged vertically with the cells above and with the same widths
- // (BEFORE the cell that contains the nested table)
- for (int i = 0; (xOffset < pc.xOffset)
- && (i < parentITableColumnsInfo.getNumberOfColumns()); i++) {
- // Get the width of the cell above
- xOffset += parentITableColumnsInfo.getColumnWidth();
- // Create the empty cell merged vertically
- row.newTableCellMergedVertically((int) parentITableColumnsInfo.getColumnWidth(),
- pc.cell.attrib);
- // Select next column in order to have its width
- parentITableColumnsInfo.selectNextColumn();
- }
- }
-
- row.addChild(pc.cell);
- // Line added by Boris Poudérous
- xOffsetOfLastPositionedCell = pc.xOffset + pc.cell.getCellWidth();
- cellIndex++;
- }
-
- /**
- * Added by Boris Poudérous
- */
- // Add empty cells merged vertically with the cells above AFTER the cell
- // that contains the nested table
- // The cells added have the same widths than the cells above.
- if (parentITableColumnsInfo.getColumnIndex()
- < (parentITableColumnsInfo.getNumberOfColumns() - 1)) {
- parentITableColumnsInfo.selectNextColumn();
-
- while (parentITableColumnsInfo.getColumnIndex()
- < parentITableColumnsInfo.getNumberOfColumns()) {
- // Create the empty cell merged vertically
- // TODO : the new cells after the extra cell don't have its
- // attributes as we did for the previous cells.
- // => in fact the m_attrib below (last argument) is
- // empty => should be the attributes of the above cells.
- row.newTableCellMergedVertically((int)parentITableColumnsInfo.getColumnWidth(),
- attrib);
- // Select next column in order to have its width
- parentITableColumnsInfo.selectNextColumn();
- }
- }
-
- row.writeRtf();
- }
-
- /** true if all cells of given list are empty
- * @param cells List of PositionedCell objects
- */
- private static boolean allCellsEmpty(List cells) {
- boolean empty = true;
- for (Object cell : cells) {
- final PositionedCell pc = (PositionedCell) cell;
- if (pc.cell.containsText()) {
- empty = false;
- break;
- }
- }
- return empty;
- }
-
- /**
- * As this contains cells from several rows, we say that it's empty
- * only if we have no cells.
- * writeRow makes the decision about rendering specific rows
- * @return false (always)
- */
- public boolean isEmpty() {
- return false;
- }
-
- /**
- * @return The table context of the parent table
- * Added by Boris Poudérous on july 2002 in order to process nested tables
- */
- public ITableColumnsInfo getParentITableColumnsInfo() {
- return this.parentITableColumnsInfo;
- }
-
- /**
- *
- * @param parentITableColumnsInfo table context to set
- */
- public void setParentITableColumnsInfo(ITableColumnsInfo parentITableColumnsInfo) {
- this.parentITableColumnsInfo = parentITableColumnsInfo;
- }
- /** - end - */
- }
|