fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / filter / excel / xepivot.cxx
blob71ca745233865ad41d83640640528c2f5fb7365b
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 "xepivot.hxx"
21 #include <com/sun/star/sheet/DataPilotFieldSortInfo.hpp>
22 #include <com/sun/star/sheet/DataPilotFieldAutoShowInfo.hpp>
23 #include <com/sun/star/sheet/DataPilotFieldLayoutInfo.hpp>
24 #include <com/sun/star/sheet/DataPilotFieldReference.hpp>
25 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
27 #include <algorithm>
28 #include <math.h>
30 #include <rtl/math.hxx>
31 #include <tools/date.hxx>
32 #include <svl/zformat.hxx>
33 #include <sot/storage.hxx>
34 #include "document.hxx"
35 #include "dpobject.hxx"
36 #include "dpsave.hxx"
37 #include "dpdimsave.hxx"
38 #include "dpshttab.hxx"
39 #include "globstr.hrc"
40 #include "fapihelper.hxx"
41 #include "xestring.hxx"
42 #include "xelink.hxx"
43 #include "dputil.hxx"
45 using namespace ::oox;
47 using ::com::sun::star::sheet::DataPilotFieldOrientation;
48 using ::com::sun::star::sheet::DataPilotFieldOrientation_HIDDEN;
49 using ::com::sun::star::sheet::DataPilotFieldOrientation_ROW;
50 using ::com::sun::star::sheet::DataPilotFieldOrientation_COLUMN;
51 using ::com::sun::star::sheet::DataPilotFieldOrientation_PAGE;
52 using ::com::sun::star::sheet::DataPilotFieldOrientation_DATA;
53 using ::com::sun::star::sheet::GeneralFunction;
54 using ::com::sun::star::sheet::DataPilotFieldSortInfo;
55 using ::com::sun::star::sheet::DataPilotFieldAutoShowInfo;
56 using ::com::sun::star::sheet::DataPilotFieldLayoutInfo;
57 using ::com::sun::star::sheet::DataPilotFieldReference;
59 // Pivot cache
61 namespace {
63 // constants to track occurrence of specific data types
64 const sal_uInt16 EXC_PCITEM_DATA_STRING = 0x0001; /// String, empty, boolean, error.
65 const sal_uInt16 EXC_PCITEM_DATA_DOUBLE = 0x0002; /// Double with fraction.
66 const sal_uInt16 EXC_PCITEM_DATA_INTEGER = 0x0004; /// Integer, double without fraction.
67 const sal_uInt16 EXC_PCITEM_DATA_DATE = 0x0008; /// Date, time, date/time.
69 /** Maps a bitfield consisting of EXC_PCITEM_DATA_* flags above to SXFIELD data type bitfield. */
70 static const sal_uInt16 spnPCItemFlags[] =
71 { // STR DBL INT DAT
72 EXC_SXFIELD_DATA_NONE,
73 EXC_SXFIELD_DATA_STR, // x
74 EXC_SXFIELD_DATA_INT, // x
75 EXC_SXFIELD_DATA_STR_INT, // x x
76 EXC_SXFIELD_DATA_DBL, // x
77 EXC_SXFIELD_DATA_STR_DBL, // x x
78 EXC_SXFIELD_DATA_INT, // x x
79 EXC_SXFIELD_DATA_STR_INT, // x x x
80 EXC_SXFIELD_DATA_DATE, // x
81 EXC_SXFIELD_DATA_DATE_STR, // x x
82 EXC_SXFIELD_DATA_DATE_NUM, // x x
83 EXC_SXFIELD_DATA_DATE_STR, // x x x
84 EXC_SXFIELD_DATA_DATE_NUM, // x x
85 EXC_SXFIELD_DATA_DATE_STR, // x x x
86 EXC_SXFIELD_DATA_DATE_NUM, // x x x
87 EXC_SXFIELD_DATA_DATE_STR // x x x x
90 } // namespace
92 XclExpPCItem::XclExpPCItem( const OUString& rText ) :
93 XclExpRecord( (!rText.isEmpty()) ? EXC_ID_SXSTRING : EXC_ID_SXEMPTY, 0 ),
94 mnTypeFlag( EXC_PCITEM_DATA_STRING )
96 if( !rText.isEmpty() )
97 SetText( rText );
98 else
99 SetEmpty();
102 XclExpPCItem::XclExpPCItem( double fValue ) :
103 XclExpRecord( EXC_ID_SXDOUBLE, 8 )
105 SetDouble( fValue );
106 mnTypeFlag = (fValue - floor( fValue ) == 0.0) ?
107 EXC_PCITEM_DATA_INTEGER : EXC_PCITEM_DATA_DOUBLE;
110 XclExpPCItem::XclExpPCItem( const DateTime& rDateTime ) :
111 XclExpRecord( EXC_ID_SXDATETIME, 8 )
113 SetDateTime( rDateTime );
114 mnTypeFlag = EXC_PCITEM_DATA_DATE;
117 XclExpPCItem::XclExpPCItem( sal_Int16 nValue ) :
118 XclExpRecord( EXC_ID_SXINTEGER, 2 ),
119 mnTypeFlag( EXC_PCITEM_DATA_INTEGER )
121 SetInteger( nValue );
124 XclExpPCItem::XclExpPCItem( bool bValue ) :
125 XclExpRecord( EXC_ID_SXBOOLEAN, 2 ),
126 mnTypeFlag( EXC_PCITEM_DATA_STRING )
128 SetBool( bValue );
131 bool XclExpPCItem::EqualsText( const OUString& rText ) const
133 return rText.isEmpty() ? IsEmpty() : (GetText() && (*GetText() == rText));
136 bool XclExpPCItem::EqualsDouble( double fValue ) const
138 return GetDouble() && (*GetDouble() == fValue);
141 bool XclExpPCItem::EqualsDateTime( const DateTime& rDateTime ) const
143 return GetDateTime() && (*GetDateTime() == rDateTime);
146 bool XclExpPCItem::EqualsBool( bool bValue ) const
148 return GetBool() && (*GetBool() == bValue);
151 void XclExpPCItem::WriteBody( XclExpStream& rStrm )
153 if( const OUString* pText = GetText() )
155 rStrm << XclExpString( *pText );
157 else if( const double* pfValue = GetDouble() )
159 rStrm << *pfValue;
161 else if( const sal_Int16* pnValue = GetInteger() )
163 rStrm << *pnValue;
165 else if( const DateTime* pDateTime = GetDateTime() )
167 sal_uInt16 nYear = static_cast< sal_uInt16 >( pDateTime->GetYear() );
168 sal_uInt16 nMonth = static_cast< sal_uInt16 >( pDateTime->GetMonth() );
169 sal_uInt8 nDay = static_cast< sal_uInt8 >( pDateTime->GetDay() );
170 sal_uInt8 nHour = static_cast< sal_uInt8 >( pDateTime->GetHour() );
171 sal_uInt8 nMin = static_cast< sal_uInt8 >( pDateTime->GetMin() );
172 sal_uInt8 nSec = static_cast< sal_uInt8 >( pDateTime->GetSec() );
173 if( nYear < 1900 ) { nYear = 1900; nMonth = 1; nDay = 0; }
174 rStrm << nYear << nMonth << nDay << nHour << nMin << nSec;
176 else if( const bool* pbValue = GetBool() )
178 rStrm << static_cast< sal_uInt16 >( *pbValue ? 1 : 0 );
180 else
182 // nothing to do for SXEMPTY
183 OSL_ENSURE( IsEmpty(), "XclExpPCItem::WriteBody - no data found" );
187 XclExpPCField::XclExpPCField(
188 const XclExpRoot& rRoot, const XclExpPivotCache& rPCache, sal_uInt16 nFieldIdx,
189 const ScDPObject& rDPObj, const ScRange& rRange ) :
190 XclExpRecord( EXC_ID_SXFIELD ),
191 XclPCField( EXC_PCFIELD_STANDARD, nFieldIdx ),
192 XclExpRoot( rRoot ),
193 mrPCache( rPCache ),
194 mnTypeFlags( 0 )
196 // general settings for the standard field, insert all items from source range
197 InitStandardField( rRange );
199 // add special settings for inplace numeric grouping
200 if( const ScDPSaveData* pSaveData = rDPObj.GetSaveData() )
202 if( const ScDPDimensionSaveData* pSaveDimData = pSaveData->GetExistingDimensionData() )
204 if( const ScDPSaveNumGroupDimension* pNumGroupDim = pSaveDimData->GetNumGroupDim( GetFieldName() ) )
206 const ScDPNumGroupInfo& rNumInfo = pNumGroupDim->GetInfo();
207 const ScDPNumGroupInfo& rDateInfo = pNumGroupDim->GetDateInfo();
208 OSL_ENSURE( !rNumInfo.mbEnable || !rDateInfo.mbEnable,
209 "XclExpPCField::XclExpPCField - numeric and date grouping enabled" );
211 if( rNumInfo.mbEnable )
212 InitNumGroupField( rDPObj, rNumInfo );
213 else if( rDateInfo.mbEnable )
214 InitDateGroupField( rDPObj, rDateInfo, pNumGroupDim->GetDatePart() );
219 // final settings (flags, item numbers)
220 Finalize();
223 XclExpPCField::XclExpPCField(
224 const XclExpRoot& rRoot, const XclExpPivotCache& rPCache, sal_uInt16 nFieldIdx,
225 const ScDPObject& rDPObj, const ScDPSaveGroupDimension& rGroupDim, const XclExpPCField& rBaseField ) :
226 XclExpRecord( EXC_ID_SXFIELD ),
227 XclPCField( EXC_PCFIELD_STDGROUP, nFieldIdx ),
228 XclExpRoot( rRoot ),
229 mrPCache( rPCache ),
230 mnTypeFlags( 0 )
232 // add base field info (always using first base field, not predecessor of this field) ***
233 OSL_ENSURE( rBaseField.GetFieldName() == rGroupDim.GetSourceDimName(),
234 "XclExpPCField::FillFromGroup - wrong base cache field" );
235 maFieldInfo.maName = rGroupDim.GetGroupDimName();
236 maFieldInfo.mnGroupBase = rBaseField.GetFieldIndex();
238 // add standard group info or date group info
239 const ScDPNumGroupInfo& rDateInfo = rGroupDim.GetDateInfo();
240 if( rDateInfo.mbEnable && (rGroupDim.GetDatePart() != 0) )
241 InitDateGroupField( rDPObj, rDateInfo, rGroupDim.GetDatePart() );
242 else
243 InitStdGroupField( rBaseField, rGroupDim );
245 // final settings (flags, item numbers)
246 Finalize();
249 XclExpPCField::~XclExpPCField()
253 void XclExpPCField::SetGroupChildField( const XclExpPCField& rChildField )
255 OSL_ENSURE( !::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_HASCHILD ),
256 "XclExpPCField::SetGroupChildIndex - field already has a grouping child field" );
257 ::set_flag( maFieldInfo.mnFlags, EXC_SXFIELD_HASCHILD );
258 maFieldInfo.mnGroupChild = rChildField.GetFieldIndex();
261 sal_uInt16 XclExpPCField::GetItemCount() const
263 return static_cast< sal_uInt16 >( GetVisItemList().GetSize() );
266 const XclExpPCItem* XclExpPCField::GetItem( sal_uInt16 nItemIdx ) const
268 return GetVisItemList().GetRecord( nItemIdx ).get();
271 sal_uInt16 XclExpPCField::GetItemIndex( const OUString& rItemName ) const
273 const XclExpPCItemList& rItemList = GetVisItemList();
274 for( size_t nPos = 0, nSize = rItemList.GetSize(); nPos < nSize; ++nPos )
275 if( rItemList.GetRecord( nPos )->ConvertToText() == rItemName )
276 return static_cast< sal_uInt16 >( nPos );
277 return EXC_PC_NOITEM;
280 sal_Size XclExpPCField::GetIndexSize() const
282 return Has16BitIndexes() ? 2 : 1;
285 void XclExpPCField::WriteIndex( XclExpStream& rStrm, sal_uInt32 nSrcRow ) const
287 // only standard fields write item indexes
288 if( nSrcRow < maIndexVec.size() )
290 sal_uInt16 nIndex = maIndexVec[ nSrcRow ];
291 if( Has16BitIndexes() )
292 rStrm << nIndex;
293 else
294 rStrm << static_cast< sal_uInt8 >( nIndex );
298 void XclExpPCField::Save( XclExpStream& rStrm )
300 OSL_ENSURE( IsSupportedField(), "XclExpPCField::Save - unknown field type" );
301 // SXFIELD
302 XclExpRecord::Save( rStrm );
303 // SXFDBTYPE
304 XclExpUInt16Record( EXC_ID_SXFDBTYPE, EXC_SXFDBTYPE_DEFAULT ).Save( rStrm );
305 // list of grouping items
306 maGroupItemList.Save( rStrm );
307 // SXGROUPINFO
308 WriteSxgroupinfo( rStrm );
309 // SXNUMGROUP and additional grouping items (grouping limit settings)
310 WriteSxnumgroup( rStrm );
311 // list of original items
312 maOrigItemList.Save( rStrm );
315 // private --------------------------------------------------------------------
317 const XclExpPCField::XclExpPCItemList& XclExpPCField::GetVisItemList() const
319 OSL_ENSURE( IsStandardField() == maGroupItemList.IsEmpty(),
320 "XclExpPCField::GetVisItemList - unexpected additional items in standard field" );
321 return IsStandardField() ? maOrigItemList : maGroupItemList;
324 void XclExpPCField::InitStandardField( const ScRange& rRange )
326 OSL_ENSURE( IsStandardField(), "XclExpPCField::InitStandardField - only for standard fields" );
327 OSL_ENSURE( rRange.aStart.Col() == rRange.aEnd.Col(), "XclExpPCField::InitStandardField - cell range with multiple columns" );
329 ScDocument& rDoc = GetDoc();
330 SvNumberFormatter& rFormatter = GetFormatter();
332 // field name is in top cell of the range
333 ScAddress aPos( rRange.aStart );
334 maFieldInfo.maName = rDoc.GetString(aPos.Col(), aPos.Row(), aPos.Tab());
335 // #i76047# maximum field name length in pivot cache is 255
336 if (maFieldInfo.maName.getLength() > EXC_PC_MAXSTRLEN)
337 maFieldInfo.maName = maFieldInfo.maName.copy(0, EXC_PC_MAXSTRLEN);
339 // loop over all cells, create pivot cache items
340 for( aPos.IncRow(); (aPos.Row() <= rRange.aEnd.Row()) && (maOrigItemList.GetSize() < EXC_PC_MAXITEMCOUNT); aPos.IncRow() )
342 if( rDoc.HasValueData( aPos.Col(), aPos.Row(), aPos.Tab() ) )
344 double fValue = rDoc.GetValue( aPos );
345 short nFmtType = rFormatter.GetType( rDoc.GetNumberFormat( aPos ) );
346 if( nFmtType == css::util::NumberFormat::LOGICAL )
347 InsertOrigBoolItem( fValue != 0 );
348 else if( nFmtType & css::util::NumberFormat::DATETIME )
349 InsertOrigDateTimeItem( GetDateTimeFromDouble( ::std::max( fValue, 0.0 ) ) );
350 else
351 InsertOrigDoubleItem( fValue );
353 else
355 OUString aText = rDoc.GetString(aPos.Col(), aPos.Row(), aPos.Tab());
356 InsertOrigTextItem( aText );
361 void XclExpPCField::InitStdGroupField( const XclExpPCField& rBaseField, const ScDPSaveGroupDimension& rGroupDim )
363 OSL_ENSURE( IsGroupField(), "XclExpPCField::InitStdGroupField - only for standard grouping fields" );
365 maFieldInfo.mnBaseItems = rBaseField.GetItemCount();
366 maGroupOrder.resize( maFieldInfo.mnBaseItems, EXC_PC_NOITEM );
368 // loop over all groups of this field
369 for( long nGroupIdx = 0, nGroupCount = rGroupDim.GetGroupCount(); nGroupIdx < nGroupCount; ++nGroupIdx )
371 if( const ScDPSaveGroupItem* pGroupItem = rGroupDim.GetGroupByIndex( nGroupIdx ) )
373 // the index of the new item containing the grouping name
374 sal_uInt16 nGroupItemIdx = EXC_PC_NOITEM;
375 // loop over all elements of one group
376 for( size_t nElemIdx = 0, nElemCount = pGroupItem->GetElementCount(); nElemIdx < nElemCount; ++nElemIdx )
378 if (const OUString* pElemName = pGroupItem->GetElementByIndex(nElemIdx))
380 // try to find the item that is part of the group in the base field
381 sal_uInt16 nBaseItemIdx = rBaseField.GetItemIndex( *pElemName );
382 if( nBaseItemIdx < maFieldInfo.mnBaseItems )
384 // add group name item only if there are any valid base items
385 if( nGroupItemIdx == EXC_PC_NOITEM )
386 nGroupItemIdx = InsertGroupItem( new XclExpPCItem( pGroupItem->GetGroupName() ) );
387 maGroupOrder[ nBaseItemIdx ] = nGroupItemIdx;
394 // add items and base item indexes of all ungrouped elements
395 for( sal_uInt16 nBaseItemIdx = 0; nBaseItemIdx < maFieldInfo.mnBaseItems; ++nBaseItemIdx )
396 // items that are not part of a group still have the EXC_PC_NOITEM entry
397 if( maGroupOrder[ nBaseItemIdx ] == EXC_PC_NOITEM )
398 // try to find the base item
399 if( const XclExpPCItem* pBaseItem = rBaseField.GetItem( nBaseItemIdx ) )
400 // create a clone of the base item, insert its index into item order list
401 maGroupOrder[ nBaseItemIdx ] = InsertGroupItem( new XclExpPCItem( *pBaseItem ) );
404 void XclExpPCField::InitNumGroupField( const ScDPObject& rDPObj, const ScDPNumGroupInfo& rNumInfo )
406 OSL_ENSURE( IsStandardField(), "XclExpPCField::InitNumGroupField - only for standard fields" );
407 OSL_ENSURE( rNumInfo.mbEnable, "XclExpPCField::InitNumGroupField - numeric grouping not enabled" );
409 // new field type, date type, limit settings (min/max/step/auto)
410 if( rNumInfo.mbDateValues )
412 // special case: group by days with step count
413 meFieldType = EXC_PCFIELD_DATEGROUP;
414 maNumGroupInfo.SetScDateType( com::sun::star::sheet::DataPilotFieldGroupBy::DAYS );
415 SetDateGroupLimit( rNumInfo, true );
417 else
419 meFieldType = EXC_PCFIELD_NUMGROUP;
420 maNumGroupInfo.SetNumType();
421 SetNumGroupLimit( rNumInfo );
424 // generate visible items
425 InsertNumDateGroupItems( rDPObj, rNumInfo );
428 void XclExpPCField::InitDateGroupField( const ScDPObject& rDPObj, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nDatePart )
430 OSL_ENSURE( IsStandardField() || IsStdGroupField(), "XclExpPCField::InitDateGroupField - only for standard fields" );
431 OSL_ENSURE( rDateInfo.mbEnable, "XclExpPCField::InitDateGroupField - date grouping not enabled" );
433 // new field type
434 meFieldType = IsStandardField() ? EXC_PCFIELD_DATEGROUP : EXC_PCFIELD_DATECHILD;
436 // date type, limit settings (min/max/step/auto)
437 maNumGroupInfo.SetScDateType( nDatePart );
438 SetDateGroupLimit( rDateInfo, false );
440 // generate visible items
441 InsertNumDateGroupItems( rDPObj, rDateInfo, nDatePart );
444 void XclExpPCField::InsertItemArrayIndex( size_t nListPos )
446 OSL_ENSURE( IsStandardField(), "XclExpPCField::InsertItemArrayIndex - only for standard fields" );
447 maIndexVec.push_back( static_cast< sal_uInt16 >( nListPos ) );
450 void XclExpPCField::InsertOrigItem( XclExpPCItem* pNewItem )
452 size_t nItemIdx = maOrigItemList.GetSize();
453 maOrigItemList.AppendNewRecord( pNewItem );
454 InsertItemArrayIndex( nItemIdx );
455 mnTypeFlags |= pNewItem->GetTypeFlag();
458 void XclExpPCField::InsertOrigTextItem( const OUString& rText )
460 size_t nPos = 0;
461 bool bFound = false;
462 // #i76047# maximum item text length in pivot cache is 255
463 OUString aShortText = rText.copy( 0, ::std::min(rText.getLength(), EXC_PC_MAXSTRLEN ) );
464 for( size_t nSize = maOrigItemList.GetSize(); !bFound && (nPos < nSize); ++nPos )
465 if( (bFound = maOrigItemList.GetRecord( nPos )->EqualsText( aShortText )) )
466 InsertItemArrayIndex( nPos );
467 if( !bFound )
468 InsertOrigItem( new XclExpPCItem( aShortText ) );
471 void XclExpPCField::InsertOrigDoubleItem( double fValue )
473 size_t nPos = 0;
474 bool bFound = false;
475 for( size_t nSize = maOrigItemList.GetSize(); !bFound && (nPos < nSize); ++nPos )
476 if( (bFound = maOrigItemList.GetRecord( nPos )->EqualsDouble( fValue )) )
477 InsertItemArrayIndex( nPos );
478 if( !bFound )
479 InsertOrigItem( new XclExpPCItem( fValue ) );
482 void XclExpPCField::InsertOrigDateTimeItem( const DateTime& rDateTime )
484 size_t nPos = 0;
485 bool bFound = false;
486 for( size_t nSize = maOrigItemList.GetSize(); !bFound && (nPos < nSize); ++nPos )
487 if( (bFound = maOrigItemList.GetRecord( nPos )->EqualsDateTime( rDateTime )) )
488 InsertItemArrayIndex( nPos );
489 if( !bFound )
490 InsertOrigItem( new XclExpPCItem( rDateTime ) );
493 void XclExpPCField::InsertOrigBoolItem( bool bValue )
495 size_t nPos = 0;
496 bool bFound = false;
497 for( size_t nSize = maOrigItemList.GetSize(); !bFound && (nPos < nSize); ++nPos )
498 if( (bFound = maOrigItemList.GetRecord( nPos )->EqualsBool( bValue )) )
499 InsertItemArrayIndex( nPos );
500 if( !bFound )
501 InsertOrigItem( new XclExpPCItem( bValue ) );
504 sal_uInt16 XclExpPCField::InsertGroupItem( XclExpPCItem* pNewItem )
506 maGroupItemList.AppendNewRecord( pNewItem );
507 return static_cast< sal_uInt16 >( maGroupItemList.GetSize() - 1 );
510 void XclExpPCField::InsertNumDateGroupItems( const ScDPObject& rDPObj, const ScDPNumGroupInfo& rNumInfo, sal_Int32 nDatePart )
512 OSL_ENSURE( rDPObj.GetSheetDesc(), "XclExpPCField::InsertNumDateGroupItems - cannot generate element list" );
513 if( const ScSheetSourceDesc* pSrcDesc = rDPObj.GetSheetDesc() )
515 // get the string collection with original source elements
516 const ScDPSaveData* pSaveData = rDPObj.GetSaveData();
517 const ScDPDimensionSaveData* pDimData = NULL;
518 if (pSaveData)
519 pDimData = pSaveData->GetExistingDimensionData();
521 const ScDPCache* pCache = pSrcDesc->CreateCache(pDimData);
522 if (!pCache)
523 return;
525 ScSheetDPData aDPData(GetDocPtr(), *pSrcDesc, *pCache);
526 long nDim = GetFieldIndex();
527 // get the string collection with generated grouping elements
528 ScDPNumGroupDimension aTmpDim( rNumInfo );
529 if( nDatePart != 0 )
530 aTmpDim.SetDateDimension();
531 const std::vector<SCROW>& aMemberIds = aTmpDim.GetNumEntries(
532 static_cast<SCCOL>(nDim), pCache);
533 for ( size_t nIdx = 0 ; nIdx < aMemberIds.size(); nIdx++ )
535 const ScDPItemData* pData = aDPData.GetMemberById(nDim , aMemberIds[nIdx]);
536 if ( pData )
538 OUString aStr = pCache->GetFormattedString(nDim, *pData);
539 InsertGroupItem(new XclExpPCItem(aStr));
545 void XclExpPCField::SetNumGroupLimit( const ScDPNumGroupInfo& rNumInfo )
547 ::set_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMIN, rNumInfo.mbAutoStart );
548 ::set_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMAX, rNumInfo.mbAutoEnd );
549 maNumGroupLimits.AppendNewRecord( new XclExpPCItem( rNumInfo.mfStart ) );
550 maNumGroupLimits.AppendNewRecord( new XclExpPCItem( rNumInfo.mfEnd ) );
551 maNumGroupLimits.AppendNewRecord( new XclExpPCItem( rNumInfo.mfStep ) );
554 void XclExpPCField::SetDateGroupLimit( const ScDPNumGroupInfo& rDateInfo, bool bUseStep )
556 ::set_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMIN, rDateInfo.mbAutoStart );
557 ::set_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMAX, rDateInfo.mbAutoEnd );
558 maNumGroupLimits.AppendNewRecord( new XclExpPCItem( GetDateTimeFromDouble( rDateInfo.mfStart ) ) );
559 maNumGroupLimits.AppendNewRecord( new XclExpPCItem( GetDateTimeFromDouble( rDateInfo.mfEnd ) ) );
560 sal_Int16 nStep = bUseStep ? limit_cast< sal_Int16 >( rDateInfo.mfStep, 1, SAL_MAX_INT16 ) : 1;
561 maNumGroupLimits.AppendNewRecord( new XclExpPCItem( nStep ) );
564 void XclExpPCField::Finalize()
566 // flags
567 ::set_flag( maFieldInfo.mnFlags, EXC_SXFIELD_HASITEMS, !GetVisItemList().IsEmpty() );
568 // Excel writes long indexes even for 0x0100 items (indexes from 0x00 to 0xFF)
569 ::set_flag( maFieldInfo.mnFlags, EXC_SXFIELD_16BIT, maOrigItemList.GetSize() >= 0x0100 );
570 ::set_flag( maFieldInfo.mnFlags, EXC_SXFIELD_NUMGROUP, IsNumGroupField() || IsDateGroupField() );
571 /* mnTypeFlags is updated in all Insert***Item() functions. Now the flags
572 for the current combination of item types is added to the flags. */
573 ::set_flag( maFieldInfo.mnFlags, spnPCItemFlags[ mnTypeFlags ] );
575 // item count fields
576 maFieldInfo.mnVisItems = static_cast< sal_uInt16 >( GetVisItemList().GetSize() );
577 maFieldInfo.mnGroupItems = static_cast< sal_uInt16 >( maGroupItemList.GetSize() );
578 // maFieldInfo.mnBaseItems set in InitStdGroupField()
579 maFieldInfo.mnOrigItems = static_cast< sal_uInt16 >( maOrigItemList.GetSize() );
582 void XclExpPCField::WriteSxnumgroup( XclExpStream& rStrm )
584 if( IsNumGroupField() || IsDateGroupField() )
586 // SXNUMGROUP record
587 rStrm.StartRecord( EXC_ID_SXNUMGROUP, 2 );
588 rStrm << maNumGroupInfo;
589 rStrm.EndRecord();
591 // limits (min/max/step) for numeric grouping
592 OSL_ENSURE( maNumGroupLimits.GetSize() == 3,
593 "XclExpPCField::WriteSxnumgroup - missing numeric grouping limits" );
594 maNumGroupLimits.Save( rStrm );
598 void XclExpPCField::WriteSxgroupinfo( XclExpStream& rStrm )
600 OSL_ENSURE( IsStdGroupField() != maGroupOrder.empty(),
601 "XclExpPCField::WriteSxgroupinfo - missing grouping info" );
602 if( IsStdGroupField() && !maGroupOrder.empty() )
604 rStrm.StartRecord( EXC_ID_SXGROUPINFO, 2 * maGroupOrder.size() );
605 for( ScfUInt16Vec::const_iterator aIt = maGroupOrder.begin(), aEnd = maGroupOrder.end(); aIt != aEnd; ++aIt )
606 rStrm << *aIt;
607 rStrm.EndRecord();
611 void XclExpPCField::WriteBody( XclExpStream& rStrm )
613 rStrm << maFieldInfo;
616 XclExpPivotCache::XclExpPivotCache( const XclExpRoot& rRoot, const ScDPObject& rDPObj, sal_uInt16 nListIdx ) :
617 XclExpRoot( rRoot ),
618 mnListIdx( nListIdx ),
619 mbValid( false )
621 // source from sheet only
622 if( const ScSheetSourceDesc* pSrcDesc = rDPObj.GetSheetDesc() )
624 /* maOrigSrcRange: Range received from the DataPilot object.
625 maExpSrcRange: Range written to the DCONREF record.
626 maDocSrcRange: Range used to get source data from Calc document.
627 This range may be shorter than maExpSrcRange to improve export
628 performance (#i22541#). */
629 maOrigSrcRange = maExpSrcRange = maDocSrcRange = pSrcDesc->GetSourceRange();
630 maSrcRangeName = pSrcDesc->GetRangeName();
632 // internal sheet data only
633 SCTAB nScTab = maExpSrcRange.aStart.Tab();
634 if( (nScTab == maExpSrcRange.aEnd.Tab()) && GetTabInfo().IsExportTab( nScTab ) )
636 // ValidateRange() restricts source range to valid Excel limits
637 if( GetAddressConverter().ValidateRange( maExpSrcRange, true ) )
639 // #i22541# skip empty cell areas (performance)
640 SCCOL nDocCol1, nDocCol2;
641 SCROW nDocRow1, nDocRow2;
642 GetDoc().GetDataStart( nScTab, nDocCol1, nDocRow1 );
643 GetDoc().GetPrintArea( nScTab, nDocCol2, nDocRow2, false );
644 SCCOL nSrcCol1 = maExpSrcRange.aStart.Col();
645 SCROW nSrcRow1 = maExpSrcRange.aStart.Row();
646 SCCOL nSrcCol2 = maExpSrcRange.aEnd.Col();
647 SCROW nSrcRow2 = maExpSrcRange.aEnd.Row();
649 // #i22541# do not store index list for too big ranges
650 if( 2 * (nDocRow2 - nDocRow1) < (nSrcRow2 - nSrcRow1) )
651 ::set_flag( maPCInfo.mnFlags, EXC_SXDB_SAVEDATA, false );
653 // adjust row indexes, keep one row of empty area to surely have the empty cache item
654 if( nSrcRow1 < nDocRow1 )
655 nSrcRow1 = nDocRow1 - 1;
656 if( nSrcRow2 > nDocRow2 )
657 nSrcRow2 = nDocRow2 + 1;
659 maDocSrcRange.aStart.SetCol( ::std::max( nDocCol1, nSrcCol1 ) );
660 maDocSrcRange.aStart.SetRow( nSrcRow1 );
661 maDocSrcRange.aEnd.SetCol( ::std::min( nDocCol2, nSrcCol2 ) );
662 maDocSrcRange.aEnd.SetRow( nSrcRow2 );
664 GetDoc().GetName( nScTab, maTabName );
665 maPCInfo.mnSrcRecs = static_cast< sal_uInt32 >( maExpSrcRange.aEnd.Row() - maExpSrcRange.aStart.Row() );
666 maPCInfo.mnStrmId = nListIdx + 1;
667 maPCInfo.mnSrcType = EXC_SXDB_SRC_SHEET;
669 AddFields( rDPObj );
671 mbValid = true;
677 bool XclExpPivotCache::HasItemIndexList() const
679 return ::get_flag( maPCInfo.mnFlags, EXC_SXDB_SAVEDATA );
682 sal_uInt16 XclExpPivotCache::GetFieldCount() const
684 return static_cast< sal_uInt16 >( maFieldList.GetSize() );
687 const XclExpPCField* XclExpPivotCache::GetField( sal_uInt16 nFieldIdx ) const
689 return maFieldList.GetRecord( nFieldIdx ).get();
692 bool XclExpPivotCache::HasAddFields() const
694 // pivot cache can be shared, if there are no additional cache fields
695 return maPCInfo.mnStdFields < maPCInfo.mnTotalFields;
698 bool XclExpPivotCache::HasEqualDataSource( const ScDPObject& rDPObj ) const
700 /* For now, only sheet sources are supported, therefore it is enough to
701 compare the ScSheetSourceDesc. Later, there should be done more complicated
702 comparisons regarding the source type of rDPObj and this cache. */
703 if( const ScSheetSourceDesc* pSrcDesc = rDPObj.GetSheetDesc() )
704 return pSrcDesc->GetSourceRange() == maOrigSrcRange;
705 return false;
708 void XclExpPivotCache::Save( XclExpStream& rStrm )
710 OSL_ENSURE( mbValid, "XclExpPivotCache::Save - invalid pivot cache" );
711 // SXIDSTM
712 XclExpUInt16Record( EXC_ID_SXIDSTM, maPCInfo.mnStrmId ).Save( rStrm );
713 // SXVS
714 XclExpUInt16Record( EXC_ID_SXVS, EXC_SXVS_SHEET ).Save( rStrm );
716 if (!maSrcRangeName.isEmpty())
717 // DCONNAME
718 WriteDConName(rStrm);
719 else
720 // DCONREF
721 WriteDconref(rStrm);
723 // create the pivot cache storage stream
724 WriteCacheStream();
727 void XclExpPivotCache::SaveXml( XclExpXmlStream& /*rStrm*/ )
731 XclExpPCField* XclExpPivotCache::GetFieldAcc( sal_uInt16 nFieldIdx )
733 return maFieldList.GetRecord( nFieldIdx ).get();
736 void XclExpPivotCache::AddFields( const ScDPObject& rDPObj )
738 AddStdFields( rDPObj );
739 maPCInfo.mnStdFields = GetFieldCount();
740 AddGroupFields( rDPObj );
741 maPCInfo.mnTotalFields = GetFieldCount();
744 void XclExpPivotCache::AddStdFields( const ScDPObject& rDPObj )
746 // if item index list is not written, used shortened source range (maDocSrcRange) for performance
747 const ScRange& rRange = HasItemIndexList() ? maExpSrcRange : maDocSrcRange;
748 // create a standard pivot cache field for each source column
749 for( SCCOL nScCol = rRange.aStart.Col(), nEndScCol = rRange.aEnd.Col(); nScCol <= nEndScCol; ++nScCol )
751 ScRange aColRange( rRange );
752 aColRange.aStart.SetCol( nScCol );
753 aColRange.aEnd.SetCol( nScCol );
754 maFieldList.AppendNewRecord( new XclExpPCField(
755 GetRoot(), *this, GetFieldCount(), rDPObj, aColRange ) );
759 void XclExpPivotCache::AddGroupFields( const ScDPObject& rDPObj )
761 if( const ScDPSaveData* pSaveData = rDPObj.GetSaveData() )
763 if( const ScDPDimensionSaveData* pSaveDimData = pSaveData->GetExistingDimensionData() )
765 // loop over all existing standard fields to find their group fields
766 for( sal_uInt16 nFieldIdx = 0; nFieldIdx < maPCInfo.mnStdFields; ++nFieldIdx )
768 if( XclExpPCField* pCurrStdField = GetFieldAcc( nFieldIdx ) )
770 const ScDPSaveGroupDimension* pGroupDim = pSaveDimData->GetGroupDimForBase( pCurrStdField->GetFieldName() );
771 XclExpPCField* pLastGroupField = pCurrStdField;
772 while( pGroupDim )
774 // insert the new grouping field
775 XclExpPCFieldRef xNewGroupField( new XclExpPCField(
776 GetRoot(), *this, GetFieldCount(), rDPObj, *pGroupDim, *pCurrStdField ) );
777 maFieldList.AppendRecord( xNewGroupField );
779 // register new grouping field at current grouping field, building a chain
780 pLastGroupField->SetGroupChildField( *xNewGroupField );
782 // next grouping dimension
783 pGroupDim = pSaveDimData->GetGroupDimForBase( pGroupDim->GetGroupDimName() );
784 pLastGroupField = xNewGroupField.get();
792 void XclExpPivotCache::WriteDconref( XclExpStream& rStrm ) const
794 XclExpString aRef( XclExpUrlHelper::EncodeUrl( GetRoot(), EMPTY_OUSTRING, &maTabName ) );
795 rStrm.StartRecord( EXC_ID_DCONREF, 7 + aRef.GetSize() );
796 rStrm << static_cast< sal_uInt16 >( maExpSrcRange.aStart.Row() )
797 << static_cast< sal_uInt16 >( maExpSrcRange.aEnd.Row() )
798 << static_cast< sal_uInt8 >( maExpSrcRange.aStart.Col() )
799 << static_cast< sal_uInt8 >( maExpSrcRange.aEnd.Col() )
800 << aRef
801 << sal_uInt8( 0 );
802 rStrm.EndRecord();
805 void XclExpPivotCache::WriteDConName( XclExpStream& rStrm ) const
807 XclExpString aName(maSrcRangeName);
808 rStrm.StartRecord(EXC_ID_DCONNAME, aName.GetSize() + 2);
809 rStrm << aName << sal_uInt16(0);
810 rStrm.EndRecord();
813 void XclExpPivotCache::WriteCacheStream()
815 tools::SvRef<SotStorage> xSvStrg = OpenStorage( EXC_STORAGE_PTCACHE );
816 tools::SvRef<SotStorageStream> xSvStrm = OpenStream( xSvStrg, ScfTools::GetHexStr( maPCInfo.mnStrmId ) );
817 if( xSvStrm.Is() )
819 XclExpStream aStrm( *xSvStrm, GetRoot() );
820 // SXDB
821 WriteSxdb( aStrm );
822 // SXDBEX
823 WriteSxdbex( aStrm );
824 // field list (SXFIELD and items)
825 maFieldList.Save( aStrm );
826 // index table (list of SXINDEXLIST)
827 WriteSxindexlistList( aStrm );
828 // EOF
829 XclExpEmptyRecord( EXC_ID_EOF ).Save( aStrm );
833 void XclExpPivotCache::WriteSxdb( XclExpStream& rStrm ) const
835 rStrm.StartRecord( EXC_ID_SXDB, 21 );
836 rStrm << maPCInfo;
837 rStrm.EndRecord();
840 void XclExpPivotCache::WriteSxdbex( XclExpStream& rStrm )
842 rStrm.StartRecord( EXC_ID_SXDBEX, 12 );
843 rStrm << EXC_SXDBEX_CREATION_DATE
844 << sal_uInt32( 0 ); // number of SXFORMULA records
845 rStrm.EndRecord();
848 void XclExpPivotCache::WriteSxindexlistList( XclExpStream& rStrm ) const
850 if( HasItemIndexList() )
852 sal_Size nRecSize = 0;
853 size_t nPos, nSize = maFieldList.GetSize();
854 for( nPos = 0; nPos < nSize; ++nPos )
855 nRecSize += maFieldList.GetRecord( nPos )->GetIndexSize();
857 for( sal_uInt32 nSrcRow = 0; nSrcRow < maPCInfo.mnSrcRecs; ++nSrcRow )
859 rStrm.StartRecord( EXC_ID_SXINDEXLIST, nRecSize );
860 for( nPos = 0; nPos < nSize; ++nPos )
861 maFieldList.GetRecord( nPos )->WriteIndex( rStrm, nSrcRow );
862 rStrm.EndRecord();
867 // Pivot table
869 namespace {
871 /** Returns a display string for a data field containing the field name and aggregation function. */
872 OUString lclGetDataFieldCaption( const OUString& rFieldName, GeneralFunction eFunc )
874 OUString aCaption;
876 sal_uInt16 nResIdx = 0;
877 using namespace ::com::sun::star::sheet;
878 switch( eFunc )
880 case GeneralFunction_SUM: nResIdx = STR_FUN_TEXT_SUM; break;
881 case GeneralFunction_COUNT: nResIdx = STR_FUN_TEXT_COUNT; break;
882 case GeneralFunction_AVERAGE: nResIdx = STR_FUN_TEXT_AVG; break;
883 case GeneralFunction_MAX: nResIdx = STR_FUN_TEXT_MAX; break;
884 case GeneralFunction_MIN: nResIdx = STR_FUN_TEXT_MIN; break;
885 case GeneralFunction_PRODUCT: nResIdx = STR_FUN_TEXT_PRODUCT; break;
886 case GeneralFunction_COUNTNUMS: nResIdx = STR_FUN_TEXT_COUNT; break;
887 case GeneralFunction_STDEV: nResIdx = STR_FUN_TEXT_STDDEV; break;
888 case GeneralFunction_STDEVP: nResIdx = STR_FUN_TEXT_STDDEV; break;
889 case GeneralFunction_VAR: nResIdx = STR_FUN_TEXT_VAR; break;
890 case GeneralFunction_VARP: nResIdx = STR_FUN_TEXT_VAR; break;
891 default:;
893 if( nResIdx )
894 aCaption = ScGlobal::GetRscString( nResIdx ) + " - ";
895 aCaption += rFieldName;
896 return aCaption;
899 } // namespace
901 XclExpPTItem::XclExpPTItem( const XclExpPCField& rCacheField, sal_uInt16 nCacheIdx ) :
902 XclExpRecord( EXC_ID_SXVI, 8 ),
903 mpCacheItem( rCacheField.GetItem( nCacheIdx ) )
905 maItemInfo.mnType = EXC_SXVI_TYPE_DATA;
906 maItemInfo.mnCacheIdx = nCacheIdx;
907 maItemInfo.maVisName.mbUseCache = mpCacheItem != 0;
910 XclExpPTItem::XclExpPTItem( sal_uInt16 nItemType, sal_uInt16 nCacheIdx, bool bUseCache ) :
911 XclExpRecord( EXC_ID_SXVI, 8 ),
912 mpCacheItem( 0 )
914 maItemInfo.mnType = nItemType;
915 maItemInfo.mnCacheIdx = nCacheIdx;
916 maItemInfo.maVisName.mbUseCache = bUseCache;
919 OUString XclExpPTItem::GetItemName() const
921 return mpCacheItem ? mpCacheItem->ConvertToText() : OUString();
924 void XclExpPTItem::SetPropertiesFromMember( const ScDPSaveMember& rSaveMem )
926 // #i115659# GetIsVisible() is not valid if HasIsVisible() returns false, default is 'visible' then
927 ::set_flag( maItemInfo.mnFlags, EXC_SXVI_HIDDEN, rSaveMem.HasIsVisible() && !rSaveMem.GetIsVisible() );
928 // #i115659# GetShowDetails() is not valid if HasShowDetails() returns false, default is 'show detail' then
929 ::set_flag( maItemInfo.mnFlags, EXC_SXVI_HIDEDETAIL, rSaveMem.HasShowDetails() && !rSaveMem.GetShowDetails() );
931 // visible name
932 const OUString* pVisName = rSaveMem.GetLayoutName();
933 if (pVisName && !pVisName->equals(GetItemName()))
934 maItemInfo.SetVisName(*pVisName);
937 void XclExpPTItem::WriteBody( XclExpStream& rStrm )
939 rStrm << maItemInfo;
942 XclExpPTField::XclExpPTField( const XclExpPivotTable& rPTable, sal_uInt16 nCacheIdx ) :
943 mrPTable( rPTable ),
944 mpCacheField( rPTable.GetCacheField( nCacheIdx ) )
946 maFieldInfo.mnCacheIdx = nCacheIdx;
948 // create field items
949 if( mpCacheField )
950 for( sal_uInt16 nItemIdx = 0, nItemCount = mpCacheField->GetItemCount(); nItemIdx < nItemCount; ++nItemIdx )
951 maItemList.AppendNewRecord( new XclExpPTItem( *mpCacheField, nItemIdx ) );
952 maFieldInfo.mnItemCount = static_cast< sal_uInt16 >( maItemList.GetSize() );
955 // data access ----------------------------------------------------------------
957 OUString XclExpPTField::GetFieldName() const
959 return mpCacheField ? mpCacheField->GetFieldName() : OUString();
962 sal_uInt16 XclExpPTField::GetLastDataInfoIndex() const
964 OSL_ENSURE( !maDataInfoVec.empty(), "XclExpPTField::GetLastDataInfoIndex - no data info found" );
965 // will return 0xFFFF for empty vector -> ok
966 return static_cast< sal_uInt16 >( maDataInfoVec.size() - 1 );
969 sal_uInt16 XclExpPTField::GetItemIndex( const OUString& rName, sal_uInt16 nDefaultIdx ) const
971 for( size_t nPos = 0, nSize = maItemList.GetSize(); nPos < nSize; ++nPos )
972 if( maItemList.GetRecord( nPos )->GetItemName() == rName )
973 return static_cast< sal_uInt16 >( nPos );
974 return nDefaultIdx;
977 // fill data --------------------------------------------------------------
980 * Calc's subtotal names are escaped with backslashes ('\'), while Excel's
981 * are not escaped at all.
983 static OUString lcl_convertCalcSubtotalName(const OUString& rName)
985 OUStringBuffer aBuf;
986 const sal_Unicode* p = rName.getStr();
987 sal_Int32 n = rName.getLength();
988 bool bEscaped = false;
989 for (sal_Int32 i = 0; i < n; ++i)
991 const sal_Unicode c = p[i];
992 if (!bEscaped && c == '\\')
994 bEscaped = true;
995 continue;
998 aBuf.append(c);
999 bEscaped = false;
1001 return aBuf.makeStringAndClear();
1004 void XclExpPTField::SetPropertiesFromDim( const ScDPSaveDimension& rSaveDim )
1006 // orientation
1007 DataPilotFieldOrientation eOrient = static_cast< DataPilotFieldOrientation >( rSaveDim.GetOrientation() );
1008 OSL_ENSURE( eOrient != DataPilotFieldOrientation_DATA, "XclExpPTField::SetPropertiesFromDim - called for data field" );
1009 maFieldInfo.AddApiOrient( eOrient );
1011 // show empty items (#i115659# GetShowEmpty() is not valid if HasShowEmpty() returns false, default is false then)
1012 ::set_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_SHOWALL, rSaveDim.HasShowEmpty() && rSaveDim.GetShowEmpty() );
1014 // visible name
1015 const OUString* pLayoutName = rSaveDim.GetLayoutName();
1016 if (pLayoutName && !pLayoutName->equals(GetFieldName()))
1017 maFieldInfo.SetVisName(*pLayoutName);
1019 const OUString* pSubtotalName = rSaveDim.GetSubtotalName();
1020 if (pSubtotalName)
1022 OUString aSubName = lcl_convertCalcSubtotalName(*pSubtotalName);
1023 maFieldExtInfo.mpFieldTotalName.reset(new OUString(aSubName));
1026 // subtotals
1027 XclPTSubtotalVec aSubtotals;
1028 aSubtotals.reserve( static_cast< size_t >( rSaveDim.GetSubTotalsCount() ) );
1029 for( long nSubtIdx = 0, nSubtCount = rSaveDim.GetSubTotalsCount(); nSubtIdx < nSubtCount; ++nSubtIdx )
1030 aSubtotals.push_back( rSaveDim.GetSubTotalFunc( nSubtIdx ) );
1031 maFieldInfo.SetSubtotals( aSubtotals );
1033 // sorting
1034 if( const DataPilotFieldSortInfo* pSortInfo = rSaveDim.GetSortInfo() )
1036 maFieldExtInfo.SetApiSortMode( pSortInfo->Mode );
1037 if( pSortInfo->Mode == ::com::sun::star::sheet::DataPilotFieldSortMode::DATA )
1038 maFieldExtInfo.mnSortField = mrPTable.GetDataFieldIndex( pSortInfo->Field, EXC_SXVDEX_SORT_OWN );
1039 ::set_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_SORT_ASC, pSortInfo->IsAscending );
1042 // auto show
1043 if( const DataPilotFieldAutoShowInfo* pShowInfo = rSaveDim.GetAutoShowInfo() )
1045 ::set_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_AUTOSHOW, pShowInfo->IsEnabled );
1046 maFieldExtInfo.SetApiAutoShowMode( pShowInfo->ShowItemsMode );
1047 maFieldExtInfo.SetApiAutoShowCount( pShowInfo->ItemCount );
1048 maFieldExtInfo.mnShowField = mrPTable.GetDataFieldIndex( pShowInfo->DataField, EXC_SXVDEX_SHOW_NONE );
1051 // layout
1052 if( const DataPilotFieldLayoutInfo* pLayoutInfo = rSaveDim.GetLayoutInfo() )
1054 maFieldExtInfo.SetApiLayoutMode( pLayoutInfo->LayoutMode );
1055 ::set_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_LAYOUT_BLANK, pLayoutInfo->AddEmptyLines );
1058 // special page field properties
1059 if( eOrient == DataPilotFieldOrientation_PAGE )
1061 maPageInfo.mnField = GetFieldIndex();
1062 maPageInfo.mnSelItem = EXC_SXPI_ALLITEMS;
1065 // item properties
1066 const ScDPSaveDimension::MemberList &rMembers = rSaveDim.GetMembers();
1067 for (ScDPSaveDimension::MemberList::const_iterator i=rMembers.begin(); i != rMembers.end() ; ++i)
1068 if( XclExpPTItem* pItem = GetItemAcc( (*i)->GetName() ) )
1069 pItem->SetPropertiesFromMember( **i );
1072 void XclExpPTField::SetDataPropertiesFromDim( const ScDPSaveDimension& rSaveDim )
1074 maDataInfoVec.push_back( XclPTDataFieldInfo() );
1075 XclPTDataFieldInfo& rDataInfo = maDataInfoVec.back();
1076 rDataInfo.mnField = GetFieldIndex();
1078 // orientation
1079 maFieldInfo.AddApiOrient( DataPilotFieldOrientation_DATA );
1081 // aggregation function
1082 GeneralFunction eFunc = static_cast< GeneralFunction >( rSaveDim.GetFunction() );
1083 rDataInfo.SetApiAggFunc( eFunc );
1085 // visible name
1086 const OUString* pVisName = rSaveDim.GetLayoutName();
1087 if (pVisName)
1088 rDataInfo.SetVisName(*pVisName);
1089 else
1090 rDataInfo.SetVisName( lclGetDataFieldCaption( GetFieldName(), eFunc ) );
1092 // result field reference
1093 if( const DataPilotFieldReference* pFieldRef = rSaveDim.GetReferenceValue() )
1095 rDataInfo.SetApiRefType( pFieldRef->ReferenceType );
1096 rDataInfo.SetApiRefItemType( pFieldRef->ReferenceItemType );
1097 if( const XclExpPTField* pRefField = mrPTable.GetField( pFieldRef->ReferenceField ) )
1099 rDataInfo.mnRefField = pRefField->GetFieldIndex();
1100 if( pFieldRef->ReferenceItemType == ::com::sun::star::sheet::DataPilotFieldReferenceItemType::NAMED )
1101 rDataInfo.mnRefItem = pRefField->GetItemIndex( pFieldRef->ReferenceItemName, 0 );
1106 void XclExpPTField::AppendSubtotalItems()
1108 if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_DEFAULT ) AppendSubtotalItem( EXC_SXVI_TYPE_DEFAULT );
1109 if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_SUM ) AppendSubtotalItem( EXC_SXVI_TYPE_SUM );
1110 if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_COUNT ) AppendSubtotalItem( EXC_SXVI_TYPE_COUNT );
1111 if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_AVERAGE ) AppendSubtotalItem( EXC_SXVI_TYPE_AVERAGE );
1112 if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_MAX ) AppendSubtotalItem( EXC_SXVI_TYPE_MAX );
1113 if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_MIN ) AppendSubtotalItem( EXC_SXVI_TYPE_MIN );
1114 if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_PROD ) AppendSubtotalItem( EXC_SXVI_TYPE_PROD );
1115 if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_COUNTNUM ) AppendSubtotalItem( EXC_SXVI_TYPE_COUNTNUM );
1116 if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_STDDEV ) AppendSubtotalItem( EXC_SXVI_TYPE_STDDEV );
1117 if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_STDDEVP ) AppendSubtotalItem( EXC_SXVI_TYPE_STDDEVP );
1118 if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_VAR ) AppendSubtotalItem( EXC_SXVI_TYPE_VAR );
1119 if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_VARP ) AppendSubtotalItem( EXC_SXVI_TYPE_VARP );
1122 // records --------------------------------------------------------------------
1124 void XclExpPTField::WriteSxpiEntry( XclExpStream& rStrm ) const
1126 rStrm << maPageInfo;
1129 void XclExpPTField::WriteSxdi( XclExpStream& rStrm, sal_uInt16 nDataInfoIdx ) const
1131 OSL_ENSURE( nDataInfoIdx < maDataInfoVec.size(), "XclExpPTField::WriteSxdi - data field not found" );
1132 if( nDataInfoIdx < maDataInfoVec.size() )
1134 rStrm.StartRecord( EXC_ID_SXDI, 12 );
1135 rStrm << maDataInfoVec[ nDataInfoIdx ];
1136 rStrm.EndRecord();
1140 void XclExpPTField::Save( XclExpStream& rStrm )
1142 // SXVD
1143 WriteSxvd( rStrm );
1144 // list of SXVI records
1145 maItemList.Save( rStrm );
1146 // SXVDEX
1147 WriteSxvdex( rStrm );
1150 // private --------------------------------------------------------------------
1152 XclExpPTItem* XclExpPTField::GetItemAcc( const OUString& rName )
1154 XclExpPTItem* pItem = 0;
1155 for( size_t nPos = 0, nSize = maItemList.GetSize(); !pItem && (nPos < nSize); ++nPos )
1156 if( maItemList.GetRecord( nPos )->GetItemName() == rName )
1157 pItem = maItemList.GetRecord( nPos ).get();
1158 return pItem;
1161 void XclExpPTField::AppendSubtotalItem( sal_uInt16 nItemType )
1163 maItemList.AppendNewRecord( new XclExpPTItem( nItemType, EXC_SXVI_DEFAULT_CACHE, true ) );
1164 ++maFieldInfo.mnItemCount;
1167 void XclExpPTField::WriteSxvd( XclExpStream& rStrm ) const
1169 rStrm.StartRecord( EXC_ID_SXVD, 10 );
1170 rStrm << maFieldInfo;
1171 rStrm.EndRecord();
1174 void XclExpPTField::WriteSxvdex( XclExpStream& rStrm ) const
1176 rStrm.StartRecord( EXC_ID_SXVDEX, 20 );
1177 rStrm << maFieldExtInfo;
1178 rStrm.EndRecord();
1181 XclExpPivotTable::XclExpPivotTable( const XclExpRoot& rRoot, const ScDPObject& rDPObj, const XclExpPivotCache& rPCache, size_t ) :
1182 XclExpRoot( rRoot ),
1183 mrPCache( rPCache ),
1184 maDataOrientField( *this, EXC_SXIVD_DATA ),
1185 mnOutScTab( 0 ),
1186 mbValid( false ),
1187 mbFilterBtn( false )
1189 const ScRange& rOutScRange = rDPObj.GetOutRange();
1190 if( GetAddressConverter().ConvertRange( maPTInfo.maOutXclRange, rOutScRange, true ) )
1192 // DataPilot properties -----------------------------------------------
1194 // pivot table properties from DP object
1195 mnOutScTab = rOutScRange.aStart.Tab();
1196 maPTInfo.maTableName = rDPObj.GetName();
1197 maPTInfo.mnCacheIdx = mrPCache.GetCacheIndex();
1199 maPTViewEx9Info.Init( rDPObj );
1201 if( const ScDPSaveData* pSaveData = rDPObj.GetSaveData() )
1203 // additional properties from ScDPSaveData
1204 SetPropertiesFromDP( *pSaveData );
1206 // loop over all dimensions ---------------------------------------
1208 /* 1) Default-construct all pivot table fields for all pivot cache fields. */
1209 for( sal_uInt16 nFieldIdx = 0, nFieldCount = mrPCache.GetFieldCount(); nFieldIdx < nFieldCount; ++nFieldIdx )
1210 maFieldList.AppendNewRecord( new XclExpPTField( *this, nFieldIdx ) );
1212 boost::ptr_vector<ScDPSaveDimension>::const_iterator iter;
1213 const ScDPSaveData::DimsType& rDimList = pSaveData->GetDimensions();
1215 /* 2) First process all data dimensions, they are needed for extended
1216 settings of row/column/page fields (sorting/auto show). */
1217 for (iter = rDimList.begin(); iter != rDimList.end(); ++iter)
1218 if (iter->GetOrientation() == DataPilotFieldOrientation_DATA)
1219 SetDataFieldPropertiesFromDim(*iter);
1221 /* 3) Row/column/page/hidden fields. */
1222 for (iter = rDimList.begin(); iter != rDimList.end(); ++iter)
1223 if (iter->GetOrientation() != DataPilotFieldOrientation_DATA)
1224 SetFieldPropertiesFromDim(*iter);
1226 // Finalize -------------------------------------------------------
1228 Finalize();
1229 mbValid = true;
1234 const XclExpPCField* XclExpPivotTable::GetCacheField( sal_uInt16 nCacheIdx ) const
1236 return mrPCache.GetField( nCacheIdx );
1239 const XclExpPTField* XclExpPivotTable::GetField( sal_uInt16 nFieldIdx ) const
1241 return (nFieldIdx == EXC_SXIVD_DATA) ? &maDataOrientField : maFieldList.GetRecord( nFieldIdx ).get();
1244 const XclExpPTField* XclExpPivotTable::GetField( const OUString& rName ) const
1246 return const_cast< XclExpPivotTable* >( this )->GetFieldAcc( rName );
1249 sal_uInt16 XclExpPivotTable::GetDataFieldIndex( const OUString& rName, sal_uInt16 nDefaultIdx ) const
1251 for( XclPTDataFieldPosVec::const_iterator aIt = maDataFields.begin(), aEnd = maDataFields.end(); aIt != aEnd; ++aIt )
1252 if( const XclExpPTField* pField = GetField( aIt->first ) )
1253 if( pField->GetFieldName() == rName )
1254 return static_cast< sal_uInt16 >( aIt - maDataFields.begin() );
1255 return nDefaultIdx;
1258 void XclExpPivotTable::Save( XclExpStream& rStrm )
1260 if( mbValid )
1262 // SXVIEW
1263 WriteSxview( rStrm );
1264 // pivot table fields (SXVD, SXVDEX, and item records)
1265 maFieldList.Save( rStrm );
1266 // SXIVD records for row and column fields
1267 WriteSxivd( rStrm, maRowFields );
1268 WriteSxivd( rStrm, maColFields );
1269 // SXPI
1270 WriteSxpi( rStrm );
1271 // list of SXDI records containing data field info
1272 WriteSxdiList( rStrm );
1273 // SXLI records
1274 WriteSxli( rStrm, maPTInfo.mnDataRows, maPTInfo.mnRowFields );
1275 WriteSxli( rStrm, maPTInfo.mnDataCols, maPTInfo.mnColFields );
1276 // SXEX
1277 WriteSxex( rStrm );
1278 // QSISXTAG
1279 WriteQsiSxTag( rStrm );
1280 // SXVIEWEX9
1281 WriteSxViewEx9( rStrm );
1285 XclExpPTField* XclExpPivotTable::GetFieldAcc( const OUString& rName )
1287 XclExpPTField* pField = 0;
1288 for( size_t nPos = 0, nSize = maFieldList.GetSize(); !pField && (nPos < nSize); ++nPos )
1289 if( maFieldList.GetRecord( nPos )->GetFieldName() == rName )
1290 pField = maFieldList.GetRecord( nPos ).get();
1291 return pField;
1294 XclExpPTField* XclExpPivotTable::GetFieldAcc( const ScDPSaveDimension& rSaveDim )
1296 // data field orientation field?
1297 if( rSaveDim.IsDataLayout() )
1298 return &maDataOrientField;
1300 // a real dimension
1301 OUString aFieldName = ScDPUtil::getSourceDimensionName(rSaveDim.GetName());
1302 return aFieldName.isEmpty() ? NULL : GetFieldAcc(aFieldName);
1305 // fill data --------------------------------------------------------------
1307 void XclExpPivotTable::SetPropertiesFromDP( const ScDPSaveData& rSaveData )
1309 ::set_flag( maPTInfo.mnFlags, EXC_SXVIEW_ROWGRAND, rSaveData.GetRowGrand() );
1310 ::set_flag( maPTInfo.mnFlags, EXC_SXVIEW_COLGRAND, rSaveData.GetColumnGrand() );
1311 ::set_flag( maPTExtInfo.mnFlags, EXC_SXEX_DRILLDOWN, rSaveData.GetDrillDown() );
1312 mbFilterBtn = rSaveData.GetFilterButton();
1313 const ScDPSaveDimension* pDim = rSaveData.GetExistingDataLayoutDimension();
1314 if (!pDim)
1315 return;
1317 const OUString* pLayoutName = pDim->GetLayoutName();
1318 if (pLayoutName)
1319 maPTInfo.maDataName = *pLayoutName;
1320 else
1321 maPTInfo.maDataName = ScGlobal::GetRscString(STR_PIVOT_DATA);
1324 void XclExpPivotTable::SetFieldPropertiesFromDim( const ScDPSaveDimension& rSaveDim )
1326 if( XclExpPTField* pField = GetFieldAcc( rSaveDim ) )
1328 // field properties
1329 pField->SetPropertiesFromDim( rSaveDim );
1331 // update the corresponding field position list
1332 DataPilotFieldOrientation eOrient = static_cast< DataPilotFieldOrientation >( rSaveDim.GetOrientation() );
1333 sal_uInt16 nFieldIdx = pField->GetFieldIndex();
1334 bool bDataLayout = nFieldIdx == EXC_SXIVD_DATA;
1335 bool bMultiData = maDataFields.size() > 1;
1337 if( !bDataLayout || bMultiData ) switch( eOrient )
1339 case DataPilotFieldOrientation_ROW:
1340 maRowFields.push_back( nFieldIdx );
1341 if( bDataLayout )
1342 maPTInfo.mnDataAxis = EXC_SXVD_AXIS_ROW;
1343 break;
1344 case DataPilotFieldOrientation_COLUMN:
1345 maColFields.push_back( nFieldIdx );
1346 if( bDataLayout )
1347 maPTInfo.mnDataAxis = EXC_SXVD_AXIS_COL;
1348 break;
1349 case DataPilotFieldOrientation_PAGE:
1350 maPageFields.push_back( nFieldIdx );
1351 OSL_ENSURE( !bDataLayout, "XclExpPivotTable::SetFieldPropertiesFromDim - wrong orientation for data fields" );
1352 break;
1353 case DataPilotFieldOrientation_DATA:
1354 OSL_FAIL( "XclExpPivotTable::SetFieldPropertiesFromDim - called for data field" );
1355 break;
1356 default:;
1361 void XclExpPivotTable::SetDataFieldPropertiesFromDim( const ScDPSaveDimension& rSaveDim )
1363 if( XclExpPTField* pField = GetFieldAcc( rSaveDim ) )
1365 // field properties
1366 pField->SetDataPropertiesFromDim( rSaveDim );
1367 // update the data field position list
1368 maDataFields.push_back( XclPTDataFieldPos( pField->GetFieldIndex(), pField->GetLastDataInfoIndex() ) );
1372 void XclExpPivotTable::Finalize()
1374 // field numbers
1375 maPTInfo.mnFields = static_cast< sal_uInt16 >( maFieldList.GetSize() );
1376 maPTInfo.mnRowFields = static_cast< sal_uInt16 >( maRowFields.size() );
1377 maPTInfo.mnColFields = static_cast< sal_uInt16 >( maColFields.size() );
1378 maPTInfo.mnPageFields = static_cast< sal_uInt16 >( maPageFields.size() );
1379 maPTInfo.mnDataFields = static_cast< sal_uInt16 >( maDataFields.size() );
1381 maPTExtInfo.mnPagePerRow = maPTInfo.mnPageFields;
1382 maPTExtInfo.mnPagePerCol = (maPTInfo.mnPageFields > 0) ? 1 : 0;
1384 // subtotal items
1385 for( size_t nPos = 0, nSize = maFieldList.GetSize(); nPos < nSize; ++nPos )
1386 maFieldList.GetRecord( nPos )->AppendSubtotalItems();
1388 // find data field orientation field
1389 maPTInfo.mnDataPos = EXC_SXVIEW_DATALAST;
1390 const ScfUInt16Vec* pFieldVec = 0;
1391 switch( maPTInfo.mnDataAxis )
1393 case EXC_SXVD_AXIS_ROW: pFieldVec = &maRowFields; break;
1394 case EXC_SXVD_AXIS_COL: pFieldVec = &maColFields; break;
1397 if( pFieldVec && !pFieldVec->empty() && (pFieldVec->back() != EXC_SXIVD_DATA) )
1399 ScfUInt16Vec::const_iterator aIt = ::std::find( pFieldVec->begin(), pFieldVec->end(), EXC_SXIVD_DATA );
1400 if( aIt != pFieldVec->end() )
1401 maPTInfo.mnDataPos = static_cast< sal_uInt16 >( aIt - pFieldVec->begin() );
1404 // single data field is always row oriented
1405 if( maPTInfo.mnDataAxis == EXC_SXVD_AXIS_NONE )
1406 maPTInfo.mnDataAxis = EXC_SXVD_AXIS_ROW;
1408 // update output range (initialized in ctor)
1409 sal_uInt16& rnXclCol1 = maPTInfo.maOutXclRange.maFirst.mnCol;
1410 sal_uInt32& rnXclRow1 = maPTInfo.maOutXclRange.maFirst.mnRow;
1411 sal_uInt16& rnXclCol2 = maPTInfo.maOutXclRange.maLast.mnCol;
1412 sal_uInt32& rnXclRow2 = maPTInfo.maOutXclRange.maLast.mnRow;
1413 // exclude page fields from output range
1414 rnXclRow1 = rnXclRow1 + maPTInfo.mnPageFields;
1415 // exclude filter button from output range
1416 if( mbFilterBtn )
1417 ++rnXclRow1;
1418 // exclude empty row between (filter button and/or page fields) and table
1419 if( mbFilterBtn || maPTInfo.mnPageFields )
1420 ++rnXclRow1;
1422 // data area
1423 sal_uInt16& rnDataXclCol = maPTInfo.maDataXclPos.mnCol;
1424 sal_uInt32& rnDataXclRow = maPTInfo.maDataXclPos.mnRow;
1425 rnDataXclCol = rnXclCol1 + maPTInfo.mnRowFields;
1426 rnDataXclRow = rnXclRow1 + maPTInfo.mnColFields + 1;
1427 if( maDataFields.empty() )
1428 ++rnDataXclRow;
1430 bool bExtraHeaderRow = (0 == maPTViewEx9Info.mnGridLayout && maPTInfo.mnColFields == 0);
1431 if (bExtraHeaderRow)
1432 // Insert an extra row only when there is no column field.
1433 ++rnDataXclRow;
1435 rnXclCol2 = ::std::max( rnXclCol2, rnDataXclCol );
1436 rnXclRow2 = ::std::max( rnXclRow2, rnDataXclRow );
1437 maPTInfo.mnDataCols = rnXclCol2 - rnDataXclCol + 1;
1438 maPTInfo.mnDataRows = rnXclRow2 - rnDataXclRow + 1;
1440 // first heading
1441 maPTInfo.mnFirstHeadRow = rnXclRow1;
1442 if (bExtraHeaderRow)
1443 maPTInfo.mnFirstHeadRow += 2;
1446 // records ----------------------------------------------------------------
1448 void XclExpPivotTable::WriteSxview( XclExpStream& rStrm ) const
1450 rStrm.StartRecord( EXC_ID_SXVIEW, 46 + maPTInfo.maTableName.getLength() + maPTInfo.maDataName.getLength() );
1451 rStrm << maPTInfo;
1452 rStrm.EndRecord();
1455 void XclExpPivotTable::WriteSxivd( XclExpStream& rStrm, const ScfUInt16Vec& rFields )
1457 if( !rFields.empty() )
1459 rStrm.StartRecord( EXC_ID_SXIVD, rFields.size() * 2 );
1460 for( ScfUInt16Vec::const_iterator aIt = rFields.begin(), aEnd = rFields.end(); aIt != aEnd; ++aIt )
1461 rStrm << *aIt;
1462 rStrm.EndRecord();
1466 void XclExpPivotTable::WriteSxpi( XclExpStream& rStrm ) const
1468 if( !maPageFields.empty() )
1470 rStrm.StartRecord( EXC_ID_SXPI, maPageFields.size() * 6 );
1471 rStrm.SetSliceSize( 6 );
1472 for( ScfUInt16Vec::const_iterator aIt = maPageFields.begin(), aEnd = maPageFields.end(); aIt != aEnd; ++aIt )
1474 XclExpPTFieldRef xField = maFieldList.GetRecord( *aIt );
1475 if( xField )
1476 xField->WriteSxpiEntry( rStrm );
1478 rStrm.EndRecord();
1482 void XclExpPivotTable::WriteSxdiList( XclExpStream& rStrm ) const
1484 for( XclPTDataFieldPosVec::const_iterator aIt = maDataFields.begin(), aEnd = maDataFields.end(); aIt != aEnd; ++aIt )
1486 XclExpPTFieldRef xField = maFieldList.GetRecord( aIt->first );
1487 if( xField )
1488 xField->WriteSxdi( rStrm, aIt->second );
1492 void XclExpPivotTable::WriteSxli( XclExpStream& rStrm, sal_uInt16 nLineCount, sal_uInt16 nIndexCount )
1494 if( nLineCount > 0 )
1496 sal_Size nLineSize = 8 + 2 * nIndexCount;
1497 rStrm.StartRecord( EXC_ID_SXLI, nLineSize * nLineCount );
1499 /* Excel expects the records to be filled completely, do not
1500 set a segment size... */
1501 // rStrm.SetSliceSize( nLineSize );
1503 for( sal_uInt16 nLine = 0; nLine < nLineCount; ++nLine )
1505 // Excel XP needs a partly initialized SXLI record
1506 rStrm << sal_uInt16( 0 ) // number of equal index entries
1507 << EXC_SXVI_TYPE_DATA
1508 << nIndexCount
1509 << EXC_SXLI_DEFAULTFLAGS;
1510 rStrm.WriteZeroBytes( 2 * nIndexCount );
1512 rStrm.EndRecord();
1516 void XclExpPivotTable::WriteSxex( XclExpStream& rStrm ) const
1518 rStrm.StartRecord( EXC_ID_SXEX, 24 );
1519 rStrm << maPTExtInfo;
1520 rStrm.EndRecord();
1523 void XclExpPivotTable::WriteQsiSxTag( XclExpStream& rStrm ) const
1525 rStrm.StartRecord( 0x0802, 32 );
1527 sal_uInt16 nRecordType = 0x0802;
1528 sal_uInt16 nDummyFlags = 0x0000;
1529 sal_uInt16 nTableType = 1; // 0 = query table : 1 = pivot table
1531 rStrm << nRecordType << nDummyFlags << nTableType;
1533 // General flags
1534 sal_uInt16 nFlags = 0x0001;
1535 #if 0
1536 // for doc purpose
1537 sal_uInt16 nFlags = 0x0000;
1538 bool bEnableRefresh = true;
1539 bool bPCacheInvalid = false;
1540 bool bOlapPTReport = false;
1542 if (bEnableRefresh) nFlags |= 0x0001;
1543 if (bPCacheInvalid) nFlags |= 0x0002;
1544 if (bOlapPTReport) nFlags |= 0x0004;
1545 #endif
1546 rStrm << nFlags;
1548 // Feature-specific options. The value differs depending on the table
1549 // type, but we assume the table type is always pivot table.
1550 sal_uInt32 nOptions = 0x00000000;
1551 #if 0
1552 // documentation for which bit is for what
1553 bool bNoStencil = false;
1554 bool bHideTotal = false;
1555 bool bEmptyRows = false;
1556 bool bEmptyCols = false;
1557 if (bNoStencil) nOptions |= 0x00000001;
1558 if (bHideTotal) nOptions |= 0x00000002;
1559 if (bEmptyRows) nOptions |= 0x00000008;
1560 if (bEmptyCols) nOptions |= 0x00000010;
1561 #endif
1562 rStrm << nOptions;
1564 enum ExcelVersion
1566 Excel2000 = 0,
1567 ExcelXP = 1,
1568 Excel2003 = 2,
1569 Excel2007 = 3
1571 ExcelVersion eXclVer = Excel2000;
1572 sal_uInt8 nOffsetBytes = 16;
1573 rStrm << static_cast<sal_uInt8>(eXclVer) // version table last refreshed
1574 << static_cast<sal_uInt8>(eXclVer) // minimum version to refresh
1575 << nOffsetBytes
1576 << static_cast<sal_uInt8>(eXclVer); // first version created
1578 rStrm << XclExpString(maPTInfo.maTableName);
1579 rStrm << static_cast<sal_uInt16>(0x0001); // no idea what this is for.
1581 rStrm.EndRecord();
1584 void XclExpPivotTable::WriteSxViewEx9( XclExpStream& rStrm ) const
1586 // Until we sync the autoformat ids only export if using grid header layout
1587 // That could only have been set via xls import so far.
1588 if ( 0 == maPTViewEx9Info.mnGridLayout )
1590 rStrm.StartRecord( EXC_ID_SXVIEWEX9, 17 );
1591 rStrm << maPTViewEx9Info;
1592 rStrm.EndRecord();
1596 namespace {
1598 const SCTAB EXC_PTMGR_PIVOTCACHES = SCTAB_MAX;
1600 /** Record wrapper class to write the pivot caches or pivot tables. */
1601 class XclExpPivotRecWrapper : public XclExpRecordBase
1603 public:
1604 explicit XclExpPivotRecWrapper( XclExpPivotTableManager& rPTMgr, SCTAB nScTab );
1605 virtual void Save( XclExpStream& rStrm ) SAL_OVERRIDE;
1606 private:
1607 XclExpPivotTableManager& mrPTMgr;
1608 SCTAB mnScTab;
1611 XclExpPivotRecWrapper::XclExpPivotRecWrapper( XclExpPivotTableManager& rPTMgr, SCTAB nScTab ) :
1612 mrPTMgr( rPTMgr ),
1613 mnScTab( nScTab )
1617 void XclExpPivotRecWrapper::Save( XclExpStream& rStrm )
1619 if( mnScTab == EXC_PTMGR_PIVOTCACHES )
1620 mrPTMgr.WritePivotCaches( rStrm );
1621 else
1622 mrPTMgr.WritePivotTables( rStrm, mnScTab );
1625 } // namespace
1627 XclExpPivotTableManager::XclExpPivotTableManager( const XclExpRoot& rRoot ) :
1628 XclExpRoot( rRoot ),
1629 mbShareCaches( true )
1633 void XclExpPivotTableManager::CreatePivotTables()
1635 if( ScDPCollection* pDPColl = GetDoc().GetDPCollection() )
1636 for( size_t nDPObj = 0, nCount = pDPColl->GetCount(); nDPObj < nCount; ++nDPObj )
1637 if( ScDPObject* pDPObj = (*pDPColl)[ nDPObj ] )
1638 if( const XclExpPivotCache* pPCache = CreatePivotCache( *pDPObj ) )
1639 maPTableList.AppendNewRecord( new XclExpPivotTable( GetRoot(), *pDPObj, *pPCache, nDPObj ) );
1642 XclExpRecordRef XclExpPivotTableManager::CreatePivotCachesRecord()
1644 return XclExpRecordRef( new XclExpPivotRecWrapper( *this, EXC_PTMGR_PIVOTCACHES ) );
1647 XclExpRecordRef XclExpPivotTableManager::CreatePivotTablesRecord( SCTAB nScTab )
1649 return XclExpRecordRef( new XclExpPivotRecWrapper( *this, nScTab ) );
1652 void XclExpPivotTableManager::WritePivotCaches( XclExpStream& rStrm )
1654 maPCacheList.Save( rStrm );
1657 void XclExpPivotTableManager::WritePivotTables( XclExpStream& rStrm, SCTAB nScTab )
1659 for( size_t nPos = 0, nSize = maPTableList.GetSize(); nPos < nSize; ++nPos )
1661 XclExpPivotTableRef xPTable = maPTableList.GetRecord( nPos );
1662 if( xPTable->GetScTab() == nScTab )
1663 xPTable->Save( rStrm );
1667 const XclExpPivotCache* XclExpPivotTableManager::CreatePivotCache( const ScDPObject& rDPObj )
1669 // try to find a pivot cache with the same data source
1670 /* #i25110# In Excel, the pivot cache contains additional fields
1671 (i.e. grouping info, calculated fields). If the passed DataPilot object
1672 or the found cache contains this data, do not share the cache with
1673 multiple pivot tables. */
1674 if( mbShareCaches )
1676 if( const ScDPSaveData* pSaveData = rDPObj.GetSaveData() )
1678 const ScDPDimensionSaveData* pDimSaveData = pSaveData->GetExistingDimensionData();
1679 // no dimension save data at all or save data does not contain grouping info
1680 if( !pDimSaveData || !pDimSaveData->HasGroupDimensions() )
1682 // check all existing pivot caches
1683 for( size_t nPos = 0, nSize = maPCacheList.GetSize(); nPos < nSize; ++nPos )
1685 XclExpPivotCacheRef xPCache = maPCacheList.GetRecord( nPos );
1686 // pivot cache does not have grouping info and source data is equal
1687 if( !xPCache->HasAddFields() && xPCache->HasEqualDataSource( rDPObj ) )
1688 return xPCache.get();
1694 // create a new pivot cache
1695 sal_uInt16 nNewCacheIdx = static_cast< sal_uInt16 >( maPCacheList.GetSize() );
1696 XclExpPivotCacheRef xNewPCache( new XclExpPivotCache( GetRoot(), rDPObj, nNewCacheIdx ) );
1697 if( xNewPCache->IsValid() )
1699 maPCacheList.AppendRecord( xNewPCache );
1700 return xNewPCache.get();
1703 return 0;
1706 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */