Update ooo320-m1
[ooovba.git] / oox / source / xls / pivotcachefragment.cxx
blob713e0ed3ac39d6d2c2f78a7280c321ecdaa0165d
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: pivotcachefragment.cxx,v $
10 * $Revision: 1.5 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "oox/xls/pivotcachefragment.hxx"
32 #include "oox/helper/attributelist.hxx"
33 #include "oox/helper/recordinputstream.hxx"
34 #include "oox/xls/addressconverter.hxx"
35 #include "oox/xls/biffinputstream.hxx"
36 #include "oox/xls/pivotcachebuffer.hxx"
38 using ::rtl::OUString;
39 using ::com::sun::star::uno::Any;
40 using ::oox::core::ContextHandlerRef;
41 using ::oox::core::RecordInfo;
43 namespace oox {
44 namespace xls {
46 // ============================================================================
48 OoxPivotCacheFieldContext::OoxPivotCacheFieldContext( OoxWorkbookFragmentBase& rFragment, PivotCacheField& rCacheField ) :
49 OoxWorkbookContextBase( rFragment ),
50 mrCacheField( rCacheField )
54 ContextHandlerRef OoxPivotCacheFieldContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
56 switch( getCurrentElement() )
58 case XLS_TOKEN( cacheField ):
59 if( nElement == XLS_TOKEN( sharedItems ) ) { mrCacheField.importSharedItems( rAttribs ); return this; }
60 if( nElement == XLS_TOKEN( fieldGroup ) ) { mrCacheField.importFieldGroup( rAttribs ); return this; }
61 break;
63 case XLS_TOKEN( fieldGroup ):
64 switch( nElement )
66 case XLS_TOKEN( rangePr ): mrCacheField.importRangePr( rAttribs ); break;
67 case XLS_TOKEN( discretePr ): return this;
68 case XLS_TOKEN( groupItems ): return this;
70 break;
72 case XLS_TOKEN( sharedItems ): mrCacheField.importSharedItem( nElement, rAttribs ); break;
73 case XLS_TOKEN( discretePr ): mrCacheField.importDiscretePrItem( nElement, rAttribs ); break;
74 case XLS_TOKEN( groupItems ): mrCacheField.importGroupItem( nElement, rAttribs ); break;
76 return 0;
79 void OoxPivotCacheFieldContext::onStartElement( const AttributeList& rAttribs )
81 if( isRootElement() )
82 mrCacheField.importCacheField( rAttribs );
85 ContextHandlerRef OoxPivotCacheFieldContext::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& rStrm )
87 switch( getCurrentElement() )
89 case OOBIN_ID_PCDFIELD:
90 switch( nRecId )
92 case OOBIN_ID_PCDFSHAREDITEMS: mrCacheField.importPCDFSharedItems( rStrm ); return this;
93 case OOBIN_ID_PCDFIELDGROUP: mrCacheField.importPCDFieldGroup( rStrm ); return this;
95 break;
97 case OOBIN_ID_PCDFIELDGROUP:
98 switch( nRecId )
100 case OOBIN_ID_PCDFRANGEPR: mrCacheField.importPCDFRangePr( rStrm ); break;
101 case OOBIN_ID_PCDFDISCRETEPR: return this;
102 case OOBIN_ID_PCDFGROUPITEMS: return this;
104 break;
106 case OOBIN_ID_PCDFSHAREDITEMS: mrCacheField.importPCDFSharedItem( nRecId, rStrm ); break;
107 case OOBIN_ID_PCDFDISCRETEPR: mrCacheField.importPCDFDiscretePrItem( nRecId, rStrm ); break;
108 case OOBIN_ID_PCDFGROUPITEMS: mrCacheField.importPCDFGroupItem( nRecId, rStrm ); break;
110 return 0;
113 void OoxPivotCacheFieldContext::onStartRecord( RecordInputStream& rStrm )
115 if( isRootElement() )
116 mrCacheField.importPCDField( rStrm );
119 // ============================================================================
121 OoxPivotCacheDefinitionFragment::OoxPivotCacheDefinitionFragment(
122 const WorkbookHelper& rHelper, const OUString& rFragmentPath, PivotCache& rPivotCache ) :
123 OoxWorkbookFragmentBase( rHelper, rFragmentPath ),
124 mrPivotCache( rPivotCache )
128 ContextHandlerRef OoxPivotCacheDefinitionFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
130 switch( getCurrentElement() )
132 case XML_ROOT_CONTEXT:
133 if( nElement == XLS_TOKEN( pivotCacheDefinition ) ) { mrPivotCache.importPivotCacheDefinition( rAttribs ); return this; }
134 break;
136 case XLS_TOKEN( pivotCacheDefinition ):
137 switch( nElement )
139 case XLS_TOKEN( cacheSource ): mrPivotCache.importCacheSource( rAttribs ); return this;
140 case XLS_TOKEN( cacheFields ): return this;
142 break;
144 case XLS_TOKEN( cacheSource ):
145 if( nElement == XLS_TOKEN( worksheetSource ) ) mrPivotCache.importWorksheetSource( rAttribs, getRelations() );
146 break;
148 case XLS_TOKEN( cacheFields ):
149 if( nElement == XLS_TOKEN( cacheField ) ) return new OoxPivotCacheFieldContext( *this, mrPivotCache.createCacheField() );
150 break;
152 return 0;
155 ContextHandlerRef OoxPivotCacheDefinitionFragment::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& rStrm )
157 switch( getCurrentElement() )
159 case XML_ROOT_CONTEXT:
160 if( nRecId == OOBIN_ID_PCDEFINITION ) { mrPivotCache.importPCDefinition( rStrm ); return this; }
161 break;
163 case OOBIN_ID_PCDEFINITION:
164 switch( nRecId )
166 case OOBIN_ID_PCDSOURCE: mrPivotCache.importPCDSource( rStrm ); return this;
167 case OOBIN_ID_PCDFIELDS: return this;
169 break;
171 case OOBIN_ID_PCDSOURCE:
172 if( nRecId == OOBIN_ID_PCDSHEETSOURCE ) mrPivotCache.importPCDSheetSource( rStrm, getRelations() );
173 break;
175 case OOBIN_ID_PCDFIELDS:
176 if( nRecId == OOBIN_ID_PCDFIELD ) return new OoxPivotCacheFieldContext( *this, mrPivotCache.createCacheField() );
177 break;
179 return 0;
182 const RecordInfo* OoxPivotCacheDefinitionFragment::getRecordInfos() const
184 static const RecordInfo spRecInfos[] =
186 { OOBIN_ID_PCDEFINITION, OOBIN_ID_PCDEFINITION + 1 },
187 { OOBIN_ID_PCDFDISCRETEPR, OOBIN_ID_PCDFDISCRETEPR + 1 },
188 { OOBIN_ID_PCDFGROUPITEMS, OOBIN_ID_PCDFGROUPITEMS + 1 },
189 { OOBIN_ID_PCDFIELD, OOBIN_ID_PCDFIELD + 1 },
190 { OOBIN_ID_PCDFIELDGROUP, OOBIN_ID_PCDFIELDGROUP + 1 },
191 { OOBIN_ID_PCDFIELDS, OOBIN_ID_PCDFIELDS + 1 },
192 { OOBIN_ID_PCDFRANGEPR, OOBIN_ID_PCDFRANGEPR + 1 },
193 { OOBIN_ID_PCDFSHAREDITEMS, OOBIN_ID_PCDFSHAREDITEMS + 1 },
194 { OOBIN_ID_PCITEM_ARRAY, OOBIN_ID_PCITEM_ARRAY + 1 },
195 { OOBIN_ID_PCDSHEETSOURCE, OOBIN_ID_PCDSHEETSOURCE + 1 },
196 { OOBIN_ID_PCDSOURCE, OOBIN_ID_PCDSOURCE + 1 },
197 { -1, -1 }
199 return spRecInfos;
202 void OoxPivotCacheDefinitionFragment::finalizeImport()
204 // finalize the cache (check source range etc.)
205 mrPivotCache.finalizeImport();
207 // load the cache records, if the cache is based on a deleted or an external worksheet
208 if( mrPivotCache.isValidDataSource() && mrPivotCache.isBasedOnDummySheet() )
210 OUString aRecFragmentPath = getRelations().getFragmentPathFromRelId( mrPivotCache.getRecordsRelId() );
211 if( aRecFragmentPath.getLength() > 0 )
212 importOoxFragment( new OoxPivotCacheRecordsFragment( *this, aRecFragmentPath, mrPivotCache ) );
216 // ============================================================================
218 OoxPivotCacheRecordsFragment::OoxPivotCacheRecordsFragment( const WorkbookHelper& rHelper,
219 const OUString& rFragmentPath, const PivotCache& rPivotCache ) :
220 OoxWorksheetFragmentBase( rHelper, rFragmentPath, ISegmentProgressBarRef(), SHEETTYPE_WORKSHEET, rPivotCache.getSourceRange().Sheet ),
221 mrPivotCache( rPivotCache ),
222 mnCol( 0 ),
223 mnRow( 0 ),
224 mbInRecord( false )
226 // prepare sheet: insert column header names into top row
227 rPivotCache.writeSourceHeaderCells( *this );
230 ContextHandlerRef OoxPivotCacheRecordsFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
232 switch( getCurrentElement() )
234 case XML_ROOT_CONTEXT:
235 if( nElement == XLS_TOKEN( pivotCacheRecords ) ) return this;
236 break;
238 case XLS_TOKEN( pivotCacheRecords ):
239 if( nElement == XLS_TOKEN( r ) ) { startCacheRecord(); return this; }
240 break;
242 case XLS_TOKEN( r ):
244 PivotCacheItem aItem;
245 switch( nElement )
247 case XLS_TOKEN( m ): break;
248 case XLS_TOKEN( s ): aItem.readString( rAttribs ); break;
249 case XLS_TOKEN( n ): aItem.readNumeric( rAttribs ); break;
250 case XLS_TOKEN( d ): aItem.readDate( rAttribs ); break;
251 case XLS_TOKEN( b ): aItem.readBool( rAttribs ); break;
252 case XLS_TOKEN( e ): aItem.readError( rAttribs, getUnitConverter() ); break;
253 case XLS_TOKEN( x ): aItem.readIndex( rAttribs ); break;
254 default: OSL_ENSURE( false, "OoxPivotCacheRecordsFragment::onCreateContext - unexpected element" );
256 mrPivotCache.writeSourceDataCell( *this, mnCol, mnRow, aItem );
257 ++mnCol;
259 break;
261 return 0;
264 ContextHandlerRef OoxPivotCacheRecordsFragment::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& rStrm )
266 switch( getCurrentElement() )
268 case XML_ROOT_CONTEXT:
269 if( nRecId == OOBIN_ID_PCRECORDS ) return this;
270 break;
272 case OOBIN_ID_PCRECORDS:
273 switch( nRecId )
275 case OOBIN_ID_PCRECORD: importPCRecord( rStrm ); break;
276 case OOBIN_ID_PCRECORDDT: startCacheRecord(); break;
277 default: importPCRecordItem( nRecId, rStrm ); break;
279 break;
281 return 0;
284 const RecordInfo* OoxPivotCacheRecordsFragment::getRecordInfos() const
286 static const RecordInfo spRecInfos[] =
288 { OOBIN_ID_PCRECORDS, OOBIN_ID_PCRECORDS + 1 },
289 { -1, -1 }
291 return spRecInfos;
294 // private --------------------------------------------------------------------
296 void OoxPivotCacheRecordsFragment::startCacheRecord()
298 mnCol = 0;
299 ++mnRow;
300 mbInRecord = true;
303 void OoxPivotCacheRecordsFragment::importPCRecord( RecordInputStream& rStrm )
305 startCacheRecord();
306 mrPivotCache.importPCRecord( rStrm, *this, mnRow );
307 mbInRecord = false;
310 void OoxPivotCacheRecordsFragment::importPCRecordItem( sal_Int32 nRecId, RecordInputStream& rStrm )
312 if( mbInRecord )
314 PivotCacheItem aItem;
315 switch( nRecId )
317 case OOBIN_ID_PCITEM_MISSING: break;
318 case OOBIN_ID_PCITEM_STRING: aItem.readString( rStrm ); break;
319 case OOBIN_ID_PCITEM_DOUBLE: aItem.readDouble( rStrm ); break;
320 case OOBIN_ID_PCITEM_DATE: aItem.readDate( rStrm ); break;
321 case OOBIN_ID_PCITEM_BOOL: aItem.readBool( rStrm ); break;
322 case OOBIN_ID_PCITEM_ERROR: aItem.readError( rStrm ); break;
323 case OOBIN_ID_PCITEM_INDEX: aItem.readIndex( rStrm ); break;
324 default: OSL_ENSURE( false, "OoxPivotCacheRecordsFragment::importPCRecordItem - unexpected record" );
326 mrPivotCache.writeSourceDataCell( *this, mnCol, mnRow, aItem );
327 ++mnCol;
331 // ============================================================================
332 // ============================================================================
334 namespace {
336 bool lclSeekToPCDField( BiffInputStream& rStrm )
338 sal_Int64 nRecHandle = rStrm.getRecHandle();
339 while( rStrm.startNextRecord() )
340 if( rStrm.getRecId() == BIFF_ID_PCDFIELD )
341 return true;
342 rStrm.startRecordByHandle( nRecHandle );
343 return false;
346 } // namespace
348 // ----------------------------------------------------------------------------
350 BiffPivotCacheFragment::BiffPivotCacheFragment(
351 const WorkbookHelper& rHelper, const ::rtl::OUString& rStrmName, PivotCache& rPivotCache ) :
352 BiffWorkbookFragmentBase( rHelper, rStrmName, true ),
353 mrPivotCache( rPivotCache )
357 bool BiffPivotCacheFragment::importFragment()
359 if( mrStrm.startNextRecord() && (mrStrm.getRecId() == BIFF_ID_PCDEFINITION) )
361 // read PCDEFINITION and optional PCDEFINITION2 records
362 mrPivotCache.importPCDefinition( mrStrm );
364 // read cache fields as long as another PCDFIELD record can be found
365 while( lclSeekToPCDField( mrStrm ) )
366 mrPivotCache.createCacheField( true ).importPCDField( mrStrm );
368 // finalize the cache (check source range etc.)
369 mrPivotCache.finalizeImport();
371 // load the cache records, if the cache is based on a deleted or an external worksheet
372 if( mrPivotCache.isValidDataSource() && mrPivotCache.isBasedOnDummySheet() )
374 /* Last call of lclSeekToPCDField() failed and kept stream position
375 unchanged. Stream should point to source data table now. */
376 BiffPivotCacheRecordsContext aContext( *this, mrPivotCache );
377 if( aContext.isValidSheet() )
378 while( mrStrm.startNextRecord() && (mrStrm.getRecId() != BIFF_ID_EOF) )
379 aContext.importRecord();
383 return mrStrm.getRecId() == BIFF_ID_EOF;
386 // ============================================================================
388 BiffPivotCacheRecordsContext::BiffPivotCacheRecordsContext(
389 const BiffWorkbookFragmentBase& rFragment, const PivotCache& rPivotCache ) :
390 BiffWorksheetContextBase( rFragment, ISegmentProgressBarRef(), SHEETTYPE_WORKSHEET, rPivotCache.getSourceRange().Sheet ),
391 mrPivotCache( rPivotCache ),
392 mnColIdx( 0 ),
393 mnRow( 0 ),
394 mbHasShared( false ),
395 mbInRow( false )
397 // prepare sheet: insert column header names into top row
398 mrPivotCache.writeSourceHeaderCells( *this );
400 // find all fields without shared items, remember column indexes in source data
401 for( sal_Int32 nFieldIdx = 0, nFieldCount = mrPivotCache.getCacheFieldCount(), nCol = 0; nFieldIdx < nFieldCount; ++nFieldIdx )
403 const PivotCacheField* pCacheField = mrPivotCache.getCacheField( nFieldIdx );
404 if( pCacheField && pCacheField->isDatabaseField() )
406 if( pCacheField->hasSharedItems() )
407 mbHasShared = true;
408 else
409 maUnsharedCols.push_back( nCol );
410 ++nCol;
415 void BiffPivotCacheRecordsContext::importRecord()
417 if( mrStrm.getRecId() == BIFF_ID_PCITEM_INDEXLIST )
419 OSL_ENSURE( mbHasShared, "BiffPivotCacheRecordsContext::importRecord - unexpected PCITEM_INDEXLIST record" );
420 // PCITEM_INDEXLIST record always in front of a new data row
421 startNextRow();
422 mrPivotCache.importPCItemIndexList( mrStrm, *this, mnRow );
423 mbInRow = !maUnsharedCols.empty(); // mbInRow remains true, if unshared items are expected
424 return;
427 PivotCacheItem aItem;
428 switch( mrStrm.getRecId() )
430 case BIFF_ID_PCITEM_MISSING: break;
431 case BIFF_ID_PCITEM_STRING: aItem.readString( mrStrm, *this ); break;
432 case BIFF_ID_PCITEM_DOUBLE: aItem.readDouble( mrStrm ); break;
433 case BIFF_ID_PCITEM_INTEGER: aItem.readInteger( mrStrm ); break;
434 case BIFF_ID_PCITEM_DATE: aItem.readDate( mrStrm ); break;
435 case BIFF_ID_PCITEM_BOOL: aItem.readBool( mrStrm ); break;
436 case BIFF_ID_PCITEM_ERROR: aItem.readError( mrStrm ); break;
437 default: return; // unknown record, ignore
440 // find next column index, might start new row if no fields with shared items exist
441 if( mbInRow && (mnColIdx == maUnsharedCols.size()) )
443 OSL_ENSURE( !mbHasShared, "BiffPivotCacheRecordsContext::importRecord - PCITEM_INDEXLIST record missing" );
444 mbInRow = mbHasShared; // do not leave current row if PCITEM_INDEXLIST is expected
446 // start next row on first call, or on row wrap without shared items
447 if( !mbInRow )
448 startNextRow();
450 // write the item data to the sheet cell
451 OSL_ENSURE( mnColIdx < maUnsharedCols.size(), "BiffPivotCacheRecordsContext::importRecord - invalid column index" );
452 if( mnColIdx < maUnsharedCols.size() )
453 mrPivotCache.writeSourceDataCell( *this, maUnsharedCols[ mnColIdx ], mnRow, aItem );
454 ++mnColIdx;
457 void BiffPivotCacheRecordsContext::startNextRow()
459 mnColIdx = 0;
460 ++mnRow;
461 mbInRow = true;
464 // ============================================================================
466 } // namespace xls
467 } // namespace oox