Version 7.5.1.1, tag libreoffice-7.5.1.1
[LibreOffice.git] / sc / source / filter / oox / pivotcachebuffer.cxx
blob4896f3123e92ffb56c16320e13f6f9d6a6b914f6
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>
30 #include <comphelper/sequence.hxx>
31 #include <o3tl/safeint.hxx>
32 #include <osl/diagnose.h>
33 #include <sal/log.hxx>
34 #include <oox/helper/attributelist.hxx>
35 #include <oox/helper/binaryinputstream.hxx>
36 #include <oox/helper/containerhelper.hxx>
37 #include <oox/helper/propertyset.hxx>
38 #include <oox/token/namespaces.hxx>
39 #include <oox/token/properties.hxx>
40 #include <oox/token/tokens.hxx>
41 #include <comphelper/diagnose_ex.hxx>
42 #include <defnamesbuffer.hxx>
43 #include <pivotcachefragment.hxx>
44 #include <sheetdatabuffer.hxx>
45 #include <tablebuffer.hxx>
46 #include <unitconverter.hxx>
47 #include <worksheetbuffer.hxx>
48 #include <dpobject.hxx>
49 #include <dpsave.hxx>
50 #include <tools/datetime.hxx>
51 #include <addressconverter.hxx>
52 #include <biffhelper.hxx>
54 namespace oox::xls {
56 using namespace ::com::sun::star::container;
57 using namespace ::com::sun::star::sheet;
58 using namespace ::com::sun::star::uno;
60 using ::oox::core::Relations;
62 namespace {
64 const sal_uInt16 BIFF12_PCDFIELD_SERVERFIELD = 0x0001;
65 const sal_uInt16 BIFF12_PCDFIELD_NOUNIQUEITEMS = 0x0002;
66 const sal_uInt16 BIFF12_PCDFIELD_DATABASEFIELD = 0x0004;
67 const sal_uInt16 BIFF12_PCDFIELD_HASCAPTION = 0x0008;
68 const sal_uInt16 BIFF12_PCDFIELD_MEMBERPROPFIELD = 0x0010;
69 const sal_uInt16 BIFF12_PCDFIELD_HASFORMULA = 0x0100;
70 const sal_uInt16 BIFF12_PCDFIELD_HASPROPERTYNAME = 0x0200;
72 const sal_uInt16 BIFF12_PCDFSITEMS_HASSEMIMIXED = 0x0001;
73 const sal_uInt16 BIFF12_PCDFSITEMS_HASNONDATE = 0x0002;
74 const sal_uInt16 BIFF12_PCDFSITEMS_HASDATE = 0x0004;
75 const sal_uInt16 BIFF12_PCDFSITEMS_HASSTRING = 0x0008;
76 const sal_uInt16 BIFF12_PCDFSITEMS_HASBLANK = 0x0010;
77 const sal_uInt16 BIFF12_PCDFSITEMS_HASMIXED = 0x0020;
78 const sal_uInt16 BIFF12_PCDFSITEMS_ISNUMERIC = 0x0040;
79 const sal_uInt16 BIFF12_PCDFSITEMS_ISINTEGER = 0x0080;
80 const sal_uInt16 BIFF12_PCDFSITEMS_HASLONGTEXT = 0x0200;
82 const sal_uInt16 BIFF12_PCITEM_ARRAY_DOUBLE = 0x0001;
83 const sal_uInt16 BIFF12_PCITEM_ARRAY_STRING = 0x0002;
84 const sal_uInt16 BIFF12_PCITEM_ARRAY_ERROR = 0x0010;
85 const sal_uInt16 BIFF12_PCITEM_ARRAY_DATE = 0x0020;
87 const sal_uInt8 BIFF12_PCDFRANGEPR_AUTOSTART = 0x01;
88 const sal_uInt8 BIFF12_PCDFRANGEPR_AUTOEND = 0x02;
89 const sal_uInt8 BIFF12_PCDFRANGEPR_DATEGROUP = 0x04;
91 const sal_uInt8 BIFF12_PCDEFINITION_SAVEDATA = 0x01;
92 const sal_uInt8 BIFF12_PCDEFINITION_INVALID = 0x02;
93 const sal_uInt8 BIFF12_PCDEFINITION_REFRESHONLOAD = 0x04;
94 const sal_uInt8 BIFF12_PCDEFINITION_OPTIMIZEMEMORY = 0x08;
95 const sal_uInt8 BIFF12_PCDEFINITION_ENABLEREFRESH = 0x10;
96 const sal_uInt8 BIFF12_PCDEFINITION_BACKGROUNDQUERY = 0x20;
97 const sal_uInt8 BIFF12_PCDEFINITION_UPGRADEONREFR = 0x40;
98 const sal_uInt8 BIFF12_PCDEFINITION_TUPLECACHE = 0x80;
100 const sal_uInt8 BIFF12_PCDEFINITION_HASUSERNAME = 0x01;
101 const sal_uInt8 BIFF12_PCDEFINITION_HASRELID = 0x02;
102 const sal_uInt8 BIFF12_PCDEFINITION_SUPPORTSUBQUERY = 0x04;
103 const sal_uInt8 BIFF12_PCDEFINITION_SUPPORTDRILL = 0x08;
105 const sal_uInt8 BIFF12_PCDWBSOURCE_HASRELID = 0x01;
106 const sal_uInt8 BIFF12_PCDWBSOURCE_HASSHEET = 0x02;
109 /** Adjusts the weird date format read from binary streams.
111 Dates before 1900-Mar-01 are stored including the non-existing leap day
112 1900-02-29. tools::Time values (without date) are stored as times of day
113 1900-Jan-00. Nothing has to be done when the workbook is stored in 1904
114 date mode (dates before 1904-Jan-01 will not occur in this case).
116 void lclAdjustBinDateTime( css::util::DateTime& orDateTime )
118 if( (orDateTime.Year == 1900) && (orDateTime.Month <= 2) )
120 OSL_ENSURE( (orDateTime.Month == 1) || ((orDateTime.Month == 2) && (orDateTime.Day > 0)), "lclAdjustBinDateTime - invalid date" );
121 switch( orDateTime.Month )
123 case 2: if( orDateTime.Day > 1 ) --orDateTime.Day; else { orDateTime.Day += 30; --orDateTime.Month; } break;
124 case 1: if( orDateTime.Day > 1 ) --orDateTime.Day; else { orDateTime.Day += 30; orDateTime.Month = 12; --orDateTime.Year; } break;
129 } // namespace
131 PivotCacheItem::PivotCacheItem() :
132 mnType( XML_m ), mbUnused( false )
136 void PivotCacheItem::readString( const AttributeList& rAttribs )
138 maValue <<= rAttribs.getXString( XML_v, OUString() );
139 mnType = XML_s;
142 void PivotCacheItem::readNumeric( const AttributeList& rAttribs )
144 maValue <<= rAttribs.getDouble( XML_v, 0.0 );
145 mnType = XML_n;
146 mbUnused = rAttribs.getBool( XML_u, false );
149 void PivotCacheItem::readDate( const AttributeList& rAttribs )
151 maValue <<= rAttribs.getDateTime( XML_v, css::util::DateTime() );
152 mnType = XML_d;
155 void PivotCacheItem::readBool( const AttributeList& rAttribs )
157 maValue <<= rAttribs.getBool( XML_v, false );
158 mnType = XML_b;
161 void PivotCacheItem::readError( const AttributeList& rAttribs )
163 maValue <<= rAttribs.getXString( XML_v, OUString() );
164 mnType = XML_e;
167 void PivotCacheItem::readIndex( const AttributeList& rAttribs )
169 maValue <<= rAttribs.getInteger( XML_v, -1 );
170 mnType = XML_x;
173 void PivotCacheItem::readString( SequenceInputStream& rStrm )
175 maValue <<= BiffHelper::readString( rStrm );
176 mnType = XML_s;
179 void PivotCacheItem::readDouble( SequenceInputStream& rStrm )
181 maValue <<= rStrm.readDouble();
182 mnType = XML_n;
185 void PivotCacheItem::readDate( SequenceInputStream& rStrm )
187 css::util::DateTime aDateTime;
188 aDateTime.Year = rStrm.readuInt16();
189 aDateTime.Month = rStrm.readuInt16();
190 aDateTime.Day = rStrm.readuInt8();
191 aDateTime.Hours = rStrm.readuInt8();
192 aDateTime.Minutes = rStrm.readuInt8();
193 aDateTime.Seconds = rStrm.readuInt8();
194 lclAdjustBinDateTime( aDateTime );
195 maValue <<= aDateTime;
196 mnType = XML_d;
199 void PivotCacheItem::readBool( SequenceInputStream& rStrm )
201 maValue <<= (rStrm.readuInt8() != 0);
202 mnType = XML_b;
205 void PivotCacheItem::readError(SequenceInputStream& rStrm, const UnitConverter& rUnitConverter)
207 maValue <<= rUnitConverter.calcErrorString(rStrm.readuInt8());
208 mnType = XML_e;
211 void PivotCacheItem::readIndex( SequenceInputStream& rStrm )
213 maValue <<= rStrm.readInt32();
214 mnType = XML_x;
217 void PivotCacheItem::setStringValue( const OUString& sString )
219 mnType = XML_s;
220 maValue <<= sString;
223 OUString PivotCacheItem::getName() const
225 switch( mnType )
227 case XML_m: return OUString();
228 case XML_s: return maValue.get< OUString >();
229 case XML_n: return OUString::number( maValue.get< double >() ); // !TODO
230 case XML_i: return OUString::number( maValue.get< sal_Int32 >() );
231 case XML_d: return OUString(); // !TODO
232 case XML_b: return OUString::boolean( maValue.get< bool >() ); // !TODO
233 case XML_e: return OUString(); // !TODO
235 OSL_FAIL( "PivotCacheItem::getName - invalid data type" );
236 return OUString();
239 OUString PivotCacheItem::getFormattedName(const ScDPSaveDimension& rSaveDim, ScDPObject* pObj, const DateTime& rNullDate) const
241 switch( mnType )
243 case XML_m: return OUString();
244 case XML_s: return maValue.get< OUString >();
245 case XML_n: return pObj->GetFormattedString(rSaveDim.GetName(), maValue.get<double>());
246 case XML_i: return pObj->GetFormattedString(rSaveDim.GetName(), static_cast<double>(maValue.get< sal_Int32 >()));
247 case XML_b: return pObj->GetFormattedString(rSaveDim.GetName(), static_cast<double>(maValue.get< bool >()));
248 case XML_d:
250 css::util::DateTime aDateTime(maValue.get< css::util::DateTime >());
251 if (aDateTime.Year == 0)
253 SAL_WARN("sc", "PivotCacheField::getFormattedName - invalid date");
254 return OUString();
256 return pObj->GetFormattedString(rSaveDim.GetName(), aDateTime - rNullDate);
258 case XML_e: return maValue.get< OUString >();
260 OSL_FAIL( "PivotCacheItem::getFormattedName - invalid data type" );
261 return OUString();
264 PivotCacheItemList::PivotCacheItemList( const WorkbookHelper& rHelper ) :
265 WorkbookHelper( rHelper )
269 void PivotCacheItemList::importItem( sal_Int32 nElement, const AttributeList& rAttribs )
271 PivotCacheItem& rItem = createItem();
272 switch( nElement )
274 case XLS_TOKEN( m ): break;
275 case XLS_TOKEN( s ): rItem.readString( rAttribs ); break;
276 case XLS_TOKEN( n ): rItem.readNumeric( rAttribs ); break;
277 case XLS_TOKEN( d ): rItem.readDate( rAttribs ); break;
278 case XLS_TOKEN( b ): rItem.readBool( rAttribs ); break;
279 case XLS_TOKEN( e ): rItem.readError( rAttribs ); break;
280 default: OSL_FAIL( "PivotCacheItemList::importItem - unknown element type" );
284 void PivotCacheItemList::importItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
286 if( nRecId == BIFF12_ID_PCITEM_ARRAY )
288 importArray( rStrm );
289 return;
292 PivotCacheItem& rItem = createItem();
293 switch( nRecId )
295 case BIFF12_ID_PCITEM_MISSING:
296 case BIFF12_ID_PCITEMA_MISSING: break;
297 case BIFF12_ID_PCITEM_STRING:
298 case BIFF12_ID_PCITEMA_STRING: rItem.readString( rStrm ); break;
299 case BIFF12_ID_PCITEM_DOUBLE:
300 case BIFF12_ID_PCITEMA_DOUBLE: rItem.readDouble( rStrm ); break;
301 case BIFF12_ID_PCITEM_DATE:
302 case BIFF12_ID_PCITEMA_DATE: rItem.readDate( rStrm ); break;
303 case BIFF12_ID_PCITEM_BOOL:
304 case BIFF12_ID_PCITEMA_BOOL: rItem.readBool( rStrm ); break;
305 case BIFF12_ID_PCITEM_ERROR:
306 case BIFF12_ID_PCITEMA_ERROR: rItem.readError(rStrm, getUnitConverter()); break;
307 default: OSL_FAIL( "PivotCacheItemList::importItem - unknown record type" );
311 const PivotCacheItem* PivotCacheItemList::getCacheItem( sal_Int32 nItemIdx ) const
313 return ContainerHelper::getVectorElement( maItems, nItemIdx );
316 void PivotCacheItemList::applyItemCaptions( const IdCaptionPairList& vCaptions )
318 for( const auto& [rId, rCaption] : vCaptions )
320 if ( o3tl::make_unsigned( rId ) < maItems.size() )
321 maItems[ rId ].setStringValue( rCaption );
325 void PivotCacheItemList::getCacheItemNames( ::std::vector< OUString >& orItemNames ) const
327 orItemNames.clear();
328 orItemNames.reserve( maItems.size() );
329 for( const auto& rItem : maItems )
330 orItemNames.push_back( rItem.getName() );
333 // private --------------------------------------------------------------------
335 PivotCacheItem& PivotCacheItemList::createItem()
337 maItems.emplace_back();
338 return maItems.back();
341 void PivotCacheItemList::importArray( SequenceInputStream& rStrm )
343 sal_uInt16 nType = rStrm.readuInt16();
344 sal_Int32 nCount = rStrm.readInt32();
345 for( sal_Int32 nIdx = 0; !rStrm.isEof() && (nIdx < nCount); ++nIdx )
347 switch( nType )
349 case BIFF12_PCITEM_ARRAY_DOUBLE: createItem().readDouble( rStrm ); break;
350 case BIFF12_PCITEM_ARRAY_STRING: createItem().readString( rStrm ); break;
351 case BIFF12_PCITEM_ARRAY_ERROR: createItem().readError(rStrm, getUnitConverter()); break;
352 case BIFF12_PCITEM_ARRAY_DATE: createItem().readDate( rStrm ); break;
353 default:
354 OSL_FAIL( "PivotCacheItemList::importArray - unknown data type" );
355 return;
360 PCFieldModel::PCFieldModel() :
361 mnNumFmtId( 0 ),
362 mnSqlType( 0 ),
363 mnHierarchy( 0 ),
364 mnLevel( 0 ),
365 mnMappingCount( 0 ),
366 mbDatabaseField( true ),
367 mbServerField( false ),
368 mbUniqueList( true ),
369 mbMemberPropField( false )
373 PCSharedItemsModel::PCSharedItemsModel() :
374 mbHasSemiMixed( true ),
375 mbHasNonDate( true ),
376 mbHasDate( false ),
377 mbHasString( true ),
378 mbHasBlank( false ),
379 mbHasMixed( false ),
380 mbIsNumeric( false ),
381 mbIsInteger( false ),
382 mbHasLongText( false )
386 PCFieldGroupModel::PCFieldGroupModel() :
387 mfStartValue( 0.0 ),
388 mfEndValue( 0.0 ),
389 mfInterval( 1.0 ),
390 mnParentField( -1 ),
391 mnBaseField( -1 ),
392 mnGroupBy( XML_range ),
393 mbRangeGroup( false ),
394 mbDateGroup( false ),
395 mbAutoStart( true ),
396 mbAutoEnd( true )
400 void PCFieldGroupModel::setBiffGroupBy( sal_uInt8 nGroupBy )
402 static const sal_Int32 spnGroupBy[] = { XML_range,
403 XML_seconds, XML_minutes, XML_hours, XML_days, XML_months, XML_quarters, XML_years };
404 mnGroupBy = STATIC_ARRAY_SELECT( spnGroupBy, nGroupBy, XML_range );
407 PivotCacheField::PivotCacheField( const WorkbookHelper& rHelper, bool bIsDatabaseField ) :
408 WorkbookHelper( rHelper ),
409 maSharedItems( rHelper ),
410 maGroupItems( rHelper )
412 maFieldModel.mbDatabaseField = bIsDatabaseField;
415 void PivotCacheField::importCacheField( const AttributeList& rAttribs )
417 maFieldModel.maName = rAttribs.getXString( XML_name, OUString() );
418 maFieldModel.maCaption = rAttribs.getXString( XML_caption, OUString() );
419 maFieldModel.maPropertyName = rAttribs.getXString( XML_propertyName, OUString() );
420 maFieldModel.maFormula = rAttribs.getXString( XML_formula, OUString() );
421 maFieldModel.mnNumFmtId = rAttribs.getInteger( XML_numFmtId, 0 );
422 maFieldModel.mnSqlType = rAttribs.getInteger( XML_sqlType, 0 );
423 maFieldModel.mnHierarchy = rAttribs.getInteger( XML_hierarchy, 0 );
424 maFieldModel.mnLevel = rAttribs.getInteger( XML_level, 0 );
425 maFieldModel.mnMappingCount = rAttribs.getInteger( XML_mappingCount, 0 );
426 maFieldModel.mbDatabaseField = rAttribs.getBool( XML_databaseField, true );
427 maFieldModel.mbServerField = rAttribs.getBool( XML_serverField, false );
428 maFieldModel.mbUniqueList = rAttribs.getBool( XML_uniqueList, true );
429 maFieldModel.mbMemberPropField = rAttribs.getBool( XML_memberPropertyField, false );
432 void PivotCacheField::importSharedItems( const AttributeList& rAttribs )
434 OSL_ENSURE( maSharedItems.empty(), "PivotCacheField::importSharedItems - multiple shared items elements" );
435 maSharedItemsModel.mbHasSemiMixed = rAttribs.getBool( XML_containsSemiMixedTypes, true );
436 maSharedItemsModel.mbHasNonDate = rAttribs.getBool( XML_containsNonDate, true );
437 maSharedItemsModel.mbHasDate = rAttribs.getBool( XML_containsDate, false );
438 maSharedItemsModel.mbHasString = rAttribs.getBool( XML_containsString, true );
439 maSharedItemsModel.mbHasBlank = rAttribs.getBool( XML_containsBlank, false );
440 maSharedItemsModel.mbHasMixed = rAttribs.getBool( XML_containsMixedTypes, false );
441 maSharedItemsModel.mbIsNumeric = rAttribs.getBool( XML_containsNumber, false );
442 maSharedItemsModel.mbIsInteger = rAttribs.getBool( XML_containsInteger, false );
443 maSharedItemsModel.mbHasLongText = rAttribs.getBool( XML_longText, false );
446 void PivotCacheField::importSharedItem( sal_Int32 nElement, const AttributeList& rAttribs )
448 maSharedItems.importItem( nElement, rAttribs );
451 void PivotCacheField::importFieldGroup( const AttributeList& rAttribs )
453 maFieldGroupModel.mnParentField = rAttribs.getInteger( XML_par, -1 );
454 maFieldGroupModel.mnBaseField = rAttribs.getInteger( XML_base, -1 );
457 void PivotCacheField::importRangePr( const AttributeList& rAttribs )
459 maFieldGroupModel.maStartDate = rAttribs.getDateTime( XML_startDate, css::util::DateTime() );
460 maFieldGroupModel.maEndDate = rAttribs.getDateTime( XML_endDate, css::util::DateTime() );
461 maFieldGroupModel.mfStartValue = rAttribs.getDouble( XML_startNum, 0.0 );
462 maFieldGroupModel.mfEndValue = rAttribs.getDouble( XML_endNum, 0.0 );
463 maFieldGroupModel.mfInterval = rAttribs.getDouble( XML_groupInterval, 1.0 );
464 maFieldGroupModel.mnGroupBy = rAttribs.getToken( XML_groupBy, XML_range );
465 maFieldGroupModel.mbRangeGroup = true;
466 maFieldGroupModel.mbDateGroup = maFieldGroupModel.mnGroupBy != XML_range;
467 maFieldGroupModel.mbAutoStart = rAttribs.getBool( XML_autoStart, true );
468 maFieldGroupModel.mbAutoEnd = rAttribs.getBool( XML_autoEnd, true );
471 void PivotCacheField::importDiscretePrItem( sal_Int32 nElement, const AttributeList& rAttribs )
473 OSL_ENSURE( nElement == XLS_TOKEN( x ), "PivotCacheField::importDiscretePrItem - unexpected element" );
474 if( nElement == XLS_TOKEN( x ) )
475 maDiscreteItems.push_back( rAttribs.getInteger( XML_v, -1 ) );
478 void PivotCacheField::importGroupItem( sal_Int32 nElement, const AttributeList& rAttribs )
480 maGroupItems.importItem( nElement, rAttribs );
483 void PivotCacheField::importPCDField( SequenceInputStream& rStrm )
485 sal_uInt16 nFlags;
486 nFlags = rStrm.readuInt16();
487 maFieldModel.mnNumFmtId = rStrm.readInt32();
488 maFieldModel.mnSqlType = rStrm.readInt16();
489 maFieldModel.mnHierarchy = rStrm.readInt32();
490 maFieldModel.mnLevel = rStrm.readInt32();
491 maFieldModel.mnMappingCount = rStrm.readInt32();
492 rStrm >> maFieldModel.maName;
493 if( getFlag( nFlags, BIFF12_PCDFIELD_HASCAPTION ) )
494 rStrm >> maFieldModel.maCaption;
495 if( getFlag( nFlags, BIFF12_PCDFIELD_HASFORMULA ) )
496 rStrm.skip( ::std::max< sal_Int32 >( rStrm.readInt32(), 0 ) );
497 if( maFieldModel.mnMappingCount > 0 )
498 rStrm.skip( ::std::max< sal_Int32 >( rStrm.readInt32(), 0 ) );
499 if( getFlag( nFlags, BIFF12_PCDFIELD_HASPROPERTYNAME ) )
500 rStrm >> maFieldModel.maPropertyName;
502 maFieldModel.mbDatabaseField = getFlag( nFlags, BIFF12_PCDFIELD_DATABASEFIELD );
503 maFieldModel.mbServerField = getFlag( nFlags, BIFF12_PCDFIELD_SERVERFIELD );
504 maFieldModel.mbUniqueList = !getFlag( nFlags, BIFF12_PCDFIELD_NOUNIQUEITEMS );
505 maFieldModel.mbMemberPropField = getFlag( nFlags, BIFF12_PCDFIELD_MEMBERPROPFIELD );
508 void PivotCacheField::importPCDFSharedItems( SequenceInputStream& rStrm )
510 sal_uInt16 nFlags;
511 nFlags = rStrm.readuInt16();
512 maSharedItemsModel.mbHasSemiMixed = getFlag( nFlags, BIFF12_PCDFSITEMS_HASSEMIMIXED );
513 maSharedItemsModel.mbHasNonDate = getFlag( nFlags, BIFF12_PCDFSITEMS_HASNONDATE );
514 maSharedItemsModel.mbHasDate = getFlag( nFlags, BIFF12_PCDFSITEMS_HASDATE );
515 maSharedItemsModel.mbHasString = getFlag( nFlags, BIFF12_PCDFSITEMS_HASSTRING );
516 maSharedItemsModel.mbHasBlank = getFlag( nFlags, BIFF12_PCDFSITEMS_HASBLANK );
517 maSharedItemsModel.mbHasMixed = getFlag( nFlags, BIFF12_PCDFSITEMS_HASMIXED );
518 maSharedItemsModel.mbIsNumeric = getFlag( nFlags, BIFF12_PCDFSITEMS_ISNUMERIC );
519 maSharedItemsModel.mbIsInteger = getFlag( nFlags, BIFF12_PCDFSITEMS_ISINTEGER );
520 maSharedItemsModel.mbHasLongText = getFlag( nFlags, BIFF12_PCDFSITEMS_HASLONGTEXT );
523 void PivotCacheField::importPCDFSharedItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
525 maSharedItems.importItem( nRecId, rStrm );
528 void PivotCacheField::importPCDFieldGroup( SequenceInputStream& rStrm )
530 maFieldGroupModel.mnParentField = rStrm.readInt32();
531 maFieldGroupModel.mnBaseField = rStrm.readInt32();
534 void PivotCacheField::importPCDFRangePr( SequenceInputStream& rStrm )
536 sal_uInt8 nGroupBy, nFlags;
537 nGroupBy = rStrm.readuChar();
538 nFlags = rStrm.readuChar();
539 maFieldGroupModel.mfStartValue = rStrm.readDouble();
540 maFieldGroupModel.mfEndValue = rStrm.readDouble();
541 maFieldGroupModel.mfInterval = rStrm.readDouble();
543 maFieldGroupModel.setBiffGroupBy( nGroupBy );
544 maFieldGroupModel.mbRangeGroup = true;
545 maFieldGroupModel.mbDateGroup = getFlag( nFlags, BIFF12_PCDFRANGEPR_DATEGROUP );
546 maFieldGroupModel.mbAutoStart = getFlag( nFlags, BIFF12_PCDFRANGEPR_AUTOSTART );
547 maFieldGroupModel.mbAutoEnd = getFlag( nFlags, BIFF12_PCDFRANGEPR_AUTOEND );
549 OSL_ENSURE( maFieldGroupModel.mbDateGroup == (maFieldGroupModel.mnGroupBy != XML_range), "PivotCacheField::importPCDFRangePr - wrong date flag" );
550 if( maFieldGroupModel.mbDateGroup )
552 maFieldGroupModel.maStartDate = getUnitConverter().calcDateTimeFromSerial( maFieldGroupModel.mfStartValue );
553 maFieldGroupModel.maEndDate = getUnitConverter().calcDateTimeFromSerial( maFieldGroupModel.mfEndValue );
557 void PivotCacheField::importPCDFDiscretePrItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
559 OSL_ENSURE( nRecId == BIFF12_ID_PCITEM_INDEX, "PivotCacheField::importPCDFDiscretePrItem - unexpected record" );
560 if( nRecId == BIFF12_ID_PCITEM_INDEX )
561 maDiscreteItems.push_back( rStrm.readInt32() );
564 void PivotCacheField::importPCDFGroupItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
566 maGroupItems.importItem( nRecId, rStrm );
569 const PivotCacheItem* PivotCacheField::getCacheItem( sal_Int32 nItemIdx ) const
571 if( hasGroupItems() )
572 return maGroupItems.getCacheItem( nItemIdx );
573 if( hasSharedItems() )
574 return maSharedItems.getCacheItem( nItemIdx );
575 return nullptr;
578 void PivotCacheField::applyItemCaptions( const IdCaptionPairList& vCaptions )
580 if( hasGroupItems() )
581 maGroupItems.applyItemCaptions( vCaptions );
582 if( hasSharedItems() )
583 maSharedItems.applyItemCaptions( vCaptions );
586 void PivotCacheField::getCacheItemNames( ::std::vector< OUString >& orItemNames ) const
588 if( hasGroupItems() )
589 maGroupItems.getCacheItemNames( orItemNames );
590 else if( hasSharedItems() )
591 maSharedItems.getCacheItemNames( orItemNames );
594 const PivotCacheItemList& PivotCacheField::getCacheItems() const
596 if( hasGroupItems() )
597 return maGroupItems;
598 return maSharedItems;
601 void PivotCacheField::convertNumericGrouping( const Reference< XDataPilotField >& rxDPField ) const
603 OSL_ENSURE( hasGroupItems() && hasNumericGrouping(), "PivotCacheField::convertNumericGrouping - not a numeric group field" );
604 PropertySet aPropSet( rxDPField );
605 if( hasGroupItems() && hasNumericGrouping() && aPropSet.is() )
607 DataPilotFieldGroupInfo aGroupInfo;
608 aGroupInfo.HasAutoStart = maFieldGroupModel.mbAutoStart;
609 aGroupInfo.HasAutoEnd = maFieldGroupModel.mbAutoEnd;
610 aGroupInfo.HasDateValues = false;
611 aGroupInfo.Start = maFieldGroupModel.mfStartValue;
612 aGroupInfo.End = maFieldGroupModel.mfEndValue;
613 aGroupInfo.Step = maFieldGroupModel.mfInterval;
614 aGroupInfo.GroupBy = 0;
615 aPropSet.setProperty( PROP_GroupInfo, aGroupInfo );
619 OUString PivotCacheField::createDateGroupField( const Reference< XDataPilotField >& rxBaseDPField ) const
621 OSL_ENSURE( hasGroupItems() && hasDateGrouping(), "PivotCacheField::createDateGroupField - not a numeric group field" );
622 Reference< XDataPilotField > xDPGroupField;
623 PropertySet aPropSet( rxBaseDPField );
624 if( hasGroupItems() && hasDateGrouping() && aPropSet.is() )
626 bool bDayRanges = (maFieldGroupModel.mnGroupBy == XML_days) && (maFieldGroupModel.mfInterval >= 2.0);
628 DataPilotFieldGroupInfo aGroupInfo;
629 aGroupInfo.HasAutoStart = maFieldGroupModel.mbAutoStart;
630 aGroupInfo.HasAutoEnd = maFieldGroupModel.mbAutoEnd;
631 aGroupInfo.HasDateValues = true;
632 aGroupInfo.Start = getUnitConverter().calcSerialFromDateTime( maFieldGroupModel.maStartDate );
633 aGroupInfo.End = getUnitConverter().calcSerialFromDateTime( maFieldGroupModel.maEndDate );
634 aGroupInfo.Step = bDayRanges ? maFieldGroupModel.mfInterval : 0.0;
636 using namespace ::com::sun::star::sheet::DataPilotFieldGroupBy;
637 switch( maFieldGroupModel.mnGroupBy )
639 case XML_years: aGroupInfo.GroupBy = YEARS; break;
640 case XML_quarters: aGroupInfo.GroupBy = QUARTERS; break;
641 case XML_months: aGroupInfo.GroupBy = MONTHS; break;
642 case XML_days: aGroupInfo.GroupBy = DAYS; break;
643 case XML_hours: aGroupInfo.GroupBy = HOURS; break;
644 case XML_minutes: aGroupInfo.GroupBy = MINUTES; break;
645 case XML_seconds: aGroupInfo.GroupBy = SECONDS; break;
646 default: OSL_FAIL( "PivotCacheField::convertRangeGrouping - unknown date/time interval" );
651 Reference< XDataPilotFieldGrouping > xDPGrouping( rxBaseDPField, UNO_QUERY_THROW );
652 xDPGroupField = xDPGrouping->createDateGroup( aGroupInfo );
654 catch( Exception& )
659 Reference< XNamed > xFieldName( xDPGroupField, UNO_QUERY );
660 return xFieldName.is() ? xFieldName->getName() : OUString();
663 OUString PivotCacheField::createParentGroupField( const Reference< XDataPilotField >& rxBaseDPField, const PivotCacheField& rBaseCacheField, PivotCacheGroupItemVector& orItemNames ) const
665 SAL_WARN_IF( !hasGroupItems() || maDiscreteItems.empty(), "sc", "PivotCacheField::createParentGroupField - not a group field" );
666 SAL_WARN_IF( maDiscreteItems.size() != orItemNames.size(), "sc", "PivotCacheField::createParentGroupField - number of item names does not match grouping info" );
667 Reference< XDataPilotFieldGrouping > xDPGrouping( rxBaseDPField, UNO_QUERY );
668 if( !xDPGrouping.is() ) return OUString();
670 // map the group item indexes from maGroupItems to all item indexes from maDiscreteItems
671 std::vector< std::vector<sal_Int32> > aItemMap( maGroupItems.size() );
672 sal_Int32 nIndex = -1;
673 for( const auto& rDiscreteItem : maDiscreteItems )
675 ++nIndex;
676 if( std::vector<sal_Int32>* pItems = ContainerHelper::getVectorElementAccess( aItemMap, rDiscreteItem ) )
678 if ( const PivotCacheItem* pItem = rBaseCacheField.getCacheItems().getCacheItem( nIndex ) )
680 // Skip unspecified or unused entries or errors
681 if ( pItem->isUnused() || ( pItem->getType() == XML_m ) || ( pItem->getType() == XML_e ) )
682 continue;
684 pItems->push_back( nIndex );
688 // process all groups
689 Reference< XDataPilotField > xDPGroupField;
690 nIndex = 0;
691 for( const auto& rItems : aItemMap )
693 SAL_WARN_IF( rItems.empty(), "sc", "PivotCacheField::createParentGroupField - item/group should not be empty" );
694 if( !rItems.empty() )
696 /* Insert the names of the items that are part of this group. Calc
697 expects the names of the members of the field whose members are
698 grouped (which may be the names of groups too). Excel provides
699 the names of the base field items instead (no group names
700 involved). Therefore, the passed collection of current item
701 names as they are already grouped is used here to resolve the
702 item names. */
703 ::std::vector< OUString > aMembers;
704 for( auto i : rItems )
705 if( const PivotCacheGroupItem* pName = ContainerHelper::getVectorElement( orItemNames, i ) )
706 if( ::std::find( aMembers.begin(), aMembers.end(), pName->maGroupName ) == aMembers.end() )
707 aMembers.push_back( pName->maGroupName );
709 /* Check again, that this is not just a group that is not grouped
710 further with other items. */
711 if( !aMembers.empty() ) try
713 // only the first call of createNameGroup() returns the new field
714 Reference< XDataPilotField > xDPNewField = xDPGrouping->createNameGroup( comphelper::containerToSequence( aMembers ) );
715 SAL_WARN_IF( xDPGroupField.is() == xDPNewField.is(), "sc", "PivotCacheField::createParentGroupField - missing group field" );
716 if( !xDPGroupField.is() )
717 xDPGroupField = xDPNewField;
719 // get current grouping info
720 DataPilotFieldGroupInfo aGroupInfo;
721 PropertySet aPropSet( xDPGroupField );
722 aPropSet.getProperty( aGroupInfo, PROP_GroupInfo );
724 /* Find the group object and the auto-generated group name.
725 The returned field contains all groups derived from the
726 previous field if that is grouped too. To find the correct
727 group, the first item used to create the group is searched.
728 Calc provides the original item names of the base field
729 when the group is querried for its members. Its does not
730 provide the names of members that are already groups in the
731 field used to create the new groups. (Is this a bug?)
732 Therefore, a name from the passed list of original item
733 names is used to find the correct group. */
734 OUString aFirstItem;
735 if( const PivotCacheGroupItem* pName = ContainerHelper::getVectorElement( orItemNames, rItems.front() ) )
736 aFirstItem = pName->maOrigName;
737 Reference< XNamed > xGroupName;
738 OUString aAutoName;
739 Reference< XIndexAccess > xGroupsIA( aGroupInfo.Groups, UNO_QUERY_THROW );
740 for( sal_Int32 nIdx = 0, nCount = xGroupsIA->getCount(); (nIdx < nCount) && (aAutoName.isEmpty()); ++nIdx ) try
742 Reference< XNameAccess > xItemsNA( xGroupsIA->getByIndex( nIdx ), UNO_QUERY_THROW );
743 if( xItemsNA->hasByName( aFirstItem ) )
745 xGroupName.set( xGroupsIA->getByIndex( nIdx ), UNO_QUERY_THROW );
746 aAutoName = xGroupName->getName();
749 catch( Exception const & )
751 TOOLS_WARN_EXCEPTION("sc", "PivotCacheField::createParentGroupField" );
753 SAL_WARN_IF( aAutoName.isEmpty(), "sc", "PivotCacheField::createParentGroupField - cannot find auto-generated group name" );
755 // get the real group name from the list of group items
756 OUString aGroupName;
757 if( const PivotCacheItem* pGroupItem = maGroupItems.getCacheItem( nIndex ) )
758 aGroupName = pGroupItem->getName();
759 SAL_WARN_IF( aGroupName.isEmpty(), "sc", "PivotCacheField::createParentGroupField - cannot find group name" );
760 if( aGroupName.isEmpty() )
761 aGroupName = aAutoName;
763 if( xGroupName.is() && !aGroupName.isEmpty() )
765 // replace the auto-generated group name with the real name
766 if( aAutoName != aGroupName )
768 xGroupName->setName( aGroupName );
769 aPropSet.setProperty( PROP_GroupInfo, aGroupInfo );
771 // replace original item names in passed vector with group name
772 for( auto i : rItems )
773 if( PivotCacheGroupItem* pName = ContainerHelper::getVectorElementAccess( orItemNames, i ) )
774 pName->maGroupName = aGroupName;
777 catch( Exception const & )
779 TOOLS_WARN_EXCEPTION("sc", "PivotCacheField::createParentGroupField" );
782 ++nIndex;
785 Reference< XNamed > xFieldName( xDPGroupField, UNO_QUERY );
786 return xFieldName.is() ? xFieldName->getName() : OUString();
789 void PivotCacheField::writeSourceHeaderCell( const WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow ) const
791 CellModel aModel;
792 aModel.maCellAddr = ScAddress( SCCOL( nCol ), SCROW( nRow ), rSheetHelper.getSheetIndex() );
793 rSheetHelper.getSheetData().setStringCell( aModel, maFieldModel.maName );
796 void PivotCacheField::writeSourceDataCell( const WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow, const PivotCacheItem& rItem ) const
798 bool bHasIndex = rItem.getType() == XML_x;
799 OSL_ENSURE( bHasIndex != maSharedItems.empty(), "PivotCacheField::writeSourceDataCell - shared items missing or not expected" );
800 if( bHasIndex )
801 writeSharedItemToSourceDataCell( rSheetHelper, nCol, nRow, rItem.getValue().get< sal_Int32 >() );
802 else
803 writeItemToSourceDataCell( rSheetHelper, nCol, nRow, rItem );
806 void PivotCacheField::importPCRecordItem( SequenceInputStream& rStrm, const WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow ) const
808 if( hasSharedItems() )
810 writeSharedItemToSourceDataCell( rSheetHelper, nCol, nRow, rStrm.readInt32() );
812 else
814 PivotCacheItem aItem;
815 if( maSharedItemsModel.mbIsNumeric )
816 aItem.readDouble( rStrm );
817 else if( maSharedItemsModel.mbHasDate && !maSharedItemsModel.mbHasString )
818 aItem.readDate( rStrm );
819 else
820 aItem.readString( rStrm );
821 writeItemToSourceDataCell( rSheetHelper, nCol, nRow, aItem );
825 // private --------------------------------------------------------------------
827 void PivotCacheField::writeItemToSourceDataCell( const WorksheetHelper& rSheetHelper,
828 sal_Int32 nCol, sal_Int32 nRow, const PivotCacheItem& rItem )
830 if( rItem.getType() == XML_m )
831 return;
833 CellModel aModel;
834 aModel.maCellAddr = ScAddress( SCCOL( nCol ), SCROW( nRow ), rSheetHelper.getSheetIndex() );
835 SheetDataBuffer& rSheetData = rSheetHelper.getSheetData();
836 switch( rItem.getType() )
838 case XML_s: rSheetData.setStringCell( aModel, rItem.getValue().get< OUString >() ); break;
839 case XML_n: rSheetData.setValueCell( aModel, rItem.getValue().get< double >() ); break;
840 case XML_i: rSheetData.setValueCell( aModel, rItem.getValue().get< sal_Int16 >() ); break;
841 case XML_d: rSheetData.setDateTimeCell( aModel, rItem.getValue().get< css::util::DateTime >() ); break;
842 case XML_b: rSheetData.setBooleanCell( aModel, rItem.getValue().get< bool >() ); break;
843 case XML_e: rSheetData.setErrorCell(aModel, rItem.getValue().get<OUString>()); break;
844 default: OSL_FAIL( "PivotCacheField::writeItemToSourceDataCell - unexpected item data type" );
848 void PivotCacheField::writeSharedItemToSourceDataCell(
849 const WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nItemIdx ) const
851 if( const PivotCacheItem* pCacheItem = maSharedItems.getCacheItem( nItemIdx ) )
852 writeItemToSourceDataCell( rSheetHelper, nCol, nRow, *pCacheItem );
855 PCDefinitionModel::PCDefinitionModel() :
856 mfRefreshedDate( 0.0 ),
857 mnRecords( 0 ),
858 mnMissItemsLimit( 0 ),
859 mbInvalid( false ),
860 mbSaveData( true ),
861 mbRefreshOnLoad( false ),
862 mbOptimizeMemory( false ),
863 mbEnableRefresh( true ),
864 mbBackgroundQuery( false ),
865 mbUpgradeOnRefresh( false ),
866 mbTupleCache( false ),
867 mbSupportSubquery( false ),
868 mbSupportDrill( false )
872 PCSourceModel::PCSourceModel() :
873 mnSourceType( XML_TOKEN_INVALID ),
874 mnConnectionId( 0 )
878 PCWorksheetSourceModel::PCWorksheetSourceModel()
880 maRange.SetInvalid();
883 PivotCache::PivotCache( const WorkbookHelper& rHelper ) :
884 WorkbookHelper( rHelper ),
885 mnCurrRow( -1 ),
886 mbValidSource( false ),
887 mbDummySheet( false )
891 void PivotCache::importPivotCacheDefinition( const AttributeList& rAttribs )
893 maDefModel.maRelId = rAttribs.getString( R_TOKEN( id ), OUString() );
894 maDefModel.maRefreshedBy = rAttribs.getXString( XML_refreshedBy, OUString() );
895 maDefModel.mfRefreshedDate = rAttribs.getDouble( XML_refreshedDate, 0.0 );
896 maDefModel.mnRecords = rAttribs.getInteger( XML_recordCount, 0 );
897 maDefModel.mnMissItemsLimit = rAttribs.getInteger( XML_missingItemsLimit, 0 );
898 maDefModel.mbInvalid = rAttribs.getBool( XML_invalid, false );
899 maDefModel.mbSaveData = rAttribs.getBool( XML_saveData, true );
900 maDefModel.mbRefreshOnLoad = rAttribs.getBool( XML_refreshOnLoad, false );
901 maDefModel.mbOptimizeMemory = rAttribs.getBool( XML_optimizeMemory, false );
902 maDefModel.mbEnableRefresh = rAttribs.getBool( XML_enableRefresh, true );
903 maDefModel.mbBackgroundQuery = rAttribs.getBool( XML_backgroundQuery, false );
904 maDefModel.mbUpgradeOnRefresh = rAttribs.getBool( XML_upgradeOnRefresh, false );
905 maDefModel.mbTupleCache = rAttribs.getBool( XML_tupleCache, false );
906 maDefModel.mbSupportSubquery = rAttribs.getBool( XML_supportSubquery, false );
907 maDefModel.mbSupportDrill = rAttribs.getBool( XML_supportAdvancedDrill, false );
910 void PivotCache::importCacheSource( const AttributeList& rAttribs )
912 maSourceModel.mnSourceType = rAttribs.getToken( XML_type, XML_TOKEN_INVALID );
913 maSourceModel.mnConnectionId = rAttribs.getInteger( XML_connectionId, 0 );
916 void PivotCache::importWorksheetSource( const AttributeList& rAttribs, const Relations& rRelations )
918 maSheetSrcModel.maRelId = rAttribs.getString( R_TOKEN( id ), OUString() );
919 maSheetSrcModel.maSheet = rAttribs.getXString( XML_sheet, OUString() );
920 maSheetSrcModel.maDefName = rAttribs.getXString( XML_name, OUString() );
922 // resolve URL of external document
923 maTargetUrl = rRelations.getExternalTargetFromRelId( maSheetSrcModel.maRelId );
924 // store range address unchecked with sheet index 0, will be resolved/checked later
925 AddressConverter::convertToCellRangeUnchecked( maSheetSrcModel.maRange, rAttribs.getString( XML_ref, OUString() ), 0 );
928 void PivotCache::importPCDefinition( SequenceInputStream& rStrm )
930 sal_uInt8 nFlags1, nFlags2;
931 rStrm.skip( 3 ); // create/refresh version id's
932 nFlags1 = rStrm.readuChar();
933 maDefModel.mnMissItemsLimit = rStrm.readInt32();
934 maDefModel.mfRefreshedDate = rStrm.readDouble();
935 nFlags2 = rStrm.readuChar();
936 maDefModel.mnRecords = rStrm.readInt32();
937 if( getFlag( nFlags2, BIFF12_PCDEFINITION_HASUSERNAME ) )
938 rStrm >> maDefModel.maRefreshedBy;
939 if( getFlag( nFlags2, BIFF12_PCDEFINITION_HASRELID ) )
940 rStrm >> maDefModel.maRelId;
942 maDefModel.mbInvalid = getFlag( nFlags1, BIFF12_PCDEFINITION_INVALID );
943 maDefModel.mbSaveData = getFlag( nFlags1, BIFF12_PCDEFINITION_SAVEDATA );
944 maDefModel.mbRefreshOnLoad = getFlag( nFlags1, BIFF12_PCDEFINITION_REFRESHONLOAD );
945 maDefModel.mbOptimizeMemory = getFlag( nFlags1, BIFF12_PCDEFINITION_OPTIMIZEMEMORY );
946 maDefModel.mbEnableRefresh = getFlag( nFlags1, BIFF12_PCDEFINITION_ENABLEREFRESH );
947 maDefModel.mbBackgroundQuery = getFlag( nFlags1, BIFF12_PCDEFINITION_BACKGROUNDQUERY );
948 maDefModel.mbUpgradeOnRefresh = getFlag( nFlags1, BIFF12_PCDEFINITION_UPGRADEONREFR );
949 maDefModel.mbTupleCache = getFlag( nFlags1, BIFF12_PCDEFINITION_TUPLECACHE );
950 maDefModel.mbSupportSubquery = getFlag( nFlags2, BIFF12_PCDEFINITION_SUPPORTSUBQUERY );
951 maDefModel.mbSupportDrill = getFlag( nFlags2, BIFF12_PCDEFINITION_SUPPORTDRILL );
954 void PivotCache::importPCDSource( SequenceInputStream& rStrm )
956 sal_Int32 nSourceType;
957 nSourceType = rStrm.readInt32();
958 maSourceModel.mnConnectionId = rStrm.readInt32();
959 static const sal_Int32 spnSourceTypes[] = { XML_worksheet, XML_external, XML_consolidation, XML_scenario };
960 maSourceModel.mnSourceType = STATIC_ARRAY_SELECT( spnSourceTypes, nSourceType, XML_TOKEN_INVALID );
963 void PivotCache::importPCDSheetSource( SequenceInputStream& rStrm, const Relations& rRelations )
965 sal_uInt8 nIsDefName, nIsBuiltinName, nFlags;
966 nIsDefName = rStrm.readuChar();
967 nIsBuiltinName = rStrm.readuChar();
968 nFlags = rStrm.readuChar();
969 if( getFlag( nFlags, BIFF12_PCDWBSOURCE_HASSHEET ) )
970 rStrm >> maSheetSrcModel.maSheet;
971 if( getFlag( nFlags, BIFF12_PCDWBSOURCE_HASRELID ) )
972 rStrm >> maSheetSrcModel.maRelId;
974 // read cell range or defined name
975 if( nIsDefName == 0 )
977 BinRange aBinRange;
978 rStrm >> aBinRange;
979 // store range address unchecked with sheet index 0, will be resolved/checked later
980 AddressConverter::convertToCellRangeUnchecked( maSheetSrcModel.maRange, aBinRange, 0 );
982 else
984 rStrm >> maSheetSrcModel.maDefName;
985 if( nIsBuiltinName != 0 )
986 maSheetSrcModel.maDefName = "_xlnm." + maSheetSrcModel.maDefName;
989 // resolve URL of external document
990 maTargetUrl = rRelations.getExternalTargetFromRelId( maSheetSrcModel.maRelId );
993 PivotCacheField& PivotCache::createCacheField()
995 PivotCacheFieldVector::value_type xCacheField = std::make_shared<PivotCacheField>( *this, true/*bIsDatabaseField*/ );
996 maFields.push_back( xCacheField );
997 return *xCacheField;
1000 void PivotCache::finalizeImport()
1002 // collect all fields that are based on source data (needed to finalize source data below)
1003 OSL_ENSURE( !maFields.empty(), "PivotCache::finalizeImport - no pivot cache fields found" );
1004 for( PivotCacheFieldVector::const_iterator aIt = maFields.begin(), aEnd = maFields.end(); aIt != aEnd; ++aIt )
1006 if( (*aIt)->isDatabaseField() )
1008 OSL_ENSURE( (aIt == maFields.begin()) || (*(aIt - 1))->isDatabaseField(),
1009 "PivotCache::finalizeImport - database field follows a calculated field" );
1010 maDatabaseIndexes.push_back( static_cast< sal_Int32 >( maDatabaseFields.size() ) );
1011 maDatabaseFields.push_back( *aIt );
1013 else
1015 maDatabaseIndexes.push_back( -1 );
1018 OSL_ENSURE( !maDatabaseFields.empty(), "PivotCache::finalizeImport - no pivot cache source fields found" );
1020 // finalize source data depending on source type
1021 switch( maSourceModel.mnSourceType )
1023 case XML_worksheet:
1025 // decide whether an external document is used
1026 bool bInternal = maTargetUrl.isEmpty() && maSheetSrcModel.maRelId.isEmpty();
1027 bool bExternal = !maTargetUrl.isEmpty(); // relation ID may be empty, e.g. BIFF import
1028 OSL_ENSURE( bInternal || bExternal, "PivotCache::finalizeImport - invalid external document URL" );
1029 if( bInternal )
1030 finalizeInternalSheetSource();
1031 else if( bExternal )
1032 finalizeExternalSheetSource();
1034 break;
1036 // currently, we only support worksheet data sources
1037 case XML_external:
1038 break;
1039 case XML_consolidation:
1040 break;
1041 case XML_scenario:
1042 break;
1046 PivotCacheField* PivotCache::getCacheField( sal_Int32 nFieldIdx )
1048 return maFields.get( nFieldIdx ).get();
1051 const PivotCacheField* PivotCache::getCacheField( sal_Int32 nFieldIdx ) const
1053 return maFields.get( nFieldIdx ).get();
1056 sal_Int32 PivotCache::getCacheDatabaseIndex( sal_Int32 nFieldIdx ) const
1058 return ContainerHelper::getVectorElement( maDatabaseIndexes, nFieldIdx, -1 );
1061 void PivotCache::writeSourceHeaderCells( const WorksheetHelper& rSheetHelper ) const
1063 OSL_ENSURE( static_cast< size_t >( maSheetSrcModel.maRange.aEnd.Col() - maSheetSrcModel.maRange.aStart.Col() + 1 ) == maDatabaseFields.size(),
1064 "PivotCache::writeSourceHeaderCells - source cell range width does not match number of source fields" );
1065 SCCOL nCol = maSheetSrcModel.maRange.aStart.Col();
1066 SCCOL nMaxCol = getAddressConverter().getMaxApiAddress().Col();
1067 SCROW nRow = maSheetSrcModel.maRange.aStart.Row();
1068 mnCurrRow = -1;
1069 updateSourceDataRow( nRow );
1070 for( const auto& rxDatabaseField : maDatabaseFields )
1072 if (nCol > nMaxCol)
1073 break;
1074 rxDatabaseField->writeSourceHeaderCell( rSheetHelper, nCol, nRow );
1075 ++nCol;
1079 void PivotCache::writeSourceDataCell( const WorksheetHelper& rSheetHelper, sal_Int32 nColIdx, sal_Int32 nRowIdx, const PivotCacheItem& rItem ) const
1081 SCCOL nCol = maSheetSrcModel.maRange.aStart.Col() + nColIdx;
1082 OSL_ENSURE( ( maSheetSrcModel.maRange.aStart.Col() <= nCol ) && ( nCol <= maSheetSrcModel.maRange.aEnd.Col() ), "PivotCache::writeSourceDataCell - invalid column index" );
1083 SCROW nRow = maSheetSrcModel.maRange.aStart.Row() + nRowIdx;
1084 OSL_ENSURE( ( maSheetSrcModel.maRange.aStart.Row() < nRow ) && ( nRow <= maSheetSrcModel.maRange.aEnd.Row() ), "PivotCache::writeSourceDataCell - invalid row index" );
1085 updateSourceDataRow( nRow );
1086 if( const PivotCacheField* pCacheField = maDatabaseFields.get( nColIdx ).get() )
1087 pCacheField->writeSourceDataCell( rSheetHelper, nCol, nRow, rItem );
1090 void PivotCache::importPCRecord( SequenceInputStream& rStrm, const WorksheetHelper& rSheetHelper, sal_Int32 nRowIdx ) const
1092 SCROW nRow = maSheetSrcModel.maRange.aStart.Row() + nRowIdx;
1093 OSL_ENSURE( ( maSheetSrcModel.maRange.aStart.Row() < nRow ) && ( nRow <= maSheetSrcModel.maRange.aEnd.Row() ), "PivotCache::importPCRecord - invalid row index" );
1094 SCCOL nCol = maSheetSrcModel.maRange.aStart.Col();
1095 SCCOL nMaxCol = getAddressConverter().getMaxApiAddress().Col();
1096 for( const auto& rxDatabaseField : maDatabaseFields )
1098 if( rStrm.isEof() || (nCol > nMaxCol) )
1099 break;
1100 rxDatabaseField->importPCRecordItem( rStrm, rSheetHelper, nCol, nRow );
1101 ++nCol;
1105 // private --------------------------------------------------------------------
1107 void PivotCache::finalizeInternalSheetSource()
1109 // resolve sheet name to sheet index
1110 sal_Int16 nSheet = getWorksheets().getCalcSheetIndex( maSheetSrcModel.maSheet );
1112 // if cache is based on a defined name or table, try to resolve to cell range
1113 if( !maSheetSrcModel.maDefName.isEmpty() )
1115 // local or global defined name
1116 if( const DefinedName* pDefName = getDefinedNames().getByModelName( maSheetSrcModel.maDefName, nSheet ).get() )
1118 mbValidSource = pDefName->getAbsoluteRange( maSheetSrcModel.maRange );
1120 // table
1121 else if( const Table* pTable = getTables().getTable( maSheetSrcModel.maDefName ).get() )
1123 // get original range from table, but exclude the totals row(s)
1124 maSheetSrcModel.maRange = pTable->getOriginalRange();
1125 mbValidSource = (pTable->getHeight() - pTable->getTotalsRows()) > 1;
1126 if( mbValidSource )
1127 maSheetSrcModel.maRange.aEnd.SetRow( maSheetSrcModel.maRange.aEnd.Row() - pTable->getTotalsRows() );
1130 // else try the cell range (if the sheet exists)
1131 else if( nSheet >= 0 )
1133 // insert sheet index into the range, range address will be checked below
1134 maSheetSrcModel.maRange.aStart.SetTab( nSheet );
1135 mbValidSource = true;
1137 // else sheet has been deleted, generate the source data from cache
1138 else if( !maSheetSrcModel.maSheet.isEmpty() )
1140 prepareSourceDataSheet();
1141 // return here to skip the source range check below
1142 return;
1145 // check range location, do not allow ranges that overflow the sheet partly
1146 mbValidSource = mbValidSource &&
1147 getAddressConverter().checkCellRange( maSheetSrcModel.maRange, false, true ) &&
1148 ( maSheetSrcModel.maRange.aStart.Row() < maSheetSrcModel.maRange.aEnd.Row() );
1151 void PivotCache::finalizeExternalSheetSource()
1153 /* If pivot cache is based on external sheet data, try to restore sheet
1154 data from cache records. No support for external defined names or tables,
1155 sheet name and path to cache records fragment (OOXML only) are required. */
1156 bool bHasRelation = !maDefModel.maRelId.isEmpty();
1157 if( bHasRelation && maSheetSrcModel.maDefName.isEmpty() && !maSheetSrcModel.maSheet.isEmpty() )
1158 prepareSourceDataSheet();
1161 void PivotCache::prepareSourceDataSheet()
1163 ScRange& rRange = maSheetSrcModel.maRange;
1164 // data will be inserted in top-left cell, sheet index is still set to 0 (will be set below)
1165 rRange.aEnd.SetCol( rRange.aEnd.Col() - rRange.aStart.Col() );
1166 rRange.aStart.SetCol( 0 );
1167 rRange.aEnd.SetRow( rRange.aEnd.Row() - rRange.aStart.Row() );
1168 rRange.aStart.SetRow( 0 );
1169 // check range location, do not allow ranges that overflow the sheet partly
1170 if( getAddressConverter().checkCellRange( rRange, false, true ) )
1172 maColSpans.insert( ValueRange( rRange.aStart.Col(), rRange.aEnd.Col() ) );
1173 OUString aSheetName = "DPCache_" + maSheetSrcModel.maSheet;
1174 rRange.aStart.SetTab( getWorksheets().insertEmptySheet( aSheetName ) );
1175 mbValidSource = mbDummySheet = rRange.aStart.Tab() >= 0;
1179 void PivotCache::updateSourceDataRow( sal_Int32 nRow ) const
1181 if( mnCurrRow != nRow )
1183 mnCurrRow = nRow;
1187 PivotCacheBuffer::PivotCacheBuffer( const WorkbookHelper& rHelper ) :
1188 WorkbookHelper( rHelper )
1192 void PivotCacheBuffer::registerPivotCacheFragment( sal_Int32 nCacheId, const OUString& rFragmentPath )
1194 OSL_ENSURE( nCacheId >= 0, "PivotCacheBuffer::registerPivotCacheFragment - invalid pivot cache identifier" );
1195 OSL_ENSURE( maFragmentPaths.count( nCacheId ) == 0, "PivotCacheBuffer::registerPivotCacheFragment - fragment path exists already" );
1196 if( (nCacheId >= 0) && !rFragmentPath.isEmpty() )
1197 maFragmentPaths[ nCacheId ] = rFragmentPath;
1200 PivotCache* PivotCacheBuffer::importPivotCacheFragment( sal_Int32 nCacheId )
1202 /* OOXML/BIFF12 filter: On first call for the cache ID, the pivot
1203 cache object is created and inserted into maCaches. Then, the cache
1204 definition fragment is read and the cache is returned. On
1205 subsequent calls, the created cache will be found in maCaches and
1206 returned immediately. */
1207 // try to find an imported pivot cache
1208 if( PivotCache* pCache = maCaches.get( nCacheId ).get() )
1209 return pCache;
1211 // check if a fragment path exists for the passed cache identifier
1212 FragmentPathMap::iterator aIt = maFragmentPaths.find( nCacheId );
1213 if( aIt == maFragmentPaths.end() )
1214 return nullptr;
1216 /* Import the cache fragment. This may create a dummy data sheet
1217 for external sheet sources. */
1218 PivotCache& rCache = createPivotCache( nCacheId );
1219 importOoxFragment( new PivotCacheDefinitionFragment( *this, aIt->second, rCache ) );
1220 return &rCache;
1223 PivotCache& PivotCacheBuffer::createPivotCache( sal_Int32 nCacheId )
1225 maCacheIds.push_back( nCacheId );
1226 PivotCacheMap::mapped_type& rxCache = maCaches[ nCacheId ];
1227 rxCache = std::make_shared<PivotCache>( *this );
1228 return *rxCache;
1231 } // namespace oox
1233 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */