Version 5.2.6.1, tag libreoffice-5.2.6.1
[LibreOffice.git] / sc / source / filter / oox / pivotcachebuffer.cxx
blob687a47d976e727c787b7c07f9dfed3fa5b03a4d6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "pivotcachebuffer.hxx"
22 #include <set>
23 #include <com/sun/star/beans/XPropertySet.hpp>
24 #include <com/sun/star/container/XIndexAccess.hpp>
25 #include <com/sun/star/container/XNameAccess.hpp>
26 #include <com/sun/star/container/XNamed.hpp>
27 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
28 #include <com/sun/star/sheet/DataPilotFieldGroupInfo.hpp>
29 #include <com/sun/star/sheet/XDataPilotFieldGrouping.hpp>
30 #include <osl/diagnose.h>
31 #include <rtl/ustrbuf.hxx>
32 #include <oox/core/filterbase.hxx>
33 #include <oox/helper/attributelist.hxx>
34 #include <oox/helper/containerhelper.hxx>
35 #include <oox/helper/propertyset.hxx>
36 #include <oox/token/namespaces.hxx>
37 #include <oox/token/properties.hxx>
38 #include <oox/token/tokens.hxx>
39 #include "biffinputstream.hxx"
40 #include "defnamesbuffer.hxx"
41 #include "excelhandlers.hxx"
42 #include "pivotcachefragment.hxx"
43 #include "sheetdatabuffer.hxx"
44 #include "tablebuffer.hxx"
45 #include "unitconverter.hxx"
46 #include "worksheetbuffer.hxx"
48 namespace oox {
49 namespace xls {
51 using namespace ::com::sun::star::container;
52 using namespace ::com::sun::star::sheet;
53 using namespace ::com::sun::star::table;
54 using namespace ::com::sun::star::uno;
55 using namespace ::com::sun::star::util;
57 using ::oox::core::Relations;
59 namespace {
61 const sal_uInt16 BIFF12_PCDFIELD_SERVERFIELD = 0x0001;
62 const sal_uInt16 BIFF12_PCDFIELD_NOUNIQUEITEMS = 0x0002;
63 const sal_uInt16 BIFF12_PCDFIELD_DATABASEFIELD = 0x0004;
64 const sal_uInt16 BIFF12_PCDFIELD_HASCAPTION = 0x0008;
65 const sal_uInt16 BIFF12_PCDFIELD_MEMBERPROPFIELD = 0x0010;
66 const sal_uInt16 BIFF12_PCDFIELD_HASFORMULA = 0x0100;
67 const sal_uInt16 BIFF12_PCDFIELD_HASPROPERTYNAME = 0x0200;
69 const sal_uInt16 BIFF12_PCDFSITEMS_HASSEMIMIXED = 0x0001;
70 const sal_uInt16 BIFF12_PCDFSITEMS_HASNONDATE = 0x0002;
71 const sal_uInt16 BIFF12_PCDFSITEMS_HASDATE = 0x0004;
72 const sal_uInt16 BIFF12_PCDFSITEMS_HASSTRING = 0x0008;
73 const sal_uInt16 BIFF12_PCDFSITEMS_HASBLANK = 0x0010;
74 const sal_uInt16 BIFF12_PCDFSITEMS_HASMIXED = 0x0020;
75 const sal_uInt16 BIFF12_PCDFSITEMS_ISNUMERIC = 0x0040;
76 const sal_uInt16 BIFF12_PCDFSITEMS_ISINTEGER = 0x0080;
77 const sal_uInt16 BIFF12_PCDFSITEMS_HASLONGTEXT = 0x0200;
79 const sal_uInt16 BIFF12_PCITEM_ARRAY_DOUBLE = 0x0001;
80 const sal_uInt16 BIFF12_PCITEM_ARRAY_STRING = 0x0002;
81 const sal_uInt16 BIFF12_PCITEM_ARRAY_ERROR = 0x0010;
82 const sal_uInt16 BIFF12_PCITEM_ARRAY_DATE = 0x0020;
84 const sal_uInt8 BIFF12_PCDFRANGEPR_AUTOSTART = 0x01;
85 const sal_uInt8 BIFF12_PCDFRANGEPR_AUTOEND = 0x02;
86 const sal_uInt8 BIFF12_PCDFRANGEPR_DATEGROUP = 0x04;
88 const sal_uInt8 BIFF12_PCDEFINITION_SAVEDATA = 0x01;
89 const sal_uInt8 BIFF12_PCDEFINITION_INVALID = 0x02;
90 const sal_uInt8 BIFF12_PCDEFINITION_REFRESHONLOAD = 0x04;
91 const sal_uInt8 BIFF12_PCDEFINITION_OPTIMIZEMEMORY = 0x08;
92 const sal_uInt8 BIFF12_PCDEFINITION_ENABLEREFRESH = 0x10;
93 const sal_uInt8 BIFF12_PCDEFINITION_BACKGROUNDQUERY = 0x20;
94 const sal_uInt8 BIFF12_PCDEFINITION_UPGRADEONREFR = 0x40;
95 const sal_uInt8 BIFF12_PCDEFINITION_TUPELCACHE = 0x80;
97 const sal_uInt8 BIFF12_PCDEFINITION_HASUSERNAME = 0x01;
98 const sal_uInt8 BIFF12_PCDEFINITION_HASRELID = 0x02;
99 const sal_uInt8 BIFF12_PCDEFINITION_SUPPORTSUBQUERY = 0x04;
100 const sal_uInt8 BIFF12_PCDEFINITION_SUPPORTDRILL = 0x08;
102 const sal_uInt8 BIFF12_PCDWBSOURCE_HASRELID = 0x01;
103 const sal_uInt8 BIFF12_PCDWBSOURCE_HASSHEET = 0x02;
105 const sal_uInt16 BIFF_PC_NOSTRING = 0xFFFF;
107 const sal_uInt16 BIFF_PCDFIELD_HASITEMS = 0x0001;
108 const sal_uInt16 BIFF_PCDFIELD_HASPARENT = 0x0008;
109 const sal_uInt16 BIFF_PCDFIELD_RANGEGROUP = 0x0010;
110 const sal_uInt16 BIFF_PCDFIELD_ISNUMERIC = 0x0020;
111 const sal_uInt16 BIFF_PCDFIELD_HASSEMIMIXED = 0x0080;
112 const sal_uInt16 BIFF_PCDFIELD_HASLONGINDEX = 0x0200;
113 const sal_uInt16 BIFF_PCDFIELD_HASNONDATE = 0x0400;
114 const sal_uInt16 BIFF_PCDFIELD_HASDATE = 0x0800;
115 const sal_uInt16 BIFF_PCDFIELD_SERVERFIELD = 0x2000;
116 const sal_uInt16 BIFF_PCDFIELD_NOUNIQUEITEMS = 0x4000;
118 const sal_uInt16 BIFF_PCDFRANGEPR_AUTOSTART = 0x0001;
119 const sal_uInt16 BIFF_PCDFRANGEPR_AUTOEND = 0x0002;
121 const sal_uInt16 BIFF_PCDEFINITION_SAVEDATA = 0x0001;
122 const sal_uInt16 BIFF_PCDEFINITION_INVALID = 0x0002;
123 const sal_uInt16 BIFF_PCDEFINITION_REFRESHONLOAD = 0x0004;
124 const sal_uInt16 BIFF_PCDEFINITION_OPTIMIZEMEMORY = 0x0008;
125 const sal_uInt16 BIFF_PCDEFINITION_BACKGROUNDQUERY = 0x0010;
126 const sal_uInt16 BIFF_PCDEFINITION_ENABLEREFRESH = 0x0020;
128 /** Adjusts the weird date format read from binary streams.
130 Dates before 1900-Mar-01 are stored including the non-existing leap day
131 1900-02-29. tools::Time values (without date) are stored as times of day
132 1900-Jan-00. Nothing has to be done when the workbook is stored in 1904
133 date mode (dates before 1904-Jan-01 will not occur in this case).
135 void lclAdjustBinDateTime( css::util::DateTime& orDateTime )
137 if( (orDateTime.Year == 1900) && (orDateTime.Month <= 2) )
139 OSL_ENSURE( (orDateTime.Month == 1) || ((orDateTime.Month == 2) && (orDateTime.Day > 0)), "lclAdjustBinDateTime - invalid date" );
140 switch( orDateTime.Month )
142 case 2: if( orDateTime.Day > 1 ) --orDateTime.Day; else { orDateTime.Day += 30; --orDateTime.Month; } break;
143 case 1: if( orDateTime.Day > 1 ) --orDateTime.Day; else { orDateTime.Day += 30; orDateTime.Month = 12; --orDateTime.Year; } break;
148 } // namespace
150 PivotCacheItem::PivotCacheItem() :
151 mnType( XML_m ), mbUnused( false )
155 void PivotCacheItem::readString( const AttributeList& rAttribs )
157 maValue <<= rAttribs.getXString( XML_v, OUString() );
158 mnType = XML_s;
161 void PivotCacheItem::readNumeric( const AttributeList& rAttribs )
163 maValue <<= rAttribs.getDouble( XML_v, 0.0 );
164 mnType = XML_n;
165 mbUnused = rAttribs.getBool( XML_u, false );
168 void PivotCacheItem::readDate( const AttributeList& rAttribs )
170 maValue <<= rAttribs.getDateTime( XML_v, css::util::DateTime() );
171 mnType = XML_d;
174 void PivotCacheItem::readBool( const AttributeList& rAttribs )
176 maValue <<= rAttribs.getBool( XML_v, false );
177 mnType = XML_b;
180 void PivotCacheItem::readError( const AttributeList& rAttribs, const UnitConverter& rUnitConverter )
182 maValue <<= static_cast< sal_Int32 >( rUnitConverter.calcBiffErrorCode( rAttribs.getXString( XML_v, OUString() ) ) );
183 mnType = XML_e;
186 void PivotCacheItem::readIndex( const AttributeList& rAttribs )
188 maValue <<= rAttribs.getInteger( XML_v, -1 );
189 mnType = XML_x;
192 void PivotCacheItem::readString( SequenceInputStream& rStrm )
194 maValue <<= BiffHelper::readString( rStrm );
195 mnType = XML_s;
198 void PivotCacheItem::readDouble( SequenceInputStream& rStrm )
200 maValue <<= rStrm.readDouble();
201 mnType = XML_n;
204 void PivotCacheItem::readDate( SequenceInputStream& rStrm )
206 css::util::DateTime aDateTime;
207 aDateTime.Year = rStrm.readuInt16();
208 aDateTime.Month = rStrm.readuInt16();
209 aDateTime.Day = rStrm.readuInt8();
210 aDateTime.Hours = rStrm.readuInt8();
211 aDateTime.Minutes = rStrm.readuInt8();
212 aDateTime.Seconds = rStrm.readuInt8();
213 lclAdjustBinDateTime( aDateTime );
214 maValue <<= aDateTime;
215 mnType = XML_d;
218 void PivotCacheItem::readBool( SequenceInputStream& rStrm )
220 maValue <<= (rStrm.readuInt8() != 0);
221 mnType = XML_b;
224 void PivotCacheItem::readError( SequenceInputStream& rStrm )
226 maValue <<= static_cast< sal_Int32 >( rStrm.readuInt8() );
227 mnType = XML_e;
230 void PivotCacheItem::readIndex( SequenceInputStream& rStrm )
232 maValue <<= rStrm.readInt32();
233 mnType = XML_x;
236 void PivotCacheItem::readString( BiffInputStream& rStrm, const WorkbookHelper& rHelper )
238 maValue <<= (rHelper.getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( true, rHelper.getTextEncoding() );
239 mnType = XML_s;
242 void PivotCacheItem::readDouble( BiffInputStream& rStrm )
244 maValue <<= rStrm.readDouble();
245 mnType = XML_n;
248 void PivotCacheItem::readInteger( BiffInputStream& rStrm )
250 maValue <<= rStrm.readInt16();
251 mnType = XML_i; // fake, used for BIFF only
254 void PivotCacheItem::readDate( BiffInputStream& rStrm )
256 css::util::DateTime aDateTime;
257 aDateTime.Year = rStrm.readuInt16();
258 aDateTime.Month = rStrm.readuInt16();
259 aDateTime.Day = rStrm.readuInt8();
260 aDateTime.Hours = rStrm.readuInt8();
261 aDateTime.Minutes = rStrm.readuInt8();
262 aDateTime.Seconds = rStrm.readuInt8();
263 lclAdjustBinDateTime( aDateTime );
264 maValue <<= aDateTime;
265 mnType = XML_d;
268 void PivotCacheItem::readBool( BiffInputStream& rStrm )
270 maValue <<= (rStrm.readuInt8() != 0);
271 mnType = XML_b;
274 void PivotCacheItem::readError( BiffInputStream& rStrm )
276 maValue <<= static_cast< sal_Int32 >( rStrm.readuInt8() );
277 mnType = XML_e;
280 void PivotCacheItem::setStringValue( const OUString& sString )
282 mnType = XML_s;
283 maValue <<= sString;
286 OUString PivotCacheItem::getName() const
288 switch( mnType )
290 case XML_m: return OUString();
291 case XML_s: return maValue.get< OUString >();
292 case XML_n: return OUString::number( maValue.get< double >() ); // !TODO
293 case XML_i: return OUString::number( maValue.get< sal_Int32 >() );
294 case XML_d: return OUString(); // !TODO
295 case XML_b: return OUString::boolean( maValue.get< bool >() ); // !TODO
296 case XML_e: return OUString(); // !TODO
298 OSL_FAIL( "PivotCacheItem::getName - invalid data type" );
299 return OUString();
302 PivotCacheItemList::PivotCacheItemList( const WorkbookHelper& rHelper ) :
303 WorkbookHelper( rHelper )
307 void PivotCacheItemList::importItem( sal_Int32 nElement, const AttributeList& rAttribs )
309 PivotCacheItem& rItem = createItem();
310 switch( nElement )
312 case XLS_TOKEN( m ): break;
313 case XLS_TOKEN( s ): rItem.readString( rAttribs ); break;
314 case XLS_TOKEN( n ): rItem.readNumeric( rAttribs ); break;
315 case XLS_TOKEN( d ): rItem.readDate( rAttribs ); break;
316 case XLS_TOKEN( b ): rItem.readBool( rAttribs ); break;
317 case XLS_TOKEN( e ): rItem.readError( rAttribs, getUnitConverter() ); break;
318 default: OSL_FAIL( "PivotCacheItemList::importItem - unknown element type" );
322 void PivotCacheItemList::importItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
324 if( nRecId == BIFF12_ID_PCITEM_ARRAY )
326 importArray( rStrm );
327 return;
330 PivotCacheItem& rItem = createItem();
331 switch( nRecId )
333 case BIFF12_ID_PCITEM_MISSING:
334 case BIFF12_ID_PCITEMA_MISSING: break;
335 case BIFF12_ID_PCITEM_STRING:
336 case BIFF12_ID_PCITEMA_STRING: rItem.readString( rStrm ); break;
337 case BIFF12_ID_PCITEM_DOUBLE:
338 case BIFF12_ID_PCITEMA_DOUBLE: rItem.readDouble( rStrm ); break;
339 case BIFF12_ID_PCITEM_DATE:
340 case BIFF12_ID_PCITEMA_DATE: rItem.readDate( rStrm ); break;
341 case BIFF12_ID_PCITEM_BOOL:
342 case BIFF12_ID_PCITEMA_BOOL: rItem.readBool( rStrm ); break;
343 case BIFF12_ID_PCITEM_ERROR:
344 case BIFF12_ID_PCITEMA_ERROR: rItem.readError( rStrm ); break;
345 default: OSL_FAIL( "PivotCacheItemList::importItem - unknown record type" );
349 void PivotCacheItemList::importItemList( BiffInputStream& rStrm, sal_uInt16 nCount )
351 bool bLoop = true;
352 for( sal_uInt16 nItemIdx = 0; bLoop && (nItemIdx < nCount); ++nItemIdx )
354 bLoop = rStrm.startNextRecord();
355 if( bLoop ) switch( rStrm.getRecId() )
357 case BIFF_ID_PCITEM_MISSING: createItem(); break;
358 case BIFF_ID_PCITEM_STRING: createItem().readString( rStrm, *this ); break;
359 case BIFF_ID_PCITEM_DOUBLE: createItem().readDouble( rStrm ); break;
360 case BIFF_ID_PCITEM_INTEGER: createItem().readInteger( rStrm ); break;
361 case BIFF_ID_PCITEM_DATE: createItem().readDate( rStrm ); break;
362 case BIFF_ID_PCITEM_BOOL: createItem().readBool( rStrm ); break;
363 case BIFF_ID_PCITEM_ERROR: createItem().readError( rStrm ); break;
364 default: rStrm.rewindRecord(); bLoop = false;
367 OSL_ENSURE( bLoop, "PivotCacheItemList::importItemList - could not read all cache item records" );
370 const PivotCacheItem* PivotCacheItemList::getCacheItem( sal_Int32 nItemIdx ) const
372 return ContainerHelper::getVectorElement( maItems, nItemIdx );
375 void PivotCacheItemList::applyItemCaptions( const IdCaptionPairList& vCaptions )
377 for( IdCaptionPairList::const_iterator aIt = vCaptions.begin(), aEnd = vCaptions.end(); aIt != aEnd; ++aIt )
379 if ( static_cast<sal_uInt32>( aIt->first ) < maItems.size() )
380 maItems[ aIt->first ].setStringValue( aIt->second );
384 void PivotCacheItemList::getCacheItemNames( ::std::vector< OUString >& orItemNames ) const
386 orItemNames.clear();
387 orItemNames.reserve( maItems.size() );
388 for( CacheItemVector::const_iterator aIt = maItems.begin(), aEnd = maItems.end(); aIt != aEnd; ++aIt )
389 orItemNames.push_back( aIt->getName() );
392 // private --------------------------------------------------------------------
394 PivotCacheItem& PivotCacheItemList::createItem()
396 maItems.resize( maItems.size() + 1 );
397 return maItems.back();
400 void PivotCacheItemList::importArray( SequenceInputStream& rStrm )
402 sal_uInt16 nType = rStrm.readuInt16();
403 sal_Int32 nCount = rStrm.readInt32();
404 for( sal_Int32 nIdx = 0; !rStrm.isEof() && (nIdx < nCount); ++nIdx )
406 switch( nType )
408 case BIFF12_PCITEM_ARRAY_DOUBLE: createItem().readDouble( rStrm ); break;
409 case BIFF12_PCITEM_ARRAY_STRING: createItem().readString( rStrm ); break;
410 case BIFF12_PCITEM_ARRAY_ERROR: createItem().readError( rStrm ); break;
411 case BIFF12_PCITEM_ARRAY_DATE: createItem().readDate( rStrm ); break;
412 default:
413 OSL_FAIL( "PivotCacheItemList::importArray - unknown data type" );
414 return;
419 PCFieldModel::PCFieldModel() :
420 mnNumFmtId( 0 ),
421 mnSqlType( 0 ),
422 mnHierarchy( 0 ),
423 mnLevel( 0 ),
424 mnMappingCount( 0 ),
425 mbDatabaseField( true ),
426 mbServerField( false ),
427 mbUniqueList( true ),
428 mbMemberPropField( false )
432 PCSharedItemsModel::PCSharedItemsModel() :
433 mbHasSemiMixed( true ),
434 mbHasNonDate( true ),
435 mbHasDate( false ),
436 mbHasString( true ),
437 mbHasBlank( false ),
438 mbHasMixed( false ),
439 mbIsNumeric( false ),
440 mbIsInteger( false ),
441 mbHasLongText( false ),
442 mbHasLongIndexes( false )
446 PCFieldGroupModel::PCFieldGroupModel() :
447 mfStartValue( 0.0 ),
448 mfEndValue( 0.0 ),
449 mfInterval( 1.0 ),
450 mnParentField( -1 ),
451 mnBaseField( -1 ),
452 mnGroupBy( XML_range ),
453 mbRangeGroup( false ),
454 mbDateGroup( false ),
455 mbAutoStart( true ),
456 mbAutoEnd( true )
460 void PCFieldGroupModel::setBiffGroupBy( sal_uInt8 nGroupBy )
462 static const sal_Int32 spnGroupBy[] = { XML_range,
463 XML_seconds, XML_minutes, XML_hours, XML_days, XML_months, XML_quarters, XML_years };
464 mnGroupBy = STATIC_ARRAY_SELECT( spnGroupBy, nGroupBy, XML_range );
467 PivotCacheField::PivotCacheField( const WorkbookHelper& rHelper, bool bIsDatabaseField ) :
468 WorkbookHelper( rHelper ),
469 maSharedItems( rHelper ),
470 maGroupItems( rHelper )
472 maFieldModel.mbDatabaseField = bIsDatabaseField;
475 void PivotCacheField::importCacheField( const AttributeList& rAttribs )
477 maFieldModel.maName = rAttribs.getXString( XML_name, OUString() );
478 maFieldModel.maCaption = rAttribs.getXString( XML_caption, OUString() );
479 maFieldModel.maPropertyName = rAttribs.getXString( XML_propertyName, OUString() );
480 maFieldModel.maFormula = rAttribs.getXString( XML_formula, OUString() );
481 maFieldModel.mnNumFmtId = rAttribs.getInteger( XML_numFmtId, 0 );
482 maFieldModel.mnSqlType = rAttribs.getInteger( XML_sqlType, 0 );
483 maFieldModel.mnHierarchy = rAttribs.getInteger( XML_hierarchy, 0 );
484 maFieldModel.mnLevel = rAttribs.getInteger( XML_level, 0 );
485 maFieldModel.mnMappingCount = rAttribs.getInteger( XML_mappingCount, 0 );
486 maFieldModel.mbDatabaseField = rAttribs.getBool( XML_databaseField, true );
487 maFieldModel.mbServerField = rAttribs.getBool( XML_serverField, false );
488 maFieldModel.mbUniqueList = rAttribs.getBool( XML_uniqueList, true );
489 maFieldModel.mbMemberPropField = rAttribs.getBool( XML_memberPropertyField, false );
492 void PivotCacheField::importSharedItems( const AttributeList& rAttribs )
494 OSL_ENSURE( maSharedItems.empty(), "PivotCacheField::importSharedItems - multiple shared items elements" );
495 maSharedItemsModel.mbHasSemiMixed = rAttribs.getBool( XML_containsSemiMixedTypes, true );
496 maSharedItemsModel.mbHasNonDate = rAttribs.getBool( XML_containsNonDate, true );
497 maSharedItemsModel.mbHasDate = rAttribs.getBool( XML_containsDate, false );
498 maSharedItemsModel.mbHasString = rAttribs.getBool( XML_containsString, true );
499 maSharedItemsModel.mbHasBlank = rAttribs.getBool( XML_containsBlank, false );
500 maSharedItemsModel.mbHasMixed = rAttribs.getBool( XML_containsMixedTypes, false );
501 maSharedItemsModel.mbIsNumeric = rAttribs.getBool( XML_containsNumber, false );
502 maSharedItemsModel.mbIsInteger = rAttribs.getBool( XML_containsInteger, false );
503 maSharedItemsModel.mbHasLongText = rAttribs.getBool( XML_longText, false );
506 void PivotCacheField::importSharedItem( sal_Int32 nElement, const AttributeList& rAttribs )
508 maSharedItems.importItem( nElement, rAttribs );
511 void PivotCacheField::importFieldGroup( const AttributeList& rAttribs )
513 maFieldGroupModel.mnParentField = rAttribs.getInteger( XML_par, -1 );
514 maFieldGroupModel.mnBaseField = rAttribs.getInteger( XML_base, -1 );
517 void PivotCacheField::importRangePr( const AttributeList& rAttribs )
519 maFieldGroupModel.maStartDate = rAttribs.getDateTime( XML_startDate, css::util::DateTime() );
520 maFieldGroupModel.maEndDate = rAttribs.getDateTime( XML_endDate, css::util::DateTime() );
521 maFieldGroupModel.mfStartValue = rAttribs.getDouble( XML_startNum, 0.0 );
522 maFieldGroupModel.mfEndValue = rAttribs.getDouble( XML_endNum, 0.0 );
523 maFieldGroupModel.mfInterval = rAttribs.getDouble( XML_groupInterval, 1.0 );
524 maFieldGroupModel.mnGroupBy = rAttribs.getToken( XML_groupBy, XML_range );
525 maFieldGroupModel.mbRangeGroup = true;
526 maFieldGroupModel.mbDateGroup = maFieldGroupModel.mnGroupBy != XML_range;
527 maFieldGroupModel.mbAutoStart = rAttribs.getBool( XML_autoStart, true );
528 maFieldGroupModel.mbAutoEnd = rAttribs.getBool( XML_autoEnd, true );
531 void PivotCacheField::importDiscretePrItem( sal_Int32 nElement, const AttributeList& rAttribs )
533 OSL_ENSURE( nElement == XLS_TOKEN( x ), "PivotCacheField::importDiscretePrItem - unexpected element" );
534 if( nElement == XLS_TOKEN( x ) )
535 maDiscreteItems.push_back( rAttribs.getInteger( XML_v, -1 ) );
538 void PivotCacheField::importGroupItem( sal_Int32 nElement, const AttributeList& rAttribs )
540 maGroupItems.importItem( nElement, rAttribs );
543 void PivotCacheField::importPCDField( SequenceInputStream& rStrm )
545 sal_uInt16 nFlags;
546 nFlags = rStrm.readuInt16();
547 maFieldModel.mnNumFmtId = rStrm.readInt32();
548 maFieldModel.mnSqlType = rStrm.readInt16();
549 maFieldModel.mnHierarchy = rStrm.readInt32();
550 maFieldModel.mnLevel = rStrm.readInt32();
551 maFieldModel.mnMappingCount = rStrm.readInt32();
552 rStrm >> maFieldModel.maName;
553 if( getFlag( nFlags, BIFF12_PCDFIELD_HASCAPTION ) )
554 rStrm >> maFieldModel.maCaption;
555 if( getFlag( nFlags, BIFF12_PCDFIELD_HASFORMULA ) )
556 rStrm.skip( ::std::max< sal_Int32 >( rStrm.readInt32(), 0 ) );
557 if( maFieldModel.mnMappingCount > 0 )
558 rStrm.skip( ::std::max< sal_Int32 >( rStrm.readInt32(), 0 ) );
559 if( getFlag( nFlags, BIFF12_PCDFIELD_HASPROPERTYNAME ) )
560 rStrm >> maFieldModel.maPropertyName;
562 maFieldModel.mbDatabaseField = getFlag( nFlags, BIFF12_PCDFIELD_DATABASEFIELD );
563 maFieldModel.mbServerField = getFlag( nFlags, BIFF12_PCDFIELD_SERVERFIELD );
564 maFieldModel.mbUniqueList = !getFlag( nFlags, BIFF12_PCDFIELD_NOUNIQUEITEMS );
565 maFieldModel.mbMemberPropField = getFlag( nFlags, BIFF12_PCDFIELD_MEMBERPROPFIELD );
568 void PivotCacheField::importPCDFSharedItems( SequenceInputStream& rStrm )
570 sal_uInt16 nFlags;
571 nFlags = rStrm.readuInt16();
572 maSharedItemsModel.mbHasSemiMixed = getFlag( nFlags, BIFF12_PCDFSITEMS_HASSEMIMIXED );
573 maSharedItemsModel.mbHasNonDate = getFlag( nFlags, BIFF12_PCDFSITEMS_HASNONDATE );
574 maSharedItemsModel.mbHasDate = getFlag( nFlags, BIFF12_PCDFSITEMS_HASDATE );
575 maSharedItemsModel.mbHasString = getFlag( nFlags, BIFF12_PCDFSITEMS_HASSTRING );
576 maSharedItemsModel.mbHasBlank = getFlag( nFlags, BIFF12_PCDFSITEMS_HASBLANK );
577 maSharedItemsModel.mbHasMixed = getFlag( nFlags, BIFF12_PCDFSITEMS_HASMIXED );
578 maSharedItemsModel.mbIsNumeric = getFlag( nFlags, BIFF12_PCDFSITEMS_ISNUMERIC );
579 maSharedItemsModel.mbIsInteger = getFlag( nFlags, BIFF12_PCDFSITEMS_ISINTEGER );
580 maSharedItemsModel.mbHasLongText = getFlag( nFlags, BIFF12_PCDFSITEMS_HASLONGTEXT );
583 void PivotCacheField::importPCDFSharedItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
585 maSharedItems.importItem( nRecId, rStrm );
588 void PivotCacheField::importPCDFieldGroup( SequenceInputStream& rStrm )
590 maFieldGroupModel.mnParentField = rStrm.readInt32();
591 maFieldGroupModel.mnBaseField = rStrm.readInt32();
594 void PivotCacheField::importPCDFRangePr( SequenceInputStream& rStrm )
596 sal_uInt8 nGroupBy, nFlags;
597 nGroupBy = rStrm.readuChar();
598 nFlags = rStrm.readuChar();
599 maFieldGroupModel.mfStartValue = rStrm.readDouble();
600 maFieldGroupModel.mfEndValue = rStrm.readDouble();
601 maFieldGroupModel.mfInterval = rStrm.readDouble();
603 maFieldGroupModel.setBiffGroupBy( nGroupBy );
604 maFieldGroupModel.mbRangeGroup = true;
605 maFieldGroupModel.mbDateGroup = getFlag( nFlags, BIFF12_PCDFRANGEPR_DATEGROUP );
606 maFieldGroupModel.mbAutoStart = getFlag( nFlags, BIFF12_PCDFRANGEPR_AUTOSTART );
607 maFieldGroupModel.mbAutoEnd = getFlag( nFlags, BIFF12_PCDFRANGEPR_AUTOEND );
609 OSL_ENSURE( maFieldGroupModel.mbDateGroup == (maFieldGroupModel.mnGroupBy != XML_range), "PivotCacheField::importPCDFRangePr - wrong date flag" );
610 if( maFieldGroupModel.mbDateGroup )
612 maFieldGroupModel.maStartDate = getUnitConverter().calcDateTimeFromSerial( maFieldGroupModel.mfStartValue );
613 maFieldGroupModel.maEndDate = getUnitConverter().calcDateTimeFromSerial( maFieldGroupModel.mfEndValue );
617 void PivotCacheField::importPCDFDiscretePrItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
619 OSL_ENSURE( nRecId == BIFF12_ID_PCITEM_INDEX, "PivotCacheField::importPCDFDiscretePrItem - unexpected record" );
620 if( nRecId == BIFF12_ID_PCITEM_INDEX )
621 maDiscreteItems.push_back( rStrm.readInt32() );
624 void PivotCacheField::importPCDFGroupItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
626 maGroupItems.importItem( nRecId, rStrm );
629 void PivotCacheField::importPCDField( BiffInputStream& rStrm )
631 sal_uInt16 nFlags, nGroupItems, nBaseItems, nSharedItems;
632 rStrm >> nFlags;
633 maFieldGroupModel.mnParentField = rStrm.readuInt16();
634 maFieldGroupModel.mnBaseField = rStrm.readuInt16();
635 rStrm.skip( 2 ); // number of unique items (either shared or group)
636 rStrm >> nGroupItems >> nBaseItems >> nSharedItems;
637 maFieldModel.maName = (getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( true, getTextEncoding() );
639 maFieldModel.mbServerField = getFlag( nFlags, BIFF_PCDFIELD_SERVERFIELD );
640 maFieldModel.mbUniqueList = !getFlag( nFlags, BIFF_PCDFIELD_NOUNIQUEITEMS );
641 maSharedItemsModel.mbHasSemiMixed = getFlag( nFlags, BIFF_PCDFIELD_HASSEMIMIXED );
642 maSharedItemsModel.mbHasNonDate = getFlag( nFlags, BIFF_PCDFIELD_HASNONDATE );
643 maSharedItemsModel.mbHasDate = getFlag( nFlags, BIFF_PCDFIELD_HASDATE );
644 maSharedItemsModel.mbIsNumeric = getFlag( nFlags, BIFF_PCDFIELD_ISNUMERIC );
645 maSharedItemsModel.mbHasLongIndexes = getFlag( nFlags, BIFF_PCDFIELD_HASLONGINDEX );
646 maFieldGroupModel.mbRangeGroup = getFlag( nFlags, BIFF_PCDFIELD_RANGEGROUP );
648 // in BIFF, presence of parent group field is denoted by a flag
649 if( !getFlag( nFlags, BIFF_PCDFIELD_HASPARENT ) )
650 maFieldGroupModel.mnParentField = -1;
652 // following PCDFSQLTYPE record contains SQL type
653 if( (rStrm.getNextRecId() == BIFF_ID_PCDFSQLTYPE) && rStrm.startNextRecord() )
654 maFieldModel.mnSqlType = rStrm.readInt16();
656 // read group items, if any
657 if( nGroupItems > 0 )
659 SAL_WARN_IF(
660 !getFlag(nFlags, BIFF_PCDFIELD_HASITEMS), "sc.filter",
661 "PivotCacheField::importPCDField - missing items flag");
662 maGroupItems.importItemList( rStrm, nGroupItems );
664 sal_uInt16 nNextRecId = rStrm.getNextRecId();
665 bool bHasRangePr = nNextRecId == BIFF_ID_PCDFRANGEPR;
666 bool bHasDiscretePr = nNextRecId == BIFF_ID_PCDFDISCRETEPR;
668 OSL_ENSURE( bHasRangePr || bHasDiscretePr, "PivotCacheField::importPCDField - missing group properties record" );
669 OSL_ENSURE( bHasRangePr == maFieldGroupModel.mbRangeGroup, "PivotCacheField::importPCDField - invalid range grouping flag" );
670 if( bHasRangePr && rStrm.startNextRecord() )
671 importPCDFRangePr( rStrm );
672 else if( bHasDiscretePr && rStrm.startNextRecord() )
673 importPCDFDiscretePr( rStrm );
676 // read the shared items, if any
677 if( nSharedItems > 0 )
679 SAL_WARN_IF(
680 !getFlag(nFlags, BIFF_PCDFIELD_HASITEMS), "sc.filter",
681 "PivotCacheField::importPCDField - missing items flag");
682 maSharedItems.importItemList( rStrm, nSharedItems );
686 void PivotCacheField::importPCDFRangePr( BiffInputStream& rStrm )
688 sal_uInt16 nFlags;
689 rStrm >> nFlags;
690 maFieldGroupModel.setBiffGroupBy( extractValue< sal_uInt8 >( nFlags, 2, 3 ) );
691 maFieldGroupModel.mbRangeGroup = true;
692 maFieldGroupModel.mbDateGroup = maFieldGroupModel.mnGroupBy != XML_range;
693 maFieldGroupModel.mbAutoStart = getFlag( nFlags, BIFF_PCDFRANGEPR_AUTOSTART );
694 maFieldGroupModel.mbAutoEnd = getFlag( nFlags, BIFF_PCDFRANGEPR_AUTOEND );
696 /* Start, end, and interval are stored in 3 separate item records. Type of
697 the items is dependent on numeric/date mode. Numeric groups expect
698 three PCITEM_DOUBLE records, date groups expect two PCITEM_DATE records
699 and one PCITEM_INT record. */
700 PivotCacheItemList aLimits( *this );
701 aLimits.importItemList( rStrm, 3 );
702 OSL_ENSURE( aLimits.size() == 3, "PivotCacheField::importPCDFRangePr - missing grouping records" );
703 const PivotCacheItem* pStartValue = aLimits.getCacheItem( 0 );
704 const PivotCacheItem* pEndValue = aLimits.getCacheItem( 1 );
705 const PivotCacheItem* pInterval = aLimits.getCacheItem( 2 );
706 if( pStartValue && pEndValue && pInterval )
708 if( maFieldGroupModel.mbDateGroup )
710 bool bHasTypes = (pStartValue->getType() == XML_d) && (pEndValue->getType() == XML_d) && (pInterval->getType() == XML_i);
711 OSL_ENSURE( bHasTypes, "PivotCacheField::importPCDFRangePr - wrong data types in grouping items" );
712 if( bHasTypes )
714 maFieldGroupModel.maStartDate = pStartValue->getValue().get< css::util::DateTime >();
715 maFieldGroupModel.maEndDate = pEndValue->getValue().get< css::util::DateTime >();
716 maFieldGroupModel.mfInterval = pInterval->getValue().get< sal_Int16 >();
719 else
721 bool bHasTypes = (pStartValue->getType() == XML_n) && (pEndValue->getType() == XML_n) && (pInterval->getType() == XML_n);
722 OSL_ENSURE( bHasTypes, "PivotCacheField::importPCDFRangePr - wrong data types in grouping items" );
723 if( bHasTypes )
725 maFieldGroupModel.mfStartValue = pStartValue->getValue().get< double >();
726 maFieldGroupModel.mfEndValue = pEndValue->getValue().get< double >();
727 maFieldGroupModel.mfInterval = pInterval->getValue().get< double >();
733 void PivotCacheField::importPCDFDiscretePr( BiffInputStream& rStrm )
735 sal_Int32 nCount = static_cast< sal_Int32 >( rStrm.size() / 2 );
736 for( sal_Int32 nIndex = 0; !rStrm.isEof() && (nIndex < nCount); ++nIndex )
737 maDiscreteItems.push_back( rStrm.readuInt16() );
740 const PivotCacheItem* PivotCacheField::getCacheItem( sal_Int32 nItemIdx ) const
742 if( hasGroupItems() )
743 return maGroupItems.getCacheItem( nItemIdx );
744 if( hasSharedItems() )
745 return maSharedItems.getCacheItem( nItemIdx );
746 return nullptr;
749 void PivotCacheField::applyItemCaptions( const IdCaptionPairList& vCaptions )
751 if( hasGroupItems() )
752 maGroupItems.applyItemCaptions( vCaptions );
753 if( hasSharedItems() )
754 maSharedItems.applyItemCaptions( vCaptions );
757 void PivotCacheField::getCacheItemNames( ::std::vector< OUString >& orItemNames ) const
759 if( hasGroupItems() )
760 maGroupItems.getCacheItemNames( orItemNames );
761 else if( hasSharedItems() )
762 maSharedItems.getCacheItemNames( orItemNames );
765 const PivotCacheItemList& PivotCacheField::getCacheItems() const
767 if( hasGroupItems() )
768 return maGroupItems;
769 return maSharedItems;
772 void PivotCacheField::convertNumericGrouping( const Reference< XDataPilotField >& rxDPField ) const
774 OSL_ENSURE( hasGroupItems() && hasNumericGrouping(), "PivotCacheField::convertNumericGrouping - not a numeric group field" );
775 PropertySet aPropSet( rxDPField );
776 if( hasGroupItems() && hasNumericGrouping() && aPropSet.is() )
778 DataPilotFieldGroupInfo aGroupInfo;
779 aGroupInfo.HasAutoStart = maFieldGroupModel.mbAutoStart;
780 aGroupInfo.HasAutoEnd = maFieldGroupModel.mbAutoEnd;
781 aGroupInfo.HasDateValues = false;
782 aGroupInfo.Start = maFieldGroupModel.mfStartValue;
783 aGroupInfo.End = maFieldGroupModel.mfEndValue;
784 aGroupInfo.Step = maFieldGroupModel.mfInterval;
785 aGroupInfo.GroupBy = 0;
786 aPropSet.setProperty( PROP_GroupInfo, aGroupInfo );
790 OUString PivotCacheField::createDateGroupField( const Reference< XDataPilotField >& rxBaseDPField ) const
792 OSL_ENSURE( hasGroupItems() && hasDateGrouping(), "PivotCacheField::createDateGroupField - not a numeric group field" );
793 Reference< XDataPilotField > xDPGroupField;
794 PropertySet aPropSet( rxBaseDPField );
795 if( hasGroupItems() && hasDateGrouping() && aPropSet.is() )
797 bool bDayRanges = (maFieldGroupModel.mnGroupBy == XML_days) && (maFieldGroupModel.mfInterval >= 2.0);
799 DataPilotFieldGroupInfo aGroupInfo;
800 aGroupInfo.HasAutoStart = maFieldGroupModel.mbAutoStart;
801 aGroupInfo.HasAutoEnd = maFieldGroupModel.mbAutoEnd;
802 aGroupInfo.HasDateValues = true;
803 aGroupInfo.Start = getUnitConverter().calcSerialFromDateTime( maFieldGroupModel.maStartDate );
804 aGroupInfo.End = getUnitConverter().calcSerialFromDateTime( maFieldGroupModel.maEndDate );
805 aGroupInfo.Step = bDayRanges ? maFieldGroupModel.mfInterval : 0.0;
807 using namespace ::com::sun::star::sheet::DataPilotFieldGroupBy;
808 switch( maFieldGroupModel.mnGroupBy )
810 case XML_years: aGroupInfo.GroupBy = YEARS; break;
811 case XML_quarters: aGroupInfo.GroupBy = QUARTERS; break;
812 case XML_months: aGroupInfo.GroupBy = MONTHS; break;
813 case XML_days: aGroupInfo.GroupBy = DAYS; break;
814 case XML_hours: aGroupInfo.GroupBy = HOURS; break;
815 case XML_minutes: aGroupInfo.GroupBy = MINUTES; break;
816 case XML_seconds: aGroupInfo.GroupBy = SECONDS; break;
817 default: OSL_FAIL( "PivotCacheField::convertRangeGrouping - unknown date/time interval" );
822 Reference< XDataPilotFieldGrouping > xDPGrouping( rxBaseDPField, UNO_QUERY_THROW );
823 xDPGroupField = xDPGrouping->createDateGroup( aGroupInfo );
825 catch( Exception& )
830 Reference< XNamed > xFieldName( xDPGroupField, UNO_QUERY );
831 return xFieldName.is() ? xFieldName->getName() : OUString();
834 OUString PivotCacheField::createParentGroupField( const Reference< XDataPilotField >& rxBaseDPField, const PivotCacheField& rBaseCacheField, PivotCacheGroupItemVector& orItemNames ) const
836 OSL_ENSURE( hasGroupItems() && !maDiscreteItems.empty(), "PivotCacheField::createParentGroupField - not a group field" );
837 OSL_ENSURE( maDiscreteItems.size() == orItemNames.size(), "PivotCacheField::createParentGroupField - number of item names does not match grouping info" );
838 Reference< XDataPilotFieldGrouping > xDPGrouping( rxBaseDPField, UNO_QUERY );
839 if( !xDPGrouping.is() ) return OUString();
841 // map the group item indexes from maGroupItems to all item indexes from maDiscreteItems
842 typedef ::std::vector< sal_Int32 > GroupItemList;
843 typedef ::std::vector< GroupItemList > GroupItemMap;
844 GroupItemMap aItemMap( maGroupItems.size() );
845 for( IndexVector::const_iterator aBeg = maDiscreteItems.begin(), aIt = aBeg, aEnd = maDiscreteItems.end(); aIt != aEnd; ++aIt )
847 if( GroupItemList* pItems = ContainerHelper::getVectorElementAccess( aItemMap, *aIt ) )
849 if ( const PivotCacheItem* pItem = rBaseCacheField.getCacheItems().getCacheItem( aIt - aBeg ) )
851 // Skip unspecified or ununsed entries or errors
852 if ( pItem->isUnused() || ( pItem->getType() == XML_m ) || ( pItem->getType() == XML_e ) )
853 continue;
855 pItems->push_back( static_cast< sal_Int32 >( aIt - aBeg ) );
859 // process all groups
860 Reference< XDataPilotField > xDPGroupField;
861 for( GroupItemMap::iterator aBeg = aItemMap.begin(), aIt = aBeg, aEnd = aItemMap.end(); aIt != aEnd; ++aIt )
863 OSL_ENSURE( !aIt->empty(), "PivotCacheField::createParentGroupField - item/group should not be empty" );
864 if( !aIt->empty() )
866 /* Insert the names of the items that are part of this group. Calc
867 expects the names of the members of the field whose members are
868 grouped (which may be the names of groups too). Excel provides
869 the names of the base field items instead (no group names
870 involved). Therefore, the passed collection of current item
871 names as they are already grouped is used here to resolve the
872 item names. */
873 ::std::vector< OUString > aMembers;
874 for( GroupItemList::iterator aBeg2 = aIt->begin(), aIt2 = aBeg2, aEnd2 = aIt->end(); aIt2 != aEnd2; ++aIt2 )
875 if( const PivotCacheGroupItem* pName = ContainerHelper::getVectorElement( orItemNames, *aIt2 ) )
876 if( ::std::find( aMembers.begin(), aMembers.end(), pName->maGroupName ) == aMembers.end() )
877 aMembers.push_back( pName->maGroupName );
879 /* Check again, that this is not just a group that is not grouped
880 further with other items. */
881 if( !aMembers.empty() ) try
883 // only the first call of createNameGroup() returns the new field
884 Reference< XDataPilotField > xDPNewField = xDPGrouping->createNameGroup( ContainerHelper::vectorToSequence( aMembers ) );
885 OSL_ENSURE( xDPGroupField.is() != xDPNewField.is(), "PivotCacheField::createParentGroupField - missing group field" );
886 if( !xDPGroupField.is() )
887 xDPGroupField = xDPNewField;
889 // get current grouping info
890 DataPilotFieldGroupInfo aGroupInfo;
891 PropertySet aPropSet( xDPGroupField );
892 aPropSet.getProperty( aGroupInfo, PROP_GroupInfo );
894 /* Find the group object and the auto-generated group name.
895 The returned field contains all groups derived from the
896 previous field if that is grouped too. To find the correct
897 group, the first item used to create the group is searched.
898 Calc provides the original item names of the base field
899 when the group is querried for its members. Its does not
900 provide the names of members that are already groups in the
901 field used to create the new groups. (Is this a bug?)
902 Therefore, a name from the passed list of original item
903 names is used to find the correct group. */
904 OUString aFirstItem;
905 if( const PivotCacheGroupItem* pName = ContainerHelper::getVectorElement( orItemNames, aIt->front() ) )
906 aFirstItem = pName->maOrigName;
907 Reference< XNamed > xGroupName;
908 OUString aAutoName;
909 Reference< XIndexAccess > xGroupsIA( aGroupInfo.Groups, UNO_QUERY_THROW );
910 for( sal_Int32 nIdx = 0, nCount = xGroupsIA->getCount(); (nIdx < nCount) && (aAutoName.isEmpty()); ++nIdx ) try
912 Reference< XNameAccess > xItemsNA( xGroupsIA->getByIndex( nIdx ), UNO_QUERY_THROW );
913 if( xItemsNA->hasByName( aFirstItem ) )
915 xGroupName.set( xGroupsIA->getByIndex( nIdx ), UNO_QUERY_THROW );
916 aAutoName = xGroupName->getName();
919 catch( Exception& )
922 OSL_ENSURE( !aAutoName.isEmpty(), "PivotCacheField::createParentGroupField - cannot find auto-generated group name" );
924 // get the real group name from the list of group items
925 OUString aGroupName;
926 if( const PivotCacheItem* pGroupItem = maGroupItems.getCacheItem( static_cast< sal_Int32 >( aIt - aBeg ) ) )
927 aGroupName = pGroupItem->getName();
928 OSL_ENSURE( !aGroupName.isEmpty(), "PivotCacheField::createParentGroupField - cannot find group name" );
929 if( aGroupName.isEmpty() )
930 aGroupName = aAutoName;
932 if( xGroupName.is() && !aGroupName.isEmpty() )
934 // replace the auto-generated group name with the real name
935 if( aAutoName != aGroupName )
937 xGroupName->setName( aGroupName );
938 aPropSet.setProperty( PROP_GroupInfo, aGroupInfo );
940 // replace original item names in passed vector with group name
941 for( GroupItemList::iterator aIt2 = aIt->begin(), aEnd2 = aIt->end(); aIt2 != aEnd2; ++aIt2 )
942 if( PivotCacheGroupItem* pName = ContainerHelper::getVectorElementAccess( orItemNames, *aIt2 ) )
943 pName->maGroupName = aGroupName;
946 catch( Exception& )
952 Reference< XNamed > xFieldName( xDPGroupField, UNO_QUERY );
953 return xFieldName.is() ? xFieldName->getName() : OUString();
956 void PivotCacheField::writeSourceHeaderCell( WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow ) const
958 CellModel aModel;
959 aModel.maCellAddr = ScAddress( SCCOL( nCol ), SCROW( nRow ), SCTAB( rSheetHelper.getSheetIndex() ) );
960 rSheetHelper.getSheetData().setStringCell( aModel, maFieldModel.maName );
963 void PivotCacheField::writeSourceDataCell( WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow, const PivotCacheItem& rItem ) const
965 bool bHasIndex = rItem.getType() == XML_x;
966 OSL_ENSURE( bHasIndex != maSharedItems.empty(), "PivotCacheField::writeSourceDataCell - shared items missing or not expected" );
967 if( bHasIndex )
968 writeSharedItemToSourceDataCell( rSheetHelper, nCol, nRow, rItem.getValue().get< sal_Int32 >() );
969 else
970 writeItemToSourceDataCell( rSheetHelper, nCol, nRow, rItem );
973 void PivotCacheField::importPCRecordItem( SequenceInputStream& rStrm, WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow ) const
975 if( hasSharedItems() )
977 writeSharedItemToSourceDataCell( rSheetHelper, nCol, nRow, rStrm.readInt32() );
979 else
981 PivotCacheItem aItem;
982 if( maSharedItemsModel.mbIsNumeric )
983 aItem.readDouble( rStrm );
984 else if( maSharedItemsModel.mbHasDate && !maSharedItemsModel.mbHasString )
985 aItem.readDate( rStrm );
986 else
987 aItem.readString( rStrm );
988 writeItemToSourceDataCell( rSheetHelper, nCol, nRow, aItem );
992 void PivotCacheField::importPCItemIndex( BiffInputStream& rStrm, WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow ) const
994 OSL_ENSURE( hasSharedItems(), "PivotCacheField::importPCItemIndex - invalid call, no shared items found" );
995 sal_Int32 nIndex = maSharedItemsModel.mbHasLongIndexes ? rStrm.readuInt16() : rStrm.readuInt8();
996 writeSharedItemToSourceDataCell( rSheetHelper, nCol, nRow, nIndex );
999 // private --------------------------------------------------------------------
1001 void PivotCacheField::writeItemToSourceDataCell( WorksheetHelper& rSheetHelper,
1002 sal_Int32 nCol, sal_Int32 nRow, const PivotCacheItem& rItem )
1004 if( rItem.getType() != XML_m )
1006 CellModel aModel;
1007 aModel.maCellAddr = ScAddress( SCCOL( nCol ), SCROW( nRow ), SCTAB( rSheetHelper.getSheetIndex() ) );
1008 SheetDataBuffer& rSheetData = rSheetHelper.getSheetData();
1009 switch( rItem.getType() )
1011 case XML_s: rSheetData.setStringCell( aModel, rItem.getValue().get< OUString >() ); break;
1012 case XML_n: rSheetData.setValueCell( aModel, rItem.getValue().get< double >() ); break;
1013 case XML_i: rSheetData.setValueCell( aModel, rItem.getValue().get< sal_Int16 >() ); break;
1014 case XML_d: rSheetData.setDateTimeCell( aModel, rItem.getValue().get< css::util::DateTime >() ); break;
1015 case XML_b: rSheetData.setBooleanCell( aModel, rItem.getValue().get< bool >() ); break;
1016 case XML_e: rSheetData.setErrorCell( aModel, static_cast< sal_uInt8 >( rItem.getValue().get< sal_Int32 >() ) ); break;
1017 default: OSL_FAIL( "PivotCacheField::writeItemToSourceDataCell - unexpected item data type" );
1022 void PivotCacheField::writeSharedItemToSourceDataCell(
1023 WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nItemIdx ) const
1025 if( const PivotCacheItem* pCacheItem = maSharedItems.getCacheItem( nItemIdx ) )
1026 writeItemToSourceDataCell( rSheetHelper, nCol, nRow, *pCacheItem );
1029 PCDefinitionModel::PCDefinitionModel() :
1030 mfRefreshedDate( 0.0 ),
1031 mnRecords( 0 ),
1032 mnMissItemsLimit( 0 ),
1033 mnDatabaseFields( 0 ),
1034 mbInvalid( false ),
1035 mbSaveData( true ),
1036 mbRefreshOnLoad( false ),
1037 mbOptimizeMemory( false ),
1038 mbEnableRefresh( true ),
1039 mbBackgroundQuery( false ),
1040 mbUpgradeOnRefresh( false ),
1041 mbTupleCache( false ),
1042 mbSupportSubquery( false ),
1043 mbSupportDrill( false )
1047 PCSourceModel::PCSourceModel() :
1048 mnSourceType( XML_TOKEN_INVALID ),
1049 mnConnectionId( 0 )
1053 PCWorksheetSourceModel::PCWorksheetSourceModel()
1055 maRange.StartColumn = maRange.StartRow = maRange.EndColumn = maRange.EndRow = -1;
1058 PivotCache::PivotCache( const WorkbookHelper& rHelper ) :
1059 WorkbookHelper( rHelper ),
1060 mnCurrRow( -1 ),
1061 mbValidSource( false ),
1062 mbDummySheet( false )
1066 void PivotCache::importPivotCacheDefinition( const AttributeList& rAttribs )
1068 maDefModel.maRelId = rAttribs.getString( R_TOKEN( id ), OUString() );
1069 maDefModel.maRefreshedBy = rAttribs.getXString( XML_refreshedBy, OUString() );
1070 maDefModel.mfRefreshedDate = rAttribs.getDouble( XML_refreshedDate, 0.0 );
1071 maDefModel.mnRecords = rAttribs.getInteger( XML_recordCount, 0 );
1072 maDefModel.mnMissItemsLimit = rAttribs.getInteger( XML_missingItemsLimit, 0 );
1073 maDefModel.mbInvalid = rAttribs.getBool( XML_invalid, false );
1074 maDefModel.mbSaveData = rAttribs.getBool( XML_saveData, true );
1075 maDefModel.mbRefreshOnLoad = rAttribs.getBool( XML_refreshOnLoad, false );
1076 maDefModel.mbOptimizeMemory = rAttribs.getBool( XML_optimizeMemory, false );
1077 maDefModel.mbEnableRefresh = rAttribs.getBool( XML_enableRefresh, true );
1078 maDefModel.mbBackgroundQuery = rAttribs.getBool( XML_backgroundQuery, false );
1079 maDefModel.mbUpgradeOnRefresh = rAttribs.getBool( XML_upgradeOnRefresh, false );
1080 maDefModel.mbTupleCache = rAttribs.getBool( XML_tupleCache, false );
1081 maDefModel.mbSupportSubquery = rAttribs.getBool( XML_supportSubquery, false );
1082 maDefModel.mbSupportDrill = rAttribs.getBool( XML_supportAdvancedDrill, false );
1085 void PivotCache::importCacheSource( const AttributeList& rAttribs )
1087 maSourceModel.mnSourceType = rAttribs.getToken( XML_type, XML_TOKEN_INVALID );
1088 maSourceModel.mnConnectionId = rAttribs.getInteger( XML_connectionId, 0 );
1091 void PivotCache::importWorksheetSource( const AttributeList& rAttribs, const Relations& rRelations )
1093 maSheetSrcModel.maRelId = rAttribs.getString( R_TOKEN( id ), OUString() );
1094 maSheetSrcModel.maSheet = rAttribs.getXString( XML_sheet, OUString() );
1095 maSheetSrcModel.maDefName = rAttribs.getXString( XML_name, OUString() );
1097 // resolve URL of external document
1098 maTargetUrl = rRelations.getExternalTargetFromRelId( maSheetSrcModel.maRelId );
1099 // store range address unchecked with sheet index 0, will be resolved/checked later
1100 AddressConverter::convertToCellRangeUnchecked( maSheetSrcModel.maRange, rAttribs.getString( XML_ref, OUString() ), 0 );
1103 void PivotCache::importPCDefinition( SequenceInputStream& rStrm )
1105 sal_uInt8 nFlags1, nFlags2;
1106 rStrm.skip( 3 ); // create/refresh version id's
1107 nFlags1 = rStrm.readuChar();
1108 maDefModel.mnMissItemsLimit = rStrm.readInt32();
1109 maDefModel.mfRefreshedDate = rStrm.readDouble();
1110 nFlags2 = rStrm.readuChar();
1111 maDefModel.mnRecords = rStrm.readInt32();
1112 if( getFlag( nFlags2, BIFF12_PCDEFINITION_HASUSERNAME ) )
1113 rStrm >> maDefModel.maRefreshedBy;
1114 if( getFlag( nFlags2, BIFF12_PCDEFINITION_HASRELID ) )
1115 rStrm >> maDefModel.maRelId;
1117 maDefModel.mbInvalid = getFlag( nFlags1, BIFF12_PCDEFINITION_INVALID );
1118 maDefModel.mbSaveData = getFlag( nFlags1, BIFF12_PCDEFINITION_SAVEDATA );
1119 maDefModel.mbRefreshOnLoad = getFlag( nFlags1, BIFF12_PCDEFINITION_REFRESHONLOAD );
1120 maDefModel.mbOptimizeMemory = getFlag( nFlags1, BIFF12_PCDEFINITION_OPTIMIZEMEMORY );
1121 maDefModel.mbEnableRefresh = getFlag( nFlags1, BIFF12_PCDEFINITION_ENABLEREFRESH );
1122 maDefModel.mbBackgroundQuery = getFlag( nFlags1, BIFF12_PCDEFINITION_BACKGROUNDQUERY );
1123 maDefModel.mbUpgradeOnRefresh = getFlag( nFlags1, BIFF12_PCDEFINITION_UPGRADEONREFR );
1124 maDefModel.mbTupleCache = getFlag( nFlags1, BIFF12_PCDEFINITION_TUPELCACHE );
1125 maDefModel.mbSupportSubquery = getFlag( nFlags2, BIFF12_PCDEFINITION_SUPPORTSUBQUERY );
1126 maDefModel.mbSupportDrill = getFlag( nFlags2, BIFF12_PCDEFINITION_SUPPORTDRILL );
1129 void PivotCache::importPCDSource( SequenceInputStream& rStrm )
1131 sal_Int32 nSourceType;
1132 nSourceType = rStrm.readInt32();
1133 maSourceModel.mnConnectionId = rStrm.readInt32();
1134 static const sal_Int32 spnSourceTypes[] = { XML_worksheet, XML_external, XML_consolidation, XML_scenario };
1135 maSourceModel.mnSourceType = STATIC_ARRAY_SELECT( spnSourceTypes, nSourceType, XML_TOKEN_INVALID );
1138 void PivotCache::importPCDSheetSource( SequenceInputStream& rStrm, const Relations& rRelations )
1140 sal_uInt8 nIsDefName, nIsBuiltinName, nFlags;
1141 nIsDefName = rStrm.readuChar();
1142 nIsBuiltinName = rStrm.readuChar();
1143 nFlags = rStrm.readuChar();
1144 if( getFlag( nFlags, BIFF12_PCDWBSOURCE_HASSHEET ) )
1145 rStrm >> maSheetSrcModel.maSheet;
1146 if( getFlag( nFlags, BIFF12_PCDWBSOURCE_HASRELID ) )
1147 rStrm >> maSheetSrcModel.maRelId;
1149 // read cell range or defined name
1150 if( nIsDefName == 0 )
1152 BinRange aBinRange;
1153 rStrm >> aBinRange;
1154 // store range address unchecked with sheet index 0, will be resolved/checked later
1155 AddressConverter::convertToCellRangeUnchecked( maSheetSrcModel.maRange, aBinRange, 0 );
1157 else
1159 rStrm >> maSheetSrcModel.maDefName;
1160 if( nIsBuiltinName != 0 )
1161 maSheetSrcModel.maDefName = "_xlnm." + maSheetSrcModel.maDefName;
1164 // resolve URL of external document
1165 maTargetUrl = rRelations.getExternalTargetFromRelId( maSheetSrcModel.maRelId );
1168 void PivotCache::importPCDefinition( BiffInputStream& rStrm )
1170 sal_uInt16 nFlags, nUserNameLen;
1171 rStrm >> maDefModel.mnRecords;
1172 rStrm.skip( 2 ); // repeated cache ID
1173 rStrm >> nFlags;
1174 rStrm.skip( 2 ); // unused
1175 rStrm >> maDefModel.mnDatabaseFields;
1176 rStrm.skip( 6 ); // total field count, report record count, (repeated) cache type
1177 rStrm >> nUserNameLen;
1178 if( nUserNameLen != BIFF_PC_NOSTRING )
1179 maDefModel.maRefreshedBy = (getBiff() == BIFF8) ?
1180 rStrm.readUniString( nUserNameLen ) :
1181 rStrm.readCharArrayUC( nUserNameLen, getTextEncoding() );
1183 maDefModel.mbInvalid = getFlag( nFlags, BIFF_PCDEFINITION_INVALID );
1184 maDefModel.mbSaveData = getFlag( nFlags, BIFF_PCDEFINITION_SAVEDATA );
1185 maDefModel.mbRefreshOnLoad = getFlag( nFlags, BIFF_PCDEFINITION_REFRESHONLOAD );
1186 maDefModel.mbOptimizeMemory = getFlag( nFlags, BIFF_PCDEFINITION_OPTIMIZEMEMORY );
1187 maDefModel.mbEnableRefresh = getFlag( nFlags, BIFF_PCDEFINITION_ENABLEREFRESH );
1188 maDefModel.mbBackgroundQuery = getFlag( nFlags, BIFF_PCDEFINITION_BACKGROUNDQUERY );
1190 if( (rStrm.getNextRecId() == BIFF_ID_PCDEFINITION2) && rStrm.startNextRecord() )
1191 rStrm >> maDefModel.mfRefreshedDate;
1194 PivotCacheField& PivotCache::createCacheField( bool bInitDatabaseField )
1196 bool bIsDatabaseField = !bInitDatabaseField || (maFields.size() < maDefModel.mnDatabaseFields);
1197 PivotCacheFieldVector::value_type xCacheField( new PivotCacheField( *this, bIsDatabaseField ) );
1198 maFields.push_back( xCacheField );
1199 return *xCacheField;
1202 void PivotCache::finalizeImport()
1204 // collect all fields that are based on source data (needed to finalize source data below)
1205 OSL_ENSURE( !maFields.empty(), "PivotCache::finalizeImport - no pivot cache fields found" );
1206 for( PivotCacheFieldVector::const_iterator aIt = maFields.begin(), aEnd = maFields.end(); aIt != aEnd; ++aIt )
1208 if( (*aIt)->isDatabaseField() )
1210 OSL_ENSURE( (aIt == maFields.begin()) || (*(aIt - 1))->isDatabaseField(),
1211 "PivotCache::finalizeImport - database field follows a calculated field" );
1212 maDatabaseIndexes.push_back( static_cast< sal_Int32 >( maDatabaseFields.size() ) );
1213 maDatabaseFields.push_back( *aIt );
1215 else
1217 maDatabaseIndexes.push_back( -1 );
1220 OSL_ENSURE( !maDatabaseFields.empty(), "PivotCache::finalizeImport - no pivot cache source fields found" );
1222 // finalize source data depending on source type
1223 switch( maSourceModel.mnSourceType )
1225 case XML_worksheet:
1227 // decide whether an external document is used
1228 bool bInternal = maTargetUrl.isEmpty() && maSheetSrcModel.maRelId.isEmpty();
1229 bool bExternal = !maTargetUrl.isEmpty(); // relation ID may be empty, e.g. BIFF import
1230 OSL_ENSURE( bInternal || bExternal, "PivotCache::finalizeImport - invalid external document URL" );
1231 if( bInternal )
1232 finalizeInternalSheetSource();
1233 else if( bExternal )
1234 finalizeExternalSheetSource();
1236 break;
1238 // currently, we only support worksheet data sources
1239 case XML_external:
1240 break;
1241 case XML_consolidation:
1242 break;
1243 case XML_scenario:
1244 break;
1248 sal_Int32 PivotCache::getCacheFieldCount() const
1250 return static_cast< sal_Int32 >( maFields.size() );
1253 PivotCacheField* PivotCache::getCacheField( sal_Int32 nFieldIdx )
1255 return maFields.get( nFieldIdx ).get();
1258 const PivotCacheField* PivotCache::getCacheField( sal_Int32 nFieldIdx ) const
1260 return maFields.get( nFieldIdx ).get();
1263 sal_Int32 PivotCache::getCacheDatabaseIndex( sal_Int32 nFieldIdx ) const
1265 return ContainerHelper::getVectorElement( maDatabaseIndexes, nFieldIdx, -1 );
1268 void PivotCache::writeSourceHeaderCells( WorksheetHelper& rSheetHelper ) const
1270 OSL_ENSURE( static_cast< size_t >( maSheetSrcModel.maRange.EndColumn - maSheetSrcModel.maRange.StartColumn + 1 ) == maDatabaseFields.size(),
1271 "PivotCache::writeSourceHeaderCells - source cell range width does not match number of source fields" );
1272 sal_Int32 nCol = maSheetSrcModel.maRange.StartColumn;
1273 sal_Int32 nMaxCol = getAddressConverter().getMaxApiAddress().Col();
1274 sal_Int32 nRow = maSheetSrcModel.maRange.StartRow;
1275 mnCurrRow = -1;
1276 updateSourceDataRow( rSheetHelper, nRow );
1277 for( PivotCacheFieldVector::const_iterator aIt = maDatabaseFields.begin(), aEnd = maDatabaseFields.end(); (aIt != aEnd) && (nCol <= nMaxCol); ++aIt, ++nCol )
1278 (*aIt)->writeSourceHeaderCell( rSheetHelper, nCol, nRow );
1281 void PivotCache::writeSourceDataCell( WorksheetHelper& rSheetHelper, sal_Int32 nColIdx, sal_Int32 nRowIdx, const PivotCacheItem& rItem ) const
1283 sal_Int32 nCol = maSheetSrcModel.maRange.StartColumn + nColIdx;
1284 OSL_ENSURE( (maSheetSrcModel.maRange.StartColumn <= nCol) && (nCol <= maSheetSrcModel.maRange.EndColumn), "PivotCache::writeSourceDataCell - invalid column index" );
1285 sal_Int32 nRow = maSheetSrcModel.maRange.StartRow + nRowIdx;
1286 OSL_ENSURE( (maSheetSrcModel.maRange.StartRow < nRow) && (nRow <= maSheetSrcModel.maRange.EndRow), "PivotCache::writeSourceDataCell - invalid row index" );
1287 updateSourceDataRow( rSheetHelper, nRow );
1288 if( const PivotCacheField* pCacheField = maDatabaseFields.get( nColIdx ).get() )
1289 pCacheField->writeSourceDataCell( rSheetHelper, nCol, nRow, rItem );
1292 void PivotCache::importPCRecord( SequenceInputStream& rStrm, WorksheetHelper& rSheetHelper, sal_Int32 nRowIdx ) const
1294 sal_Int32 nRow = maSheetSrcModel.maRange.StartRow + nRowIdx;
1295 OSL_ENSURE( (maSheetSrcModel.maRange.StartRow < nRow) && (nRow <= maSheetSrcModel.maRange.EndRow), "PivotCache::importPCRecord - invalid row index" );
1296 sal_Int32 nCol = maSheetSrcModel.maRange.StartColumn;
1297 sal_Int32 nMaxCol = getAddressConverter().getMaxApiAddress().Col();
1298 for( PivotCacheFieldVector::const_iterator aIt = maDatabaseFields.begin(), aEnd = maDatabaseFields.end(); !rStrm.isEof() && (aIt != aEnd) && (nCol <= nMaxCol); ++aIt, ++nCol )
1299 (*aIt)->importPCRecordItem( rStrm, rSheetHelper, nCol, nRow );
1302 void PivotCache::importPCItemIndexList( BiffInputStream& rStrm, WorksheetHelper& rSheetHelper, sal_Int32 nRowIdx ) const
1304 sal_Int32 nRow = maSheetSrcModel.maRange.StartRow + nRowIdx;
1305 OSL_ENSURE( (maSheetSrcModel.maRange.StartRow < nRow) && (nRow <= maSheetSrcModel.maRange.EndRow), "PivotCache::importPCItemIndexList - invalid row index" );
1306 sal_Int32 nCol = maSheetSrcModel.maRange.StartColumn;
1307 sal_Int32 nMaxCol = getAddressConverter().getMaxApiAddress().Col();
1308 for( PivotCacheFieldVector::const_iterator aIt = maDatabaseFields.begin(), aEnd = maDatabaseFields.end(); !rStrm.isEof() && (aIt != aEnd) && (nCol <= nMaxCol); ++aIt, ++nCol )
1309 if( (*aIt)->hasSharedItems() )
1310 (*aIt)->importPCItemIndex( rStrm, rSheetHelper, nCol, nRow );
1313 // private --------------------------------------------------------------------
1315 void PivotCache::finalizeInternalSheetSource()
1317 // resolve sheet name to sheet index
1318 sal_Int16 nSheet = getWorksheets().getCalcSheetIndex( maSheetSrcModel.maSheet );
1320 // if cache is based on a defined name or table, try to resolve to cell range
1321 if( !maSheetSrcModel.maDefName.isEmpty() )
1323 // local or global defined name
1324 if( const DefinedName* pDefName = getDefinedNames().getByModelName( maSheetSrcModel.maDefName, nSheet ).get() )
1326 mbValidSource = pDefName->getAbsoluteRange( maSheetSrcModel.maRange );
1328 // table
1329 else if( const Table* pTable = getTables().getTable( maSheetSrcModel.maDefName ).get() )
1331 // get original range from table, but exclude the totals row(s)
1332 maSheetSrcModel.maRange = pTable->getOriginalRange();
1333 mbValidSource = (pTable->getHeight() - pTable->getTotalsRows()) > 1;
1334 if( mbValidSource )
1335 maSheetSrcModel.maRange.EndRow -= pTable->getTotalsRows();
1338 // else try the cell range (if the sheet exists)
1339 else if( nSheet >= 0 )
1341 // insert sheet index into the range, range address will be checked below
1342 maSheetSrcModel.maRange.Sheet = nSheet;
1343 mbValidSource = true;
1345 // else sheet has been deleted, generate the source data from cache
1346 else if( !maSheetSrcModel.maSheet.isEmpty() )
1348 prepareSourceDataSheet();
1349 // return here to skip the source range check below
1350 return;
1353 // check range location, do not allow ranges that overflow the sheet partly
1354 mbValidSource = mbValidSource &&
1355 getAddressConverter().checkCellRange( maSheetSrcModel.maRange, false, true ) &&
1356 (maSheetSrcModel.maRange.StartRow < maSheetSrcModel.maRange.EndRow);
1359 void PivotCache::finalizeExternalSheetSource()
1361 /* If pivot cache is based on external sheet data, try to restore sheet
1362 data from cache records. No support for external defined names or tables,
1363 sheet name and path to cache records fragment (OOXML only) are required. */
1364 bool bHasRelation = (getFilterType() == FILTER_BIFF) || !maDefModel.maRelId.isEmpty();
1365 if( bHasRelation && maSheetSrcModel.maDefName.isEmpty() && !maSheetSrcModel.maSheet.isEmpty() )
1366 prepareSourceDataSheet();
1369 void PivotCache::prepareSourceDataSheet()
1371 CellRangeAddress& rRange = maSheetSrcModel.maRange;
1372 // data will be inserted in top-left cell, sheet index is still set to 0 (will be set below)
1373 rRange.EndColumn -= rRange.StartColumn;
1374 rRange.StartColumn = 0;
1375 rRange.EndRow -= rRange.StartRow;
1376 rRange.StartRow = 0;
1377 // check range location, do not allow ranges that overflow the sheet partly
1378 if( getAddressConverter().checkCellRange( rRange, false, true ) )
1380 maColSpans.insert( ValueRange( rRange.StartColumn, rRange.EndColumn ) );
1381 OUString aSheetName = "DPCache_" + maSheetSrcModel.maSheet;
1382 rRange.Sheet = getWorksheets().insertEmptySheet( aSheetName );
1383 mbValidSource = mbDummySheet = rRange.Sheet >= 0;
1387 void PivotCache::updateSourceDataRow( WorksheetHelper& rSheetHelper, sal_Int32 nRow ) const
1389 if( mnCurrRow != nRow )
1391 rSheetHelper.getSheetData().setColSpans( nRow, maColSpans );
1392 mnCurrRow = nRow;
1396 PivotCacheBuffer::PivotCacheBuffer( const WorkbookHelper& rHelper ) :
1397 WorkbookHelper( rHelper )
1401 void PivotCacheBuffer::registerPivotCacheFragment( sal_Int32 nCacheId, const OUString& rFragmentPath )
1403 OSL_ENSURE( nCacheId >= 0, "PivotCacheBuffer::registerPivotCacheFragment - invalid pivot cache identifier" );
1404 OSL_ENSURE( maFragmentPaths.count( nCacheId ) == 0, "PivotCacheBuffer::registerPivotCacheFragment - fragment path exists already" );
1405 if( (nCacheId >= 0) && !rFragmentPath.isEmpty() )
1406 maFragmentPaths[ nCacheId ] = rFragmentPath;
1409 PivotCache* PivotCacheBuffer::importPivotCacheFragment( sal_Int32 nCacheId )
1411 switch( getFilterType() )
1413 /* OOXML/BIFF12 filter: On first call for the cache ID, the pivot
1414 cache object is created and inserted into maCaches. Then, the cache
1415 definition fragment is read and the cache is returned. On
1416 subsequent calls, the created cache will be found in maCaches and
1417 returned immediately. */
1418 case FILTER_OOXML:
1420 // try to find an imported pivot cache
1421 if( PivotCache* pCache = maCaches.get( nCacheId ).get() )
1422 return pCache;
1424 // check if a fragment path exists for the passed cache identifier
1425 FragmentPathMap::iterator aIt = maFragmentPaths.find( nCacheId );
1426 if( aIt == maFragmentPaths.end() )
1427 return nullptr;
1429 /* Import the cache fragment. This may create a dummy data sheet
1430 for external sheet sources. */
1431 PivotCache& rCache = createPivotCache( nCacheId );
1432 importOoxFragment( new PivotCacheDefinitionFragment( *this, aIt->second, rCache ) );
1433 return &rCache;
1436 /* BIFF filter: Pivot table provides 0-based index into list of pivot
1437 cache source links (PIVOTCACHE/PCDSOURCE/... record blocks in
1438 workbook stream). First, this index has to be resolved to the cache
1439 identifier that is used to manage the cache stream names (the
1440 maFragmentPaths member). The cache object itself exists already
1441 before the first call for the cache source index, because source data
1442 link is part of workbook data, not of the cache stream. To detect
1443 subsequent calls with an already initialized cache, the entry in
1444 maFragmentPaths will be removed after reading the cache stream. */
1445 case FILTER_BIFF:
1447 /* Resolve cache index to cache identifier and try to find pivot
1448 cache. Cache must exist already for a valid cache index. */
1449 nCacheId = ContainerHelper::getVectorElement( maCacheIds, nCacheId, -1 );
1450 PivotCache* pCache = maCaches.get( nCacheId ).get();
1451 if( !pCache )
1452 return nullptr;
1454 /* Try to find fragment path entry (stream name). If missing, the
1455 stream has been read already, and the cache can be returned. */
1456 FragmentPathMap::iterator aIt = maFragmentPaths.find( nCacheId );
1457 if( aIt != maFragmentPaths.end() )
1459 /* Import the cache stream. This may create a dummy data sheet
1460 for external sheet sources. */
1461 BiffPivotCacheFragment( *this, aIt->second, *pCache ).importFragment();
1462 // remove the fragment entry to mark that the cache is initialized
1463 maFragmentPaths.erase( aIt );
1465 return pCache;
1468 case FILTER_UNKNOWN:
1469 OSL_FAIL( "PivotCacheBuffer::importPivotCacheFragment - unknown filter type" );
1471 return nullptr;
1474 PivotCache& PivotCacheBuffer::createPivotCache( sal_Int32 nCacheId )
1476 maCacheIds.push_back( nCacheId );
1477 PivotCacheMap::mapped_type& rxCache = maCaches[ nCacheId ];
1478 rxCache.reset( new PivotCache( *this ) );
1479 return *rxCache;
1482 } // namespace xls
1483 } // namespace oox
1485 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */