Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "pivotcachefragment.hxx"
21 :
22 : #include "oox/helper/attributelist.hxx"
23 : #include "addressconverter.hxx"
24 : #include "biffinputstream.hxx"
25 : #include "pivotcachebuffer.hxx"
26 :
27 : namespace oox {
28 : namespace xls {
29 :
30 : using namespace ::com::sun::star::uno;
31 : using namespace ::oox::core;
32 :
33 :
34 0 : PivotCacheFieldContext::PivotCacheFieldContext( WorkbookFragmentBase& rFragment, PivotCacheField& rCacheField ) :
35 : WorkbookContextBase( rFragment ),
36 0 : mrCacheField( rCacheField )
37 : {
38 0 : }
39 :
40 0 : ContextHandlerRef PivotCacheFieldContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
41 : {
42 0 : switch( getCurrentElement() )
43 : {
44 : case XLS_TOKEN( cacheField ):
45 0 : if( nElement == XLS_TOKEN( sharedItems ) ) { mrCacheField.importSharedItems( rAttribs ); return this; }
46 0 : if( nElement == XLS_TOKEN( fieldGroup ) ) { mrCacheField.importFieldGroup( rAttribs ); return this; }
47 0 : break;
48 :
49 : case XLS_TOKEN( fieldGroup ):
50 0 : switch( nElement )
51 : {
52 0 : case XLS_TOKEN( rangePr ): mrCacheField.importRangePr( rAttribs ); break;
53 0 : case XLS_TOKEN( discretePr ): return this;
54 0 : case XLS_TOKEN( groupItems ): return this;
55 : }
56 0 : break;
57 :
58 0 : case XLS_TOKEN( sharedItems ): mrCacheField.importSharedItem( nElement, rAttribs ); break;
59 0 : case XLS_TOKEN( discretePr ): mrCacheField.importDiscretePrItem( nElement, rAttribs ); break;
60 0 : case XLS_TOKEN( groupItems ): mrCacheField.importGroupItem( nElement, rAttribs ); break;
61 : }
62 0 : return 0;
63 : }
64 :
65 0 : void PivotCacheFieldContext::onStartElement( const AttributeList& rAttribs )
66 : {
67 0 : if( isRootElement() )
68 0 : mrCacheField.importCacheField( rAttribs );
69 0 : }
70 :
71 0 : ContextHandlerRef PivotCacheFieldContext::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
72 : {
73 0 : switch( getCurrentElement() )
74 : {
75 : case BIFF12_ID_PCDFIELD:
76 0 : switch( nRecId )
77 : {
78 0 : case BIFF12_ID_PCDFSHAREDITEMS: mrCacheField.importPCDFSharedItems( rStrm ); return this;
79 0 : case BIFF12_ID_PCDFIELDGROUP: mrCacheField.importPCDFieldGroup( rStrm ); return this;
80 : }
81 0 : break;
82 :
83 : case BIFF12_ID_PCDFIELDGROUP:
84 0 : switch( nRecId )
85 : {
86 0 : case BIFF12_ID_PCDFRANGEPR: mrCacheField.importPCDFRangePr( rStrm ); break;
87 0 : case BIFF12_ID_PCDFDISCRETEPR: return this;
88 0 : case BIFF12_ID_PCDFGROUPITEMS: return this;
89 : }
90 0 : break;
91 :
92 0 : case BIFF12_ID_PCDFSHAREDITEMS: mrCacheField.importPCDFSharedItem( nRecId, rStrm ); break;
93 0 : case BIFF12_ID_PCDFDISCRETEPR: mrCacheField.importPCDFDiscretePrItem( nRecId, rStrm ); break;
94 0 : case BIFF12_ID_PCDFGROUPITEMS: mrCacheField.importPCDFGroupItem( nRecId, rStrm ); break;
95 : }
96 0 : return 0;
97 : }
98 :
99 0 : void PivotCacheFieldContext::onStartRecord( SequenceInputStream& rStrm )
100 : {
101 0 : if( isRootElement() )
102 0 : mrCacheField.importPCDField( rStrm );
103 0 : }
104 :
105 0 : PivotCacheDefinitionFragment::PivotCacheDefinitionFragment(
106 : const WorkbookHelper& rHelper, const OUString& rFragmentPath, PivotCache& rPivotCache ) :
107 : WorkbookFragmentBase( rHelper, rFragmentPath ),
108 0 : mrPivotCache( rPivotCache )
109 : {
110 0 : }
111 :
112 0 : ContextHandlerRef PivotCacheDefinitionFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
113 : {
114 0 : switch( getCurrentElement() )
115 : {
116 : case XML_ROOT_CONTEXT:
117 0 : if( nElement == XLS_TOKEN( pivotCacheDefinition ) ) { mrPivotCache.importPivotCacheDefinition( rAttribs ); return this; }
118 0 : break;
119 :
120 : case XLS_TOKEN( pivotCacheDefinition ):
121 0 : switch( nElement )
122 : {
123 0 : case XLS_TOKEN( cacheSource ): mrPivotCache.importCacheSource( rAttribs ); return this;
124 0 : case XLS_TOKEN( cacheFields ): return this;
125 : }
126 0 : break;
127 :
128 : case XLS_TOKEN( cacheSource ):
129 0 : if( nElement == XLS_TOKEN( worksheetSource ) ) mrPivotCache.importWorksheetSource( rAttribs, getRelations() );
130 0 : break;
131 :
132 : case XLS_TOKEN( cacheFields ):
133 0 : if( nElement == XLS_TOKEN( cacheField ) ) return new PivotCacheFieldContext( *this, mrPivotCache.createCacheField() );
134 0 : break;
135 : }
136 0 : return 0;
137 : }
138 :
139 0 : ContextHandlerRef PivotCacheDefinitionFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
140 : {
141 0 : switch( getCurrentElement() )
142 : {
143 : case XML_ROOT_CONTEXT:
144 0 : if( nRecId == BIFF12_ID_PCDEFINITION ) { mrPivotCache.importPCDefinition( rStrm ); return this; }
145 0 : break;
146 :
147 : case BIFF12_ID_PCDEFINITION:
148 0 : switch( nRecId )
149 : {
150 0 : case BIFF12_ID_PCDSOURCE: mrPivotCache.importPCDSource( rStrm ); return this;
151 0 : case BIFF12_ID_PCDFIELDS: return this;
152 : }
153 0 : break;
154 :
155 : case BIFF12_ID_PCDSOURCE:
156 0 : if( nRecId == BIFF12_ID_PCDSHEETSOURCE ) mrPivotCache.importPCDSheetSource( rStrm, getRelations() );
157 0 : break;
158 :
159 : case BIFF12_ID_PCDFIELDS:
160 0 : if( nRecId == BIFF12_ID_PCDFIELD ) return new PivotCacheFieldContext( *this, mrPivotCache.createCacheField() );
161 0 : break;
162 : }
163 0 : return 0;
164 : }
165 :
166 0 : const RecordInfo* PivotCacheDefinitionFragment::getRecordInfos() const
167 : {
168 : static const RecordInfo spRecInfos[] =
169 : {
170 : { BIFF12_ID_PCDEFINITION, BIFF12_ID_PCDEFINITION + 1 },
171 : { BIFF12_ID_PCDFDISCRETEPR, BIFF12_ID_PCDFDISCRETEPR + 1 },
172 : { BIFF12_ID_PCDFGROUPITEMS, BIFF12_ID_PCDFGROUPITEMS + 1 },
173 : { BIFF12_ID_PCDFIELD, BIFF12_ID_PCDFIELD + 1 },
174 : { BIFF12_ID_PCDFIELDGROUP, BIFF12_ID_PCDFIELDGROUP + 1 },
175 : { BIFF12_ID_PCDFIELDS, BIFF12_ID_PCDFIELDS + 1 },
176 : { BIFF12_ID_PCDFRANGEPR, BIFF12_ID_PCDFRANGEPR + 1 },
177 : { BIFF12_ID_PCDFSHAREDITEMS, BIFF12_ID_PCDFSHAREDITEMS + 1 },
178 : { BIFF12_ID_PCITEM_ARRAY, BIFF12_ID_PCITEM_ARRAY + 1 },
179 : { BIFF12_ID_PCDSHEETSOURCE, BIFF12_ID_PCDSHEETSOURCE + 1 },
180 : { BIFF12_ID_PCDSOURCE, BIFF12_ID_PCDSOURCE + 1 },
181 : { -1, -1 }
182 : };
183 0 : return spRecInfos;
184 : }
185 :
186 0 : void PivotCacheDefinitionFragment::finalizeImport()
187 : {
188 : // finalize the cache (check source range etc.)
189 0 : mrPivotCache.finalizeImport();
190 :
191 : // load the cache records, if the cache is based on a deleted or an external worksheet
192 0 : if( mrPivotCache.isValidDataSource() && mrPivotCache.isBasedOnDummySheet() )
193 : {
194 0 : OUString aRecFragmentPath = getRelations().getFragmentPathFromRelId( mrPivotCache.getRecordsRelId() );
195 0 : if( !aRecFragmentPath.isEmpty() )
196 : {
197 0 : sal_Int16 nSheet = mrPivotCache.getSourceRange().Sheet;
198 0 : WorksheetGlobalsRef xSheetGlob = WorksheetHelper::constructGlobals( *this, ISegmentProgressBarRef(), SHEETTYPE_WORKSHEET, nSheet );
199 0 : if( xSheetGlob.get() )
200 0 : importOoxFragment( new PivotCacheRecordsFragment( *xSheetGlob, aRecFragmentPath, mrPivotCache ) );
201 0 : }
202 : }
203 0 : }
204 :
205 0 : PivotCacheRecordsFragment::PivotCacheRecordsFragment( const WorksheetHelper& rHelper,
206 : const OUString& rFragmentPath, const PivotCache& rPivotCache ) :
207 : WorksheetFragmentBase( rHelper, rFragmentPath ),
208 : mrPivotCache( rPivotCache ),
209 : mnColIdx( 0 ),
210 : mnRowIdx( 0 ),
211 0 : mbInRecord( false )
212 : {
213 : // prepare sheet: insert column header names into top row
214 0 : rPivotCache.writeSourceHeaderCells( *this );
215 0 : }
216 :
217 0 : ContextHandlerRef PivotCacheRecordsFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
218 : {
219 0 : switch( getCurrentElement() )
220 : {
221 : case XML_ROOT_CONTEXT:
222 0 : if( nElement == XLS_TOKEN( pivotCacheRecords ) ) return this;
223 0 : break;
224 :
225 : case XLS_TOKEN( pivotCacheRecords ):
226 0 : if( nElement == XLS_TOKEN( r ) ) { startCacheRecord(); return this; }
227 0 : break;
228 :
229 : case XLS_TOKEN( r ):
230 : {
231 0 : PivotCacheItem aItem;
232 0 : switch( nElement )
233 : {
234 0 : case XLS_TOKEN( m ): break;
235 0 : case XLS_TOKEN( s ): aItem.readString( rAttribs ); break;
236 0 : case XLS_TOKEN( n ): aItem.readNumeric( rAttribs ); break;
237 0 : case XLS_TOKEN( d ): aItem.readDate( rAttribs ); break;
238 0 : case XLS_TOKEN( b ): aItem.readBool( rAttribs ); break;
239 0 : case XLS_TOKEN( e ): aItem.readError( rAttribs, getUnitConverter() ); break;
240 0 : case XLS_TOKEN( x ): aItem.readIndex( rAttribs ); break;
241 : default: OSL_FAIL( "OoxPivotCacheRecordsFragment::onCreateContext - unexpected element" );
242 : }
243 0 : mrPivotCache.writeSourceDataCell( *this, mnColIdx, mnRowIdx, aItem );
244 0 : ++mnColIdx;
245 : }
246 0 : break;
247 : }
248 0 : return 0;
249 : }
250 :
251 0 : ContextHandlerRef PivotCacheRecordsFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
252 : {
253 0 : switch( getCurrentElement() )
254 : {
255 : case XML_ROOT_CONTEXT:
256 0 : if( nRecId == BIFF12_ID_PCRECORDS ) return this;
257 0 : break;
258 :
259 : case BIFF12_ID_PCRECORDS:
260 0 : switch( nRecId )
261 : {
262 0 : case BIFF12_ID_PCRECORD: importPCRecord( rStrm ); break;
263 0 : case BIFF12_ID_PCRECORDDT: startCacheRecord(); break;
264 0 : default: importPCRecordItem( nRecId, rStrm ); break;
265 : }
266 0 : break;
267 : }
268 0 : return 0;
269 : }
270 :
271 0 : const RecordInfo* PivotCacheRecordsFragment::getRecordInfos() const
272 : {
273 : static const RecordInfo spRecInfos[] =
274 : {
275 : { BIFF12_ID_PCRECORDS, BIFF12_ID_PCRECORDS + 1 },
276 : { -1, -1 }
277 : };
278 0 : return spRecInfos;
279 : }
280 :
281 : // private --------------------------------------------------------------------
282 :
283 0 : void PivotCacheRecordsFragment::startCacheRecord()
284 : {
285 0 : mnColIdx = 0;
286 0 : ++mnRowIdx;
287 0 : mbInRecord = true;
288 0 : }
289 :
290 0 : void PivotCacheRecordsFragment::importPCRecord( SequenceInputStream& rStrm )
291 : {
292 0 : startCacheRecord();
293 0 : mrPivotCache.importPCRecord( rStrm, *this, mnRowIdx );
294 0 : mbInRecord = false;
295 0 : }
296 :
297 0 : void PivotCacheRecordsFragment::importPCRecordItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
298 : {
299 0 : if( mbInRecord )
300 : {
301 0 : PivotCacheItem aItem;
302 0 : switch( nRecId )
303 : {
304 0 : case BIFF12_ID_PCITEM_MISSING: break;
305 0 : case BIFF12_ID_PCITEM_STRING: aItem.readString( rStrm ); break;
306 0 : case BIFF12_ID_PCITEM_DOUBLE: aItem.readDouble( rStrm ); break;
307 0 : case BIFF12_ID_PCITEM_DATE: aItem.readDate( rStrm ); break;
308 0 : case BIFF12_ID_PCITEM_BOOL: aItem.readBool( rStrm ); break;
309 0 : case BIFF12_ID_PCITEM_ERROR: aItem.readError( rStrm ); break;
310 0 : case BIFF12_ID_PCITEM_INDEX: aItem.readIndex( rStrm ); break;
311 : default: OSL_FAIL( "OoxPivotCacheRecordsFragment::importPCRecordItem - unexpected record" );
312 : }
313 0 : mrPivotCache.writeSourceDataCell( *this, mnColIdx, mnRowIdx, aItem );
314 0 : ++mnColIdx;
315 : }
316 0 : }
317 :
318 :
319 : namespace {
320 :
321 0 : bool lclSeekToPCDField( BiffInputStream& rStrm )
322 : {
323 0 : sal_Int64 nRecHandle = rStrm.getRecHandle();
324 0 : while( rStrm.startNextRecord() )
325 0 : if( rStrm.getRecId() == BIFF_ID_PCDFIELD )
326 0 : return true;
327 0 : rStrm.startRecordByHandle( nRecHandle );
328 0 : return false;
329 : }
330 :
331 : } // namespace
332 :
333 0 : BiffPivotCacheFragment::BiffPivotCacheFragment(
334 : const WorkbookHelper& rHelper, const OUString& rStrmName, PivotCache& rPivotCache ) :
335 : BiffWorkbookFragmentBase( rHelper, rStrmName, true ),
336 0 : mrPivotCache( rPivotCache )
337 : {
338 0 : }
339 :
340 0 : bool BiffPivotCacheFragment::importFragment()
341 : {
342 0 : BiffInputStream& rStrm = getInputStream();
343 0 : if( rStrm.startNextRecord() && (rStrm.getRecId() == BIFF_ID_PCDEFINITION) )
344 : {
345 : // read PCDEFINITION and optional PCDEFINITION2 records
346 0 : mrPivotCache.importPCDefinition( rStrm );
347 :
348 : // read cache fields as long as another PCDFIELD record can be found
349 0 : while( lclSeekToPCDField( rStrm ) )
350 0 : mrPivotCache.createCacheField( true ).importPCDField( rStrm );
351 :
352 : // finalize the cache (check source range etc.)
353 0 : mrPivotCache.finalizeImport();
354 :
355 : // load the cache records, if the cache is based on a deleted or an external worksheet
356 0 : if( mrPivotCache.isValidDataSource() && mrPivotCache.isBasedOnDummySheet() )
357 : {
358 : /* Last call of lclSeekToPCDField() failed and kept stream position
359 : unchanged. Stream should point to source data table now. */
360 0 : sal_Int16 nSheet = mrPivotCache.getSourceRange().Sheet;
361 0 : WorksheetGlobalsRef xSheetGlob = WorksheetHelper::constructGlobals( *this, ISegmentProgressBarRef(), SHEETTYPE_WORKSHEET, nSheet );
362 0 : if( xSheetGlob.get() )
363 : {
364 0 : BiffPivotCacheRecordsContext aContext( *xSheetGlob, mrPivotCache );
365 0 : while( rStrm.startNextRecord() && (rStrm.getRecId() != BIFF_ID_EOF) )
366 0 : aContext.importRecord( rStrm );
367 0 : }
368 : }
369 : }
370 :
371 0 : return rStrm.getRecId() == BIFF_ID_EOF;
372 : }
373 :
374 0 : BiffPivotCacheRecordsContext::BiffPivotCacheRecordsContext( const WorksheetHelper& rHelper, const PivotCache& rPivotCache ) :
375 : BiffWorksheetContextBase( rHelper ),
376 : mrPivotCache( rPivotCache ),
377 : mnColIdx( 0 ),
378 : mnRowIdx( 0 ),
379 : mbHasShared( false ),
380 0 : mbInRow( false )
381 : {
382 : // prepare sheet: insert column header names into top row
383 0 : mrPivotCache.writeSourceHeaderCells( *this );
384 :
385 : // find all fields without shared items, remember column indexes in source data
386 0 : for( sal_Int32 nFieldIdx = 0, nFieldCount = mrPivotCache.getCacheFieldCount(), nCol = 0; nFieldIdx < nFieldCount; ++nFieldIdx )
387 : {
388 0 : const PivotCacheField* pCacheField = mrPivotCache.getCacheField( nFieldIdx );
389 0 : if( pCacheField && pCacheField->isDatabaseField() )
390 : {
391 0 : if( pCacheField->hasSharedItems() )
392 0 : mbHasShared = true;
393 : else
394 0 : maUnsharedCols.push_back( nCol );
395 0 : ++nCol;
396 : }
397 : }
398 0 : }
399 :
400 0 : void BiffPivotCacheRecordsContext::importRecord( BiffInputStream& rStrm )
401 : {
402 0 : if( rStrm.getRecId() == BIFF_ID_PCITEM_INDEXLIST )
403 : {
404 : OSL_ENSURE( mbHasShared, "BiffPivotCacheRecordsContext::importRecord - unexpected PCITEM_INDEXLIST record" );
405 : // PCITEM_INDEXLIST record always in front of a new data row
406 0 : startNextRow();
407 0 : mrPivotCache.importPCItemIndexList( rStrm, *this, mnRowIdx );
408 0 : mbInRow = !maUnsharedCols.empty(); // mbInRow remains true, if unshared items are expected
409 0 : return;
410 : }
411 :
412 0 : PivotCacheItem aItem;
413 0 : switch( rStrm.getRecId() )
414 : {
415 0 : case BIFF_ID_PCITEM_MISSING: break;
416 0 : case BIFF_ID_PCITEM_STRING: aItem.readString( rStrm, *this ); break;
417 0 : case BIFF_ID_PCITEM_DOUBLE: aItem.readDouble( rStrm ); break;
418 0 : case BIFF_ID_PCITEM_INTEGER: aItem.readInteger( rStrm ); break;
419 0 : case BIFF_ID_PCITEM_DATE: aItem.readDate( rStrm ); break;
420 0 : case BIFF_ID_PCITEM_BOOL: aItem.readBool( rStrm ); break;
421 0 : case BIFF_ID_PCITEM_ERROR: aItem.readError( rStrm ); break;
422 0 : default: return; // unknown record, ignore
423 : }
424 :
425 : // find next column index, might start new row if no fields with shared items exist
426 0 : if( mbInRow && (mnColIdx == maUnsharedCols.size()) )
427 : {
428 : OSL_ENSURE( !mbHasShared, "BiffPivotCacheRecordsContext::importRecord - PCITEM_INDEXLIST record missing" );
429 0 : mbInRow = mbHasShared; // do not leave current row if PCITEM_INDEXLIST is expected
430 : }
431 : // start next row on first call, or on row wrap without shared items
432 0 : if( !mbInRow )
433 0 : startNextRow();
434 :
435 : // write the item data to the sheet cell
436 : OSL_ENSURE( mnColIdx < maUnsharedCols.size(), "BiffPivotCacheRecordsContext::importRecord - invalid column index" );
437 0 : if( mnColIdx < maUnsharedCols.size() )
438 0 : mrPivotCache.writeSourceDataCell( *this, maUnsharedCols[ mnColIdx ], mnRowIdx, aItem );
439 0 : ++mnColIdx;
440 : }
441 :
442 0 : void BiffPivotCacheRecordsContext::startNextRow()
443 : {
444 0 : mnColIdx = 0;
445 0 : ++mnRowIdx;
446 0 : mbInRow = true;
447 0 : }
448 :
449 : } // namespace xls
450 18 : } // namespace oox
451 :
452 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|