KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*********************************************************************
2 *
3 * Copyright (C) 2002 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.Logger;
27 import jxl.CellType;
28 import jxl.write.Number;
29 import jxl.biff.Type;
30 import jxl.biff.WritableRecordData;
31 import jxl.biff.IntegerHelper;
32 import jxl.biff.XFRecord;
33 import jxl.biff.IndexMapping;
34 import jxl.biff.CellReferenceHelper;
35
36 /**
37  * Contains all the cells for a given row in a sheet
38  */

39 class RowRecord extends WritableRecordData
40 {
41   /**
42    * The logger
43    */

44   private static final Logger logger = Logger.getLogger(RowRecord.class);
45
46   /**
47    * The binary data
48    */

49   private byte[] data;
50   /**
51    * The cells which comprise this row
52    */

53   private CellValue[] cells;
54   /**
55    * The height of this row in 1/20ths of a point
56    */

57   private int rowHeight;
58   /**
59    * Flag to indicate whether this row is outline collapsed or not
60    */

61   private boolean collapsed;
62   /**
63    * The number of this row within the worksheet
64    */

65   private int rowNumber;
66   /**
67    * The number of columns in this row. This is the largest column value + 1
68    */

69   private int numColumns;
70   /**
71    * The xfIndex for this row
72    */

73   private int xfIndex;
74   /**
75    * The style for this row
76    */

77   private XFRecord style;
78   /**
79    * Flag indicating that this row record has an default format
80    */

81   private boolean defaultFormat;
82   /**
83    * Flag indicating whether this row matches the default font height
84    */

85   private boolean matchesDefFontHeight;
86   /**
87    * The amount to grow the cells array by
88    */

89   private static final int growSize = 10;
90
91   /**
92    * The maximum integer value that can be squeezed into 30 bits
93    */

94   private static final int maxRKValue = 0x1fffffff;
95
96   /**
97    * The minimum integer value that can be squeezed into 30 bits
98    */

99   private static final int minRKValue = -0x20000000;
100
101   /**
102    * Indicates that the row is default height
103    */

104   private static int defaultHeightIndicator = 0xff;
105
106   /**
107    * The maximum number of columns
108    */

109   private static int maxColumns = 256;
110
111
112   /**
113    * Constructs an empty row which has the specified row number
114    *
115    * @param rn the row number of this row
116    */

117   public RowRecord(int rn)
118   {
119     super(Type.ROW);
120     rowNumber = rn;
121     cells = new CellValue[0];
122     numColumns = 0;
123     rowHeight = defaultHeightIndicator;
124     collapsed = false;
125     matchesDefFontHeight = true;
126   }
127
128   /**
129    * Sets the height of this row
130    *
131    * @param h the row height
132    */

133   public void setRowHeight(int h)
134   {
135     if (h == 0)
136     {
137       setCollapsed(true);
138       matchesDefFontHeight = false;
139     }
140     else
141     {
142       rowHeight = h;
143       matchesDefFontHeight = false;
144     }
145   }
146
147   /**
148    * Sets the row details based upon the readable row record passed in
149    * Called when copying spreadsheets
150    *
151    * @param height the height of the row record in 1/20ths of a point
152    * @param mdfh matches the default font height
153    * @param col the collapsed status of the row
154    * @param xf the xfrecord for the row (NULL if no default is set)
155    */

156   void setRowDetails(int height, boolean mdfh, boolean col, XFRecord xfr)
157   {
158     rowHeight = height;
159     collapsed = col;
160     matchesDefFontHeight = mdfh;
161     
162     if (xfr != null)
163     {
164       defaultFormat = true;
165       style = xfr;
166       xfIndex = style.getXFIndex();
167     }
168   }
169
170   /**
171    * Sets the collapsed status of this row
172    *
173    * @param c the collapsed flag
174    */

175   public void setCollapsed(boolean c)
176   {
177     collapsed = c;
178   }
179   
180   /**
181    * Gets the row number of this row
182    *
183    * @return the row number
184    */

185   public int getRowNumber()
186   {
187     return rowNumber;
188   }
189
190   /**
191    * Adds a cell to this row, growing the array of cells as required
192    *
193    * @param cv the cell to add
194    */

195   public void addCell(CellValue cv)
196   {
197     int col = cv.getColumn();
198
199     if (col >= maxColumns)
200     {
201       logger.warn("Could not add cell at " +
202                   CellReferenceHelper.getCellReference(cv.getRow(),
203                                                        cv.getColumn()) +
204                   " because it exceeds the maximum column limit");
205       return;
206     }
207
208     // Grow the array if needs be
209
// Thanks to Brendan for spotting the flaw in merely adding on the
210
// grow size
211
if (col >= cells.length)
212     {
213       CellValue[] oldCells = cells;
214       cells = new CellValue[Math.max(oldCells.length + growSize, col+1)];
215       System.arraycopy(oldCells, 0, cells, 0, oldCells.length);
216       oldCells = null;
217     }
218
219     cells[col] = cv;
220
221     numColumns = Math.max(col+1, numColumns);
222   }
223
224   /**
225    * Removes a cell from this row
226    *
227    * @param col the column at which to remove the cell
228    */

229   public void removeCell(int col)
230   {
231     // Grow the array if needs be
232
if (col >= numColumns)
233     {
234       return;
235     }
236
237     cells[col] = null;
238   }
239
240   /**
241    * Writes out the row information data (but not the individual cells)
242    *
243    * @exception IOException
244    * @param outputFile the output file
245    */

246   public void write(File outputFile) throws IOException JavaDoc
247   {
248     outputFile.write(this);
249   }
250
251   /**
252    * Writes out all the cells in this row. If more than three integer
253    * values occur consecutively, then a MulRK record is used to group the
254    * numbers
255    *
256    * @exception IOException
257    * @param outputFile the output file
258    */

259   public void writeCells(File outputFile)
260     throws IOException JavaDoc
261   {
262     // This is the list for integer values
263
ArrayList JavaDoc integerValues = new ArrayList JavaDoc();
264     boolean integerValue = false;
265
266     // Write out all the records
267
for (int i = 0; i < numColumns; i++)
268     {
269       integerValue = false;
270       if (cells[i] != null)
271       {
272         // See if this cell is a 30-bit integer value (without additional
273
// cell features)
274
if (cells[i].getType() == CellType.NUMBER)
275         {
276           Number JavaDoc nc = (Number JavaDoc) cells[i];
277           if (nc.getValue() == (int) nc.getValue() &&
278               nc.getValue() < maxRKValue &&
279               nc.getValue() > minRKValue &&
280               nc.getCellFeatures() == null)
281           {
282             integerValue = true;
283           }
284         }
285
286         if (integerValue)
287         {
288           // This cell is an integer, add it to the list
289
integerValues.add(cells[i]);
290         }
291         else
292         {
293           // This cell is not an integer. Write out whatever integers we
294
// have, and then write out this cell
295
writeIntegerValues(integerValues, outputFile);
296           outputFile.write(cells[i]);
297
298           // If the cell is a string formula, write out the string record
299
// immediately afterwards
300
if (cells[i].getType() == CellType.STRING_FORMULA)
301           {
302             StringRecord sr = new StringRecord(cells[i].getContents());
303             outputFile.write(sr);
304           }
305         }
306       }
307       else
308       {
309         // Cell does not exist. Write out the list of integers that
310
// we have
311
writeIntegerValues(integerValues, outputFile);
312       }
313     }
314     
315     // All done. Write out any remaining integer values
316
writeIntegerValues(integerValues, outputFile);
317   }
318
319   /**
320    * Writes out the list of integer values. If there are more than three,
321    * a MulRK record is used, otherwise a sequence of Numbers is used
322    *
323    * @exception IOException
324    * @param outputFile the output file
325    * @param integerValues the array of integer values
326    */

327   private void writeIntegerValues(ArrayList JavaDoc integerValues, File outputFile)
328    throws IOException JavaDoc
329   {
330     if (integerValues.size() == 0)
331     {
332       return;
333     }
334
335     if (integerValues.size() >= 3 )
336     {
337       // Write out as a MulRK record
338
MulRKRecord mulrk = new MulRKRecord(integerValues);
339       outputFile.write(mulrk);
340     }
341     else
342     {
343       // Write out as number records
344
Iterator JavaDoc i = integerValues.iterator();
345       while (i.hasNext())
346       {
347         outputFile.write((CellValue) i.next());
348       }
349     }
350
351     // Clear out the list of integerValues
352
integerValues.clear();
353   }
354
355   /**
356    * Gets the row data to output to file
357    *
358    * @return the binary data
359    */

360   public byte[] getData()
361   {
362     // Write out the row record
363
byte[] data = new byte[16];
364     IntegerHelper.getTwoBytes(rowNumber, data, 0);
365     IntegerHelper.getTwoBytes(numColumns, data, 4);
366     IntegerHelper.getTwoBytes(rowHeight, data, 6);
367
368     int options = 0x100;
369
370     if (collapsed)
371     {
372       options |= 0x20;
373     }
374
375     if (!matchesDefFontHeight)
376     {
377       options |= 0x40;
378     }
379
380     if (defaultFormat)
381     {
382       options |= 0x80;
383       options |= (xfIndex << 16);
384     }
385
386     IntegerHelper.getFourBytes(options, data, 12);
387     
388     return data;
389   }
390
391   /**
392    * Gets the maximum column value which occurs in this row
393    *
394    * @return the maximum column value
395    */

396   public int getMaxColumn()
397   {
398     return numColumns;
399   }
400
401   /**
402    * Gets the cell which occurs at the specified column value
403    *
404    * @param col the colun for which to return the cell
405    * @return the cell value at the specified position, or null if the column
406    * is invalid
407    */

408   public CellValue getCell(int col)
409   {
410     return (col >= 0 && col < numColumns) ? cells[col] : null;
411   }
412
413   /**
414    * Increments the row of this cell by one. Invoked by the sheet when
415    * inserting rows
416    */

417   void incrementRow()
418   {
419     rowNumber++;
420
421     for (int i = 0; i < cells.length; i++)
422     {
423       if (cells[i] != null)
424       {
425         cells[i].incrementRow();
426       }
427     }
428   }
429
430   /**
431    * Decrements the row of this cell by one. Invoked by the sheet when
432    * removing rows
433    */

434   void decrementRow()
435   {
436     rowNumber--;
437     for (int i = 0; i < cells.length; i++)
438     {
439       if (cells[i] != null)
440       {
441         cells[i].decrementRow();
442       }
443     }
444   }
445
446   /**
447    * Inserts a new column at the position specified
448    *
449    * @param col the column to insert
450    */

451   void insertColumn(int col)
452   {
453     // Don't bother doing anything unless there are cells after the
454
// column to be inserted
455
if (col >= numColumns)
456     {
457       return;
458     }
459
460     if (numColumns >= maxColumns)
461     {
462       logger.warn("Could not insert column because maximum column limit has "+
463                   "been reached");
464       return;
465     }
466
467     // Create a new array to hold the new column. Grow it if need be
468
CellValue[] oldCells = cells;
469
470     if (numColumns >= cells.length - 1)
471     {
472       cells = new CellValue[oldCells.length + growSize];
473     }
474     else
475     {
476       cells = new CellValue[oldCells.length];
477     }
478
479     // Copy in everything up to the new column
480
System.arraycopy(oldCells, 0, cells, 0, col);
481     
482     // Copy in the remaining cells
483
System.arraycopy(oldCells, col, cells, col+1, numColumns - col);
484
485     // Increment all the internal column numbers by one
486
for (int i = col+1; i <= numColumns; i++)
487     {
488       if (cells[i] != null)
489       {
490         cells[i].incrementColumn();
491       }
492     }
493
494     // Adjust the maximum column record
495
numColumns++;
496   }
497
498   /**
499    * Remove the new column at the position specified
500    *
501    * @param col the column to remove
502    */

503   void removeColumn(int col)
504   {
505     // Don't bother doing anything unless there are cells after the
506
// column to be inserted
507
if (col >= numColumns)
508     {
509       return;
510     }
511
512     // Create a new array to hold the new columns
513
CellValue[] oldCells = cells;
514
515     cells = new CellValue[oldCells.length];
516
517     // Copy in everything up to the column
518
System.arraycopy(oldCells, 0, cells, 0, col);
519     
520     // Copy in the remaining cells after the column
521
System.arraycopy(oldCells, col + 1, cells, col, numColumns - (col+1));
522
523     // Decrement all the internal column numbers by one
524
for (int i = col; i < numColumns; i++)
525     {
526       if (cells[i] != null)
527       {
528         cells[i].decrementColumn();
529       }
530     }
531
532     // Adjust the maximum column record
533
numColumns--;
534   }
535
536   /**
537    * Interrogates whether this row is of default height
538    *
539    * @return TRUE if this is set to the default height, FALSE otherwise
540    */

541   public boolean isDefaultHeight()
542   {
543     return rowHeight == defaultHeightIndicator;
544   }
545
546   /**
547    * Gets the height of the row
548    *
549    * @return the row height
550    */

551   public int getRowHeight()
552   {
553     return rowHeight;
554   }
555
556   /**
557    * Queries whether the row is collapsed
558    *
559    * @return the collapsed indicator
560    */

561   public boolean isCollapsed()
562   {
563     return collapsed;
564   }
565
566   /**
567    * Rationalizes the sheets xf index mapping
568    * @param xfmapping the index mapping
569    */

570   void rationalize(IndexMapping xfmapping)
571   {
572     if (defaultFormat)
573     {
574       xfIndex = xfmapping.getNewIndex(xfIndex);
575     }
576   }
577
578   /**
579    * Accessor for the style. The returned value is only non-null if the
580    * default style is overridden
581    *
582    * @return the style
583    */

584   XFRecord getStyle()
585   {
586     return style;
587   }
588
589   /**
590    * Accessor for the default format flag
591    *
592    * @return TRUE if this row has its own default format
593    */

594   boolean hasDefaultFormat()
595   {
596     return defaultFormat;
597   }
598
599   /**
600    * Accessor for the matches default font height flag
601    *
602    * @return TRUE if this row matches the default font height
603    */

604   boolean matchesDefaultFontHeight()
605   {
606     return matchesDefFontHeight;
607   }
608 }
609
610
611
612
613
614
615
616
617
618
619
Popular Tags