1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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"
37 #include "dpdimsave.hxx"
38 #include "dpshttab.hxx"
39 #include "globstr.hrc"
40 #include "fapihelper.hxx"
41 #include "xestring.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
;
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
[] =
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
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() )
102 XclExpPCItem::XclExpPCItem( double fValue
) :
103 XclExpRecord( EXC_ID_SXDOUBLE
, 8 )
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
)
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() )
161 else if( const sal_Int16
* pnValue
= GetInteger() )
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 );
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
),
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)
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
),
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() );
243 InitStdGroupField( rBaseField
, rGroupDim
);
245 // final settings (flags, item numbers)
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() )
294 rStrm
<< static_cast< sal_uInt8
>( nIndex
);
298 void XclExpPCField::Save( XclExpStream
& rStrm
)
300 OSL_ENSURE( IsSupportedField(), "XclExpPCField::Save - unknown field type" );
302 XclExpRecord::Save( rStrm
);
304 XclExpUInt16Record( EXC_ID_SXFDBTYPE
, EXC_SXFDBTYPE_DEFAULT
).Save( rStrm
);
305 // list of grouping items
306 maGroupItemList
.Save( rStrm
);
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 ) ) );
351 InsertOrigDoubleItem( fValue
);
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 );
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" );
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
)
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
);
468 InsertOrigItem( new XclExpPCItem( aShortText
) );
471 void XclExpPCField::InsertOrigDoubleItem( double fValue
)
475 for( size_t nSize
= maOrigItemList
.GetSize(); !bFound
&& (nPos
< nSize
); ++nPos
)
476 if( (bFound
= maOrigItemList
.GetRecord( nPos
)->EqualsDouble( fValue
)) )
477 InsertItemArrayIndex( nPos
);
479 InsertOrigItem( new XclExpPCItem( fValue
) );
482 void XclExpPCField::InsertOrigDateTimeItem( const DateTime
& rDateTime
)
486 for( size_t nSize
= maOrigItemList
.GetSize(); !bFound
&& (nPos
< nSize
); ++nPos
)
487 if( (bFound
= maOrigItemList
.GetRecord( nPos
)->EqualsDateTime( rDateTime
)) )
488 InsertItemArrayIndex( nPos
);
490 InsertOrigItem( new XclExpPCItem( rDateTime
) );
493 void XclExpPCField::InsertOrigBoolItem( bool bValue
)
497 for( size_t nSize
= maOrigItemList
.GetSize(); !bFound
&& (nPos
< nSize
); ++nPos
)
498 if( (bFound
= maOrigItemList
.GetRecord( nPos
)->EqualsBool( bValue
)) )
499 InsertItemArrayIndex( nPos
);
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
;
519 pDimData
= pSaveData
->GetExistingDimensionData();
521 const ScDPCache
* pCache
= pSrcDesc
->CreateCache(pDimData
);
525 ScSheetDPData
aDPData(GetDocPtr(), *pSrcDesc
, *pCache
);
526 long nDim
= GetFieldIndex();
527 // get the string collection with generated grouping elements
528 ScDPNumGroupDimension
aTmpDim( rNumInfo
);
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
]);
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()
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
] );
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() )
587 rStrm
.StartRecord( EXC_ID_SXNUMGROUP
, 2 );
588 rStrm
<< maNumGroupInfo
;
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
)
611 void XclExpPCField::WriteBody( XclExpStream
& rStrm
)
613 rStrm
<< maFieldInfo
;
616 XclExpPivotCache::XclExpPivotCache( const XclExpRoot
& rRoot
, const ScDPObject
& rDPObj
, sal_uInt16 nListIdx
) :
618 mnListIdx( nListIdx
),
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
;
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
;
708 void XclExpPivotCache::Save( XclExpStream
& rStrm
)
710 OSL_ENSURE( mbValid
, "XclExpPivotCache::Save - invalid pivot cache" );
712 XclExpUInt16Record( EXC_ID_SXIDSTM
, maPCInfo
.mnStrmId
).Save( rStrm
);
714 XclExpUInt16Record( EXC_ID_SXVS
, EXC_SXVS_SHEET
).Save( rStrm
);
716 if (!maSrcRangeName
.isEmpty())
718 WriteDConName(rStrm
);
723 // create the pivot cache storage stream
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
;
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() )
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);
813 void XclExpPivotCache::WriteCacheStream()
815 tools::SvRef
<SotStorage
> xSvStrg
= OpenStorage( EXC_STORAGE_PTCACHE
);
816 tools::SvRef
<SotStorageStream
> xSvStrm
= OpenStream( xSvStrg
, ScfTools::GetHexStr( maPCInfo
.mnStrmId
) );
819 XclExpStream
aStrm( *xSvStrm
, GetRoot() );
823 WriteSxdbex( aStrm
);
824 // field list (SXFIELD and items)
825 maFieldList
.Save( aStrm
);
826 // index table (list of SXINDEXLIST)
827 WriteSxindexlistList( aStrm
);
829 XclExpEmptyRecord( EXC_ID_EOF
).Save( aStrm
);
833 void XclExpPivotCache::WriteSxdb( XclExpStream
& rStrm
) const
835 rStrm
.StartRecord( EXC_ID_SXDB
, 21 );
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
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
);
871 /** Returns a display string for a data field containing the field name and aggregation function. */
872 OUString
lclGetDataFieldCaption( const OUString
& rFieldName
, GeneralFunction eFunc
)
876 sal_uInt16 nResIdx
= 0;
877 using namespace ::com::sun::star::sheet
;
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;
894 aCaption
= ScGlobal::GetRscString( nResIdx
) + " - ";
895 aCaption
+= rFieldName
;
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 ),
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() );
932 const OUString
* pVisName
= rSaveMem
.GetLayoutName();
933 if (pVisName
&& !pVisName
->equals(GetItemName()))
934 maItemInfo
.SetVisName(*pVisName
);
937 void XclExpPTItem::WriteBody( XclExpStream
& rStrm
)
942 XclExpPTField::XclExpPTField( const XclExpPivotTable
& rPTable
, sal_uInt16 nCacheIdx
) :
944 mpCacheField( rPTable
.GetCacheField( nCacheIdx
) )
946 maFieldInfo
.mnCacheIdx
= nCacheIdx
;
948 // create field items
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
);
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
)
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
== '\\')
1001 return aBuf
.makeStringAndClear();
1004 void XclExpPTField::SetPropertiesFromDim( const ScDPSaveDimension
& rSaveDim
)
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() );
1015 const OUString
* pLayoutName
= rSaveDim
.GetLayoutName();
1016 if (pLayoutName
&& !pLayoutName
->equals(GetFieldName()))
1017 maFieldInfo
.SetVisName(*pLayoutName
);
1019 const OUString
* pSubtotalName
= rSaveDim
.GetSubtotalName();
1022 OUString aSubName
= lcl_convertCalcSubtotalName(*pSubtotalName
);
1023 maFieldExtInfo
.mpFieldTotalName
.reset(new OUString(aSubName
));
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
);
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
);
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
);
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
;
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();
1079 maFieldInfo
.AddApiOrient( DataPilotFieldOrientation_DATA
);
1081 // aggregation function
1082 GeneralFunction eFunc
= static_cast< GeneralFunction
>( rSaveDim
.GetFunction() );
1083 rDataInfo
.SetApiAggFunc( eFunc
);
1086 const OUString
* pVisName
= rSaveDim
.GetLayoutName();
1088 rDataInfo
.SetVisName(*pVisName
);
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
];
1140 void XclExpPTField::Save( XclExpStream
& rStrm
)
1144 // list of SXVI records
1145 maItemList
.Save( rStrm
);
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();
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
;
1174 void XclExpPTField::WriteSxvdex( XclExpStream
& rStrm
) const
1176 rStrm
.StartRecord( EXC_ID_SXVDEX
, 20 );
1177 rStrm
<< maFieldExtInfo
;
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
),
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 -------------------------------------------------------
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() );
1258 void XclExpPivotTable::Save( XclExpStream
& rStrm
)
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
);
1271 // list of SXDI records containing data field info
1272 WriteSxdiList( rStrm
);
1274 WriteSxli( rStrm
, maPTInfo
.mnDataRows
, maPTInfo
.mnRowFields
);
1275 WriteSxli( rStrm
, maPTInfo
.mnDataCols
, maPTInfo
.mnColFields
);
1279 WriteQsiSxTag( rStrm
);
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();
1294 XclExpPTField
* XclExpPivotTable::GetFieldAcc( const ScDPSaveDimension
& rSaveDim
)
1296 // data field orientation field?
1297 if( rSaveDim
.IsDataLayout() )
1298 return &maDataOrientField
;
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();
1317 const OUString
* pLayoutName
= pDim
->GetLayoutName();
1319 maPTInfo
.maDataName
= *pLayoutName
;
1321 maPTInfo
.maDataName
= ScGlobal::GetRscString(STR_PIVOT_DATA
);
1324 void XclExpPivotTable::SetFieldPropertiesFromDim( const ScDPSaveDimension
& rSaveDim
)
1326 if( XclExpPTField
* pField
= GetFieldAcc( rSaveDim
) )
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
);
1342 maPTInfo
.mnDataAxis
= EXC_SXVD_AXIS_ROW
;
1344 case DataPilotFieldOrientation_COLUMN
:
1345 maColFields
.push_back( nFieldIdx
);
1347 maPTInfo
.mnDataAxis
= EXC_SXVD_AXIS_COL
;
1349 case DataPilotFieldOrientation_PAGE
:
1350 maPageFields
.push_back( nFieldIdx
);
1351 OSL_ENSURE( !bDataLayout
, "XclExpPivotTable::SetFieldPropertiesFromDim - wrong orientation for data fields" );
1353 case DataPilotFieldOrientation_DATA
:
1354 OSL_FAIL( "XclExpPivotTable::SetFieldPropertiesFromDim - called for data field" );
1361 void XclExpPivotTable::SetDataFieldPropertiesFromDim( const ScDPSaveDimension
& rSaveDim
)
1363 if( XclExpPTField
* pField
= GetFieldAcc( rSaveDim
) )
1366 pField
->SetDataPropertiesFromDim( rSaveDim
);
1367 // update the data field position list
1368 maDataFields
.push_back( XclPTDataFieldPos( pField
->GetFieldIndex(), pField
->GetLastDataInfoIndex() ) );
1372 void XclExpPivotTable::Finalize()
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;
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
1418 // exclude empty row between (filter button and/or page fields) and table
1419 if( mbFilterBtn
|| maPTInfo
.mnPageFields
)
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() )
1430 bool bExtraHeaderRow
= (0 == maPTViewEx9Info
.mnGridLayout
&& maPTInfo
.mnColFields
== 0);
1431 if (bExtraHeaderRow
)
1432 // Insert an extra row only when there is no column field.
1435 rnXclCol2
= ::std::max( rnXclCol2
, rnDataXclCol
);
1436 rnXclRow2
= ::std::max( rnXclRow2
, rnDataXclRow
);
1437 maPTInfo
.mnDataCols
= rnXclCol2
- rnDataXclCol
+ 1;
1438 maPTInfo
.mnDataRows
= rnXclRow2
- rnDataXclRow
+ 1;
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() );
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
)
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
);
1476 xField
->WriteSxpiEntry( rStrm
);
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
);
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
1509 << EXC_SXLI_DEFAULTFLAGS
;
1510 rStrm
.WriteZeroBytes( 2 * nIndexCount
);
1516 void XclExpPivotTable::WriteSxex( XclExpStream
& rStrm
) const
1518 rStrm
.StartRecord( EXC_ID_SXEX
, 24 );
1519 rStrm
<< maPTExtInfo
;
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
;
1534 sal_uInt16 nFlags
= 0x0001;
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;
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;
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;
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
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.
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
;
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
1604 explicit XclExpPivotRecWrapper( XclExpPivotTableManager
& rPTMgr
, SCTAB nScTab
);
1605 virtual void Save( XclExpStream
& rStrm
) SAL_OVERRIDE
;
1607 XclExpPivotTableManager
& mrPTMgr
;
1611 XclExpPivotRecWrapper::XclExpPivotRecWrapper( XclExpPivotTableManager
& rPTMgr
, SCTAB nScTab
) :
1617 void XclExpPivotRecWrapper::Save( XclExpStream
& rStrm
)
1619 if( mnScTab
== EXC_PTMGR_PIVOTCACHES
)
1620 mrPTMgr
.WritePivotCaches( rStrm
);
1622 mrPTMgr
.WritePivotTables( rStrm
, mnScTab
);
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. */
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();
1706 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */