KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > poi > hssf > record > aggregates > RowRecordsAggregate


1
2 /* ====================================================================
3    Copyright 2002-2004 Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16 ==================================================================== */

17
18
19 package org.apache.poi.hssf.record.aggregates;
20
21 import org.apache.poi.hssf.record.DBCellRecord;
22 import org.apache.poi.hssf.record.Record;
23 import org.apache.poi.hssf.record.RowRecord;
24
25 import java.util.Iterator JavaDoc;
26 import java.util.Map JavaDoc;
27 import java.util.TreeMap JavaDoc;
28
29 /**
30  *
31  * @author andy
32  * @author Jason Height (jheight at chariot dot net dot au)
33  */

34
35 public class RowRecordsAggregate
36     extends Record
37 {
38     int firstrow = -1;
39     int lastrow = -1;
40     Map JavaDoc records = null;
41     int size = 0;
42
43     /** Creates a new instance of ValueRecordsAggregate */
44
45     public RowRecordsAggregate()
46     {
47         records = new TreeMap JavaDoc();
48     }
49
50     public void insertRow(RowRecord row)
51     {
52         size += row.getRecordSize();
53
54         // Integer integer = new Integer(row.getRowNumber());
55
records.put(row, row);
56         if ((row.getRowNumber() < firstrow) || (firstrow == -1))
57         {
58             firstrow = row.getRowNumber();
59         }
60         if ((row.getRowNumber() > lastrow) || (lastrow == -1))
61         {
62             lastrow = row.getRowNumber();
63         }
64     }
65
66     public void removeRow(RowRecord row)
67     {
68         size -= row.getRecordSize();
69
70         // Integer integer = new Integer(row.getRowNumber());
71
records.remove(row);
72     }
73
74     public RowRecord getRow(int rownum)
75     {
76
77         // Integer integer = new Integer(rownum);
78
RowRecord row = new RowRecord();
79
80         row.setRowNumber(( short ) rownum);
81         return ( RowRecord ) records.get(row);
82     }
83
84     public int getPhysicalNumberOfRows()
85     {
86         return records.size();
87     }
88
89     public int getFirstRowNum()
90     {
91         return firstrow;
92     }
93
94     public int getLastRowNum()
95     {
96         return lastrow;
97     }
98     
99     /** Returns the number of row blocks.
100      * <p/>The row blocks are goupings of rows that contain the DBCell record
101      * after them
102      */

103     public int getRowBlockCount() {
104       int size = records.size()/DBCellRecord.BLOCK_SIZE;
105       if ((records.size() % DBCellRecord.BLOCK_SIZE) != 0)
106           size++;
107       return size;
108     }
109
110     public int getRowBlockSize(int block) {
111       return 20 * getRowCountForBlock(block);
112     }
113
114     /** Returns the number of physical rows within a block*/
115     public int getRowCountForBlock(int block) {
116       int startIndex = block * DBCellRecord.BLOCK_SIZE;
117       int endIndex = startIndex + DBCellRecord.BLOCK_SIZE - 1;
118       if (endIndex >= records.size())
119         endIndex = records.size()-1;
120
121       return endIndex-startIndex+1;
122     }
123
124     /** Returns the physical row number of the first row in a block*/
125     public int getStartRowNumberForBlock(int block) {
126       //JMH Given that we basically iterate through the rows in order,
127
//For a performance improvement, it would be better to return an instance of
128
//an iterator and use that instance throughout, rather than recreating one and
129
//having to move it to the right position.
130
int startIndex = block * DBCellRecord.BLOCK_SIZE;
131       Iterator JavaDoc rowIter = records.values().iterator();
132       RowRecord row = null;
133       //Position the iterator at the start of the block
134
for (int i=0; i<=startIndex;i++) {
135         row = (RowRecord)rowIter.next();
136       }
137
138       return row.getRowNumber();
139     }
140
141     /** Returns the physical row number of the end row in a block*/
142     public int getEndRowNumberForBlock(int block) {
143       int endIndex = ((block + 1)*DBCellRecord.BLOCK_SIZE)-1;
144       if (endIndex >= records.size())
145         endIndex = records.size()-1;
146
147       Iterator JavaDoc rowIter = records.values().iterator();
148       RowRecord row = null;
149       for (int i=0; i<=endIndex;i++) {
150         row = (RowRecord)rowIter.next();
151       }
152       return row.getRowNumber();
153     }
154
155
156     /** Serializes a block of the rows */
157     private int serializeRowBlock(final int block, final int offset, byte[] data) {
158       final int startIndex = block*DBCellRecord.BLOCK_SIZE;
159       final int endIndex = startIndex + DBCellRecord.BLOCK_SIZE;
160
161       Iterator JavaDoc rowIterator = records.values().iterator();
162       int pos = offset;
163
164       //JMH Given that we basically iterate through the rows in order,
165
//For a performance improvement, it would be better to return an instance of
166
//an iterator and use that instance throughout, rather than recreating one and
167
//having to move it to the right position.
168
int i=0;
169       for (;i<startIndex;i++)
170         rowIterator.next();
171       while(rowIterator.hasNext() && (i++ < endIndex)) {
172         RowRecord row = (RowRecord)rowIterator.next();
173         pos += row.serialize(pos, data);
174       }
175       return pos - offset;
176     }
177
178     public int serialize(int offset, byte [] data) {
179       throw new RuntimeException JavaDoc("The serialize method that passes in cells should be used");
180     }
181     
182
183     /**
184      * called by the class that is responsible for writing this sucker.
185      * Subclasses should implement this so that their data is passed back in a
186      * byte array.
187      *
188      * @param offset offset to begin writing at
189      * @param data byte array containing instance data
190      * @return number of bytes written
191      */

192
193     public int serialize(int offset, byte [] data, ValueRecordsAggregate cells)
194     {
195         int pos = offset;
196
197         //DBCells are serialized before row records.
198
final int blockCount = getRowBlockCount();
199         for (int block=0;block<blockCount;block++) {
200           //Serialize a block of rows.
201
//Hold onto the position of the first row in the block
202
final int rowStartPos = pos;
203           //Hold onto the size of this block that was serialized
204
final int rowBlockSize = serializeRowBlock(block, pos, data);
205           pos += rowBlockSize;
206           //Serialize a block of cells for those rows
207
final int startRowNumber = getStartRowNumberForBlock(block);
208           final int endRowNumber = getEndRowNumberForBlock(block);
209           DBCellRecord cellRecord = new DBCellRecord();
210           //Note: Cell references start from the second row...
211
int cellRefOffset = (rowBlockSize-20);
212           for (int row=startRowNumber;row<=endRowNumber;row++) {
213             if (cells.rowHasCells(row)) {
214               final int rowCellSize = cells.serializeCellRow(row, pos, data);
215               pos += rowCellSize;
216               //Add the offset to the first cell for the row into the DBCellRecord.
217
cellRecord.addCellOffset((short)cellRefOffset);
218               cellRefOffset = rowCellSize;
219             }
220           }
221           //Calculate Offset from the start of a DBCellRecord to the first Row
222
cellRecord.setRowOffset(pos - rowStartPos);
223           pos += cellRecord.serialize(pos, data);
224
225         }
226         return pos - offset;
227     }
228
229     /**
230      * called by the constructor, should set class level fields. Should throw
231      * runtime exception for bad/icomplete data.
232      *
233      * @param data raw data
234      * @param size size of data
235      * @param offset of the record's data (provided a big array of the file)
236      */

237
238     protected void fillFields(byte [] data, short size, int offset)
239     {
240     }
241
242     /**
243      * called by constructor, should throw runtime exception in the event of a
244      * record passed with a differing ID.
245      *
246      * @param id alleged id for this record
247      */

248
249     protected void validateSid(short id)
250     {
251     }
252
253     /**
254      * return the non static version of the id for this record.
255      */

256
257     public short getSid()
258     {
259         return -1000;
260     }
261
262     public int getRecordSize()
263     {
264         return size;
265     }
266
267     public Iterator JavaDoc getIterator()
268     {
269         return records.values().iterator();
270     }
271     
272     /**
273      * Performs a deep clone of the record
274      */

275     public Object JavaDoc clone()
276     {
277         RowRecordsAggregate rec = new RowRecordsAggregate();
278         for ( Iterator JavaDoc rowIter = getIterator(); rowIter.hasNext(); )
279         {
280             //return the cloned Row Record & insert
281
RowRecord row = (RowRecord) ( (RowRecord) rowIter.next() ).clone();
282             rec.insertRow( row );
283         }
284         return rec;
285     }
286
287
288     public int findStartOfRowOutlineGroup(int row)
289     {
290         // Find the start of the group.
291
RowRecord rowRecord = this.getRow( row );
292         int level = rowRecord.getOutlineLevel();
293         int currentRow = row;
294         while (this.getRow( currentRow ) != null)
295         {
296             rowRecord = this.getRow( currentRow );
297             if (rowRecord.getOutlineLevel() < level)
298                 return currentRow + 1;
299             currentRow--;
300         }
301
302         return currentRow + 1;
303     }
304
305     public int findEndOfRowOutlineGroup( int row )
306     {
307         int level = getRow( row ).getOutlineLevel();
308         int currentRow;
309         for (currentRow = row; currentRow < this.getLastRowNum(); currentRow++)
310         {
311             if (getRow(currentRow) == null || getRow(currentRow).getOutlineLevel() < level)
312             {
313                 break;
314             }
315         }
316
317         return currentRow-1;
318     }
319
320     public int writeHidden( RowRecord rowRecord, int row, boolean hidden )
321     {
322         int level = rowRecord.getOutlineLevel();
323         while (rowRecord != null && this.getRow(row).getOutlineLevel() >= level)
324         {
325             rowRecord.setZeroHeight( hidden );
326             row++;
327             rowRecord = this.getRow( row );
328         }
329         return row - 1;
330     }
331
332     public void collapseRow( int rowNumber )
333     {
334
335         // Find the start of the group.
336
int startRow = findStartOfRowOutlineGroup( rowNumber );
337         RowRecord rowRecord = (RowRecord) getRow( startRow );
338
339         // Hide all the columns until the end of the group
340
int lastRow = writeHidden( rowRecord, startRow, true );
341
342         // Write collapse field
343
if (getRow(lastRow + 1) != null)
344         {
345             getRow(lastRow + 1).setColapsed( true );
346         }
347         else
348         {
349             RowRecord row = createRow( lastRow + 1);
350             row.setColapsed( true );
351             insertRow( row );
352         }
353     }
354
355     /**
356      * Create a row record.
357      *
358      * @param row number
359      * @return RowRecord created for the passed in row number
360      * @see org.apache.poi.hssf.record.RowRecord
361      */

362     public static RowRecord createRow(int row)
363     {
364         RowRecord rowrec = new RowRecord();
365
366         //rowrec.setRowNumber(( short ) row);
367
rowrec.setRowNumber(row);
368         rowrec.setHeight(( short ) 0xff);
369         rowrec.setOptimize(( short ) 0x0);
370         rowrec.setOptionFlags(( short ) 0x100); // seems necessary for outlining
371
rowrec.setXFIndex(( short ) 0xf);
372         return rowrec;
373     }
374
375     public boolean isRowGroupCollapsed( int row )
376     {
377         int collapseRow = findEndOfRowOutlineGroup( row ) + 1;
378
379         if (getRow(collapseRow) == null)
380             return false;
381         else
382             return getRow( collapseRow ).getColapsed();
383     }
384
385     public void expandRow( int rowNumber )
386     {
387         int idx = rowNumber;
388         if (idx == -1)
389             return;
390
391         // If it is already expanded do nothing.
392
if (!isRowGroupCollapsed(idx))
393             return;
394
395         // Find the start of the group.
396
int startIdx = findStartOfRowOutlineGroup( idx );
397         RowRecord row = getRow( startIdx );
398
399         // Find the end of the group.
400
int endIdx = findEndOfRowOutlineGroup( idx );
401
402         // expand:
403
// colapsed bit must be unset
404
// hidden bit gets unset _if_ surrounding groups are expanded you can determine
405
// this by looking at the hidden bit of the enclosing group. You will have
406
// to look at the start and the end of the current group to determine which
407
// is the enclosing group
408
// hidden bit only is altered for this outline level. ie. don't uncollapse contained groups
409
if ( !isRowGroupHiddenByParent( idx ) )
410         {
411             for ( int i = startIdx; i <= endIdx; i++ )
412             {
413                 if ( row.getOutlineLevel() == getRow( i ).getOutlineLevel() )
414                     getRow( i ).setZeroHeight( false );
415                 else if (!isRowGroupCollapsed(i))
416                     getRow( i ).setZeroHeight( false );
417             }
418         }
419
420         // Write collapse field
421
getRow( endIdx + 1 ).setColapsed( false );
422     }
423
424     public boolean isRowGroupHiddenByParent( int row )
425     {
426         // Look out outline details of end
427
int endLevel;
428         boolean endHidden;
429         int endOfOutlineGroupIdx = findEndOfRowOutlineGroup( row );
430         if (getRow( endOfOutlineGroupIdx + 1 ) == null)
431         {
432             endLevel = 0;
433             endHidden = false;
434         }
435         else
436         {
437             endLevel = getRow( endOfOutlineGroupIdx + 1).getOutlineLevel();
438             endHidden = getRow( endOfOutlineGroupIdx + 1).getZeroHeight();
439         }
440
441         // Look out outline details of start
442
int startLevel;
443         boolean startHidden;
444         int startOfOutlineGroupIdx = findStartOfRowOutlineGroup( row );
445         if (startOfOutlineGroupIdx - 1 < 0 || getRow(startOfOutlineGroupIdx - 1) == null)
446         {
447             startLevel = 0;
448             startHidden = false;
449         }
450         else
451         {
452             startLevel = getRow( startOfOutlineGroupIdx - 1).getOutlineLevel();
453             startHidden = getRow( startOfOutlineGroupIdx - 1 ).getZeroHeight();
454         }
455
456         if (endLevel > startLevel)
457         {
458             return endHidden;
459         }
460         else
461         {
462             return startHidden;
463         }
464     }
465
466 }
467
468
Popular Tags