KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jxl > write > biff > MergedCells


1 /*********************************************************************
2  *
3  * Copyright (C) 2003 Andrew Khan
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  ***************************************************************************/

19
20 package jxl.write.biff;
21
22 import java.util.ArrayList JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.io.IOException JavaDoc;
25
26 import common.Assert;
27 import common.Logger;
28
29 import jxl.Range;
30 import jxl.Cell;
31 import jxl.CellType;
32 import jxl.write.WritableSheet;
33 import jxl.write.WriteException;
34 import jxl.write.Blank;
35 import jxl.biff.SheetRangeImpl;
36 import jxl.write.biff.File;
37 /**
38  * Contains all the merged cells, and the necessary logic for checking
39  * for intersections and for handling very large amounts of merging
40  */

41 class MergedCells
42 {
43   /**
44    * The logger
45    */

46   private static Logger logger = Logger.getLogger(MergedCells.class);
47
48   /**
49    * The list of merged cells
50    */

51   private ArrayList JavaDoc ranges;
52
53   /**
54    * The sheet containing the cells
55    */

56   private WritableSheet sheet;
57
58   /**
59    * The maximum number of ranges per sheet
60    */

61   private static final int maxRangesPerSheet = 1020;
62
63   /**
64    * Constructor
65    */

66   public MergedCells(WritableSheet ws)
67   {
68     ranges = new ArrayList JavaDoc();
69     sheet = ws;
70   }
71
72   /**
73    * Adds the range to the list of merged cells. Does no checking
74    * at this stage
75    *
76    * @param range the range to add
77    */

78   void add(Range r)
79   {
80     ranges.add(r);
81   }
82
83   /**
84    * Used to adjust the merged cells following a row insertion
85    */

86   void insertRow(int row)
87   {
88     // Adjust any merged cells
89
SheetRangeImpl sr = null;
90     Iterator JavaDoc i = ranges.iterator();
91     while (i.hasNext())
92     {
93       sr = (SheetRangeImpl) i.next();
94       sr.insertRow(row);
95     }
96   }
97
98   /**
99    * Used to adjust the merged cells following a column insertion
100    */

101   void insertColumn(int col)
102   {
103     SheetRangeImpl sr = null;
104     Iterator JavaDoc i = ranges.iterator();
105     while (i.hasNext())
106     {
107       sr = (SheetRangeImpl) i.next();
108       sr.insertColumn(col);
109     }
110   }
111
112   /**
113    * Used to adjust the merged cells following a column removal
114    */

115   void removeColumn(int col)
116   {
117     SheetRangeImpl sr = null;
118     Iterator JavaDoc i = ranges.iterator();
119     while (i.hasNext())
120     {
121       sr = (SheetRangeImpl) i.next();
122       if (sr.getTopLeft().getColumn() == col &&
123           sr.getBottomRight().getColumn() == col)
124       {
125         // The column with the merged cells on has been removed, so get
126
// rid of it from the list
127
ranges.remove(ranges.indexOf(sr));
128       }
129       else
130       {
131         sr.removeColumn(col);
132       }
133     }
134   }
135
136   /**
137    * Used to adjust the merged cells following a row removal
138    */

139   void removeRow(int row)
140   {
141     SheetRangeImpl sr = null;
142     Iterator JavaDoc i = ranges.iterator();
143     while (i.hasNext())
144     {
145       sr = (SheetRangeImpl) i.next();
146       if (sr.getTopLeft().getRow() == row &&
147           sr.getBottomRight().getRow() == row)
148       {
149         // The row with the merged cells on has been removed, so get
150
// rid of it from the list
151
i.remove();
152       }
153       else
154       {
155         sr.removeRow(row);
156       }
157     }
158   }
159
160   /**
161    * Gets the cells which have been merged on this sheet
162    *
163    * @return an array of range objects
164    */

165   Range[] getMergedCells()
166   {
167     Range[] cells = new Range[ranges.size()];
168
169     for (int i=0; i < cells.length; i++)
170     {
171       cells[i] = (Range) ranges.get(i);
172     }
173
174     return cells;
175   }
176
177   /**
178    * Unmerges the specified cells. The Range passed in should be one that
179    * has been previously returned as a result of the getMergedCells method
180    *
181    * @param r the range of cells to unmerge
182    */

183   void unmergeCells(Range r)
184   {
185     int index = ranges.indexOf(r);
186     
187     if (index != -1)
188     {
189       ranges.remove(index);
190     }
191   }
192
193   /**
194    * Called prior to writing out in order to check for intersections
195    */

196   void checkIntersections()
197   {
198     ArrayList JavaDoc newcells = new ArrayList JavaDoc(ranges.size());
199
200     for (Iterator JavaDoc mci = ranges.iterator(); mci.hasNext() ; )
201     {
202       SheetRangeImpl r = (SheetRangeImpl) mci.next();
203
204       // Check that the range doesn't intersect with any existing range
205
Iterator JavaDoc i = newcells.iterator();
206       SheetRangeImpl range = null;
207       boolean intersects = false;
208       while (i.hasNext() && !intersects)
209       {
210         range = (SheetRangeImpl) i.next();
211         
212         if (range.intersects(r))
213         {
214           logger.warn("Could not merge cells " + r +
215                       " as they clash with an existing set of merged cells.");
216
217           intersects = true;
218         }
219       }
220       
221       if (!intersects)
222       {
223         newcells.add(r);
224       }
225     }
226
227     ranges = newcells;
228   }
229
230   /**
231    * Checks the cell ranges for intersections, or if the merged cells
232    * contains more than one item of data
233    */

234   private void checkRanges()
235   {
236     try
237     {
238       SheetRangeImpl range = null;
239
240       // Check all the ranges to make sure they only contain one entry
241
for (int i = 0; i < ranges.size(); i++)
242       {
243         range = (SheetRangeImpl) ranges.get(i);
244
245         // Get the cell in the top left
246
Cell tl = range.getTopLeft();
247         Cell br = range.getBottomRight();
248         boolean found = false;
249
250         for (int c = tl.getColumn(); c <= br.getColumn(); c++)
251         {
252           for (int r = tl.getRow(); r <= br.getRow(); r++)
253           {
254             Cell cell = sheet.getCell(c, r);
255             if (cell.getType() != CellType.EMPTY)
256             {
257               if (!found)
258               {
259                 found = true;
260               }
261               else
262               {
263                 logger.warn("Range " + range +
264                             " contains more than one data cell. " +
265                             "Setting the other cells to blank.");
266                 Blank b = new Blank(c, r);
267                 sheet.addCell(b);
268               }
269             }
270           }
271         }
272       }
273     }
274     catch (WriteException e)
275     {
276       // This should already have been checked - bomb out
277
Assert.verify(false);
278     }
279   }
280
281   void write(File outputFile) throws IOException JavaDoc
282   {
283     if (ranges.size() == 0)
284     {
285       return;
286     }
287
288     checkIntersections();
289     checkRanges();
290
291     // If they will all fit into one record, then create a single
292
// record, write them and get out
293
if (ranges.size() < maxRangesPerSheet)
294     {
295       MergedCellsRecord mcr = new MergedCellsRecord(ranges);
296       outputFile.write(mcr);
297       return;
298     }
299
300     int numRecordsRequired = ranges.size() / maxRangesPerSheet + 1;
301     int pos = 0;
302
303     for (int i = 0 ; i < numRecordsRequired ; i++)
304     {
305       int numranges = Math.min(maxRangesPerSheet, ranges.size() - pos);
306
307       ArrayList JavaDoc cells = new ArrayList JavaDoc(numranges);
308       for (int j = 0 ; j < numranges ; j++)
309       {
310         cells.add(ranges.get(pos+j));
311       }
312
313       MergedCellsRecord mcr = new MergedCellsRecord(cells);
314       outputFile.write(mcr);
315
316       pos += numranges;
317     }
318   }
319 }
320
Popular Tags