Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / sc / source / filter / oox / pivotcachebuffer.cxx
blobfdb7b15da2e2ac7ad363ff4d089c9a7b677329f1
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 <com/sun/star/beans/XPropertySet.hpp>
23 #include <com/sun/star/container/XIndexAccess.hpp>
24 #include <com/sun/star/container/XNameAccess.hpp>
25 #include <com/sun/star/container/XNamed.hpp>
26 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
27 #include <com/sun/star/sheet/DataPilotFieldGroupInfo.hpp>
28 #include <com/sun/star/sheet/XDataPilotFieldGrouping.hpp>
29 #include <osl/diagnose.h>
30 #include <sal/log.hxx>
31 #include <oox/helper/attributelist.hxx>
32 #include <oox/helper/binaryinputstream.hxx>
33 #include <oox/helper/containerhelper.hxx>
34 #include <oox/helper/propertyset.hxx>
35 #include <oox/token/namespaces.hxx>
36 #include <oox/token/properties.hxx>
37 #include <oox/token/tokens.hxx>
38 #include <tools/diagnose_ex.h>
39 #include <defnamesbuffer.hxx>
40 #include <pivotcachefragment.hxx>
41 #include <sheetdatabuffer.hxx>
42 #include <tablebuffer.hxx>
43 #include <unitconverter.hxx>
44 #include <worksheetbuffer.hxx>
45 #include <dpobject.hxx>
46 #include <dpsave.hxx>
47 #include <tools/datetime.hxx>
48 #include <addressconverter.hxx>
49 #include <biffhelper.hxx>
51 namespace oox {
52 namespace xls {
54 using namespace ::com::sun::star::container;
55 using namespace ::com::sun::star::sheet;
56 using namespace ::com::sun::star::uno;
58 using ::oox::core::Relations;
60 namespace {
62 const sal_uInt16 BIFF12_PCDFIELD_SERVERFIELD = 0x0001;
63 const sal_uInt16 BIFF12_PCDFIELD_NOUNIQUEITEMS = 0x0002;
64 const sal_uInt16 BIFF12_PCDFIELD_DATABASEFIELD = 0x0004;
65 const sal_uInt16 BIFF12_PCDFIELD_HASCAPTION = 0x0008;
66 const sal_uInt16 BIFF12_PCDFIELD_MEMBERPROPFIELD = 0x0010;
67 const sal_uInt16 BIFF12_PCDFIELD_HASFORMULA = 0x0100;
68 const sal_uInt16 BIFF12_PCDFIELD_HASPROPERTYNAME = 0x0200;
70 const sal_uInt16 BIFF12_PCDFSITEMS_HASSEMIMIXED = 0x0001;
71 const sal_uInt16 BIFF12_PCDFSITEMS_HASNONDATE = 0x0002;
72 const sal_uInt16 BIFF12_PCDFSITEMS_HASDATE = 0x0004;
73 const sal_uInt16 BIFF12_PCDFSITEMS_HASSTRING = 0x0008;
74 const sal_uInt16 BIFF12_PCDFSITEMS_HASBLANK = 0x0010;
75 const sal_uInt16 BIFF12_PCDFSITEMS_HASMIXED = 0x0020;
76 const sal_uInt16 BIFF12_PCDFSITEMS_ISNUMERIC = 0x0040;
77 const sal_uInt16 BIFF12_PCDFSITEMS_ISINTEGER = 0x0080;
78 const sal_uInt16 BIFF12_PCDFSITEMS_HASLONGTEXT = 0x0200;
80 const sal_uInt16 BIFF12_PCITEM_ARRAY_DOUBLE = 0x0001;
81 const sal_uInt16 BIFF12_PCITEM_ARRAY_STRING = 0x0002;
82 const sal_uInt16 BIFF12_PCITEM_ARRAY_ERROR = 0x0010;
83 const sal_uInt16 BIFF12_PCITEM_ARRAY_DATE = 0x0020;
85 const sal_uInt8 BIFF12_PCDFRANGEPR_AUTOSTART = 0x01;
86 const sal_uInt8 BIFF12_PCDFRANGEPR_AUTOEND = 0x02;
87 const sal_uInt8 BIFF12_PCDFRANGEPR_DATEGROUP = 0x04;
89 const sal_uInt8 BIFF12_PCDEFINITION_SAVEDATA = 0x01;
90 const sal_uInt8 BIFF12_PCDEFINITION_INVALID = 0x02;
91 const sal_uInt8 BIFF12_PCDEFINITION_REFRESHONLOAD = 0x04;
92 const sal_uInt8 BIFF12_PCDEFINITION_OPTIMIZEMEMORY = 0x08;
93 const sal_uInt8 BIFF12_PCDEFINITION_ENABLEREFRESH = 0x10;
94 const sal_uInt8 BIFF12_PCDEFINITION_BACKGROUNDQUERY = 0x20;
95 const sal_uInt8 BIFF12_PCDEFINITION_UPGRADEONREFR = 0x40;
96 const sal_uInt8 BIFF12_PCDEFINITION_TUPELCACHE = 0x80;
98 const sal_uInt8 BIFF12_PCDEFINITION_HASUSERNAME = 0x01;
99 const sal_uInt8 BIFF12_PCDEFINITION_HASRELID = 0x02;
100 const sal_uInt8 BIFF12_PCDEFINITION_SUPPORTSUBQUERY = 0x04;
101 const sal_uInt8 BIFF12_PCDEFINITION_SUPPORTDRILL = 0x08;
103 const sal_uInt8 BIFF12_PCDWBSOURCE_HASRELID = 0x01;
104 const sal_uInt8 BIFF12_PCDWBSOURCE_HASSHEET = 0x02;
107 /** Adjusts the weird date format read from binary streams.
109 Dates before 1900-Mar-01 are stored including the non-existing leap day
110 1900-02-29. tools::Time values (without date) are stored as times of day
111 1900-Jan-00. Nothing has to be done when the workbook is stored in 1904
112 date mode (dates before 1904-Jan-01 will not occur in this case).
114 void lclAdjustBinDateTime( css::util::DateTime& orDateTime )
116 if( (orDateTime.Year == 1900) && (orDateTime.Month <= 2) )
118 OSL_ENSURE( (orDateTime.Month == 1) || ((orDateTime.Month == 2) && (orDateTime.Day > 0)), "lclAdjustBinDateTime - invalid date" );
119 switch( orDateTime.Month )
121 case 2: if( orDateTime.Day > 1 ) --orDateTime.Day; else { orDateTime.Day += 30; --orDateTime.Month; } break;
122 case 1: if( orDateTime.Day > 1 ) --orDateTime.Day; else { orDateTime.Day += 30; orDateTime.Month = 12; --orDateTime.Year; } break;
127 } // namespace
129 PivotCacheItem::PivotCacheItem() :
130 mnType( XML_m ), mbUnused( false )
134 void PivotCacheItem::readString( const AttributeList& rAttribs )
136 maValue <<= rAttribs.getXString( XML_v, OUString() );
137 mnType = XML_s;
140 void PivotCacheItem::readNumeric( const AttributeList& rAttribs )
142 maValue <<= rAttribs.getDouble( XML_v, 0.0 );
143 mnType = XML_n;
144 mbUnused = rAttribs.getBool( XML_u, false );
147 void PivotCacheItem::readDate( const AttributeList& rAttribs )
149 maValue <<= rAttribs.getDateTime( XML_v, css::util::DateTime() );
150 mnType = XML_d;
153 void PivotCacheItem::readBool( const AttributeList& rAttribs )
155 maValue <<= rAttribs.getBool( XML_v, false );
156 mnType = XML_b;
159 void PivotCacheItem::readError( const AttributeList& rAttribs )
161 maValue <<= rAttribs.getXString( XML_v, OUString() );
162 mnType = XML_e;
165 void PivotCacheItem::readIndex( const AttributeList& rAttribs )
167 maValue <<= rAttribs.getInteger( XML_v, -1 );
168 mnType = XML_x;
171 void PivotCacheItem::readString( SequenceInputStream& rStrm )
173 maValue <<= BiffHelper::readString( rStrm );
174 mnType = XML_s;
177 void PivotCacheItem::readDouble( SequenceInputStream& rStrm )
179 maValue <<= rStrm.readDouble();
180 mnType = XML_n;
183 void PivotCacheItem::readDate( SequenceInputStream& rStrm )
185 css::util::DateTime aDateTime;
186 aDateTime.Year = rStrm.readuInt16();
187 aDateTime.Month = rStrm.readuInt16();
188 aDateTime.Day = rStrm.readuInt8();
189 aDateTime.Hours = rStrm.readuInt8();
190 aDateTime.Minutes = rStrm.readuInt8();
191 aDateTime.Seconds = rStrm.readuInt8();
192 lclAdjustBinDateTime( aDateTime );
193 maValue <<= aDateTime;
194 mnType = XML_d;
197 void PivotCacheItem::readBool( SequenceInputStream& rStrm )
199 maValue <<= (rStrm.readuInt8() != 0);
200 mnType = XML_b;
203 void PivotCacheItem::readError( SequenceInputStream& rStrm )
205 maValue <<= static_cast< sal_Int32 >( rStrm.readuInt8() );
206 mnType = XML_e;
209 void PivotCacheItem::readIndex( SequenceInputStream& rStrm )
211 maValue <<= rStrm.readInt32();
212 mnType = XML_x;
215 void PivotCacheItem::setStringValue( const OUString& sString )
217 mnType = XML_s;
218 maValue <<= sString;
221 OUString PivotCacheItem::getName() const
223 switch( mnType )
225 case XML_m: return OUString();
226 case XML_s: return maValue.get< OUString >();
227 case XML_n: return OUString::number( maValue.get< double >() ); // !TODO
228 case XML_i: return OUString::number( maValue.get< sal_Int32 >() );
229 case XML_d: return OUString(); // !TODO
230 case XML_b: return OUString::boolean( maValue.get< bool >() ); // !TODO
231 case XML_e: return OUString(); // !TODO
233 OSL_FAIL( "PivotCacheItem::getName - invalid data type" );
234 return OUString();
237 OUString PivotCacheItem::getFormattedName(const ScDPSaveDimension& rSaveDim, ScDPObject* pObj, const DateTime& rNullDate) const
239 switch( mnType )
241 case XML_m: return OUString();
242 case XML_s: return maValue.get< OUString >();
243 case XML_n: return pObj->GetFormattedString(rSaveDim.GetName(), maValue.get<double>());
244 case XML_i: return pObj->GetFormattedString(rSaveDim.GetName(), static_cast<double>(maValue.get< sal_Int32 >()));
245 case XML_b: return pObj->GetFormattedString(rSaveDim.GetName(), static_cast<double>(maValue.get< bool >()));
246 case XML_d: return pObj->GetFormattedString(rSaveDim.GetName(), maValue.get< css::util::DateTime >() - rNullDate);
247 case XML_e: return maValue.get< OUString >();
249 OSL_FAIL( "PivotCacheItem::getFormattedName - invalid data type" );
250 return OUString();
253 PivotCacheItemList::PivotCacheItemList( const WorkbookHelper& rHelper ) :
254 WorkbookHelper( rHelper )
258 void PivotCacheItemList::importItem( sal_Int32 nElement, const AttributeList& rAttribs )
260 PivotCacheItem& rItem = createItem();
261 switch( nElement )
263 case XLS_TOKEN( m ): break;
264 case XLS_TOKEN( s ): rItem.readString( rAttribs ); break;
265 case XLS_TOKEN( n ): rItem.readNumeric( rAttribs ); break;
266 case XLS_TOKEN( d ): rItem.readDate( rAttribs ); break;
267 case XLS_TOKEN( b ): rItem.readBool( rAttribs ); break;
268 case XLS_TOKEN( e ): rItem.readError( rAttribs ); break;
269 default: OSL_FAIL( "PivotCacheItemList::importItem - unknown element type" );
273 void PivotCacheItemList::importItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
275 if( nRecId == BIFF12_ID_PCITEM_ARRAY )
277 importArray( rStrm );
278 return;
281 PivotCacheItem& rItem = createItem();
282 switch( nRecId )
284 case BIFF12_ID_PCITEM_MISSING:
285 case BIFF12_ID_PCITEMA_MISSING: break;
286 case BIFF12_ID_PCITEM_STRING:
287 case BIFF12_ID_PCITEMA_STRING: rItem.readString( rStrm ); break;
288 case BIFF12_ID_PCITEM_DOUBLE:
289 case BIFF12_ID_PCITEMA_DOUBLE: rItem.readDouble( rStrm ); break;
290 case BIFF12_ID_PCITEM_DATE:
291 case BIFF12_ID_PCITEMA_DATE: rItem.readDate( rStrm ); break;
292 case BIFF12_ID_PCITEM_BOOL:
293 case BIFF12_ID_PCITEMA_BOOL: rItem.readBool( rStrm ); break;
294 case BIFF12_ID_PCITEM_ERROR:
295 case BIFF12_ID_PCITEMA_ERROR: rItem.readError( rStrm ); break;
296 default: OSL_FAIL( "PivotCacheItemList::importItem - unknown record type" );
300 const PivotCacheItem* PivotCacheItemList::getCacheItem( sal_Int32 nItemIdx ) const
302 return ContainerHelper::getVectorElement( maItems, nItemIdx );
305 void PivotCacheItemList::applyItemCaptions( const IdCaptionPairList& vCaptions )
307 for( const auto& [rId, rCaption] : vCaptions )
309 if ( static_cast<sal_uInt32>( rId ) < maItems.size() )
310 maItems[ rId ].setStringValue( rCaption );
314 void PivotCacheItemList::getCacheItemNames( ::std::vector< OUString >& orItemNames ) const
316 orItemNames.clear();
317 orItemNames.reserve( maItems.size() );
318 for( const auto& rItem : maItems )
319 orItemNames.push_back( rItem.getName() );
322 // private --------------------------------------------------------------------
324 PivotCacheItem& PivotCacheItemList::createItem()
326 maItems.emplace_back();
327 return maItems.back();
330 void PivotCacheItemList::importArray( SequenceInputStream& rStrm )
332 sal_uInt16 nType = rStrm.readuInt16();
333 sal_Int32 nCount = rStrm.readInt32();
334 for( sal_Int32 nIdx = 0; !rStrm.isEof() && (nIdx < nCount); ++nIdx )
336 switch( nType )
338 case BIFF12_PCITEM_ARRAY_DOUBLE: createItem().readDouble( rStrm ); break;
339 case BIFF12_PCITEM_ARRAY_STRING: createItem().readString( rStrm ); break;
340 case BIFF12_PCITEM_ARRAY_ERROR: createItem().readError( rStrm ); break;
341 case BIFF12_PCITEM_ARRAY_DATE: createItem().readDate( rStrm ); break;
342 default:
343 OSL_FAIL( "PivotCacheItemList::importArray - unknown data type" );
344 return;
349 PCFieldModel::PCFieldModel() :
350 mnNumFmtId( 0 ),
351 mnSqlType( 0 ),
352 mnHierarchy( 0 ),
353 mnLevel( 0 ),
354 mnMappingCount( 0 ),
355 mbDatabaseField( true ),
356 mbServerField( false ),
357 mbUniqueList( true ),
358 mbMemberPropField( false )
362 PCSharedItemsModel::PCSharedItemsModel() :
363 mbHasSemiMixed( true ),
364 mbHasNonDate( true ),
365 mbHasDate( false ),
366 mbHasString( true ),
367 mbHasBlank( false ),
368 mbHasMixed( false ),
369 mbIsNumeric( false ),
370 mbIsInteger( false ),
371 mbHasLongText( false )
375 PCFieldGroupModel::PCFieldGroupModel() :
376 mfStartValue( 0.0 ),
377 mfEndValue( 0.0 ),
378 mfInterval( 1.0 ),
379 mnParentField( -1 ),
380 mnBaseField( -1 ),
381 mnGroupBy( XML_range ),
382 mbRangeGroup( false ),
383 mbDateGroup( false ),
384 mbAutoStart( true ),
385 mbAutoEnd( true )
389 void PCFieldGroupModel::setBiffGroupBy( sal_uInt8 nGroupBy )
391 static const sal_Int32 spnGroupBy[] = { XML_range,
392 XML_seconds, XML_minutes, XML_hours, XML_days, XML_months, XML_quarters, XML_years };
393 mnGroupBy = STATIC_ARRAY_SELECT( spnGroupBy, nGroupBy, XML_range );
396 PivotCacheField::PivotCacheField( const WorkbookHelper& rHelper, bool bIsDatabaseField ) :
397 WorkbookHelper( rHelper ),
398 maSharedItems( rHelper ),
399 maGroupItems( rHelper )
401 maFieldModel.mbDatabaseField = bIsDatabaseField;
404 void PivotCacheField::importCacheField( const AttributeList& rAttribs )
406 maFieldModel.maName = rAttribs.getXString( XML_name, OUString() );
407 maFieldModel.maCaption = rAttribs.getXString( XML_caption, OUString() );
408 maFieldModel.maPropertyName = rAttribs.getXString( XML_propertyName, OUString() );
409 maFieldModel.maFormula = rAttribs.getXString( XML_formula, OUString() );
410 maFieldModel.mnNumFmtId = rAttribs.getInteger( XML_numFmtId, 0 );
411 maFieldModel.mnSqlType = rAttribs.getInteger( XML_sqlType, 0 );
412 maFieldModel.mnHierarchy = rAttribs.getInteger( XML_hierarchy, 0 );
413 maFieldModel.mnLevel = rAttribs.getInteger( XML_level, 0 );
414 maFieldModel.mnMappingCount = rAttribs.getInteger( XML_mappingCount, 0 );
415 maFieldModel.mbDatabaseField = rAttribs.getBool( XML_databaseField, true );
416 maFieldModel.mbServerField = rAttribs.getBool( XML_serverField, false );
417 maFieldModel.mbUniqueList = rAttribs.getBool( XML_uniqueList, true );
418 maFieldModel.mbMemberPropField = rAttribs.getBool( XML_memberPropertyField, false );
421 void PivotCacheField::importSharedItems( const AttributeList& rAttribs )
423 OSL_ENSURE( maSharedItems.empty(), "PivotCacheField::importSharedItems - multiple shared items elements" );
424 maSharedItemsModel.mbHasSemiMixed = rAttribs.getBool( XML_containsSemiMixedTypes, true );
425 maSharedItemsModel.mbHasNonDate = rAttribs.getBool( XML_containsNonDate, true );
426 maSharedItemsModel.mbHasDate = rAttribs.getBool( XML_containsDate, false );
427 maSharedItemsModel.mbHasString = rAttribs.getBool( XML_containsString, true );
428 maSharedItemsModel.mbHasBlank = rAttribs.getBool( XML_containsBlank, false );
429 maSharedItemsModel.mbHasMixed = rAttribs.getBool( XML_containsMixedTypes, false );
430 maSharedItemsModel.mbIsNumeric = rAttribs.getBool( XML_containsNumber, false );
431 maSharedItemsModel.mbIsInteger = rAttribs.getBool( XML_containsInteger, false );
432 maSharedItemsModel.mbHasLongText = rAttribs.getBool( XML_longText, false );
435 void PivotCacheField::importSharedItem( sal_Int32 nElement, const AttributeList& rAttribs )
437 maSharedItems.importItem( nElement, rAttribs );
440 void PivotCacheField::importFieldGroup( const AttributeList& rAttribs )
442 maFieldGroupModel.mnParentField = rAttribs.getInteger( XML_par, -1 );
443 maFieldGroupModel.mnBaseField = rAttribs.getInteger( XML_base, -1 );
446 void PivotCacheField::importRangePr( const AttributeList& rAttribs )
448 maFieldGroupModel.maStartDate = rAttribs.getDateTime( XML_startDate, css::util::DateTime() );
449 maFieldGroupModel.maEndDate = rAttribs.getDateTime( XML_endDate, css::util::DateTime() );
450 maFieldGroupModel.mfStartValue = rAttribs.getDouble( XML_startNum, 0.0 );
451 maFieldGroupModel.mfEndValue = rAttribs.getDouble( XML_endNum, 0.0 );
452 maFieldGroupModel.mfInterval = rAttribs.getDouble( XML_groupInterval, 1.0 );
453 maFieldGroupModel.mnGroupBy = rAttribs.getToken( XML_groupBy, XML_range );
454 maFieldGroupModel.mbRangeGroup = true;
455 maFieldGroupModel.mbDateGroup = maFieldGroupModel.mnGroupBy != XML_range;
456 maFieldGroupModel.mbAutoStart = rAttribs.getBool( XML_autoStart, true );
457 maFieldGroupModel.mbAutoEnd = rAttribs.getBool( XML_autoEnd, true );
460 void PivotCacheField::importDiscretePrItem( sal_Int32 nElement, const AttributeList& rAttribs )
462 OSL_ENSURE( nElement == XLS_TOKEN( x ), "PivotCacheField::importDiscretePrItem - unexpected element" );
463 if( nElement == XLS_TOKEN( x ) )
464 maDiscreteItems.push_back( rAttribs.getInteger( XML_v, -1 ) );
467 void PivotCacheField::importGroupItem( sal_Int32 nElement, const AttributeList& rAttribs )
469 maGroupItems.importItem( nElement, rAttribs );
472 void PivotCacheField::importPCDField( SequenceInputStream& rStrm )
474 sal_uInt16 nFlags;
475 nFlags = rStrm.readuInt16();
476 maFieldModel.mnNumFmtId = rStrm.readInt32();
477 maFieldModel.mnSqlType = rStrm.readInt16();
478 maFieldModel.mnHierarchy = rStrm.readInt32();
479 maFieldModel.mnLevel = rStrm.readInt32();
480 maFieldModel.mnMappingCount = rStrm.readInt32();
481 rStrm >> maFieldModel.maName;
482 if( getFlag( nFlags, BIFF12_PCDFIELD_HASCAPTION ) )
483 rStrm >> maFieldModel.maCaption;
484 if( getFlag( nFlags, BIFF12_PCDFIELD_HASFORMULA ) )
485 rStrm.skip( ::std::max< sal_Int32 >( rStrm.readInt32(), 0 ) );
486 if( maFieldModel.mnMappingCount > 0 )
487 rStrm.skip( ::std::max< sal_Int32 >( rStrm.readInt32(), 0 ) );
488 if( getFlag( nFlags, BIFF12_PCDFIELD_HASPROPERTYNAME ) )
489 rStrm >> maFieldModel.maPropertyName;
491 maFieldModel.mbDatabaseField = getFlag( nFlags, BIFF12_PCDFIELD_DATABASEFIELD );
492 maFieldModel.mbServerField = getFlag( nFlags, BIFF12_PCDFIELD_SERVERFIELD );
493 maFieldModel.mbUniqueList = !getFlag( nFlags, BIFF12_PCDFIELD_NOUNIQUEITEMS );
494 maFieldModel.mbMemberPropField = getFlag( nFlags, BIFF12_PCDFIELD_MEMBERPROPFIELD );
497 void PivotCacheField::importPCDFSharedItems( SequenceInputStream& rStrm )
499 sal_uInt16 nFlags;
500 nFlags = rStrm.readuInt16();
501 maSharedItemsModel.mbHasSemiMixed = getFlag( nFlags, BIFF12_PCDFSITEMS_HASSEMIMIXED );
502 maSharedItemsModel.mbHasNonDate = getFlag( nFlags, BIFF12_PCDFSITEMS_HASNONDATE );
503 maSharedItemsModel.mbHasDate = getFlag( nFlags, BIFF12_PCDFSITEMS_HASDATE );
504 maSharedItemsModel.mbHasString = getFlag( nFlags, BIFF12_PCDFSITEMS_HASSTRING );
505 maSharedItemsModel.mbHasBlank = getFlag( nFlags, BIFF12_PCDFSITEMS_HASBLANK );
506 maSharedItemsModel.mbHasMixed = getFlag( nFlags, BIFF12_PCDFSITEMS_HASMIXED );
507 maSharedItemsModel.mbIsNumeric = getFlag( nFlags, BIFF12_PCDFSITEMS_ISNUMERIC );
508 maSharedItemsModel.mbIsInteger = getFlag( nFlags, BIFF12_PCDFSITEMS_ISINTEGER );
509 maSharedItemsModel.mbHasLongText = getFlag( nFlags, BIFF12_PCDFSITEMS_HASLONGTEXT );
512 void PivotCacheField::importPCDFSharedItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
514 maSharedItems.importItem( nRecId, rStrm );
517 void PivotCacheField::importPCDFieldGroup( SequenceInputStream& rStrm )
519 maFieldGroupModel.mnParentField = rStrm.readInt32();
520 maFieldGroupModel.mnBaseField = rStrm.readInt32();
523 void PivotCacheField::importPCDFRangePr( SequenceInputStream& rStrm )
525 sal_uInt8 nGroupBy, nFlags;
526 nGroupBy = rStrm.readuChar();
527 nFlags = rStrm.readuChar();
528 maFieldGroupModel.mfStartValue = rStrm.readDouble();
529 maFieldGroupModel.mfEndValue = rStrm.readDouble();
530 maFieldGroupModel.mfInterval = rStrm.readDouble();
532 maFieldGroupModel.setBiffGroupBy( nGroupBy );
533 maFieldGroupModel.mbRangeGroup = true;
534 maFieldGroupModel.mbDateGroup = getFlag( nFlags, BIFF12_PCDFRANGEPR_DATEGROUP );
535 maFieldGroupModel.mbAutoStart = getFlag( nFlags, BIFF12_PCDFRANGEPR_AUTOSTART );
536 maFieldGroupModel.mbAutoEnd = getFlag( nFlags, BIFF12_PCDFRANGEPR_AUTOEND );
538 OSL_ENSURE( maFieldGroupModel.mbDateGroup == (maFieldGroupModel.mnGroupBy != XML_range), "PivotCacheField::importPCDFRangePr - wrong date flag" );
539 if( maFieldGroupModel.mbDateGroup )
541 maFieldGroupModel.maStartDate = getUnitConverter().calcDateTimeFromSerial( maFieldGroupModel.mfStartValue );
542 maFieldGroupModel.maEndDate = getUnitConverter().calcDateTimeFromSerial( maFieldGroupModel.mfEndValue );
546 void PivotCacheField::importPCDFDiscretePrItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
548 OSL_ENSURE( nRecId == BIFF12_ID_PCITEM_INDEX, "PivotCacheField::importPCDFDiscretePrItem - unexpected record" );
549 if( nRecId == BIFF12_ID_PCITEM_INDEX )
550 maDiscreteItems.push_back( rStrm.readInt32() );
553 void PivotCacheField::importPCDFGroupItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
555 maGroupItems.importItem( nRecId, rStrm );
558 const PivotCacheItem* PivotCacheField::getCacheItem( sal_Int32 nItemIdx ) const
560 if( hasGroupItems() )
561 return maGroupItems.getCacheItem( nItemIdx );
562 if( hasSharedItems() )
563 return maSharedItems.getCacheItem( nItemIdx );
564 return nullptr;
567 void PivotCacheField::applyItemCaptions( const IdCaptionPairList& vCaptions )
569 if( hasGroupItems() )
570 maGroupItems.applyItemCaptions( vCaptions );
571 if( hasSharedItems() )
572 maSharedItems.applyItemCaptions( vCaptions );
575 void PivotCacheField::getCacheItemNames( ::std::vector< OUString >& orItemNames ) const
577 if( hasGroupItems() )
578 maGroupItems.getCacheItemNames( orItemNames );
579 else if( hasSharedItems() )
580 maSharedItems.getCacheItemNames( orItemNames );
583 const PivotCacheItemList& PivotCacheField::getCacheItems() const
585 if( hasGroupItems() )
586 return maGroupItems;
587 return maSharedItems;
590 void PivotCacheField::convertNumericGrouping( const Reference< XDataPilotField >& rxDPField ) const
592 OSL_ENSURE( hasGroupItems() && hasNumericGrouping(), "PivotCacheField::convertNumericGrouping - not a numeric group field" );
593 PropertySet aPropSet( rxDPField );
594 if( hasGroupItems() && hasNumericGrouping() && aPropSet.is() )
596 DataPilotFieldGroupInfo aGroupInfo;
597 aGroupInfo.HasAutoStart = maFieldGroupModel.mbAutoStart;
598 aGroupInfo.HasAutoEnd = maFieldGroupModel.mbAutoEnd;
599 aGroupInfo.HasDateValues = false;
600 aGroupInfo.Start = maFieldGroupModel.mfStartValue;
601 aGroupInfo.End = maFieldGroupModel.mfEndValue;
602 aGroupInfo.Step = maFieldGroupModel.mfInterval;
603 aGroupInfo.GroupBy = 0;
604 aPropSet.setProperty( PROP_GroupInfo, aGroupInfo );
608 OUString PivotCacheField::createDateGroupField( const Reference< XDataPilotField >& rxBaseDPField ) const
610 OSL_ENSURE( hasGroupItems() && hasDateGrouping(), "PivotCacheField::createDateGroupField - not a numeric group field" );
611 Reference< XDataPilotField > xDPGroupField;
612 PropertySet aPropSet( rxBaseDPField );
613 if( hasGroupItems() && hasDateGrouping() && aPropSet.is() )
615 bool bDayRanges = (maFieldGroupModel.mnGroupBy == XML_days) && (maFieldGroupModel.mfInterval >= 2.0);
617 DataPilotFieldGroupInfo aGroupInfo;
618 aGroupInfo.HasAutoStart = maFieldGroupModel.mbAutoStart;
619 aGroupInfo.HasAutoEnd = maFieldGroupModel.mbAutoEnd;
620 aGroupInfo.HasDateValues = true;
621 aGroupInfo.Start = getUnitConverter().calcSerialFromDateTime( maFieldGroupModel.maStartDate );
622 aGroupInfo.End = getUnitConverter().calcSerialFromDateTime( maFieldGroupModel.maEndDate );
623 aGroupInfo.Step = bDayRanges ? maFieldGroupModel.mfInterval : 0.0;
625 using namespace ::com::sun::star::sheet::DataPilotFieldGroupBy;
626 switch( maFieldGroupModel.mnGroupBy )
628 case XML_years: aGroupInfo.GroupBy = YEARS; break;
629 case XML_quarters: aGroupInfo.GroupBy = QUARTERS; break;
630 case XML_months: aGroupInfo.GroupBy = MONTHS; break;
631 case XML_days: aGroupInfo.GroupBy = DAYS; break;
632 case XML_hours: aGroupInfo.GroupBy = HOURS; break;
633 case XML_minutes: aGroupInfo.GroupBy = MINUTES; break;
634 case XML_seconds: aGroupInfo.GroupBy = SECONDS; break;
635 default: OSL_FAIL( "PivotCacheField::convertRangeGrouping - unknown date/time interval" );
640 Reference< XDataPilotFieldGrouping > xDPGrouping( rxBaseDPField, UNO_QUERY_THROW );
641 xDPGroupField = xDPGrouping->createDateGroup( aGroupInfo );
643 catch( Exception& )
648 Reference< XNamed > xFieldName( xDPGroupField, UNO_QUERY );
649 return xFieldName.is() ? xFieldName->getName() : OUString();
652 OUString PivotCacheField::createParentGroupField( const Reference< XDataPilotField >& rxBaseDPField, const PivotCacheField& rBaseCacheField, PivotCacheGroupItemVector& orItemNames ) const
654 SAL_WARN_IF( !hasGroupItems() || maDiscreteItems.empty(), "sc", "PivotCacheField::createParentGroupField - not a group field" );
655 SAL_WARN_IF( maDiscreteItems.size() != orItemNames.size(), "sc", "PivotCacheField::createParentGroupField - number of item names does not match grouping info" );
656 Reference< XDataPilotFieldGrouping > xDPGrouping( rxBaseDPField, UNO_QUERY );
657 if( !xDPGrouping.is() ) return OUString();
659 // map the group item indexes from maGroupItems to all item indexes from maDiscreteItems
660 std::vector< std::vector<sal_Int32> > aItemMap( maGroupItems.size() );
661 sal_Int32 nIndex = -1;
662 for( const auto& rDiscreteItem : maDiscreteItems )
664 ++nIndex;
665 if( std::vector<sal_Int32>* pItems = ContainerHelper::getVectorElementAccess( aItemMap, rDiscreteItem ) )
667 if ( const PivotCacheItem* pItem = rBaseCacheField.getCacheItems().getCacheItem( nIndex ) )
669 // Skip unspecified or unused entries or errors
670 if ( pItem->isUnused() || ( pItem->getType() == XML_m ) || ( pItem->getType() == XML_e ) )
671 continue;
673 pItems->push_back( nIndex );
677 // process all groups
678 Reference< XDataPilotField > xDPGroupField;
679 nIndex = 0;
680 for( const auto& rItems : aItemMap )
682 SAL_WARN_IF( rItems.empty(), "sc", "PivotCacheField::createParentGroupField - item/group should not be empty" );
683 if( !rItems.empty() )
685 /* Insert the names of the items that are part of this group. Calc
686 expects the names of the members of the field whose members are
687 grouped (which may be the names of groups too). Excel provides
688 the names of the base field items instead (no group names
689 involved). Therefore, the passed collection of current item
690 names as they are already grouped is used here to resolve the
691 item names. */
692 ::std::vector< OUString > aMembers;
693 for( auto i : rItems )
694 if( const PivotCacheGroupItem* pName = ContainerHelper::getVectorElement( orItemNames, i ) )
695 if( ::std::find( aMembers.begin(), aMembers.end(), pName->maGroupName ) == aMembers.end() )
696 aMembers.push_back( pName->maGroupName );
698 /* Check again, that this is not just a group that is not grouped
699 further with other items. */
700 if( !aMembers.empty() ) try
702 // only the first call of createNameGroup() returns the new field
703 Reference< XDataPilotField > xDPNewField = xDPGrouping->createNameGroup( ContainerHelper::vectorToSequence( aMembers ) );
704 SAL_WARN_IF( xDPGroupField.is() == xDPNewField.is(), "sc", "PivotCacheField::createParentGroupField - missing group field" );
705 if( !xDPGroupField.is() )
706 xDPGroupField = xDPNewField;
708 // get current grouping info
709 DataPilotFieldGroupInfo aGroupInfo;
710 PropertySet aPropSet( xDPGroupField );
711 aPropSet.getProperty( aGroupInfo, PROP_GroupInfo );
713 /* Find the group object and the auto-generated group name.
714 The returned field contains all groups derived from the
715 previous field if that is grouped too. To find the correct
716 group, the first item used to create the group is searched.
717 Calc provides the original item names of the base field
718 when the group is querried for its members. Its does not
719 provide the names of members that are already groups in the
720 field used to create the new groups. (Is this a bug?)
721 Therefore, a name from the passed list of original item
722 names is used to find the correct group. */
723 OUString aFirstItem;
724 if( const PivotCacheGroupItem* pName = ContainerHelper::getVectorElement( orItemNames, rItems.front() ) )
725 aFirstItem = pName->maOrigName;
726 Reference< XNamed > xGroupName;
727 OUString aAutoName;
728 Reference< XIndexAccess > xGroupsIA( aGroupInfo.Groups, UNO_QUERY_THROW );
729 for( sal_Int32 nIdx = 0, nCount = xGroupsIA->getCount(); (nIdx < nCount) && (aAutoName.isEmpty()); ++nIdx ) try
731 Reference< XNameAccess > xItemsNA( xGroupsIA->getByIndex( nIdx ), UNO_QUERY_THROW );
732 if( xItemsNA->hasByName( aFirstItem ) )
734 xGroupName.set( xGroupsIA->getByIndex( nIdx ), UNO_QUERY_THROW );
735 aAutoName = xGroupName->getName();
738 catch( Exception const & )
740 TOOLS_WARN_EXCEPTION("sc", "PivotCacheField::createParentGroupField" );
742 SAL_WARN_IF( aAutoName.isEmpty(), "sc", "PivotCacheField::createParentGroupField - cannot find auto-generated group name" );
744 // get the real group name from the list of group items
745 OUString aGroupName;
746 if( const PivotCacheItem* pGroupItem = maGroupItems.getCacheItem( nIndex ) )
747 aGroupName = pGroupItem->getName();
748 SAL_WARN_IF( aGroupName.isEmpty(), "sc", "PivotCacheField::createParentGroupField - cannot find group name" );
749 if( aGroupName.isEmpty() )
750 aGroupName = aAutoName;
752 if( xGroupName.is() && !aGroupName.isEmpty() )
754 // replace the auto-generated group name with the real name
755 if( aAutoName != aGroupName )
757 xGroupName->setName( aGroupName );
758 aPropSet.setProperty( PROP_GroupInfo, aGroupInfo );
760 // replace original item names in passed vector with group name
761 for( auto i : rItems )
762 if( PivotCacheGroupItem* pName = ContainerHelper::getVectorElementAccess( orItemNames, i ) )
763 pName->maGroupName = aGroupName;
766 catch( Exception const & )
768 TOOLS_WARN_EXCEPTION("sc", "PivotCacheField::createParentGroupField" );
771 ++nIndex;
774 Reference< XNamed > xFieldName( xDPGroupField, UNO_QUERY );
775 return xFieldName.is() ? xFieldName->getName() : OUString();
778 void PivotCacheField::writeSourceHeaderCell( const WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow ) const
780 CellModel aModel;
781 aModel.maCellAddr = ScAddress( SCCOL( nCol ), SCROW( nRow ), rSheetHelper.getSheetIndex() );
782 rSheetHelper.getSheetData().setStringCell( aModel, maFieldModel.maName );
785 void PivotCacheField::writeSourceDataCell( const WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow, const PivotCacheItem& rItem ) const
787 bool bHasIndex = rItem.getType() == XML_x;
788 OSL_ENSURE( bHasIndex != maSharedItems.empty(), "PivotCacheField::writeSourceDataCell - shared items missing or not expected" );
789 if( bHasIndex )
790 writeSharedItemToSourceDataCell( rSheetHelper, nCol, nRow, rItem.getValue().get< sal_Int32 >() );
791 else
792 writeItemToSourceDataCell( rSheetHelper, nCol, nRow, rItem );
795 void PivotCacheField::importPCRecordItem( SequenceInputStream& rStrm, const WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow ) const
797 if( hasSharedItems() )
799 writeSharedItemToSourceDataCell( rSheetHelper, nCol, nRow, rStrm.readInt32() );
801 else
803 PivotCacheItem aItem;
804 if( maSharedItemsModel.mbIsNumeric )
805 aItem.readDouble( rStrm );
806 else if( maSharedItemsModel.mbHasDate && !maSharedItemsModel.mbHasString )
807 aItem.readDate( rStrm );
808 else
809 aItem.readString( rStrm );
810 writeItemToSourceDataCell( rSheetHelper, nCol, nRow, aItem );
814 // private --------------------------------------------------------------------
816 void PivotCacheField::writeItemToSourceDataCell( const WorksheetHelper& rSheetHelper,
817 sal_Int32 nCol, sal_Int32 nRow, const PivotCacheItem& rItem )
819 if( rItem.getType() != XML_m )
821 CellModel aModel;
822 aModel.maCellAddr = ScAddress( SCCOL( nCol ), SCROW( nRow ), rSheetHelper.getSheetIndex() );
823 SheetDataBuffer& rSheetData = rSheetHelper.getSheetData();
824 switch( rItem.getType() )
826 case XML_s: rSheetData.setStringCell( aModel, rItem.getValue().get< OUString >() ); break;
827 case XML_n: rSheetData.setValueCell( aModel, rItem.getValue().get< double >() ); break;
828 case XML_i: rSheetData.setValueCell( aModel, rItem.getValue().get< sal_Int16 >() ); break;
829 case XML_d: rSheetData.setDateTimeCell( aModel, rItem.getValue().get< css::util::DateTime >() ); break;
830 case XML_b: rSheetData.setBooleanCell( aModel, rItem.getValue().get< bool >() ); break;
831 case XML_e: rSheetData.setErrorCell( aModel, static_cast< sal_uInt8 >( rItem.getValue().get< sal_Int32 >() ) ); break;
832 default: OSL_FAIL( "PivotCacheField::writeItemToSourceDataCell - unexpected item data type" );
837 void PivotCacheField::writeSharedItemToSourceDataCell(
838 const WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nItemIdx ) const
840 if( const PivotCacheItem* pCacheItem = maSharedItems.getCacheItem( nItemIdx ) )
841 writeItemToSourceDataCell( rSheetHelper, nCol, nRow, *pCacheItem );
844 PCDefinitionModel::PCDefinitionModel() :
845 mfRefreshedDate( 0.0 ),
846 mnRecords( 0 ),
847 mnMissItemsLimit( 0 ),
848 mbInvalid( false ),
849 mbSaveData( true ),
850 mbRefreshOnLoad( false ),
851 mbOptimizeMemory( false ),
852 mbEnableRefresh( true ),
853 mbBackgroundQuery( false ),
854 mbUpgradeOnRefresh( false ),
855 mbTupleCache( false ),
856 mbSupportSubquery( false ),
857 mbSupportDrill( false )
861 PCSourceModel::PCSourceModel() :
862 mnSourceType( XML_TOKEN_INVALID ),
863 mnConnectionId( 0 )
867 PCWorksheetSourceModel::PCWorksheetSourceModel()
869 maRange.SetInvalid();
872 PivotCache::PivotCache( const WorkbookHelper& rHelper ) :
873 WorkbookHelper( rHelper ),
874 mnCurrRow( -1 ),
875 mbValidSource( false ),
876 mbDummySheet( false )
880 void PivotCache::importPivotCacheDefinition( const AttributeList& rAttribs )
882 maDefModel.maRelId = rAttribs.getString( R_TOKEN( id ), OUString() );
883 maDefModel.maRefreshedBy = rAttribs.getXString( XML_refreshedBy, OUString() );
884 maDefModel.mfRefreshedDate = rAttribs.getDouble( XML_refreshedDate, 0.0 );
885 maDefModel.mnRecords = rAttribs.getInteger( XML_recordCount, 0 );
886 maDefModel.mnMissItemsLimit = rAttribs.getInteger( XML_missingItemsLimit, 0 );
887 maDefModel.mbInvalid = rAttribs.getBool( XML_invalid, false );
888 maDefModel.mbSaveData = rAttribs.getBool( XML_saveData, true );
889 maDefModel.mbRefreshOnLoad = rAttribs.getBool( XML_refreshOnLoad, false );
890 maDefModel.mbOptimizeMemory = rAttribs.getBool( XML_optimizeMemory, false );
891 maDefModel.mbEnableRefresh = rAttribs.getBool( XML_enableRefresh, true );
892 maDefModel.mbBackgroundQuery = rAttribs.getBool( XML_backgroundQuery, false );
893 maDefModel.mbUpgradeOnRefresh = rAttribs.getBool( XML_upgradeOnRefresh, false );
894 maDefModel.mbTupleCache = rAttribs.getBool( XML_tupleCache, false );
895 maDefModel.mbSupportSubquery = rAttribs.getBool( XML_supportSubquery, false );
896 maDefModel.mbSupportDrill = rAttribs.getBool( XML_supportAdvancedDrill, false );
899 void PivotCache::importCacheSource( const AttributeList& rAttribs )
901 maSourceModel.mnSourceType = rAttribs.getToken( XML_type, XML_TOKEN_INVALID );
902 maSourceModel.mnConnectionId = rAttribs.getInteger( XML_connectionId, 0 );
905 void PivotCache::importWorksheetSource( const AttributeList& rAttribs, const Relations& rRelations )
907 maSheetSrcModel.maRelId = rAttribs.getString( R_TOKEN( id ), OUString() );
908 maSheetSrcModel.maSheet = rAttribs.getXString( XML_sheet, OUString() );
909 maSheetSrcModel.maDefName = rAttribs.getXString( XML_name, OUString() );
911 // resolve URL of external document
912 maTargetUrl = rRelations.getExternalTargetFromRelId( maSheetSrcModel.maRelId );
913 // store range address unchecked with sheet index 0, will be resolved/checked later
914 AddressConverter::convertToCellRangeUnchecked( maSheetSrcModel.maRange, rAttribs.getString( XML_ref, OUString() ), 0 );
917 void PivotCache::importPCDefinition( SequenceInputStream& rStrm )
919 sal_uInt8 nFlags1, nFlags2;
920 rStrm.skip( 3 ); // create/refresh version id's
921 nFlags1 = rStrm.readuChar();
922 maDefModel.mnMissItemsLimit = rStrm.readInt32();
923 maDefModel.mfRefreshedDate = rStrm.readDouble();
924 nFlags2 = rStrm.readuChar();
925 maDefModel.mnRecords = rStrm.readInt32();
926 if( getFlag( nFlags2, BIFF12_PCDEFINITION_HASUSERNAME ) )
927 rStrm >> maDefModel.maRefreshedBy;
928 if( getFlag( nFlags2, BIFF12_PCDEFINITION_HASRELID ) )
929 rStrm >> maDefModel.maRelId;
931 maDefModel.mbInvalid = getFlag( nFlags1, BIFF12_PCDEFINITION_INVALID );
932 maDefModel.mbSaveData = getFlag( nFlags1, BIFF12_PCDEFINITION_SAVEDATA );
933 maDefModel.mbRefreshOnLoad = getFlag( nFlags1, BIFF12_PCDEFINITION_REFRESHONLOAD );
934 maDefModel.mbOptimizeMemory = getFlag( nFlags1, BIFF12_PCDEFINITION_OPTIMIZEMEMORY );
935 maDefModel.mbEnableRefresh = getFlag( nFlags1, BIFF12_PCDEFINITION_ENABLEREFRESH );
936 maDefModel.mbBackgroundQuery = getFlag( nFlags1, BIFF12_PCDEFINITION_BACKGROUNDQUERY );
937 maDefModel.mbUpgradeOnRefresh = getFlag( nFlags1, BIFF12_PCDEFINITION_UPGRADEONREFR );
938 maDefModel.mbTupleCache = getFlag( nFlags1, BIFF12_PCDEFINITION_TUPELCACHE );
939 maDefModel.mbSupportSubquery = getFlag( nFlags2, BIFF12_PCDEFINITION_SUPPORTSUBQUERY );
940 maDefModel.mbSupportDrill = getFlag( nFlags2, BIFF12_PCDEFINITION_SUPPORTDRILL );
943 void PivotCache::importPCDSource( SequenceInputStream& rStrm )
945 sal_Int32 nSourceType;
946 nSourceType = rStrm.readInt32();
947 maSourceModel.mnConnectionId = rStrm.readInt32();
948 static const sal_Int32 spnSourceTypes[] = { XML_worksheet, XML_external, XML_consolidation, XML_scenario };
949 maSourceModel.mnSourceType = STATIC_ARRAY_SELECT( spnSourceTypes, nSourceType, XML_TOKEN_INVALID );
952 void PivotCache::importPCDSheetSource( SequenceInputStream& rStrm, const Relations& rRelations )
954 sal_uInt8 nIsDefName, nIsBuiltinName, nFlags;
955 nIsDefName = rStrm.readuChar();
956 nIsBuiltinName = rStrm.readuChar();
957 nFlags = rStrm.readuChar();
958 if( getFlag( nFlags, BIFF12_PCDWBSOURCE_HASSHEET ) )
959 rStrm >> maSheetSrcModel.maSheet;
960 if( getFlag( nFlags, BIFF12_PCDWBSOURCE_HASRELID ) )
961 rStrm >> maSheetSrcModel.maRelId;
963 // read cell range or defined name
964 if( nIsDefName == 0 )
966 BinRange aBinRange;
967 rStrm >> aBinRange;
968 // store range address unchecked with sheet index 0, will be resolved/checked later
969 AddressConverter::convertToCellRangeUnchecked( maSheetSrcModel.maRange, aBinRange, 0 );
971 else
973 rStrm >> maSheetSrcModel.maDefName;
974 if( nIsBuiltinName != 0 )
975 maSheetSrcModel.maDefName = "_xlnm." + maSheetSrcModel.maDefName;
978 // resolve URL of external document
979 maTargetUrl = rRelations.getExternalTargetFromRelId( maSheetSrcModel.maRelId );
982 PivotCacheField& PivotCache::createCacheField()
984 PivotCacheFieldVector::value_type xCacheField( new PivotCacheField( *this, true/*bIsDatabaseField*/ ) );
985 maFields.push_back( xCacheField );
986 return *xCacheField;
989 void PivotCache::finalizeImport()
991 // collect all fields that are based on source data (needed to finalize source data below)
992 OSL_ENSURE( !maFields.empty(), "PivotCache::finalizeImport - no pivot cache fields found" );
993 for( PivotCacheFieldVector::const_iterator aIt = maFields.begin(), aEnd = maFields.end(); aIt != aEnd; ++aIt )
995 if( (*aIt)->isDatabaseField() )
997 OSL_ENSURE( (aIt == maFields.begin()) || (*(aIt - 1))->isDatabaseField(),
998 "PivotCache::finalizeImport - database field follows a calculated field" );
999 maDatabaseIndexes.push_back( static_cast< sal_Int32 >( maDatabaseFields.size() ) );
1000 maDatabaseFields.push_back( *aIt );
1002 else
1004 maDatabaseIndexes.push_back( -1 );
1007 OSL_ENSURE( !maDatabaseFields.empty(), "PivotCache::finalizeImport - no pivot cache source fields found" );
1009 // finalize source data depending on source type
1010 switch( maSourceModel.mnSourceType )
1012 case XML_worksheet:
1014 // decide whether an external document is used
1015 bool bInternal = maTargetUrl.isEmpty() && maSheetSrcModel.maRelId.isEmpty();
1016 bool bExternal = !maTargetUrl.isEmpty(); // relation ID may be empty, e.g. BIFF import
1017 OSL_ENSURE( bInternal || bExternal, "PivotCache::finalizeImport - invalid external document URL" );
1018 if( bInternal )
1019 finalizeInternalSheetSource();
1020 else if( bExternal )
1021 finalizeExternalSheetSource();
1023 break;
1025 // currently, we only support worksheet data sources
1026 case XML_external:
1027 break;
1028 case XML_consolidation:
1029 break;
1030 case XML_scenario:
1031 break;
1035 PivotCacheField* PivotCache::getCacheField( sal_Int32 nFieldIdx )
1037 return maFields.get( nFieldIdx ).get();
1040 const PivotCacheField* PivotCache::getCacheField( sal_Int32 nFieldIdx ) const
1042 return maFields.get( nFieldIdx ).get();
1045 sal_Int32 PivotCache::getCacheDatabaseIndex( sal_Int32 nFieldIdx ) const
1047 return ContainerHelper::getVectorElement( maDatabaseIndexes, nFieldIdx, -1 );
1050 void PivotCache::writeSourceHeaderCells( const WorksheetHelper& rSheetHelper ) const
1052 OSL_ENSURE( static_cast< size_t >( maSheetSrcModel.maRange.aEnd.Col() - maSheetSrcModel.maRange.aStart.Col() + 1 ) == maDatabaseFields.size(),
1053 "PivotCache::writeSourceHeaderCells - source cell range width does not match number of source fields" );
1054 SCCOL nCol = maSheetSrcModel.maRange.aStart.Col();
1055 SCCOL nMaxCol = getAddressConverter().getMaxApiAddress().Col();
1056 SCROW nRow = maSheetSrcModel.maRange.aStart.Row();
1057 mnCurrRow = -1;
1058 updateSourceDataRow( rSheetHelper, nRow );
1059 for( const auto& rxDatabaseField : maDatabaseFields )
1061 if (nCol > nMaxCol)
1062 break;
1063 rxDatabaseField->writeSourceHeaderCell( rSheetHelper, nCol, nRow );
1064 ++nCol;
1068 void PivotCache::writeSourceDataCell( const WorksheetHelper& rSheetHelper, sal_Int32 nColIdx, sal_Int32 nRowIdx, const PivotCacheItem& rItem ) const
1070 SCCOL nCol = maSheetSrcModel.maRange.aStart.Col() + nColIdx;
1071 OSL_ENSURE( ( maSheetSrcModel.maRange.aStart.Col() <= nCol ) && ( nCol <= maSheetSrcModel.maRange.aEnd.Col() ), "PivotCache::writeSourceDataCell - invalid column index" );
1072 SCROW nRow = maSheetSrcModel.maRange.aStart.Row() + nRowIdx;
1073 OSL_ENSURE( ( maSheetSrcModel.maRange.aStart.Row() < nRow ) && ( nRow <= maSheetSrcModel.maRange.aEnd.Row() ), "PivotCache::writeSourceDataCell - invalid row index" );
1074 updateSourceDataRow( rSheetHelper, nRow );
1075 if( const PivotCacheField* pCacheField = maDatabaseFields.get( nColIdx ).get() )
1076 pCacheField->writeSourceDataCell( rSheetHelper, nCol, nRow, rItem );
1079 void PivotCache::importPCRecord( SequenceInputStream& rStrm, const WorksheetHelper& rSheetHelper, sal_Int32 nRowIdx ) const
1081 SCROW nRow = maSheetSrcModel.maRange.aStart.Row() + nRowIdx;
1082 OSL_ENSURE( ( maSheetSrcModel.maRange.aStart.Row() < nRow ) && ( nRow <= maSheetSrcModel.maRange.aEnd.Row() ), "PivotCache::importPCRecord - invalid row index" );
1083 SCCOL nCol = maSheetSrcModel.maRange.aStart.Col();
1084 SCCOL nMaxCol = getAddressConverter().getMaxApiAddress().Col();
1085 for( const auto& rxDatabaseField : maDatabaseFields )
1087 if( rStrm.isEof() || (nCol > nMaxCol) )
1088 break;
1089 rxDatabaseField->importPCRecordItem( rStrm, rSheetHelper, nCol, nRow );
1090 ++nCol;
1094 // private --------------------------------------------------------------------
1096 void PivotCache::finalizeInternalSheetSource()
1098 // resolve sheet name to sheet index
1099 sal_Int16 nSheet = getWorksheets().getCalcSheetIndex( maSheetSrcModel.maSheet );
1101 // if cache is based on a defined name or table, try to resolve to cell range
1102 if( !maSheetSrcModel.maDefName.isEmpty() )
1104 // local or global defined name
1105 if( const DefinedName* pDefName = getDefinedNames().getByModelName( maSheetSrcModel.maDefName, nSheet ).get() )
1107 mbValidSource = pDefName->getAbsoluteRange( maSheetSrcModel.maRange );
1109 // table
1110 else if( const Table* pTable = getTables().getTable( maSheetSrcModel.maDefName ).get() )
1112 // get original range from table, but exclude the totals row(s)
1113 maSheetSrcModel.maRange = pTable->getOriginalRange();
1114 mbValidSource = (pTable->getHeight() - pTable->getTotalsRows()) > 1;
1115 if( mbValidSource )
1116 maSheetSrcModel.maRange.aEnd.SetRow( maSheetSrcModel.maRange.aEnd.Row() - pTable->getTotalsRows() );
1119 // else try the cell range (if the sheet exists)
1120 else if( nSheet >= 0 )
1122 // insert sheet index into the range, range address will be checked below
1123 maSheetSrcModel.maRange.aStart.SetTab( nSheet );
1124 mbValidSource = true;
1126 // else sheet has been deleted, generate the source data from cache
1127 else if( !maSheetSrcModel.maSheet.isEmpty() )
1129 prepareSourceDataSheet();
1130 // return here to skip the source range check below
1131 return;
1134 // check range location, do not allow ranges that overflow the sheet partly
1135 mbValidSource = mbValidSource &&
1136 getAddressConverter().checkCellRange( maSheetSrcModel.maRange, false, true ) &&
1137 ( maSheetSrcModel.maRange.aStart.Row() < maSheetSrcModel.maRange.aEnd.Row() );
1140 void PivotCache::finalizeExternalSheetSource()
1142 /* If pivot cache is based on external sheet data, try to restore sheet
1143 data from cache records. No support for external defined names or tables,
1144 sheet name and path to cache records fragment (OOXML only) are required. */
1145 bool bHasRelation = !maDefModel.maRelId.isEmpty();
1146 if( bHasRelation && maSheetSrcModel.maDefName.isEmpty() && !maSheetSrcModel.maSheet.isEmpty() )
1147 prepareSourceDataSheet();
1150 void PivotCache::prepareSourceDataSheet()
1152 ScRange& rRange = maSheetSrcModel.maRange;
1153 // data will be inserted in top-left cell, sheet index is still set to 0 (will be set below)
1154 rRange.aEnd.SetCol( rRange.aEnd.Col() - rRange.aStart.Col() );
1155 rRange.aStart.SetCol( 0 );
1156 rRange.aEnd.SetRow( rRange.aEnd.Row() - rRange.aStart.Row() );
1157 rRange.aStart.SetRow( 0 );
1158 // check range location, do not allow ranges that overflow the sheet partly
1159 if( getAddressConverter().checkCellRange( rRange, false, true ) )
1161 maColSpans.insert( ValueRange( rRange.aStart.Col(), rRange.aEnd.Col() ) );
1162 OUString aSheetName = "DPCache_" + maSheetSrcModel.maSheet;
1163 rRange.aStart.SetTab( getWorksheets().insertEmptySheet( aSheetName ) );
1164 mbValidSource = mbDummySheet = rRange.aStart.Tab() >= 0;
1168 void PivotCache::updateSourceDataRow( const WorksheetHelper& rSheetHelper, sal_Int32 nRow ) const
1170 if( mnCurrRow != nRow )
1172 rSheetHelper.getSheetData().setColSpans( nRow, maColSpans );
1173 mnCurrRow = nRow;
1177 PivotCacheBuffer::PivotCacheBuffer( const WorkbookHelper& rHelper ) :
1178 WorkbookHelper( rHelper )
1182 void PivotCacheBuffer::registerPivotCacheFragment( sal_Int32 nCacheId, const OUString& rFragmentPath )
1184 OSL_ENSURE( nCacheId >= 0, "PivotCacheBuffer::registerPivotCacheFragment - invalid pivot cache identifier" );
1185 OSL_ENSURE( maFragmentPaths.count( nCacheId ) == 0, "PivotCacheBuffer::registerPivotCacheFragment - fragment path exists already" );
1186 if( (nCacheId >= 0) && !rFragmentPath.isEmpty() )
1187 maFragmentPaths[ nCacheId ] = rFragmentPath;
1190 PivotCache* PivotCacheBuffer::importPivotCacheFragment( sal_Int32 nCacheId )
1192 /* OOXML/BIFF12 filter: On first call for the cache ID, the pivot
1193 cache object is created and inserted into maCaches. Then, the cache
1194 definition fragment is read and the cache is returned. On
1195 subsequent calls, the created cache will be found in maCaches and
1196 returned immediately. */
1197 // try to find an imported pivot cache
1198 if( PivotCache* pCache = maCaches.get( nCacheId ).get() )
1199 return pCache;
1201 // check if a fragment path exists for the passed cache identifier
1202 FragmentPathMap::iterator aIt = maFragmentPaths.find( nCacheId );
1203 if( aIt == maFragmentPaths.end() )
1204 return nullptr;
1206 /* Import the cache fragment. This may create a dummy data sheet
1207 for external sheet sources. */
1208 PivotCache& rCache = createPivotCache( nCacheId );
1209 importOoxFragment( new PivotCacheDefinitionFragment( *this, aIt->second, rCache ) );
1210 return &rCache;
1213 PivotCache& PivotCacheBuffer::createPivotCache( sal_Int32 nCacheId )
1215 maCacheIds.push_back( nCacheId );
1216 PivotCacheMap::mapped_type& rxCache = maCaches[ nCacheId ];
1217 rxCache.reset( new PivotCache( *this ) );
1218 return *rxCache;
1221 } // namespace xls
1222 } // namespace oox
1224 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */