1 /*
2  * $Id$
3  * $Name$
4  *
5  * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie.
6  *
7  * The contents of this file are subject to the Mozilla Public License Version 1.1
8  * (the "License"); you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at http://www.mozilla.org/MPL/
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the License.
14  *
15  * The Original Code is 'iText, a free JAVA-PDF library'.
16  *
17  * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
18  * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
19  * All Rights Reserved.
20  * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
21  * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
22  *
23  * Contributor(s): all the names of the contributors are added in the source code
24  * where applicable.
25  *
26  * Alternatively, the contents of this file may be used under the terms of the
27  * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
28  * provisions of LGPL are applicable instead of those above.  If you wish to
29  * allow use of your version of this file only under the terms of the LGPL
30  * License and not to allow others to use your version of this file under
31  * the MPL, indicate your decision by deleting the provisions above and
32  * replace them with the notice and other provisions required by the LGPL.
33  * If you do not delete the provisions above, a recipient may use your version
34  * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE
35  *
36  * This library is free software; you can redistribute it and/or modify it
37  * under the terms of the MPL as stated above or under the terms of the GNU
38  * Library General Public License as published by the Free Software Foundation;
39  * either version 2 of the License, or any later version.
40  *
41  * This library is distributed in the hope that it will be useful, but WITHOUT
42  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
43  * FOR A PARTICULAR PURPOSE. See the GNU LIBRARY GENERAL PUBLIC LICENSE for more
44  * details.
45  *
46  * If you didn't download this code from the following link, you should check if
47  * you aren't using an obsolete version:
48  * http://www.lowagie.com/iText/
49  */
50 
51 package com.lowagie.text;
52 
53 import java.util.ArrayList;
54 import com.lowagie.text.error_messages.MessageLocalization;
55 
56 /**
57  * A <CODE>Row</CODE> is part of a <CODE>Table</CODE>
58  * and contains some <CODE>Cells</CODE>.
59  * <P>
60  * All <CODE>Row</CODE>s are constructed by a <CODE>Table</CODE>-object.
61  * You don't have to construct any <CODE>Row</CODE> yourself.
62  * In fact you can't construct a <CODE>Row</CODE> outside the package.
63  * <P>
64  * Since a <CODE>Cell</CODE> can span several rows and/or columns
65  * a row can contain reserved space without any content.
66  *
67  * @see   Element
68  * @see   Cell
69  * @see   Table
70  */
71 public class Row implements Element {
72 
73     // constants
74 
75 	/** id of a null element in a Row*/
76     public static final int NULL = 0;
77 
78     /** id of the Cell element in a Row*/
79     public static final int CELL = 1;
80 
81     /** id of the Table element in a Row*/
82     public static final int TABLE = 2;
83 
84     // member variables
85 
86     /** This is the number of columns in the <CODE>Row</CODE>. */
87     protected int columns;
88 
89     /** This is a valid position the <CODE>Row</CODE>. */
90     protected int currentColumn;
91 
92     /** This is the array that keeps track of reserved cells. */
93     protected boolean[] reserved;
94 
95     /** This is the array of Objects (<CODE>Cell</CODE> or <CODE>Table</CODE>). */
96     protected Object[] cells;
97 
98     /** This is the vertical alignment. */
99     protected int horizontalAlignment;
100 
101     // constructors
102 
103     /**
104      * Constructs a <CODE>Row</CODE> with a certain number of <VAR>columns</VAR>.
105      *
106      * @param columns   a number of columns
107      */
Row(int columns)108     protected Row(int columns) {
109         this.columns = columns;
110         reserved = new boolean[columns];
111         cells = new Object[columns];
112         currentColumn = 0;
113     }
114 
115     // implementation of the Element-methods
116 
117     /**
118      * Processes the element by adding it (or the different parts) to a
119      * <CODE>ElementListener</CODE>.
120      *
121      * @param listener  an <CODE>ElementListener</CODE>
122      * @return  <CODE>true</CODE> if the element was processed successfully
123      */
process(ElementListener listener)124     public boolean process(ElementListener listener) {
125         try {
126             return listener.add(this);
127         }
128         catch(DocumentException de) {
129             return false;
130         }
131     }
132 
133     /**
134      * Gets the type of the text element.
135      *
136      * @return  a type
137      */
type()138     public int type() {
139         return Element.ROW;
140     }
141 
142     /**
143      * Gets all the chunks in this element.
144      *
145      * @return  an <CODE>ArrayList</CODE>
146      */
getChunks()147     public ArrayList getChunks() {
148         return new ArrayList();
149     }
150 
151 	/**
152 	 * @see com.lowagie.text.Element#isContent()
153 	 * @since	iText 2.0.8
154 	 */
isContent()155 	public boolean isContent() {
156 		return true;
157 	}
158 
159 	/**
160 	 * @see com.lowagie.text.Element#isNestable()
161 	 * @since	iText 2.0.8
162 	 */
isNestable()163 	public boolean isNestable() {
164 		return false;
165 	}
166 
167     // method to delete a column
168 
169     /**
170      * Returns a <CODE>Row</CODE> that is a copy of this <CODE>Row</CODE>
171      * in which a certain column has been deleted.
172      *
173      * @param column  the number of the column to delete
174      */
deleteColumn(int column)175     void deleteColumn(int column) {
176         if ((column >= columns) || (column < 0)) {
177             throw new IndexOutOfBoundsException(MessageLocalization.getComposedMessage("getcell.at.illegal.index.1", column));
178         }
179         columns--;
180         boolean newReserved[] = new boolean[columns];
181         Object newCells[] = new Cell[columns];
182 
183         for (int i = 0; i < column; i++) {
184             newReserved[i] = reserved[i];
185             newCells[i] = cells[i];
186             if (newCells[i] != null && (i + ((Cell) newCells[i]).getColspan() > column)) {
187                 ((Cell) newCells[i]).setColspan(((Cell) cells[i]).getColspan() - 1);
188             }
189         }
190         for (int i = column; i < columns; i++) {
191             newReserved[i] = reserved[i + 1];
192             newCells[i] = cells[i + 1];
193         }
194         if (cells[column] != null && ((Cell) cells[column]).getColspan() > 1) {
195             newCells[column] = cells[column];
196             ((Cell) newCells[column]).setColspan(((Cell) newCells[column]).getColspan() - 1);
197         }
198         reserved = newReserved;
199         cells = newCells;
200     }
201 
202     // methods
203 
204     /**
205      * Adds a <CODE>Cell</CODE> to the <CODE>Row</CODE>.
206      *
207      * @param       element the element to add (currently only Cells and Tables supported)
208      * @return      the column position the <CODE>Cell</CODE> was added,
209      *                      or <CODE>-1</CODE> if the <CODE>element</CODE> couldn't be added.
210      */
addElement(Object element)211     int addElement(Object element) {
212         return addElement(element, currentColumn);
213     }
214 
215     /**
216      * Adds an element to the <CODE>Row</CODE> at the position given.
217      *
218      * @param       element the element to add. (currently only Cells and Tables supported
219      * @param       column  the position where to add the cell.
220      * @return      the column position the <CODE>Cell</CODE> was added,
221      *                      or <CODE>-1</CODE> if the <CODE>Cell</CODE> couldn't be added.
222      */
addElement(Object element, int column)223     int addElement(Object element, int column) {
224         if (element == null) throw new NullPointerException(MessageLocalization.getComposedMessage("addcell.null.argument"));
225         if ((column < 0) || (column > columns)) throw new IndexOutOfBoundsException(MessageLocalization.getComposedMessage("addcell.illegal.column.argument"));
226         if ( !((getObjectID(element) == CELL) || (getObjectID(element) == TABLE)) ) throw new IllegalArgumentException(MessageLocalization.getComposedMessage("addcell.only.cells.or.tables.allowed"));
227 
228         int lColspan = ( (Cell.class.isInstance(element)) ? ((Cell) element).getColspan() : 1);
229 
230         if (!reserve(column, lColspan)) {
231             return -1;
232         }
233 
234         cells[column] = element;
235         currentColumn += lColspan - 1;
236 
237         return column;
238     }
239 
240     /**
241      * Puts <CODE>Cell</CODE> to the <CODE>Row</CODE> at the position given, doesn't reserve colspan.
242      *
243      * @param   aElement    the cell to add.
244      * @param   column  the position where to add the cell.
245      */
setElement(Object aElement, int column)246     void setElement(Object aElement, int column) {
247         if (reserved[column]) throw new IllegalArgumentException(MessageLocalization.getComposedMessage("setelement.position.already.taken"));
248 
249         cells[column] = aElement;
250         if (aElement != null) {
251             reserved[column] = true;
252         }
253     }
254 
255     /**
256      * Reserves a <CODE>Cell</CODE> in the <CODE>Row</CODE>.
257      *
258      * @param   column  the column that has to be reserved.
259      * @return  <CODE>true</CODE> if the column was reserved, <CODE>false</CODE> if not.
260      */
reserve(int column)261     boolean reserve(int column) {
262         return reserve(column, 1);
263     }
264 
265 
266     /**
267      * Reserves a <CODE>Cell</CODE> in the <CODE>Row</CODE>.
268      *
269      * @param   column  the column that has to be reserved.
270      * @param   size    the number of columns
271      * @return  <CODE>true</CODE> if the column was reserved, <CODE>false</CODE> if not.
272      */
reserve(int column, int size)273     boolean reserve(int column, int size) {
274         if ((column < 0) || ((column + size) > columns)) throw new IndexOutOfBoundsException(MessageLocalization.getComposedMessage("reserve.incorrect.column.size"));
275 
276         for(int i=column; i < column + size; i++)
277         {
278             if (reserved[i]) {
279                 // undo reserve
280                 for(int j=i; j >= column; j--) {
281                     reserved[j] = false;
282                 }
283                 return false;
284             }
285             reserved[i] = true;
286         }
287         return true;
288     }
289 
290     // methods to retrieve information
291 
292     /**
293      * Returns true/false when this position in the <CODE>Row</CODE> has been reserved, either filled or through a colspan of an Element.
294      *
295      * @param       column  the column.
296      * @return      <CODE>true</CODE> if the column was reserved, <CODE>false</CODE> if not.
297      */
isReserved(int column)298     boolean isReserved(int column) {
299         return reserved[column];
300     }
301 
302     /**
303      * Returns the type-id of the element in a Row.
304      *
305      * @param       column  the column of which you'd like to know the type
306      * @return the type-id of the element in the row
307      */
getElementID(int column)308     int getElementID(int column) {
309         if (cells[column] == null) return NULL;
310         else if (Cell.class.isInstance(cells[column])) return CELL;
311         else if (Table.class.isInstance(cells[column])) return TABLE;
312 
313         return -1;
314     }
315 
316     /**
317      * Returns the type-id of an Object.
318      *
319      * @param       element the object of which you'd like to know the type-id, -1 if invalid
320      * @return the type-id of an object
321      */
getObjectID(Object element)322     int getObjectID(Object element) {
323         if (element == null) return NULL;
324         else if (Cell.class.isInstance(element)) return CELL;
325         else if (Table.class.isInstance(element)) return TABLE;
326         return -1;
327     }
328 
329     /**
330      * Gets a <CODE>Cell</CODE> or <CODE>Table</CODE> from a certain column.
331      *
332      * @param   column  the column the <CODE>Cell/Table</CODE> is in.
333      * @return  the <CODE>Cell</CODE>,<CODE>Table</CODE> or <VAR>Object</VAR> if the column was
334      *                  reserved or null if empty.
335      */
getCell(int column)336     public Object getCell(int column) {
337         if ((column < 0) || (column > columns)) {
338             throw new IndexOutOfBoundsException(MessageLocalization.getComposedMessage("getcell.at.illegal.index.1.max.is.2", String.valueOf(column), String.valueOf(columns)));
339         }
340         return cells[column];
341     }
342 
343     /**
344      * Checks if the row is empty.
345      *
346      * @return  <CODE>true</CODE> if none of the columns is reserved.
347      */
isEmpty()348     public boolean isEmpty() {
349         for (int i = 0; i < columns; i++) {
350             if (cells[i] != null) {
351                 return false;
352             }
353         }
354         return true;
355     }
356 
357     /**
358      * Gets the number of columns.
359      *
360      * @return  a value
361      */
getColumns()362     public int getColumns() {
363         return columns;
364     }
365 
366     /**
367      * Sets the horizontal alignment.
368      *
369      * @param value the new value
370      */
setHorizontalAlignment(int value)371     public void setHorizontalAlignment(int value) {
372         horizontalAlignment = value;
373     }
374 
375     /**
376      * Gets the horizontal alignment.
377      *
378      * @return  a value
379      */
getHorizontalAlignment()380     public int getHorizontalAlignment() {
381         return horizontalAlignment;
382     }
383 }
384