Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/jfor/jfor/rtflib/rtfdoc/RtfExtraRowSet.java


1   package org.jfor.jfor.rtflib.rtfdoc;
2   
3   import java.io.*;
4   import java.util.*;
5   import org.jfor.jfor.interfaces.ITableColumnsInfo;
6   
7   /*-----------------------------------------------------------------------------
8    * jfor - Open-Source XSL-FO to RTF converter - see www.jfor.org
9    *
10   * ====================================================================
11   * jfor Apache-Style Software License.
12   * Copyright (c) 2002 by the jfor project. All rights reserved.
13   *
14   * Redistribution and use in source and binary forms, with or without
15   * modification, are permitted provided that the following conditions
16   * are met:
17   *
18   * 1. Redistributions of source code must retain the above copyright
19   * notice, this list of conditions and the following disclaimer.
20   *
21   * 2. Redistributions in binary form must reproduce the above copyright
22   * notice, this list of conditions and the following disclaimer in
23   * the documentation and/or other materials provided with the
24   * distribution.
25   *
26   * 3. The end-user documentation included with the redistribution,
27   * if any, must include the following acknowledgment:
28   * "This product includes software developed
29   * by the jfor project (http://www.jfor.org)."
30   * Alternately, this acknowledgment may appear in the software itself,
31   * if and wherever such third-party acknowledgments normally appear.
32   *
33   * 4. The name "jfor" must not be used to endorse
34   * or promote products derived from this software without prior written
35   * permission.  For written permission, please contact info@jfor.org.
36   *
37   * 5. Products derived from this software may not be called "jfor",
38   * nor may "jfor" appear in their name, without prior written
39   * permission of info@jfor.org.
40   *
41   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
42   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
43   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
44   * DISCLAIMED.  IN NO EVENT SHALL THE JFOR PROJECT OR ITS CONTRIBUTORS BE
45   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
46   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
47   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
48   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
49   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
50   * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
51   * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52   * ====================================================================
53   * Contributor(s):
54  -----------------------------------------------------------------------------*/
55  
56  /**  Used to add extra table rows after a row that contains a nested table:
57   *  <li> created by RtfTableRow before generating RTF code
58   *  <li> an RtfTableCell that contains a nested table can ask this to put
59   *          some of its children in extra rows that after the current row
60   *  <li> once RtfTableRow is done rendering its children, it renders this,
61   *          causing extra rows to be generated, with content that can come
62   *          from several RtfTableCells
63   *
64   *  @see org.jfor.jfor.rtflib.testdoc.NestedTable
65   *  @author Bertrand Delacretaz bdelacretaz@codeconsult.ch
66   */
67  
68  //------------------------------------------------------------------------------
69  // $Id: RtfExtraRowSet.java,v 1.5 2002/08/12 09:40:03 bdelacretaz Exp $
70  // $Log: RtfExtraRowSet.java,v $
71  // Revision 1.5  2002/08/12 09:40:03  bdelacretaz
72  // V0.7.1dev-e, contributions from Boris Poudérous for number-columns-spanned
73  // and vertical merging of tables cells.
74  //
75  // Revision 1.4  2002/07/12 08:08:31  bdelacretaz
76  // License changed to jfor Apache-style license
77  //
78  // Revision 1.3  2001/12/28 17:08:50  bdelacretaz
79  // V0.5.2 - first integration of Chris Scott's changes
80  //
81  // Revision 1.2  2001/08/31 07:51:01  bdelacretaz
82  // MPL license text added + javadoc class comments corrected
83  //
84  // Revision 1.1  2001/08/29 13:27:51  bdelacretaz
85  // V0.4.1 - base package name changed to org.jfor.jfor
86  //
87  // Revision 1.4  2001/08/27 15:56:02  bdelacretaz
88  // V0.3.10 - isEmpty() added to RtfElement to avoid rendering empty containers
89  //
90  // Revision 1.3  2001/08/20 12:26:01  bdelacretaz
91  // V0.3.1, bug fixes:
92  // -single-space whitespace elements were not handled properly
93  // -missing list items after nested tables disappeared from RTF output
94  // -SectionBuilder now correctly processes fo:page-sequence instead of fo:root
95  //
96  // Revision 1.2  2001/08/16 14:12:12  bdelacretaz
97  // V0.3 - first version with nested tables support
98  //
99  // Revision 1.1  2001/08/16 11:54:49  bdelacretaz
100 // V0.2.3 - fo:external-graphic support added (written by Andreas Putz of skynamics)
101 //
102 //------------------------------------------------------------------------------
103 
104 public class RtfExtraRowSet extends RtfContainer {
105     // TODO what is idnum?
106     final int DEFAULT_IDNUM = 0;
107 
108     /** Parent table context
109      * (added by Boris Poudérous on july 2002 in order to process nested tables)
110      */
111     private ITableColumnsInfo parentITableColumnsInfo = null;
112 
113     /** While a top-level RtfTableRow is being rendered, we build a list of
114      *  RtfTableCells that must be rendered in extra rows.
115      *  This holds a cell with positioning information
116      */
117     private final List m_cells = new LinkedList();
118     private static class PositionedCell
119     implements Comparable {
120         final RtfTableCell cell;
121         final int xOffset;
122         final int rowIndex;
123 
124         PositionedCell(RtfTableCell c,int index,int offset) {
125             cell = c;
126             xOffset = offset;
127             rowIndex = index;
128         }
129 
130         /** debugging dump */
131         public String toString() {
132             return "PositionedCell: row " + rowIndex + ", offset " + xOffset;
133         }
134 
135         /** cells need to be sorted by row index and then by x offset */
136         public int compareTo(Object o) {
137             int result = 0;
138             if(o==null) {
139                 result = 1;
140             } else if( !(o instanceof PositionedCell)) {
141                 result = 1;
142             } else {
143                 final PositionedCell pc = (PositionedCell)o;
144                 if(this.rowIndex < pc.rowIndex) {
145                     result = -1;
146                 } else if(this.rowIndex > pc.rowIndex) {
147                     result = 1;
148                 } else if(this.xOffset < pc.xOffset) {
149                     result = -1;
150                 } else if(this.xOffset > pc.xOffset) {
151                     result = 1;
152                 }
153             }
154 
155             return result;
156         }
157 
158         public boolean equals(Object o) {
159             return o!=null && this.compareTo(o) == 0;
160         }
161     }
162 
163     /** our maximum row index */
164     private int m_maxRowIndex;
165 
166     /** an RtfExtraRowSet has no parent, it is only used temporary during
167      *  generation of RTF for an RtfTableRow
168      */
169     RtfExtraRowSet(Writer w)
170     throws IOException {
171         super(null,w);
172     }
173 
174     /** Add all cells of given Table to this set for later rendering in extra rows
175      *  @return index of extra row to use for elements that follow this table in the same cell
176      *  @param rowIndex index of first extra row to create to hold cells of tbl
177      *  @param xOffset horizontal position of left edge of first column of tbl
178      */
179     int addTable(RtfTable tbl,int rowIndex,int xOffset) {
180         // process all rows of the table
181         for(Iterator it = tbl.getChildren().iterator(); it.hasNext(); ) {
182             final RtfElement e = (RtfElement)it.next();
183             if(e instanceof RtfTableRow) {
184                 addRow((RtfTableRow)e,rowIndex,xOffset);
185                 rowIndex++;
186                 m_maxRowIndex = Math.max(rowIndex,m_maxRowIndex);
187             }
188         }
189         return rowIndex;
190     }
191 
192     /** add all cells of given row to this set */
193     private void addRow(RtfTableRow row,int rowIndex,int xOffset) {
194         for(Iterator it = row.getChildren().iterator(); it.hasNext(); ) {
195             final RtfElement e = (RtfElement)it.next();
196             if(e instanceof RtfTableCell) {
197                 final RtfTableCell c = (RtfTableCell)e;
198                 m_cells.add(new PositionedCell(c,rowIndex,xOffset));
199                 xOffset += c.getCellWidth();
200             }
201         }
202     }
203 
204     /** create an extra cell to hold content that comes after a nested table in a cell
205      *  Modified by Boris Poudérous in order to permit the extra cell to have the attributes of its parent cell
206      */
207     RtfTableCell createExtraCell(int rowIndex,int xOffset,int cellWidth,RtfAttributes parentCellAttributes)
208     throws IOException {
209         final RtfTableCell c = new RtfTableCell(null,m_writer,cellWidth,parentCellAttributes,DEFAULT_IDNUM);
210         m_cells.add(new PositionedCell(c,rowIndex,xOffset));
211         return c;
212     }
213 
214     /** render extra RtfTableRows containing all the extra RtfTableCells that we contain */
215     protected void writeRtfContent() throws IOException {
216         // sort cells by rowIndex and xOffset
217         Collections.sort(m_cells);
218 
219         // process all extra cells by rendering them into extra rows
220         List rowCells = null;
221         int rowIndex = -1;
222         for(Iterator it = m_cells.iterator(); it.hasNext(); ) {
223             final PositionedCell pc = (PositionedCell)it.next();
224             if(pc.rowIndex != rowIndex) {
225                 // starting a new row, render previous one
226                 if(rowCells!=null) writeRow(rowCells);
227                 rowIndex = pc.rowIndex;
228                 rowCells = new LinkedList();
229             }
230             rowCells.add(pc);
231         }
232 
233         // render last row
234         if(rowCells!=null) writeRow(rowCells);
235     }
236 
237     /** write one RtfTableRow containing given PositionedCells */
238     private void writeRow(List cells)
239     throws IOException {
240         if(allCellsEmpty(cells)) return;
241 
242         final RtfTableRow row = new RtfTableRow(null,m_writer,DEFAULT_IDNUM);
243         int cellIndex = 0;
244 
245         // Get the context of the table that holds the nested table
246         ITableColumnsInfo parentITableColumnsInfo = getParentITableColumnsInfo();
247         parentITableColumnsInfo.selectFirstColumn();
248 
249         // X offset of the current empty cell to add
250         float xOffset = 0;
251         float xOffsetOfLastPositionedCell = 0;
252 
253         for(Iterator it = cells.iterator(); it.hasNext(); ) {
254             final PositionedCell pc = (PositionedCell)it.next();
255 
256             // if first cell is not at offset 0, add placeholder cell
257             // TODO should be merged with the cell that is above it
258             if(cellIndex==0 && pc.xOffset > 0) {
259                /**
260                 * Added by Boris Poudérous
261                 */
262                // Add empty cells merged vertically with the cells above and with the same widths
263                // (BEFORE the cell that contains the nested table)
264                for (int i = 0; (xOffset < pc.xOffset) && (i < parentITableColumnsInfo.getNumberOfColumns()); i++) {
265                    // Get the width of the cell above
266                    xOffset += parentITableColumnsInfo.getColumnWidth();
267                    // Create the empty cell merged vertically
268                    row.newTableCellMergedVertically((int)parentITableColumnsInfo.getColumnWidth(), pc.cell.m_attrib);
269                    // Select next column in order to have its width
270                    parentITableColumnsInfo.selectNextColumn();
271                }
272             }
273 
274             row.addChild(pc.cell);
275             // Line added by Boris Poudérous
276             xOffsetOfLastPositionedCell = pc.xOffset + pc.cell.getCellWidth();
277             cellIndex++;
278         }
279 
280         /**
281          * Added by Boris Poudérous
282          */
283         // Add empty cells merged vertically with the cells above AFTER the cell that contains the nested table
284         // The cells added have the same widths than the cells above.
285         if (parentITableColumnsInfo.getColumnIndex() < (parentITableColumnsInfo.getNumberOfColumns() - 1))
286           {
287             parentITableColumnsInfo.selectNextColumn();
288 
289             while (parentITableColumnsInfo.getColumnIndex() < parentITableColumnsInfo.getNumberOfColumns())
290                 {
291                   // Create the empty cell merged vertically
292                   // TODO : the new cells after the extra cell don't have its attributes as we did for the previous cells.
293                   //        => in fact the m_attrib below (last argument) is empty => should be the attributes of the above cells.
294                   row.newTableCellMergedVertically((int)parentITableColumnsInfo.getColumnWidth(), m_attrib);
295                   // Select next column in order to have its width
296                   parentITableColumnsInfo.selectNextColumn();
297                 }
298            }
299 
300         row.writeRtf();
301     }
302 
303     /** true if all cells of given list are empty
304      *  @param cells List of PositionedCell objects
305      */
306     private static boolean allCellsEmpty(List cells) {
307         boolean empty = true;
308         for(Iterator it = cells.iterator(); it.hasNext(); ) {
309             final PositionedCell pc = (PositionedCell)it.next();
310             if(pc.cell.containsText()) {
311                 empty = false;
312                 break;
313             }
314         }
315         return empty;
316     }
317 
318     /** As this contains cells from several rows, we say that it's empty
319      *  only if we have no cells.
320      *  writeRow makes the decision about rendering specific rows
321      */
322     public boolean isEmpty() {
323         return false;
324     }
325 
326     /**
327      * @return The table context of the parent table
328      * Added by Boris Poudérous on july 2002 in order to process nested tables
329      */
330      public ITableColumnsInfo getParentITableColumnsInfo()
331      {
332        return this.parentITableColumnsInfo;
333      }
334 
335      public void setParentITableColumnsInfo (ITableColumnsInfo parentITableColumnsInfo)
336      {
337        this.parentITableColumnsInfo = parentITableColumnsInfo;
338      }
339      /** - end - */
340 }