Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
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>
26 :
27 : #include <algorithm>
28 : #include <math.h>
29 :
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"
44 :
45 : using namespace ::oox;
46 :
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;
58 :
59 :
60 : // ============================================================================
61 : // Pivot cache
62 : // ============================================================================
63 :
64 : namespace {
65 :
66 : // constants to track occurrence of specific data types
67 : const sal_uInt16 EXC_PCITEM_DATA_STRING = 0x0001; /// String, empty, boolean, error.
68 : const sal_uInt16 EXC_PCITEM_DATA_DOUBLE = 0x0002; /// Double with fraction.
69 : const sal_uInt16 EXC_PCITEM_DATA_INTEGER = 0x0004; /// Integer, double without fraction.
70 : const sal_uInt16 EXC_PCITEM_DATA_DATE = 0x0008; /// Date, time, date/time.
71 :
72 : /** Maps a bitfield consisting of EXC_PCITEM_DATA_* flags above to SXFIELD data type bitfield. */
73 : static const sal_uInt16 spnPCItemFlags[] =
74 : { // STR DBL INT DAT
75 : EXC_SXFIELD_DATA_NONE, //
76 : EXC_SXFIELD_DATA_STR, // x
77 : EXC_SXFIELD_DATA_INT, // x
78 : EXC_SXFIELD_DATA_STR_INT, // x x
79 : EXC_SXFIELD_DATA_DBL, // x
80 : EXC_SXFIELD_DATA_STR_DBL, // x x
81 : EXC_SXFIELD_DATA_INT, // x x
82 : EXC_SXFIELD_DATA_STR_INT, // x x x
83 : EXC_SXFIELD_DATA_DATE, // x
84 : EXC_SXFIELD_DATA_DATE_STR, // x x
85 : EXC_SXFIELD_DATA_DATE_NUM, // x x
86 : EXC_SXFIELD_DATA_DATE_STR, // x x x
87 : EXC_SXFIELD_DATA_DATE_NUM, // x x
88 : EXC_SXFIELD_DATA_DATE_STR, // x x x
89 : EXC_SXFIELD_DATA_DATE_NUM, // x x x
90 : EXC_SXFIELD_DATA_DATE_STR // x x x x
91 : };
92 :
93 : } // namespace
94 :
95 : // ----------------------------------------------------------------------------
96 :
97 0 : XclExpPCItem::XclExpPCItem( const String& rText ) :
98 0 : XclExpRecord( (rText.Len() > 0) ? EXC_ID_SXSTRING : EXC_ID_SXEMPTY, 0 ),
99 0 : mnTypeFlag( EXC_PCITEM_DATA_STRING )
100 : {
101 0 : if( rText.Len() )
102 0 : SetText( rText );
103 : else
104 0 : SetEmpty();
105 0 : }
106 :
107 0 : XclExpPCItem::XclExpPCItem( double fValue ) :
108 0 : XclExpRecord( EXC_ID_SXDOUBLE, 8 )
109 : {
110 0 : SetDouble( fValue );
111 0 : mnTypeFlag = (fValue - floor( fValue ) == 0.0) ?
112 0 : EXC_PCITEM_DATA_INTEGER : EXC_PCITEM_DATA_DOUBLE;
113 0 : }
114 :
115 0 : XclExpPCItem::XclExpPCItem( const DateTime& rDateTime ) :
116 0 : XclExpRecord( EXC_ID_SXDATETIME, 8 )
117 : {
118 0 : SetDateTime( rDateTime );
119 0 : mnTypeFlag = EXC_PCITEM_DATA_DATE;
120 0 : }
121 :
122 0 : XclExpPCItem::XclExpPCItem( sal_Int16 nValue ) :
123 : XclExpRecord( EXC_ID_SXINTEGER, 2 ),
124 0 : mnTypeFlag( EXC_PCITEM_DATA_INTEGER )
125 : {
126 0 : SetInteger( nValue );
127 0 : }
128 :
129 0 : XclExpPCItem::XclExpPCItem( bool bValue ) :
130 : XclExpRecord( EXC_ID_SXBOOLEAN, 2 ),
131 0 : mnTypeFlag( EXC_PCITEM_DATA_STRING )
132 : {
133 0 : SetBool( bValue );
134 0 : }
135 :
136 : // ----------------------------------------------------------------------------
137 :
138 0 : bool XclExpPCItem::EqualsText( const OUString& rText ) const
139 : {
140 0 : return rText.isEmpty() ? IsEmpty() : (GetText() && (*GetText() == rText));
141 : }
142 :
143 0 : bool XclExpPCItem::EqualsDouble( double fValue ) const
144 : {
145 0 : return GetDouble() && (*GetDouble() == fValue);
146 : }
147 :
148 0 : bool XclExpPCItem::EqualsDateTime( const DateTime& rDateTime ) const
149 : {
150 0 : return GetDateTime() && (*GetDateTime() == rDateTime);
151 : }
152 :
153 0 : bool XclExpPCItem::EqualsBool( bool bValue ) const
154 : {
155 0 : return GetBool() && (*GetBool() == bValue);
156 : }
157 :
158 : // ----------------------------------------------------------------------------
159 :
160 0 : void XclExpPCItem::WriteBody( XclExpStream& rStrm )
161 : {
162 0 : if( const OUString* pText = GetText() )
163 : {
164 0 : rStrm << XclExpString( *pText );
165 : }
166 0 : else if( const double* pfValue = GetDouble() )
167 : {
168 0 : rStrm << *pfValue;
169 : }
170 0 : else if( const sal_Int16* pnValue = GetInteger() )
171 : {
172 0 : rStrm << *pnValue;
173 : }
174 0 : else if( const DateTime* pDateTime = GetDateTime() )
175 : {
176 0 : sal_uInt16 nYear = static_cast< sal_uInt16 >( pDateTime->GetYear() );
177 0 : sal_uInt16 nMonth = static_cast< sal_uInt16 >( pDateTime->GetMonth() );
178 0 : sal_uInt8 nDay = static_cast< sal_uInt8 >( pDateTime->GetDay() );
179 0 : sal_uInt8 nHour = static_cast< sal_uInt8 >( pDateTime->GetHour() );
180 0 : sal_uInt8 nMin = static_cast< sal_uInt8 >( pDateTime->GetMin() );
181 0 : sal_uInt8 nSec = static_cast< sal_uInt8 >( pDateTime->GetSec() );
182 0 : if( nYear < 1900 ) { nYear = 1900; nMonth = 1; nDay = 0; }
183 0 : rStrm << nYear << nMonth << nDay << nHour << nMin << nSec;
184 : }
185 0 : else if( const bool* pbValue = GetBool() )
186 : {
187 0 : rStrm << static_cast< sal_uInt16 >( *pbValue ? 1 : 0 );
188 : }
189 : else
190 : {
191 : // nothing to do for SXEMPTY
192 : OSL_ENSURE( IsEmpty(), "XclExpPCItem::WriteBody - no data found" );
193 : }
194 0 : }
195 :
196 : // ============================================================================
197 :
198 0 : XclExpPCField::XclExpPCField(
199 : const XclExpRoot& rRoot, const XclExpPivotCache& rPCache, sal_uInt16 nFieldIdx,
200 : const ScDPObject& rDPObj, const ScRange& rRange ) :
201 : XclExpRecord( EXC_ID_SXFIELD ),
202 : XclPCField( EXC_PCFIELD_STANDARD, nFieldIdx ),
203 : XclExpRoot( rRoot ),
204 : mrPCache( rPCache ),
205 0 : mnTypeFlags( 0 )
206 : {
207 : // general settings for the standard field, insert all items from source range
208 0 : InitStandardField( rRange );
209 :
210 : // add special settings for inplace numeric grouping
211 0 : if( const ScDPSaveData* pSaveData = rDPObj.GetSaveData() )
212 : {
213 0 : if( const ScDPDimensionSaveData* pSaveDimData = pSaveData->GetExistingDimensionData() )
214 : {
215 0 : if( const ScDPSaveNumGroupDimension* pNumGroupDim = pSaveDimData->GetNumGroupDim( GetFieldName() ) )
216 : {
217 0 : const ScDPNumGroupInfo& rNumInfo = pNumGroupDim->GetInfo();
218 0 : const ScDPNumGroupInfo& rDateInfo = pNumGroupDim->GetDateInfo();
219 : OSL_ENSURE( !rNumInfo.mbEnable || !rDateInfo.mbEnable,
220 : "XclExpPCField::XclExpPCField - numeric and date grouping enabled" );
221 :
222 0 : if( rNumInfo.mbEnable )
223 0 : InitNumGroupField( rDPObj, rNumInfo );
224 0 : else if( rDateInfo.mbEnable )
225 0 : InitDateGroupField( rDPObj, rDateInfo, pNumGroupDim->GetDatePart() );
226 : }
227 : }
228 : }
229 :
230 : // final settings (flags, item numbers)
231 0 : Finalize();
232 0 : }
233 :
234 0 : XclExpPCField::XclExpPCField(
235 : const XclExpRoot& rRoot, const XclExpPivotCache& rPCache, sal_uInt16 nFieldIdx,
236 : const ScDPObject& rDPObj, const ScDPSaveGroupDimension& rGroupDim, const XclExpPCField& rBaseField ) :
237 : XclExpRecord( EXC_ID_SXFIELD ),
238 : XclPCField( EXC_PCFIELD_STDGROUP, nFieldIdx ),
239 : XclExpRoot( rRoot ),
240 : mrPCache( rPCache ),
241 0 : mnTypeFlags( 0 )
242 : {
243 : // add base field info (always using first base field, not predecessor of this field) ***
244 : OSL_ENSURE( rBaseField.GetFieldName() == rGroupDim.GetSourceDimName(),
245 : "XclExpPCField::FillFromGroup - wrong base cache field" );
246 0 : maFieldInfo.maName = rGroupDim.GetGroupDimName();
247 0 : maFieldInfo.mnGroupBase = rBaseField.GetFieldIndex();
248 :
249 : // add standard group info or date group info
250 0 : const ScDPNumGroupInfo& rDateInfo = rGroupDim.GetDateInfo();
251 0 : if( rDateInfo.mbEnable && (rGroupDim.GetDatePart() != 0) )
252 0 : InitDateGroupField( rDPObj, rDateInfo, rGroupDim.GetDatePart() );
253 : else
254 0 : InitStdGroupField( rBaseField, rGroupDim );
255 :
256 : // final settings (flags, item numbers)
257 0 : Finalize();
258 0 : }
259 :
260 0 : XclExpPCField::~XclExpPCField()
261 : {
262 0 : }
263 :
264 0 : void XclExpPCField::SetGroupChildField( const XclExpPCField& rChildField )
265 : {
266 : OSL_ENSURE( !::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_HASCHILD ),
267 : "XclExpPCField::SetGroupChildIndex - field already has a grouping child field" );
268 0 : ::set_flag( maFieldInfo.mnFlags, EXC_SXFIELD_HASCHILD );
269 0 : maFieldInfo.mnGroupChild = rChildField.GetFieldIndex();
270 0 : }
271 :
272 0 : sal_uInt16 XclExpPCField::GetItemCount() const
273 : {
274 0 : return static_cast< sal_uInt16 >( GetVisItemList().GetSize() );
275 : }
276 :
277 0 : const XclExpPCItem* XclExpPCField::GetItem( sal_uInt16 nItemIdx ) const
278 : {
279 0 : return GetVisItemList().GetRecord( nItemIdx ).get();
280 : }
281 :
282 0 : sal_uInt16 XclExpPCField::GetItemIndex( const OUString& rItemName ) const
283 : {
284 0 : const XclExpPCItemList& rItemList = GetVisItemList();
285 0 : for( size_t nPos = 0, nSize = rItemList.GetSize(); nPos < nSize; ++nPos )
286 0 : if( rItemList.GetRecord( nPos )->ConvertToText() == rItemName )
287 0 : return static_cast< sal_uInt16 >( nPos );
288 0 : return EXC_PC_NOITEM;
289 : }
290 :
291 0 : sal_Size XclExpPCField::GetIndexSize() const
292 : {
293 0 : return Has16BitIndexes() ? 2 : 1;
294 : }
295 :
296 0 : void XclExpPCField::WriteIndex( XclExpStream& rStrm, sal_uInt32 nSrcRow ) const
297 : {
298 : // only standard fields write item indexes
299 0 : if( nSrcRow < maIndexVec.size() )
300 : {
301 0 : sal_uInt16 nIndex = maIndexVec[ nSrcRow ];
302 0 : if( Has16BitIndexes() )
303 0 : rStrm << nIndex;
304 : else
305 0 : rStrm << static_cast< sal_uInt8 >( nIndex );
306 : }
307 0 : }
308 :
309 0 : void XclExpPCField::Save( XclExpStream& rStrm )
310 : {
311 : OSL_ENSURE( IsSupportedField(), "XclExpPCField::Save - unknown field type" );
312 : // SXFIELD
313 0 : XclExpRecord::Save( rStrm );
314 : // SXFDBTYPE
315 0 : XclExpUInt16Record( EXC_ID_SXFDBTYPE, EXC_SXFDBTYPE_DEFAULT ).Save( rStrm );
316 : // list of grouping items
317 0 : maGroupItemList.Save( rStrm );
318 : // SXGROUPINFO
319 0 : WriteSxgroupinfo( rStrm );
320 : // SXNUMGROUP and additional grouping items (grouping limit settings)
321 0 : WriteSxnumgroup( rStrm );
322 : // list of original items
323 0 : maOrigItemList.Save( rStrm );
324 0 : }
325 :
326 : // private --------------------------------------------------------------------
327 :
328 0 : const XclExpPCField::XclExpPCItemList& XclExpPCField::GetVisItemList() const
329 : {
330 : OSL_ENSURE( IsStandardField() == maGroupItemList.IsEmpty(),
331 : "XclExpPCField::GetVisItemList - unexpected additional items in standard field" );
332 0 : return IsStandardField() ? maOrigItemList : maGroupItemList;
333 : }
334 :
335 0 : void XclExpPCField::InitStandardField( const ScRange& rRange )
336 : {
337 : OSL_ENSURE( IsStandardField(), "XclExpPCField::InitStandardField - only for standard fields" );
338 : OSL_ENSURE( rRange.aStart.Col() == rRange.aEnd.Col(), "XclExpPCField::InitStandardField - cell range with multiple columns" );
339 :
340 0 : ScDocument& rDoc = GetDoc();
341 0 : SvNumberFormatter& rFormatter = GetFormatter();
342 :
343 : // field name is in top cell of the range
344 0 : ScAddress aPos( rRange.aStart );
345 0 : maFieldInfo.maName = rDoc.GetString(aPos.Col(), aPos.Row(), aPos.Tab());
346 : // #i76047# maximum field name length in pivot cache is 255
347 0 : if (maFieldInfo.maName.getLength() > EXC_PC_MAXSTRLEN)
348 0 : maFieldInfo.maName = maFieldInfo.maName.copy(0, EXC_PC_MAXSTRLEN);
349 :
350 : // loop over all cells, create pivot cache items
351 0 : for( aPos.IncRow(); (aPos.Row() <= rRange.aEnd.Row()) && (maOrigItemList.GetSize() < EXC_PC_MAXITEMCOUNT); aPos.IncRow() )
352 : {
353 0 : if( rDoc.HasValueData( aPos.Col(), aPos.Row(), aPos.Tab() ) )
354 : {
355 0 : double fValue = rDoc.GetValue( aPos );
356 0 : short nFmtType = rFormatter.GetType( rDoc.GetNumberFormat( aPos ) );
357 0 : if( nFmtType == NUMBERFORMAT_LOGICAL )
358 0 : InsertOrigBoolItem( fValue != 0 );
359 0 : else if( nFmtType & NUMBERFORMAT_DATETIME )
360 0 : InsertOrigDateTimeItem( GetDateTimeFromDouble( ::std::max( fValue, 0.0 ) ) );
361 : else
362 0 : InsertOrigDoubleItem( fValue );
363 : }
364 : else
365 : {
366 0 : OUString aText = rDoc.GetString(aPos.Col(), aPos.Row(), aPos.Tab());
367 0 : InsertOrigTextItem( aText );
368 : }
369 : }
370 0 : }
371 :
372 0 : void XclExpPCField::InitStdGroupField( const XclExpPCField& rBaseField, const ScDPSaveGroupDimension& rGroupDim )
373 : {
374 : OSL_ENSURE( IsGroupField(), "XclExpPCField::InitStdGroupField - only for standard grouping fields" );
375 :
376 0 : maFieldInfo.mnBaseItems = rBaseField.GetItemCount();
377 0 : maGroupOrder.resize( maFieldInfo.mnBaseItems, EXC_PC_NOITEM );
378 :
379 : // loop over all groups of this field
380 0 : for( long nGroupIdx = 0, nGroupCount = rGroupDim.GetGroupCount(); nGroupIdx < nGroupCount; ++nGroupIdx )
381 : {
382 0 : if( const ScDPSaveGroupItem* pGroupItem = rGroupDim.GetGroupByIndex( nGroupIdx ) )
383 : {
384 : // the index of the new item containing the grouping name
385 0 : sal_uInt16 nGroupItemIdx = EXC_PC_NOITEM;
386 : // loop over all elements of one group
387 0 : for( size_t nElemIdx = 0, nElemCount = pGroupItem->GetElementCount(); nElemIdx < nElemCount; ++nElemIdx )
388 : {
389 0 : if (const OUString* pElemName = pGroupItem->GetElementByIndex(nElemIdx))
390 : {
391 : // try to find the item that is part of the group in the base field
392 0 : sal_uInt16 nBaseItemIdx = rBaseField.GetItemIndex( *pElemName );
393 0 : if( nBaseItemIdx < maFieldInfo.mnBaseItems )
394 : {
395 : // add group name item only if there are any valid base items
396 0 : if( nGroupItemIdx == EXC_PC_NOITEM )
397 0 : nGroupItemIdx = InsertGroupItem( new XclExpPCItem( pGroupItem->GetGroupName() ) );
398 0 : maGroupOrder[ nBaseItemIdx ] = nGroupItemIdx;
399 : }
400 : }
401 : }
402 : }
403 : }
404 :
405 : // add items and base item indexes of all ungrouped elements
406 0 : for( sal_uInt16 nBaseItemIdx = 0; nBaseItemIdx < maFieldInfo.mnBaseItems; ++nBaseItemIdx )
407 : // items that are not part of a group still have the EXC_PC_NOITEM entry
408 0 : if( maGroupOrder[ nBaseItemIdx ] == EXC_PC_NOITEM )
409 : // try to find the base item
410 0 : if( const XclExpPCItem* pBaseItem = rBaseField.GetItem( nBaseItemIdx ) )
411 : // create a clone of the base item, insert its index into item order list
412 0 : maGroupOrder[ nBaseItemIdx ] = InsertGroupItem( new XclExpPCItem( *pBaseItem ) );
413 0 : }
414 :
415 0 : void XclExpPCField::InitNumGroupField( const ScDPObject& rDPObj, const ScDPNumGroupInfo& rNumInfo )
416 : {
417 : OSL_ENSURE( IsStandardField(), "XclExpPCField::InitNumGroupField - only for standard fields" );
418 : OSL_ENSURE( rNumInfo.mbEnable, "XclExpPCField::InitNumGroupField - numeric grouping not enabled" );
419 :
420 : // new field type, date type, limit settings (min/max/step/auto)
421 0 : if( rNumInfo.mbDateValues )
422 : {
423 : // special case: group by days with step count
424 0 : meFieldType = EXC_PCFIELD_DATEGROUP;
425 0 : maNumGroupInfo.SetScDateType( com::sun::star::sheet::DataPilotFieldGroupBy::DAYS );
426 0 : SetDateGroupLimit( rNumInfo, true );
427 : }
428 : else
429 : {
430 0 : meFieldType = EXC_PCFIELD_NUMGROUP;
431 0 : maNumGroupInfo.SetNumType();
432 0 : SetNumGroupLimit( rNumInfo );
433 : }
434 :
435 : // generate visible items
436 0 : InsertNumDateGroupItems( rDPObj, rNumInfo );
437 0 : }
438 :
439 0 : void XclExpPCField::InitDateGroupField( const ScDPObject& rDPObj, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nDatePart )
440 : {
441 : OSL_ENSURE( IsStandardField() || IsStdGroupField(), "XclExpPCField::InitDateGroupField - only for standard fields" );
442 : OSL_ENSURE( rDateInfo.mbEnable, "XclExpPCField::InitDateGroupField - date grouping not enabled" );
443 :
444 : // new field type
445 0 : meFieldType = IsStandardField() ? EXC_PCFIELD_DATEGROUP : EXC_PCFIELD_DATECHILD;
446 :
447 : // date type, limit settings (min/max/step/auto)
448 0 : maNumGroupInfo.SetScDateType( nDatePart );
449 0 : SetDateGroupLimit( rDateInfo, false );
450 :
451 : // generate visible items
452 0 : InsertNumDateGroupItems( rDPObj, rDateInfo, nDatePart );
453 0 : }
454 :
455 0 : void XclExpPCField::InsertItemArrayIndex( size_t nListPos )
456 : {
457 : OSL_ENSURE( IsStandardField(), "XclExpPCField::InsertItemArrayIndex - only for standard fields" );
458 0 : maIndexVec.push_back( static_cast< sal_uInt16 >( nListPos ) );
459 0 : }
460 :
461 0 : void XclExpPCField::InsertOrigItem( XclExpPCItem* pNewItem )
462 : {
463 0 : size_t nItemIdx = maOrigItemList.GetSize();
464 0 : maOrigItemList.AppendNewRecord( pNewItem );
465 0 : InsertItemArrayIndex( nItemIdx );
466 0 : mnTypeFlags |= pNewItem->GetTypeFlag();
467 0 : }
468 :
469 0 : void XclExpPCField::InsertOrigTextItem( const String& rText )
470 : {
471 0 : size_t nPos = 0;
472 0 : bool bFound = false;
473 : // #i76047# maximum item text length in pivot cache is 255
474 0 : String aShortText( rText, 0, ::std::min( rText.Len(), EXC_PC_MAXSTRLEN ) );
475 0 : for( size_t nSize = maOrigItemList.GetSize(); !bFound && (nPos < nSize); ++nPos )
476 0 : if( (bFound = maOrigItemList.GetRecord( nPos )->EqualsText( aShortText )) == true )
477 0 : InsertItemArrayIndex( nPos );
478 0 : if( !bFound )
479 0 : InsertOrigItem( new XclExpPCItem( aShortText ) );
480 0 : }
481 :
482 0 : void XclExpPCField::InsertOrigDoubleItem( double fValue )
483 : {
484 0 : size_t nPos = 0;
485 0 : bool bFound = false;
486 0 : for( size_t nSize = maOrigItemList.GetSize(); !bFound && (nPos < nSize); ++nPos )
487 0 : if( (bFound = maOrigItemList.GetRecord( nPos )->EqualsDouble( fValue )) == true )
488 0 : InsertItemArrayIndex( nPos );
489 0 : if( !bFound )
490 0 : InsertOrigItem( new XclExpPCItem( fValue ) );
491 0 : }
492 :
493 0 : void XclExpPCField::InsertOrigDateTimeItem( const DateTime& rDateTime )
494 : {
495 0 : size_t nPos = 0;
496 0 : bool bFound = false;
497 0 : for( size_t nSize = maOrigItemList.GetSize(); !bFound && (nPos < nSize); ++nPos )
498 0 : if( (bFound = maOrigItemList.GetRecord( nPos )->EqualsDateTime( rDateTime )) == true )
499 0 : InsertItemArrayIndex( nPos );
500 0 : if( !bFound )
501 0 : InsertOrigItem( new XclExpPCItem( rDateTime ) );
502 0 : }
503 :
504 0 : void XclExpPCField::InsertOrigBoolItem( bool bValue )
505 : {
506 0 : size_t nPos = 0;
507 0 : bool bFound = false;
508 0 : for( size_t nSize = maOrigItemList.GetSize(); !bFound && (nPos < nSize); ++nPos )
509 0 : if( (bFound = maOrigItemList.GetRecord( nPos )->EqualsBool( bValue )) == true )
510 0 : InsertItemArrayIndex( nPos );
511 0 : if( !bFound )
512 0 : InsertOrigItem( new XclExpPCItem( bValue ) );
513 0 : }
514 :
515 0 : sal_uInt16 XclExpPCField::InsertGroupItem( XclExpPCItem* pNewItem )
516 : {
517 0 : maGroupItemList.AppendNewRecord( pNewItem );
518 0 : return static_cast< sal_uInt16 >( maGroupItemList.GetSize() - 1 );
519 : }
520 :
521 0 : void XclExpPCField::InsertNumDateGroupItems( const ScDPObject& rDPObj, const ScDPNumGroupInfo& rNumInfo, sal_Int32 nDatePart )
522 : {
523 : OSL_ENSURE( rDPObj.GetSheetDesc(), "XclExpPCField::InsertNumDateGroupItems - cannot generate element list" );
524 0 : if( const ScSheetSourceDesc* pSrcDesc = rDPObj.GetSheetDesc() )
525 : {
526 : // get the string collection with original source elements
527 0 : const ScDPSaveData* pSaveData = rDPObj.GetSaveData();
528 0 : const ScDPDimensionSaveData* pDimData = NULL;
529 0 : if (pSaveData)
530 0 : pDimData = pSaveData->GetExistingDimensionData();
531 :
532 0 : const ScDPCache* pCache = pSrcDesc->CreateCache(pDimData);
533 0 : if (!pCache)
534 0 : return;
535 :
536 0 : ScSheetDPData aDPData(GetDocPtr(), *pSrcDesc, *pCache);
537 0 : long nDim = GetFieldIndex();
538 : // get the string collection with generated grouping elements
539 0 : ScDPNumGroupDimension aTmpDim( rNumInfo );
540 0 : if( nDatePart != 0 )
541 0 : aTmpDim.SetDateDimension();
542 : const std::vector<SCROW>& aMemberIds = aTmpDim.GetNumEntries(
543 0 : static_cast<SCCOL>(nDim), pCache);
544 0 : for ( size_t nIdx = 0 ; nIdx < aMemberIds.size(); nIdx++ )
545 : {
546 0 : const ScDPItemData* pData = aDPData.GetMemberById(nDim , aMemberIds[nIdx]);
547 0 : if ( pData )
548 : {
549 0 : OUString aStr = pCache->GetFormattedString(nDim, *pData);
550 0 : InsertGroupItem(new XclExpPCItem(aStr));
551 : }
552 0 : }
553 : }
554 : }
555 :
556 0 : void XclExpPCField::SetNumGroupLimit( const ScDPNumGroupInfo& rNumInfo )
557 : {
558 0 : ::set_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMIN, rNumInfo.mbAutoStart );
559 0 : ::set_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMAX, rNumInfo.mbAutoEnd );
560 0 : maNumGroupLimits.AppendNewRecord( new XclExpPCItem( rNumInfo.mfStart ) );
561 0 : maNumGroupLimits.AppendNewRecord( new XclExpPCItem( rNumInfo.mfEnd ) );
562 0 : maNumGroupLimits.AppendNewRecord( new XclExpPCItem( rNumInfo.mfStep ) );
563 0 : }
564 :
565 0 : void XclExpPCField::SetDateGroupLimit( const ScDPNumGroupInfo& rDateInfo, bool bUseStep )
566 : {
567 0 : ::set_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMIN, rDateInfo.mbAutoStart );
568 0 : ::set_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMAX, rDateInfo.mbAutoEnd );
569 0 : maNumGroupLimits.AppendNewRecord( new XclExpPCItem( GetDateTimeFromDouble( rDateInfo.mfStart ) ) );
570 0 : maNumGroupLimits.AppendNewRecord( new XclExpPCItem( GetDateTimeFromDouble( rDateInfo.mfEnd ) ) );
571 0 : sal_Int16 nStep = bUseStep ? limit_cast< sal_Int16 >( rDateInfo.mfStep, 1, SAL_MAX_INT16 ) : 1;
572 0 : maNumGroupLimits.AppendNewRecord( new XclExpPCItem( nStep ) );
573 0 : }
574 :
575 0 : void XclExpPCField::Finalize()
576 : {
577 : // flags
578 0 : ::set_flag( maFieldInfo.mnFlags, EXC_SXFIELD_HASITEMS, !GetVisItemList().IsEmpty() );
579 : // Excel writes long indexes even for 0x0100 items (indexes from 0x00 to 0xFF)
580 0 : ::set_flag( maFieldInfo.mnFlags, EXC_SXFIELD_16BIT, maOrigItemList.GetSize() >= 0x0100 );
581 0 : ::set_flag( maFieldInfo.mnFlags, EXC_SXFIELD_NUMGROUP, IsNumGroupField() || IsDateGroupField() );
582 : /* mnTypeFlags is updated in all Insert***Item() functions. Now the flags
583 : for the current combination of item types is added to the flags. */
584 0 : ::set_flag( maFieldInfo.mnFlags, spnPCItemFlags[ mnTypeFlags ] );
585 :
586 : // item count fields
587 0 : maFieldInfo.mnVisItems = static_cast< sal_uInt16 >( GetVisItemList().GetSize() );
588 0 : maFieldInfo.mnGroupItems = static_cast< sal_uInt16 >( maGroupItemList.GetSize() );
589 : // maFieldInfo.mnBaseItems set in InitStdGroupField()
590 0 : maFieldInfo.mnOrigItems = static_cast< sal_uInt16 >( maOrigItemList.GetSize() );
591 0 : }
592 :
593 0 : void XclExpPCField::WriteSxnumgroup( XclExpStream& rStrm )
594 : {
595 0 : if( IsNumGroupField() || IsDateGroupField() )
596 : {
597 : // SXNUMGROUP record
598 0 : rStrm.StartRecord( EXC_ID_SXNUMGROUP, 2 );
599 0 : rStrm << maNumGroupInfo;
600 0 : rStrm.EndRecord();
601 :
602 : // limits (min/max/step) for numeric grouping
603 : OSL_ENSURE( maNumGroupLimits.GetSize() == 3,
604 : "XclExpPCField::WriteSxnumgroup - missing numeric grouping limits" );
605 0 : maNumGroupLimits.Save( rStrm );
606 : }
607 0 : }
608 :
609 0 : void XclExpPCField::WriteSxgroupinfo( XclExpStream& rStrm )
610 : {
611 : OSL_ENSURE( IsStdGroupField() != maGroupOrder.empty(),
612 : "XclExpPCField::WriteSxgroupinfo - missing grouping info" );
613 0 : if( IsStdGroupField() && !maGroupOrder.empty() )
614 : {
615 0 : rStrm.StartRecord( EXC_ID_SXGROUPINFO, 2 * maGroupOrder.size() );
616 0 : for( ScfUInt16Vec::const_iterator aIt = maGroupOrder.begin(), aEnd = maGroupOrder.end(); aIt != aEnd; ++aIt )
617 0 : rStrm << *aIt;
618 0 : rStrm.EndRecord();
619 : }
620 0 : }
621 :
622 0 : void XclExpPCField::WriteBody( XclExpStream& rStrm )
623 : {
624 0 : rStrm << maFieldInfo;
625 0 : }
626 :
627 : // ============================================================================
628 :
629 0 : XclExpPivotCache::XclExpPivotCache( const XclExpRoot& rRoot, const ScDPObject& rDPObj, sal_uInt16 nListIdx ) :
630 : XclExpRoot( rRoot ),
631 : mnListIdx( nListIdx ),
632 0 : mbValid( false )
633 : {
634 : // source from sheet only
635 0 : if( const ScSheetSourceDesc* pSrcDesc = rDPObj.GetSheetDesc() )
636 : {
637 : /* maOrigSrcRange: Range received from the DataPilot object.
638 : maExpSrcRange: Range written to the DCONREF record.
639 : maDocSrcRange: Range used to get source data from Calc document.
640 : This range may be shorter than maExpSrcRange to improve export
641 : performance (#i22541#). */
642 0 : maOrigSrcRange = maExpSrcRange = maDocSrcRange = pSrcDesc->GetSourceRange();
643 0 : maSrcRangeName = pSrcDesc->GetRangeName();
644 :
645 : // internal sheet data only
646 0 : SCTAB nScTab = maExpSrcRange.aStart.Tab();
647 0 : if( (nScTab == maExpSrcRange.aEnd.Tab()) && GetTabInfo().IsExportTab( nScTab ) )
648 : {
649 : // ValidateRange() restricts source range to valid Excel limits
650 0 : if( GetAddressConverter().ValidateRange( maExpSrcRange, true ) )
651 : {
652 : // #i22541# skip empty cell areas (performance)
653 : SCCOL nDocCol1, nDocCol2;
654 : SCROW nDocRow1, nDocRow2;
655 0 : GetDoc().GetDataStart( nScTab, nDocCol1, nDocRow1 );
656 0 : GetDoc().GetPrintArea( nScTab, nDocCol2, nDocRow2, false );
657 0 : SCCOL nSrcCol1 = maExpSrcRange.aStart.Col();
658 0 : SCROW nSrcRow1 = maExpSrcRange.aStart.Row();
659 0 : SCCOL nSrcCol2 = maExpSrcRange.aEnd.Col();
660 0 : SCROW nSrcRow2 = maExpSrcRange.aEnd.Row();
661 :
662 : // #i22541# do not store index list for too big ranges
663 0 : if( 2 * (nDocRow2 - nDocRow1) < (nSrcRow2 - nSrcRow1) )
664 0 : ::set_flag( maPCInfo.mnFlags, EXC_SXDB_SAVEDATA, false );
665 :
666 : // adjust row indexes, keep one row of empty area to surely have the empty cache item
667 0 : if( nSrcRow1 < nDocRow1 )
668 0 : nSrcRow1 = nDocRow1 - 1;
669 0 : if( nSrcRow2 > nDocRow2 )
670 0 : nSrcRow2 = nDocRow2 + 1;
671 :
672 0 : maDocSrcRange.aStart.SetCol( ::std::max( nDocCol1, nSrcCol1 ) );
673 0 : maDocSrcRange.aStart.SetRow( nSrcRow1 );
674 0 : maDocSrcRange.aEnd.SetCol( ::std::min( nDocCol2, nSrcCol2 ) );
675 0 : maDocSrcRange.aEnd.SetRow( nSrcRow2 );
676 :
677 0 : GetDoc().GetName( nScTab, maTabName );
678 0 : maPCInfo.mnSrcRecs = static_cast< sal_uInt32 >( maExpSrcRange.aEnd.Row() - maExpSrcRange.aStart.Row() );
679 0 : maPCInfo.mnStrmId = nListIdx + 1;
680 0 : maPCInfo.mnSrcType = EXC_SXDB_SRC_SHEET;
681 :
682 0 : AddFields( rDPObj );
683 :
684 0 : mbValid = true;
685 : }
686 : }
687 : }
688 0 : }
689 :
690 0 : bool XclExpPivotCache::HasItemIndexList() const
691 : {
692 0 : return ::get_flag( maPCInfo.mnFlags, EXC_SXDB_SAVEDATA );
693 : }
694 :
695 0 : sal_uInt16 XclExpPivotCache::GetFieldCount() const
696 : {
697 0 : return static_cast< sal_uInt16 >( maFieldList.GetSize() );
698 : }
699 :
700 0 : const XclExpPCField* XclExpPivotCache::GetField( sal_uInt16 nFieldIdx ) const
701 : {
702 0 : return maFieldList.GetRecord( nFieldIdx ).get();
703 : }
704 :
705 0 : bool XclExpPivotCache::HasAddFields() const
706 : {
707 : // pivot cache can be shared, if there are no additional cache fields
708 0 : return maPCInfo.mnStdFields < maPCInfo.mnTotalFields;
709 : }
710 :
711 0 : bool XclExpPivotCache::HasEqualDataSource( const ScDPObject& rDPObj ) const
712 : {
713 : /* For now, only sheet sources are supported, therefore it is enough to
714 : compare the ScSheetSourceDesc. Later, there should be done more complicated
715 : comparisons regarding the source type of rDPObj and this cache. */
716 0 : if( const ScSheetSourceDesc* pSrcDesc = rDPObj.GetSheetDesc() )
717 0 : return pSrcDesc->GetSourceRange() == maOrigSrcRange;
718 0 : return false;
719 : }
720 :
721 0 : void XclExpPivotCache::Save( XclExpStream& rStrm )
722 : {
723 : OSL_ENSURE( mbValid, "XclExpPivotCache::Save - invalid pivot cache" );
724 : // SXIDSTM
725 0 : XclExpUInt16Record( EXC_ID_SXIDSTM, maPCInfo.mnStrmId ).Save( rStrm );
726 : // SXVS
727 0 : XclExpUInt16Record( EXC_ID_SXVS, EXC_SXVS_SHEET ).Save( rStrm );
728 :
729 0 : if (!maSrcRangeName.isEmpty())
730 : // DCONNAME
731 0 : WriteDConName(rStrm);
732 : else
733 : // DCONREF
734 0 : WriteDconref(rStrm);
735 :
736 : // create the pivot cache storage stream
737 0 : WriteCacheStream();
738 0 : }
739 :
740 0 : void XclExpPivotCache::SaveXml( XclExpXmlStream&
741 : #ifdef XLSX_PIVOT_CACHE
742 : rStrm
743 : #endif
744 : )
745 : {
746 : OSL_ENSURE( mbValid, "XclExpPivotCache::Save - invalid pivot cache" );
747 : #ifdef XLSX_PIVOT_CACHE /* <pivotCache> without xl/pivotCaches/ cacheStream
748 : results in a broken .xlsx */
749 : sax_fastparser::FSHelperPtr& rWorkbook = rStrm.GetCurrentStream();
750 : OUString sId = OUStringBuffer()
751 : .appendAscii("rId")
752 : .append( rStrm.GetUniqueIdOUString() )
753 : .makeStringAndClear();
754 : rWorkbook->startElement( XML_pivotCache,
755 : XML_cacheId, OString::valueOf( (sal_Int32)maPCInfo.mnStrmId ).getStr(),
756 : FSNS( XML_r, XML_id ), XclXmlUtils::ToOString( sId ).getStr(),
757 : FSEND );
758 : // SXIDSTM
759 : XclExpUInt16Record( EXC_ID_SXIDSTM, maPCInfo.mnStrmId ).SaveXml( rStrm );
760 : // SXVS
761 : XclExpUInt16Record( EXC_ID_SXVS, EXC_SXVS_SHEET ).SaveXml( rStrm );
762 : // DCONREF
763 : // OOXTODO: WriteDconref( rStrm );
764 : // create the pivot cache storage stream
765 : // OOXTODO: WriteCacheStream();
766 : rWorkbook->endElement( XML_pivotCache );
767 : #endif /* XLSX_PIVOT_CACHE */
768 0 : }
769 :
770 : // private --------------------------------------------------------------------
771 :
772 0 : XclExpPCField* XclExpPivotCache::GetFieldAcc( sal_uInt16 nFieldIdx )
773 : {
774 0 : return maFieldList.GetRecord( nFieldIdx ).get();
775 : }
776 :
777 0 : void XclExpPivotCache::AddFields( const ScDPObject& rDPObj )
778 : {
779 0 : AddStdFields( rDPObj );
780 0 : maPCInfo.mnStdFields = GetFieldCount();
781 0 : AddGroupFields( rDPObj );
782 0 : AddCalcFields( rDPObj );
783 0 : maPCInfo.mnTotalFields = GetFieldCount();
784 0 : };
785 :
786 0 : void XclExpPivotCache::AddStdFields( const ScDPObject& rDPObj )
787 : {
788 : // if item index list is not written, used shortened source range (maDocSrcRange) for performance
789 0 : const ScRange& rRange = HasItemIndexList() ? maExpSrcRange : maDocSrcRange;
790 : // create a standard pivot cache field for each source column
791 0 : for( SCCOL nScCol = rRange.aStart.Col(), nEndScCol = rRange.aEnd.Col(); nScCol <= nEndScCol; ++nScCol )
792 : {
793 0 : ScRange aColRange( rRange );
794 0 : aColRange.aStart.SetCol( nScCol );
795 0 : aColRange.aEnd.SetCol( nScCol );
796 : maFieldList.AppendNewRecord( new XclExpPCField(
797 0 : GetRoot(), *this, GetFieldCount(), rDPObj, aColRange ) );
798 : }
799 0 : }
800 :
801 0 : void XclExpPivotCache::AddGroupFields( const ScDPObject& rDPObj )
802 : {
803 0 : if( const ScDPSaveData* pSaveData = rDPObj.GetSaveData() )
804 : {
805 0 : if( const ScDPDimensionSaveData* pSaveDimData = pSaveData->GetExistingDimensionData() )
806 : {
807 : // loop over all existing standard fields to find their group fields
808 0 : for( sal_uInt16 nFieldIdx = 0; nFieldIdx < maPCInfo.mnStdFields; ++nFieldIdx )
809 : {
810 0 : if( XclExpPCField* pCurrStdField = GetFieldAcc( nFieldIdx ) )
811 : {
812 0 : const ScDPSaveGroupDimension* pGroupDim = pSaveDimData->GetGroupDimForBase( pCurrStdField->GetFieldName() );
813 0 : XclExpPCField* pLastGroupField = pCurrStdField;
814 0 : while( pGroupDim )
815 : {
816 : // insert the new grouping field
817 : XclExpPCFieldRef xNewGroupField( new XclExpPCField(
818 0 : GetRoot(), *this, GetFieldCount(), rDPObj, *pGroupDim, *pCurrStdField ) );
819 0 : maFieldList.AppendRecord( xNewGroupField );
820 :
821 : // register new grouping field at current grouping field, building a chain
822 0 : pLastGroupField->SetGroupChildField( *xNewGroupField );
823 :
824 : // next grouping dimension
825 0 : pGroupDim = pSaveDimData->GetGroupDimForBase( pGroupDim->GetGroupDimName() );
826 0 : pLastGroupField = xNewGroupField.get();
827 0 : }
828 : }
829 : }
830 : }
831 : }
832 0 : }
833 :
834 0 : void XclExpPivotCache::AddCalcFields( const ScDPObject& /*rDPObj*/ )
835 : {
836 : // not supported
837 0 : }
838 :
839 0 : void XclExpPivotCache::WriteDconref( XclExpStream& rStrm ) const
840 : {
841 0 : XclExpString aRef( XclExpUrlHelper::EncodeUrl( GetRoot(), EMPTY_STRING, &maTabName ) );
842 0 : rStrm.StartRecord( EXC_ID_DCONREF, 7 + aRef.GetSize() );
843 0 : rStrm << static_cast< sal_uInt16 >( maExpSrcRange.aStart.Row() )
844 0 : << static_cast< sal_uInt16 >( maExpSrcRange.aEnd.Row() )
845 0 : << static_cast< sal_uInt8 >( maExpSrcRange.aStart.Col() )
846 0 : << static_cast< sal_uInt8 >( maExpSrcRange.aEnd.Col() )
847 0 : << aRef
848 0 : << sal_uInt8( 0 );
849 0 : rStrm.EndRecord();
850 0 : }
851 :
852 0 : void XclExpPivotCache::WriteDConName( XclExpStream& rStrm ) const
853 : {
854 0 : XclExpString aName(maSrcRangeName);
855 0 : rStrm.StartRecord(EXC_ID_DCONNAME, aName.GetSize() + 2);
856 0 : rStrm << aName << sal_uInt16(0);
857 0 : rStrm.EndRecord();
858 0 : }
859 :
860 0 : void XclExpPivotCache::WriteCacheStream()
861 : {
862 0 : SotStorageRef xSvStrg = OpenStorage( EXC_STORAGE_PTCACHE );
863 0 : SotStorageStreamRef xSvStrm = OpenStream( xSvStrg, ScfTools::GetHexStr( maPCInfo.mnStrmId ) );
864 0 : if( xSvStrm.Is() )
865 : {
866 0 : XclExpStream aStrm( *xSvStrm, GetRoot() );
867 : // SXDB
868 0 : WriteSxdb( aStrm );
869 : // SXDBEX
870 0 : WriteSxdbex( aStrm );
871 : // field list (SXFIELD and items)
872 0 : maFieldList.Save( aStrm );
873 : // index table (list of SXINDEXLIST)
874 0 : WriteSxindexlistList( aStrm );
875 : // EOF
876 0 : XclExpEmptyRecord( EXC_ID_EOF ).Save( aStrm );
877 0 : }
878 0 : }
879 :
880 0 : void XclExpPivotCache::WriteSxdb( XclExpStream& rStrm ) const
881 : {
882 0 : rStrm.StartRecord( EXC_ID_SXDB, 21 );
883 0 : rStrm << maPCInfo;
884 0 : rStrm.EndRecord();
885 0 : }
886 :
887 0 : void XclExpPivotCache::WriteSxdbex( XclExpStream& rStrm ) const
888 : {
889 0 : rStrm.StartRecord( EXC_ID_SXDBEX, 12 );
890 0 : rStrm << EXC_SXDBEX_CREATION_DATE
891 0 : << sal_uInt32( 0 ); // number of SXFORMULA records
892 0 : rStrm.EndRecord();
893 0 : }
894 :
895 0 : void XclExpPivotCache::WriteSxindexlistList( XclExpStream& rStrm ) const
896 : {
897 0 : if( HasItemIndexList() )
898 : {
899 0 : sal_Size nRecSize = 0;
900 0 : size_t nPos, nSize = maFieldList.GetSize();
901 0 : for( nPos = 0; nPos < nSize; ++nPos )
902 0 : nRecSize += maFieldList.GetRecord( nPos )->GetIndexSize();
903 :
904 0 : for( sal_uInt32 nSrcRow = 0; nSrcRow < maPCInfo.mnSrcRecs; ++nSrcRow )
905 : {
906 0 : rStrm.StartRecord( EXC_ID_SXINDEXLIST, nRecSize );
907 0 : for( nPos = 0; nPos < nSize; ++nPos )
908 0 : maFieldList.GetRecord( nPos )->WriteIndex( rStrm, nSrcRow );
909 0 : rStrm.EndRecord();
910 : }
911 : }
912 0 : }
913 :
914 : // ============================================================================
915 : // Pivot table
916 : // ============================================================================
917 :
918 : namespace {
919 :
920 : // ----------------------------------------------------------------------------
921 :
922 : /** Returns a display string for a data field containing the field name and aggregation function. */
923 0 : String lclGetDataFieldCaption( const String& rFieldName, GeneralFunction eFunc )
924 : {
925 0 : String aCaption;
926 :
927 0 : sal_uInt16 nResIdx = 0;
928 : using namespace ::com::sun::star::sheet;
929 0 : switch( eFunc )
930 : {
931 0 : case GeneralFunction_SUM: nResIdx = STR_FUN_TEXT_SUM; break;
932 0 : case GeneralFunction_COUNT: nResIdx = STR_FUN_TEXT_COUNT; break;
933 0 : case GeneralFunction_AVERAGE: nResIdx = STR_FUN_TEXT_AVG; break;
934 0 : case GeneralFunction_MAX: nResIdx = STR_FUN_TEXT_MAX; break;
935 0 : case GeneralFunction_MIN: nResIdx = STR_FUN_TEXT_MIN; break;
936 0 : case GeneralFunction_PRODUCT: nResIdx = STR_FUN_TEXT_PRODUCT; break;
937 0 : case GeneralFunction_COUNTNUMS: nResIdx = STR_FUN_TEXT_COUNT; break;
938 0 : case GeneralFunction_STDEV: nResIdx = STR_FUN_TEXT_STDDEV; break;
939 0 : case GeneralFunction_STDEVP: nResIdx = STR_FUN_TEXT_STDDEV; break;
940 0 : case GeneralFunction_VAR: nResIdx = STR_FUN_TEXT_VAR; break;
941 0 : case GeneralFunction_VARP: nResIdx = STR_FUN_TEXT_VAR; break;
942 : default:;
943 : }
944 0 : if( nResIdx )
945 0 : aCaption.Assign( ScGlobal::GetRscString( nResIdx ) ).AppendAscii( RTL_CONSTASCII_STRINGPARAM( " - " ) );
946 0 : aCaption.Append( rFieldName );
947 0 : return aCaption;
948 : }
949 :
950 : // ----------------------------------------------------------------------------
951 :
952 : } // namespace
953 :
954 : // ============================================================================
955 :
956 0 : XclExpPTItem::XclExpPTItem( const XclExpPCField& rCacheField, sal_uInt16 nCacheIdx ) :
957 : XclExpRecord( EXC_ID_SXVI, 8 ),
958 0 : mpCacheItem( rCacheField.GetItem( nCacheIdx ) )
959 : {
960 0 : maItemInfo.mnType = EXC_SXVI_TYPE_DATA;
961 0 : maItemInfo.mnCacheIdx = nCacheIdx;
962 0 : maItemInfo.maVisName.mbUseCache = mpCacheItem != 0;
963 0 : }
964 :
965 0 : XclExpPTItem::XclExpPTItem( sal_uInt16 nItemType, sal_uInt16 nCacheIdx, bool bUseCache ) :
966 : XclExpRecord( EXC_ID_SXVI, 8 ),
967 0 : mpCacheItem( 0 )
968 : {
969 0 : maItemInfo.mnType = nItemType;
970 0 : maItemInfo.mnCacheIdx = nCacheIdx;
971 0 : maItemInfo.maVisName.mbUseCache = bUseCache;
972 0 : }
973 :
974 0 : OUString XclExpPTItem::GetItemName() const
975 : {
976 0 : return mpCacheItem ? mpCacheItem->ConvertToText() : OUString();
977 : }
978 :
979 0 : void XclExpPTItem::SetPropertiesFromMember( const ScDPSaveMember& rSaveMem )
980 : {
981 : // #i115659# GetIsVisible() is not valid if HasIsVisible() returns false, default is 'visible' then
982 0 : ::set_flag( maItemInfo.mnFlags, EXC_SXVI_HIDDEN, rSaveMem.HasIsVisible() && !rSaveMem.GetIsVisible() );
983 : // #i115659# GetShowDetails() is not valid if HasShowDetails() returns false, default is 'show detail' then
984 0 : ::set_flag( maItemInfo.mnFlags, EXC_SXVI_HIDEDETAIL, rSaveMem.HasShowDetails() && !rSaveMem.GetShowDetails() );
985 :
986 : // visible name
987 0 : const OUString* pVisName = rSaveMem.GetLayoutName();
988 0 : if (pVisName && !pVisName->equals(GetItemName()))
989 0 : maItemInfo.SetVisName(*pVisName);
990 0 : }
991 :
992 0 : void XclExpPTItem::WriteBody( XclExpStream& rStrm )
993 : {
994 0 : rStrm << maItemInfo;
995 0 : }
996 :
997 : // ============================================================================
998 :
999 0 : XclExpPTField::XclExpPTField( const XclExpPivotTable& rPTable, sal_uInt16 nCacheIdx ) :
1000 : mrPTable( rPTable ),
1001 0 : mpCacheField( rPTable.GetCacheField( nCacheIdx ) )
1002 : {
1003 0 : maFieldInfo.mnCacheIdx = nCacheIdx;
1004 :
1005 : // create field items
1006 0 : if( mpCacheField )
1007 0 : for( sal_uInt16 nItemIdx = 0, nItemCount = mpCacheField->GetItemCount(); nItemIdx < nItemCount; ++nItemIdx )
1008 0 : maItemList.AppendNewRecord( new XclExpPTItem( *mpCacheField, nItemIdx ) );
1009 0 : maFieldInfo.mnItemCount = static_cast< sal_uInt16 >( maItemList.GetSize() );
1010 0 : }
1011 :
1012 : // data access ----------------------------------------------------------------
1013 :
1014 0 : OUString XclExpPTField::GetFieldName() const
1015 : {
1016 0 : return mpCacheField ? mpCacheField->GetFieldName() : OUString();
1017 : }
1018 :
1019 0 : sal_uInt16 XclExpPTField::GetFieldIndex() const
1020 : {
1021 : // field index always equal to cache index
1022 0 : return maFieldInfo.mnCacheIdx;
1023 : }
1024 :
1025 0 : sal_uInt16 XclExpPTField::GetLastDataInfoIndex() const
1026 : {
1027 : OSL_ENSURE( !maDataInfoVec.empty(), "XclExpPTField::GetLastDataInfoIndex - no data info found" );
1028 : // will return 0xFFFF for empty vector -> ok
1029 0 : return static_cast< sal_uInt16 >( maDataInfoVec.size() - 1 );
1030 : }
1031 :
1032 0 : sal_uInt16 XclExpPTField::GetItemIndex( const OUString& rName, sal_uInt16 nDefaultIdx ) const
1033 : {
1034 0 : for( size_t nPos = 0, nSize = maItemList.GetSize(); nPos < nSize; ++nPos )
1035 0 : if( maItemList.GetRecord( nPos )->GetItemName() == rName )
1036 0 : return static_cast< sal_uInt16 >( nPos );
1037 0 : return nDefaultIdx;
1038 : }
1039 :
1040 : // fill data --------------------------------------------------------------
1041 :
1042 : /**
1043 : * Calc's subtotal names are escaped with backslashes ('\'), while Excel's
1044 : * are not escaped at all.
1045 : */
1046 0 : static OUString lcl_convertCalcSubtotalName(const OUString& rName)
1047 : {
1048 0 : OUStringBuffer aBuf;
1049 0 : const sal_Unicode* p = rName.getStr();
1050 0 : sal_Int32 n = rName.getLength();
1051 0 : bool bEscaped = false;
1052 0 : for (sal_Int32 i = 0; i < n; ++i)
1053 : {
1054 0 : const sal_Unicode c = p[i];
1055 0 : if (!bEscaped && c == sal_Unicode('\\'))
1056 : {
1057 0 : bEscaped = true;
1058 0 : continue;
1059 : }
1060 :
1061 0 : aBuf.append(c);
1062 0 : bEscaped = false;
1063 : }
1064 0 : return aBuf.makeStringAndClear();
1065 : }
1066 :
1067 0 : void XclExpPTField::SetPropertiesFromDim( const ScDPSaveDimension& rSaveDim )
1068 : {
1069 : // orientation
1070 0 : DataPilotFieldOrientation eOrient = static_cast< DataPilotFieldOrientation >( rSaveDim.GetOrientation() );
1071 : OSL_ENSURE( eOrient != DataPilotFieldOrientation_DATA, "XclExpPTField::SetPropertiesFromDim - called for data field" );
1072 0 : maFieldInfo.AddApiOrient( eOrient );
1073 :
1074 : // show empty items (#i115659# GetShowEmpty() is not valid if HasShowEmpty() returns false, default is false then)
1075 0 : ::set_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_SHOWALL, rSaveDim.HasShowEmpty() && rSaveDim.GetShowEmpty() );
1076 :
1077 : // visible name
1078 0 : const OUString* pLayoutName = rSaveDim.GetLayoutName();
1079 0 : if (pLayoutName && !pLayoutName->equals(GetFieldName()))
1080 0 : maFieldInfo.SetVisName(*pLayoutName);
1081 :
1082 0 : const OUString* pSubtotalName = rSaveDim.GetSubtotalName();
1083 0 : if (pSubtotalName)
1084 : {
1085 0 : OUString aSubName = lcl_convertCalcSubtotalName(*pSubtotalName);
1086 0 : maFieldExtInfo.mpFieldTotalName.reset(new OUString(aSubName));
1087 : }
1088 :
1089 : // subtotals
1090 0 : XclPTSubtotalVec aSubtotals;
1091 0 : aSubtotals.reserve( static_cast< size_t >( rSaveDim.GetSubTotalsCount() ) );
1092 0 : for( long nSubtIdx = 0, nSubtCount = rSaveDim.GetSubTotalsCount(); nSubtIdx < nSubtCount; ++nSubtIdx )
1093 0 : aSubtotals.push_back( rSaveDim.GetSubTotalFunc( nSubtIdx ) );
1094 0 : maFieldInfo.SetSubtotals( aSubtotals );
1095 :
1096 : // sorting
1097 0 : if( const DataPilotFieldSortInfo* pSortInfo = rSaveDim.GetSortInfo() )
1098 : {
1099 0 : maFieldExtInfo.SetApiSortMode( pSortInfo->Mode );
1100 0 : if( pSortInfo->Mode == ::com::sun::star::sheet::DataPilotFieldSortMode::DATA )
1101 0 : maFieldExtInfo.mnSortField = mrPTable.GetDataFieldIndex( pSortInfo->Field, EXC_SXVDEX_SORT_OWN );
1102 0 : ::set_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_SORT_ASC, pSortInfo->IsAscending );
1103 : }
1104 :
1105 : // auto show
1106 0 : if( const DataPilotFieldAutoShowInfo* pShowInfo = rSaveDim.GetAutoShowInfo() )
1107 : {
1108 0 : ::set_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_AUTOSHOW, pShowInfo->IsEnabled );
1109 0 : maFieldExtInfo.SetApiAutoShowMode( pShowInfo->ShowItemsMode );
1110 0 : maFieldExtInfo.SetApiAutoShowCount( pShowInfo->ItemCount );
1111 0 : maFieldExtInfo.mnShowField = mrPTable.GetDataFieldIndex( pShowInfo->DataField, EXC_SXVDEX_SHOW_NONE );
1112 : }
1113 :
1114 : // layout
1115 0 : if( const DataPilotFieldLayoutInfo* pLayoutInfo = rSaveDim.GetLayoutInfo() )
1116 : {
1117 0 : maFieldExtInfo.SetApiLayoutMode( pLayoutInfo->LayoutMode );
1118 0 : ::set_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_LAYOUT_BLANK, pLayoutInfo->AddEmptyLines );
1119 : }
1120 :
1121 : // special page field properties
1122 0 : if( eOrient == DataPilotFieldOrientation_PAGE )
1123 : {
1124 0 : maPageInfo.mnField = GetFieldIndex();
1125 0 : maPageInfo.mnSelItem = EXC_SXPI_ALLITEMS;
1126 : }
1127 :
1128 : // item properties
1129 0 : const ScDPSaveDimension::MemberList &rMembers = rSaveDim.GetMembers();
1130 0 : for (ScDPSaveDimension::MemberList::const_iterator i=rMembers.begin(); i != rMembers.end() ; ++i)
1131 0 : if( XclExpPTItem* pItem = GetItemAcc( (*i)->GetName() ) )
1132 0 : pItem->SetPropertiesFromMember( **i );
1133 0 : }
1134 :
1135 0 : void XclExpPTField::SetDataPropertiesFromDim( const ScDPSaveDimension& rSaveDim )
1136 : {
1137 0 : maDataInfoVec.push_back( XclPTDataFieldInfo() );
1138 0 : XclPTDataFieldInfo& rDataInfo = maDataInfoVec.back();
1139 0 : rDataInfo.mnField = GetFieldIndex();
1140 :
1141 : // orientation
1142 0 : maFieldInfo.AddApiOrient( DataPilotFieldOrientation_DATA );
1143 :
1144 : // aggregation function
1145 0 : GeneralFunction eFunc = static_cast< GeneralFunction >( rSaveDim.GetFunction() );
1146 0 : rDataInfo.SetApiAggFunc( eFunc );
1147 :
1148 : // visible name
1149 0 : const OUString* pVisName = rSaveDim.GetLayoutName();
1150 0 : if (pVisName)
1151 0 : rDataInfo.SetVisName(*pVisName);
1152 : else
1153 0 : rDataInfo.SetVisName( lclGetDataFieldCaption( GetFieldName(), eFunc ) );
1154 :
1155 : // result field reference
1156 0 : if( const DataPilotFieldReference* pFieldRef = rSaveDim.GetReferenceValue() )
1157 : {
1158 0 : rDataInfo.SetApiRefType( pFieldRef->ReferenceType );
1159 0 : rDataInfo.SetApiRefItemType( pFieldRef->ReferenceItemType );
1160 0 : if( const XclExpPTField* pRefField = mrPTable.GetField( pFieldRef->ReferenceField ) )
1161 : {
1162 0 : rDataInfo.mnRefField = pRefField->GetFieldIndex();
1163 0 : if( pFieldRef->ReferenceItemType == ::com::sun::star::sheet::DataPilotFieldReferenceItemType::NAMED )
1164 0 : rDataInfo.mnRefItem = pRefField->GetItemIndex( pFieldRef->ReferenceItemName, 0 );
1165 : }
1166 : }
1167 0 : }
1168 :
1169 0 : void XclExpPTField::AppendSubtotalItems()
1170 : {
1171 0 : if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_DEFAULT ) AppendSubtotalItem( EXC_SXVI_TYPE_DEFAULT );
1172 0 : if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_SUM ) AppendSubtotalItem( EXC_SXVI_TYPE_SUM );
1173 0 : if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_COUNT ) AppendSubtotalItem( EXC_SXVI_TYPE_COUNT );
1174 0 : if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_AVERAGE ) AppendSubtotalItem( EXC_SXVI_TYPE_AVERAGE );
1175 0 : if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_MAX ) AppendSubtotalItem( EXC_SXVI_TYPE_MAX );
1176 0 : if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_MIN ) AppendSubtotalItem( EXC_SXVI_TYPE_MIN );
1177 0 : if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_PROD ) AppendSubtotalItem( EXC_SXVI_TYPE_PROD );
1178 0 : if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_COUNTNUM ) AppendSubtotalItem( EXC_SXVI_TYPE_COUNTNUM );
1179 0 : if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_STDDEV ) AppendSubtotalItem( EXC_SXVI_TYPE_STDDEV );
1180 0 : if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_STDDEVP ) AppendSubtotalItem( EXC_SXVI_TYPE_STDDEVP );
1181 0 : if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_VAR ) AppendSubtotalItem( EXC_SXVI_TYPE_VAR );
1182 0 : if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_VARP ) AppendSubtotalItem( EXC_SXVI_TYPE_VARP );
1183 0 : }
1184 :
1185 : // records --------------------------------------------------------------------
1186 :
1187 0 : void XclExpPTField::WriteSxpiEntry( XclExpStream& rStrm ) const
1188 : {
1189 0 : rStrm << maPageInfo;
1190 0 : }
1191 :
1192 0 : void XclExpPTField::WriteSxdi( XclExpStream& rStrm, sal_uInt16 nDataInfoIdx ) const
1193 : {
1194 : OSL_ENSURE( nDataInfoIdx < maDataInfoVec.size(), "XclExpPTField::WriteSxdi - data field not found" );
1195 0 : if( nDataInfoIdx < maDataInfoVec.size() )
1196 : {
1197 0 : rStrm.StartRecord( EXC_ID_SXDI, 12 );
1198 0 : rStrm << maDataInfoVec[ nDataInfoIdx ];
1199 0 : rStrm.EndRecord();
1200 : }
1201 0 : }
1202 :
1203 0 : void XclExpPTField::Save( XclExpStream& rStrm )
1204 : {
1205 : // SXVD
1206 0 : WriteSxvd( rStrm );
1207 : // list of SXVI records
1208 0 : maItemList.Save( rStrm );
1209 : // SXVDEX
1210 0 : WriteSxvdex( rStrm );
1211 0 : }
1212 :
1213 : // private --------------------------------------------------------------------
1214 :
1215 0 : XclExpPTItem* XclExpPTField::GetItemAcc( const OUString& rName )
1216 : {
1217 0 : XclExpPTItem* pItem = 0;
1218 0 : for( size_t nPos = 0, nSize = maItemList.GetSize(); !pItem && (nPos < nSize); ++nPos )
1219 0 : if( maItemList.GetRecord( nPos )->GetItemName() == rName )
1220 0 : pItem = maItemList.GetRecord( nPos ).get();
1221 0 : return pItem;
1222 : }
1223 :
1224 0 : void XclExpPTField::AppendSubtotalItem( sal_uInt16 nItemType )
1225 : {
1226 0 : maItemList.AppendNewRecord( new XclExpPTItem( nItemType, EXC_SXVI_DEFAULT_CACHE, true ) );
1227 0 : ++maFieldInfo.mnItemCount;
1228 0 : }
1229 :
1230 0 : void XclExpPTField::WriteSxvd( XclExpStream& rStrm ) const
1231 : {
1232 0 : rStrm.StartRecord( EXC_ID_SXVD, 10 );
1233 0 : rStrm << maFieldInfo;
1234 0 : rStrm.EndRecord();
1235 0 : }
1236 :
1237 0 : void XclExpPTField::WriteSxvdex( XclExpStream& rStrm ) const
1238 : {
1239 0 : rStrm.StartRecord( EXC_ID_SXVDEX, 20 );
1240 0 : rStrm << maFieldExtInfo;
1241 0 : rStrm.EndRecord();
1242 0 : }
1243 :
1244 : // ============================================================================
1245 :
1246 0 : XclExpPivotTable::XclExpPivotTable( const XclExpRoot& rRoot, const ScDPObject& rDPObj, const XclExpPivotCache& rPCache ) :
1247 : XclExpRoot( rRoot ),
1248 : mrPCache( rPCache ),
1249 : maDataOrientField( *this, EXC_SXIVD_DATA ),
1250 : mnOutScTab( 0 ),
1251 : mbValid( false ),
1252 0 : mbFilterBtn( false )
1253 : {
1254 0 : const ScRange& rOutScRange = rDPObj.GetOutRange();
1255 0 : if( GetAddressConverter().ConvertRange( maPTInfo.maOutXclRange, rOutScRange, true ) )
1256 : {
1257 : // DataPilot properties -----------------------------------------------
1258 :
1259 : // pivot table properties from DP object
1260 0 : mnOutScTab = rOutScRange.aStart.Tab();
1261 0 : maPTInfo.maTableName = rDPObj.GetName();
1262 0 : maPTInfo.mnCacheIdx = mrPCache.GetCacheIndex();
1263 :
1264 0 : maPTViewEx9Info.Init( rDPObj );
1265 :
1266 0 : if( const ScDPSaveData* pSaveData = rDPObj.GetSaveData() )
1267 : {
1268 : // additional properties from ScDPSaveData
1269 0 : SetPropertiesFromDP( *pSaveData );
1270 :
1271 : // loop over all dimensions ---------------------------------------
1272 :
1273 : /* 1) Default-construct all pivot table fields for all pivot cache fields. */
1274 0 : for( sal_uInt16 nFieldIdx = 0, nFieldCount = mrPCache.GetFieldCount(); nFieldIdx < nFieldCount; ++nFieldIdx )
1275 0 : maFieldList.AppendNewRecord( new XclExpPTField( *this, nFieldIdx ) );
1276 :
1277 0 : boost::ptr_vector<ScDPSaveDimension>::const_iterator iter;
1278 0 : const ScDPSaveData::DimsType& rDimList = pSaveData->GetDimensions();
1279 :
1280 : /* 2) First process all data dimensions, they are needed for extended
1281 : settings of row/column/page fields (sorting/auto show). */
1282 0 : for (iter = rDimList.begin(); iter != rDimList.end(); ++iter)
1283 0 : if (iter->GetOrientation() == DataPilotFieldOrientation_DATA)
1284 0 : SetDataFieldPropertiesFromDim(*iter);
1285 :
1286 : /* 3) Row/column/page/hidden fields. */
1287 0 : for (iter = rDimList.begin(); iter != rDimList.end(); ++iter)
1288 0 : if (iter->GetOrientation() != DataPilotFieldOrientation_DATA)
1289 0 : SetFieldPropertiesFromDim(*iter);
1290 :
1291 : // Finalize -------------------------------------------------------
1292 :
1293 0 : Finalize();
1294 0 : mbValid = true;
1295 : }
1296 : }
1297 0 : }
1298 :
1299 0 : const XclExpPCField* XclExpPivotTable::GetCacheField( sal_uInt16 nCacheIdx ) const
1300 : {
1301 0 : return mrPCache.GetField( nCacheIdx );
1302 : }
1303 :
1304 0 : const XclExpPTField* XclExpPivotTable::GetField( sal_uInt16 nFieldIdx ) const
1305 : {
1306 0 : return (nFieldIdx == EXC_SXIVD_DATA) ? &maDataOrientField : maFieldList.GetRecord( nFieldIdx ).get();
1307 : }
1308 :
1309 0 : const XclExpPTField* XclExpPivotTable::GetField( const OUString& rName ) const
1310 : {
1311 0 : return const_cast< XclExpPivotTable* >( this )->GetFieldAcc( rName );
1312 : }
1313 :
1314 0 : sal_uInt16 XclExpPivotTable::GetDataFieldIndex( const OUString& rName, sal_uInt16 nDefaultIdx ) const
1315 : {
1316 0 : for( XclPTDataFieldPosVec::const_iterator aIt = maDataFields.begin(), aEnd = maDataFields.end(); aIt != aEnd; ++aIt )
1317 0 : if( const XclExpPTField* pField = GetField( aIt->first ) )
1318 0 : if( pField->GetFieldName() == rName )
1319 0 : return static_cast< sal_uInt16 >( aIt - maDataFields.begin() );
1320 0 : return nDefaultIdx;
1321 : }
1322 :
1323 0 : void XclExpPivotTable::Save( XclExpStream& rStrm )
1324 : {
1325 0 : if( mbValid )
1326 : {
1327 : // SXVIEW
1328 0 : WriteSxview( rStrm );
1329 : // pivot table fields (SXVD, SXVDEX, and item records)
1330 0 : maFieldList.Save( rStrm );
1331 : // SXIVD records for row and column fields
1332 0 : WriteSxivd( rStrm, maRowFields );
1333 0 : WriteSxivd( rStrm, maColFields );
1334 : // SXPI
1335 0 : WriteSxpi( rStrm );
1336 : // list of SXDI records containing data field info
1337 0 : WriteSxdiList( rStrm );
1338 : // SXLI records
1339 0 : WriteSxli( rStrm, maPTInfo.mnDataRows, maPTInfo.mnRowFields );
1340 0 : WriteSxli( rStrm, maPTInfo.mnDataCols, maPTInfo.mnColFields );
1341 : // SXEX
1342 0 : WriteSxex( rStrm );
1343 : // QSISXTAG
1344 0 : WriteQsiSxTag( rStrm );
1345 : // SXVIEWEX9
1346 0 : WriteSxViewEx9( rStrm );
1347 : }
1348 0 : }
1349 :
1350 0 : void XclExpPivotTable::SaveXml( XclExpXmlStream& rStrm )
1351 : {
1352 0 : if( !mbValid )
1353 0 : return;
1354 : sax_fastparser::FSHelperPtr aPivotTableDefinition = rStrm.CreateOutputStream(
1355 0 : XclXmlUtils::GetStreamName( "xl/", "pivotTables/pivotTable", mnOutScTab+1),
1356 0 : XclXmlUtils::GetStreamName( "../", "pivotTables/pivotTable", mnOutScTab+1),
1357 0 : rStrm.GetCurrentStream()->getOutputStream(),
1358 : "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml",
1359 0 : "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable");
1360 0 : rStrm.PushStream( aPivotTableDefinition );
1361 :
1362 : aPivotTableDefinition->startElement( XML_pivotTableDefinition,
1363 : XML_xmlns, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
1364 : XML_name, XclXmlUtils::ToOString( maPTInfo.maTableName ).getStr(),
1365 : XML_cacheId, OString::valueOf( (sal_Int32) maPTInfo.mnCacheIdx ).getStr(),
1366 : XML_dataOnRows, XclXmlUtils::ToPsz( maPTInfo.mnDataAxis == EXC_SXVD_AXIS_COL ),
1367 : XML_dataPosition, OString::valueOf( (sal_Int32) maPTInfo.mnDataPos ).getStr(),
1368 : XML_autoFormatId, OString::valueOf( (sal_Int32) maPTInfo.mnAutoFmtIdx ).getStr(),
1369 : // OOXTODO: XML_applyNumberFormats, [ SXVIEW fAtrNum (maPTInfo.mnFlags) ]
1370 : // OOXTODO: XML_applyBorderFormats, [ SXVIEW fAtrBdr (maPTInfo.mnFlags) ]
1371 : // OOXTODO: XML_applyFontFormats, [ SXVIEW fAtrFnt (maPTInfo.mnFlags) ]
1372 : // OOXTODO: XML_applyPatternFormats, [ SXVIEW fAtrPat (maPTInfo.mnFlags) ]
1373 : // OOXTODO: XML_applyAlignmentFormats, [ SXVIEW fAtrAlc (maPTInfo.mnFlags) ]
1374 : // OOXTODO: XML_applyWidthHeightFormats, [ SXVIEW fAtrProc (maPTInfo.mnFlags) ]
1375 : XML_dataCaption, XclXmlUtils::ToOString( maPTInfo.maDataName ).getStr(),
1376 : // OOXTODO: XML_grandTotalCaption, [ SxViewEx9 chGrand ]
1377 : // OOXTODO: XML_errorCaption, [ SXEx stError ]
1378 : // OOXTODO: XML_showError, [ SXEx fDisplayErrorString ]
1379 : // OOXTODO: XML_missingCaption, [ SXEx stDisplayNull ]
1380 : // OOXTODO: XML_showMissing, [ SXEx fDisplayNullString ]
1381 : // OOXTODO: XML_pageStyle, [ SXEx stPageFieldStyle ]
1382 : // OOXTODO: XML_pivotTableStyle, [ SXEx stTableStyle ]
1383 : // OOXTODO: XML_vacatedStyle, [ SXEx stVacateStyle ]
1384 : // OOXTODO: XML_tag, [ SXEx stTag ]
1385 : // OOXTODO: XML_updatedVersion, [ app-dependent ]
1386 : // OOXTODO: XML_minRefreshableVersion, [ app-dependent ]
1387 : // OOXTODO: XML_asteriskTotals, [ QsiSXTag/SXView9Save fHideTotAnnotation ]
1388 : // OOXTODO: XML_showItems, [ ??? ]
1389 : // OOXTODO: XML_editData, [ ??? ]
1390 : // OOXTODO: XML_disableFieldList, [ SXEx fEnableFieldDialog? ]
1391 : // OOXTODO: XML_showCalcMbrs, [ ??? ]
1392 : // OOXTODO: XML_visualTotals, [ ??? ]
1393 : // OOXTODO: XML_showMultipleLabel, [ SXEx fMergeLabels? ]
1394 : // OOXTODO: XML_showDataDropDown, [ SXEx fEnableDrillDown? ]
1395 : // OOXTODO: XML_showDrill, [ ??? ]
1396 : // OOXTODO: XML_printDrill, [ ??? ]
1397 : // OOXTODO: XML_showMemberPropertyTips,
1398 : // OOXTODO: XML_showDataTips,
1399 : // OOXTODO: XML_enableWizard,
1400 0 : XML_enableDrill, XclXmlUtils::ToPsz( maPTExtInfo.mnFlags & EXC_SXEX_DRILLDOWN ), // ???
1401 : // OOXTODO: XML_enableFieldProperties, [ SXEx fEnableFieldDialog (maPTExtInfo.mnFlags) ]
1402 : // OOXTODO: XML_preserveFormatting, [ SXEx fPreserveFormatting (maPTExtInfo.mnFlags) ]
1403 : // OOXTODO: XML_pageWrap, [ SXEx cWrapPage (maPTExtInfo.mnFlags) ]
1404 : // OOXTODO: XML_pageOverThenDown, [ SXEx fAcrossPageLay (maPTExtInfo.mnFlags) ]
1405 : // OOXTODO: XML_subtotalHiddenItems, [ SXEx fSubtotalHiddenPageItems (maPTExtInfo.mnFlags) ]
1406 0 : XML_rowGrandTotals, XclXmlUtils::ToPsz( maPTInfo.mnFlags & EXC_SXVIEW_ROWGRAND ),
1407 0 : XML_colGrandTotals, XclXmlUtils::ToPsz( maPTInfo.mnFlags & EXC_SXVIEW_COLGRAND ),
1408 : // OOXTODO: XML_fieldPrintTitles,
1409 : // OOXTODO: XML_itemPrintTitles,
1410 : // OOXTODO: XML_mergeItem,
1411 : // OOXTODO: XML_showDropZones,
1412 : // OOXTODO: XML_createdVersion,
1413 : // OOXTODO: XML_indent,
1414 : // OOXTODO: XML_showEmptyRow,
1415 : // OOXTODO: XML_showEmptyCol,
1416 : // OOXTODO: XML_showHeaders,
1417 : // OOXTODO: XML_compact,
1418 : // OOXTODO: XML_outline,
1419 : // OOXTODO: XML_outlineData,
1420 : // OOXTODO: XML_compactData,
1421 : // OOXTODO: XML_published,
1422 : // OOXTODO: XML_gridDropZones,
1423 : // OOXTODO: XML_immersive,
1424 : // OOXTODO: XML_multipleFieldFilters,
1425 : // OOXTODO: XML_chartFormat,
1426 : // OOXTODO: XML_rowHeaderCaption,
1427 : // OOXTODO: XML_colHeaderCaption,
1428 : // OOXTODO: XML_fieldListSortAscending,
1429 : // OOXTODO: XML_mdxSubqueries,
1430 : // OOXTODO: XML_customListSort,
1431 0 : FSEND );
1432 :
1433 : aPivotTableDefinition->singleElement( XML_location,
1434 : XML_ref, XclXmlUtils::ToOString( maPTInfo.maOutXclRange ).getStr(),
1435 : XML_firstHeaderRow, OString::valueOf( (sal_Int32) maPTInfo.mnFirstHeadRow ).getStr(),
1436 : XML_firstDataRow, OString::valueOf( (sal_Int32) maPTInfo.maDataXclPos.mnRow ).getStr(),
1437 : XML_firstDataCol, OString::valueOf( (sal_Int32) maPTInfo.maDataXclPos.mnCol ).getStr(),
1438 : XML_rowPageCount, OString::valueOf( (sal_Int32) maPTInfo.mnDataRows ).getStr(), // OOXTODO?
1439 : XML_colPageCount, OString::valueOf( (sal_Int32) maPTInfo.mnDataCols ).getStr(), // OOXTODO?
1440 0 : FSEND );
1441 :
1442 : // OOXTODO: XML_pivotFields
1443 :
1444 : // maPTInfo.mnFields?
1445 0 : if( maPTInfo.mnRowFields )
1446 : {
1447 : aPivotTableDefinition->startElement( XML_rowFields,
1448 : XML_count, OString::valueOf( (sal_Int32) maPTInfo.mnRowFields ).getStr(),
1449 0 : FSEND );
1450 0 : aPivotTableDefinition->endElement( XML_rowFields );
1451 : }
1452 :
1453 : // OOXTODO: XML_rowItems
1454 :
1455 0 : if( maPTInfo.mnColFields )
1456 : {
1457 : aPivotTableDefinition->startElement( XML_colFields,
1458 : XML_count, OString::valueOf( (sal_Int32) maPTInfo.mnColFields ).getStr(),
1459 0 : FSEND );
1460 0 : aPivotTableDefinition->endElement( XML_colFields );
1461 : }
1462 :
1463 : // OOXTODO: XML_colItems
1464 :
1465 0 : if( maPTInfo.mnPageFields )
1466 : {
1467 : aPivotTableDefinition->startElement( XML_pageFields,
1468 : XML_count, OString::valueOf( (sal_Int32) maPTInfo.mnPageFields ).getStr(),
1469 0 : FSEND );
1470 0 : aPivotTableDefinition->endElement( XML_pageFields );
1471 : }
1472 :
1473 0 : if( maPTInfo.mnDataFields )
1474 : {
1475 : aPivotTableDefinition->startElement( XML_dataFields,
1476 : XML_count, OString::valueOf( (sal_Int32) maPTInfo.mnDataFields ).getStr(),
1477 0 : FSEND );
1478 0 : aPivotTableDefinition->endElement( XML_dataFields );
1479 : }
1480 :
1481 : // OOXTODO: XML_formats, XML_conditionalFormats, XML_chartFormats,
1482 : // XML_pivotHierarchies, XML_pivotTableStyleInfo, XML_filters,
1483 : // XML_rowHierarchiesUsage, XML_colHierarchiesUsage, XML_ext
1484 :
1485 0 : aPivotTableDefinition->endElement( XML_pivotTableDefinition );
1486 :
1487 0 : rStrm.PopStream();
1488 : }
1489 :
1490 : // private --------------------------------------------------------------------
1491 :
1492 0 : XclExpPTField* XclExpPivotTable::GetFieldAcc( const OUString& rName )
1493 : {
1494 0 : XclExpPTField* pField = 0;
1495 0 : for( size_t nPos = 0, nSize = maFieldList.GetSize(); !pField && (nPos < nSize); ++nPos )
1496 0 : if( maFieldList.GetRecord( nPos )->GetFieldName() == rName )
1497 0 : pField = maFieldList.GetRecord( nPos ).get();
1498 0 : return pField;
1499 : }
1500 :
1501 0 : XclExpPTField* XclExpPivotTable::GetFieldAcc( const ScDPSaveDimension& rSaveDim )
1502 : {
1503 : // data field orientation field?
1504 0 : if( rSaveDim.IsDataLayout() )
1505 0 : return &maDataOrientField;
1506 :
1507 : // a real dimension
1508 0 : OUString aFieldName = ScDPUtil::getSourceDimensionName(rSaveDim.GetName());
1509 0 : return aFieldName.isEmpty() ? NULL : GetFieldAcc(aFieldName);
1510 : }
1511 :
1512 : // fill data --------------------------------------------------------------
1513 :
1514 0 : void XclExpPivotTable::SetPropertiesFromDP( const ScDPSaveData& rSaveData )
1515 : {
1516 0 : ::set_flag( maPTInfo.mnFlags, EXC_SXVIEW_ROWGRAND, rSaveData.GetRowGrand() );
1517 0 : ::set_flag( maPTInfo.mnFlags, EXC_SXVIEW_COLGRAND, rSaveData.GetColumnGrand() );
1518 0 : ::set_flag( maPTExtInfo.mnFlags, EXC_SXEX_DRILLDOWN, rSaveData.GetDrillDown() );
1519 0 : mbFilterBtn = rSaveData.GetFilterButton();
1520 0 : const ScDPSaveDimension* pDim = rSaveData.GetExistingDataLayoutDimension();
1521 0 : if (!pDim)
1522 0 : return;
1523 :
1524 0 : const OUString* pLayoutName = pDim->GetLayoutName();
1525 0 : if (pLayoutName)
1526 0 : maPTInfo.maDataName = *pLayoutName;
1527 : else
1528 0 : maPTInfo.maDataName = ScGlobal::GetRscString(STR_PIVOT_DATA);
1529 : }
1530 :
1531 0 : void XclExpPivotTable::SetFieldPropertiesFromDim( const ScDPSaveDimension& rSaveDim )
1532 : {
1533 0 : if( XclExpPTField* pField = GetFieldAcc( rSaveDim ) )
1534 : {
1535 : // field properties
1536 0 : pField->SetPropertiesFromDim( rSaveDim );
1537 :
1538 : // update the corresponding field position list
1539 0 : DataPilotFieldOrientation eOrient = static_cast< DataPilotFieldOrientation >( rSaveDim.GetOrientation() );
1540 0 : sal_uInt16 nFieldIdx = pField->GetFieldIndex();
1541 0 : bool bDataLayout = nFieldIdx == EXC_SXIVD_DATA;
1542 0 : bool bMultiData = maDataFields.size() > 1;
1543 :
1544 0 : if( !bDataLayout || bMultiData ) switch( eOrient )
1545 : {
1546 : case DataPilotFieldOrientation_ROW:
1547 0 : maRowFields.push_back( nFieldIdx );
1548 0 : if( bDataLayout )
1549 0 : maPTInfo.mnDataAxis = EXC_SXVD_AXIS_ROW;
1550 0 : break;
1551 : case DataPilotFieldOrientation_COLUMN:
1552 0 : maColFields.push_back( nFieldIdx );
1553 0 : if( bDataLayout )
1554 0 : maPTInfo.mnDataAxis = EXC_SXVD_AXIS_COL;
1555 0 : break;
1556 : case DataPilotFieldOrientation_PAGE:
1557 0 : maPageFields.push_back( nFieldIdx );
1558 : OSL_ENSURE( !bDataLayout, "XclExpPivotTable::SetFieldPropertiesFromDim - wrong orientation for data fields" );
1559 0 : break;
1560 : case DataPilotFieldOrientation_DATA:
1561 : OSL_FAIL( "XclExpPivotTable::SetFieldPropertiesFromDim - called for data field" );
1562 0 : break;
1563 : default:;
1564 : }
1565 : }
1566 0 : }
1567 :
1568 0 : void XclExpPivotTable::SetDataFieldPropertiesFromDim( const ScDPSaveDimension& rSaveDim )
1569 : {
1570 0 : if( XclExpPTField* pField = GetFieldAcc( rSaveDim ) )
1571 : {
1572 : // field properties
1573 0 : pField->SetDataPropertiesFromDim( rSaveDim );
1574 : // update the data field position list
1575 0 : maDataFields.push_back( XclPTDataFieldPos( pField->GetFieldIndex(), pField->GetLastDataInfoIndex() ) );
1576 : }
1577 0 : }
1578 :
1579 0 : void XclExpPivotTable::Finalize()
1580 : {
1581 : // field numbers
1582 0 : maPTInfo.mnFields = static_cast< sal_uInt16 >( maFieldList.GetSize() );
1583 0 : maPTInfo.mnRowFields = static_cast< sal_uInt16 >( maRowFields.size() );
1584 0 : maPTInfo.mnColFields = static_cast< sal_uInt16 >( maColFields.size() );
1585 0 : maPTInfo.mnPageFields = static_cast< sal_uInt16 >( maPageFields.size() );
1586 0 : maPTInfo.mnDataFields = static_cast< sal_uInt16 >( maDataFields.size() );
1587 :
1588 0 : maPTExtInfo.mnPagePerRow = maPTInfo.mnPageFields;
1589 0 : maPTExtInfo.mnPagePerCol = (maPTInfo.mnPageFields > 0) ? 1 : 0;
1590 :
1591 : // subtotal items
1592 0 : for( size_t nPos = 0, nSize = maFieldList.GetSize(); nPos < nSize; ++nPos )
1593 0 : maFieldList.GetRecord( nPos )->AppendSubtotalItems();
1594 :
1595 : // find data field orientation field
1596 0 : maPTInfo.mnDataPos = EXC_SXVIEW_DATALAST;
1597 0 : const ScfUInt16Vec* pFieldVec = 0;
1598 0 : switch( maPTInfo.mnDataAxis )
1599 : {
1600 0 : case EXC_SXVD_AXIS_ROW: pFieldVec = &maRowFields; break;
1601 0 : case EXC_SXVD_AXIS_COL: pFieldVec = &maColFields; break;
1602 : }
1603 :
1604 0 : if( pFieldVec && !pFieldVec->empty() && (pFieldVec->back() != EXC_SXIVD_DATA) )
1605 : {
1606 0 : ScfUInt16Vec::const_iterator aIt = ::std::find( pFieldVec->begin(), pFieldVec->end(), EXC_SXIVD_DATA );
1607 0 : if( aIt != pFieldVec->end() )
1608 0 : maPTInfo.mnDataPos = static_cast< sal_uInt16 >( aIt - pFieldVec->begin() );
1609 : }
1610 :
1611 : // single data field is always row oriented
1612 0 : if( maPTInfo.mnDataAxis == EXC_SXVD_AXIS_NONE )
1613 0 : maPTInfo.mnDataAxis = EXC_SXVD_AXIS_ROW;
1614 :
1615 : // update output range (initialized in ctor)
1616 0 : sal_uInt16& rnXclCol1 = maPTInfo.maOutXclRange.maFirst.mnCol;
1617 0 : sal_uInt32& rnXclRow1 = maPTInfo.maOutXclRange.maFirst.mnRow;
1618 0 : sal_uInt16& rnXclCol2 = maPTInfo.maOutXclRange.maLast.mnCol;
1619 0 : sal_uInt32& rnXclRow2 = maPTInfo.maOutXclRange.maLast.mnRow;
1620 : // exclude page fields from output range
1621 0 : rnXclRow1 = rnXclRow1 + maPTInfo.mnPageFields;
1622 : // exclude filter button from output range
1623 0 : if( mbFilterBtn )
1624 0 : ++rnXclRow1;
1625 : // exclude empty row between (filter button and/or page fields) and table
1626 0 : if( mbFilterBtn || maPTInfo.mnPageFields )
1627 0 : ++rnXclRow1;
1628 :
1629 : // data area
1630 0 : sal_uInt16& rnDataXclCol = maPTInfo.maDataXclPos.mnCol;
1631 0 : sal_uInt32& rnDataXclRow = maPTInfo.maDataXclPos.mnRow;
1632 0 : rnDataXclCol = rnXclCol1 + maPTInfo.mnRowFields;
1633 0 : rnDataXclRow = rnXclRow1 + maPTInfo.mnColFields + 1;
1634 0 : if( maDataFields.empty() )
1635 0 : ++rnDataXclRow;
1636 :
1637 0 : bool bExtraHeaderRow = (0 == maPTViewEx9Info.mnGridLayout && maPTInfo.mnColFields == 0);
1638 0 : if (bExtraHeaderRow)
1639 : // Insert an extra row only when there is no column field.
1640 0 : ++rnDataXclRow;
1641 :
1642 0 : rnXclCol2 = ::std::max( rnXclCol2, rnDataXclCol );
1643 0 : rnXclRow2 = ::std::max( rnXclRow2, rnDataXclRow );
1644 0 : maPTInfo.mnDataCols = rnXclCol2 - rnDataXclCol + 1;
1645 0 : maPTInfo.mnDataRows = rnXclRow2 - rnDataXclRow + 1;
1646 :
1647 : // first heading
1648 0 : maPTInfo.mnFirstHeadRow = rnXclRow1;
1649 0 : if (bExtraHeaderRow)
1650 0 : maPTInfo.mnFirstHeadRow += 2;
1651 0 : }
1652 :
1653 : // records ----------------------------------------------------------------
1654 :
1655 0 : void XclExpPivotTable::WriteSxview( XclExpStream& rStrm ) const
1656 : {
1657 0 : rStrm.StartRecord( EXC_ID_SXVIEW, 46 + maPTInfo.maTableName.getLength() + maPTInfo.maDataName.getLength() );
1658 0 : rStrm << maPTInfo;
1659 0 : rStrm.EndRecord();
1660 0 : }
1661 :
1662 0 : void XclExpPivotTable::WriteSxivd( XclExpStream& rStrm, const ScfUInt16Vec& rFields ) const
1663 : {
1664 0 : if( !rFields.empty() )
1665 : {
1666 0 : rStrm.StartRecord( EXC_ID_SXIVD, rFields.size() * 2 );
1667 0 : for( ScfUInt16Vec::const_iterator aIt = rFields.begin(), aEnd = rFields.end(); aIt != aEnd; ++aIt )
1668 0 : rStrm << *aIt;
1669 0 : rStrm.EndRecord();
1670 : }
1671 0 : }
1672 :
1673 0 : void XclExpPivotTable::WriteSxpi( XclExpStream& rStrm ) const
1674 : {
1675 0 : if( !maPageFields.empty() )
1676 : {
1677 0 : rStrm.StartRecord( EXC_ID_SXPI, maPageFields.size() * 6 );
1678 0 : rStrm.SetSliceSize( 6 );
1679 0 : for( ScfUInt16Vec::const_iterator aIt = maPageFields.begin(), aEnd = maPageFields.end(); aIt != aEnd; ++aIt )
1680 : {
1681 0 : XclExpPTFieldRef xField = maFieldList.GetRecord( *aIt );
1682 0 : if( xField )
1683 0 : xField->WriteSxpiEntry( rStrm );
1684 0 : }
1685 0 : rStrm.EndRecord();
1686 : }
1687 0 : }
1688 :
1689 0 : void XclExpPivotTable::WriteSxdiList( XclExpStream& rStrm ) const
1690 : {
1691 0 : for( XclPTDataFieldPosVec::const_iterator aIt = maDataFields.begin(), aEnd = maDataFields.end(); aIt != aEnd; ++aIt )
1692 : {
1693 0 : XclExpPTFieldRef xField = maFieldList.GetRecord( aIt->first );
1694 0 : if( xField )
1695 0 : xField->WriteSxdi( rStrm, aIt->second );
1696 0 : }
1697 0 : }
1698 :
1699 0 : void XclExpPivotTable::WriteSxli( XclExpStream& rStrm, sal_uInt16 nLineCount, sal_uInt16 nIndexCount ) const
1700 : {
1701 0 : if( nLineCount > 0 )
1702 : {
1703 0 : sal_uInt16 nLineSize = 8 + 2 * nIndexCount;
1704 0 : rStrm.StartRecord( EXC_ID_SXLI, nLineSize * nLineCount );
1705 :
1706 : /* Excel expects the records to be filled completely, do not
1707 : set a segment size... */
1708 : // rStrm.SetSliceSize( nLineSize );
1709 :
1710 0 : for( sal_uInt16 nLine = 0; nLine < nLineCount; ++nLine )
1711 : {
1712 : // Excel XP needs a partly initialized SXLI record
1713 0 : rStrm << sal_uInt16( 0 ) // number of equal index entries
1714 0 : << EXC_SXVI_TYPE_DATA
1715 0 : << nIndexCount
1716 0 : << EXC_SXLI_DEFAULTFLAGS;
1717 0 : rStrm.WriteZeroBytes( 2 * nIndexCount );
1718 : }
1719 0 : rStrm.EndRecord();
1720 : }
1721 0 : }
1722 :
1723 0 : void XclExpPivotTable::WriteSxex( XclExpStream& rStrm ) const
1724 : {
1725 0 : rStrm.StartRecord( EXC_ID_SXEX, 24 );
1726 0 : rStrm << maPTExtInfo;
1727 0 : rStrm.EndRecord();
1728 0 : }
1729 :
1730 0 : void XclExpPivotTable::WriteQsiSxTag( XclExpStream& rStrm ) const
1731 : {
1732 0 : rStrm.StartRecord( 0x0802, 32 );
1733 :
1734 0 : sal_uInt16 nRecordType = 0x0802;
1735 0 : sal_uInt16 nDummyFlags = 0x0000;
1736 0 : sal_uInt16 nTableType = 1; // 0 = query table : 1 = pivot table
1737 :
1738 0 : rStrm << nRecordType << nDummyFlags << nTableType;
1739 :
1740 : // General flags
1741 0 : bool bEnableRefresh = true;
1742 0 : bool bPCacheInvalid = false;
1743 0 : bool bOlapPTReport = false;
1744 :
1745 0 : sal_uInt16 nFlags = 0x0000;
1746 0 : if (bEnableRefresh) nFlags |= 0x0001;
1747 0 : if (bPCacheInvalid) nFlags |= 0x0002;
1748 0 : if (bOlapPTReport) nFlags |= 0x0004;
1749 0 : rStrm << nFlags;
1750 :
1751 : // Feature-specific options. The value differs depending on the table
1752 : // type, but we assume the table type is always pivot table.
1753 0 : sal_uInt32 nOptions = 0x00000000;
1754 0 : bool bNoStencil = false;
1755 0 : bool bHideTotal = false;
1756 0 : bool bEmptyRows = false;
1757 0 : bool bEmptyCols = false;
1758 0 : if (bNoStencil) nOptions |= 0x00000001;
1759 0 : if (bHideTotal) nOptions |= 0x00000002;
1760 0 : if (bEmptyRows) nOptions |= 0x00000008;
1761 0 : if (bEmptyCols) nOptions |= 0x00000010;
1762 0 : rStrm << nOptions;
1763 :
1764 : enum ExcelVersion
1765 : {
1766 : Excel2000 = 0,
1767 : ExcelXP = 1,
1768 : Excel2003 = 2,
1769 : Excel2007 = 3
1770 : };
1771 0 : ExcelVersion eXclVer = Excel2000;
1772 0 : sal_uInt8 nOffsetBytes = 16;
1773 0 : rStrm << static_cast<sal_uInt8>(eXclVer) // version table last refreshed
1774 0 : << static_cast<sal_uInt8>(eXclVer) // minimum version to refresh
1775 0 : << nOffsetBytes
1776 0 : << static_cast<sal_uInt8>(eXclVer); // first version created
1777 :
1778 0 : rStrm << XclExpString(maPTInfo.maTableName);
1779 0 : rStrm << static_cast<sal_uInt16>(0x0001); // no idea what this is for.
1780 :
1781 0 : rStrm.EndRecord();
1782 0 : }
1783 :
1784 0 : void XclExpPivotTable::WriteSxViewEx9( XclExpStream& rStrm ) const
1785 : {
1786 : // Until we sync the autoformat ids only export if using grid header layout
1787 : // That could only have been set via xls import so far.
1788 0 : if ( 0 == maPTViewEx9Info.mnGridLayout )
1789 : {
1790 0 : rStrm.StartRecord( EXC_ID_SXVIEWEX9, 17 );
1791 0 : rStrm << maPTViewEx9Info;
1792 0 : rStrm.EndRecord();
1793 : }
1794 0 : }
1795 :
1796 : // ============================================================================
1797 :
1798 : namespace {
1799 :
1800 : const SCTAB EXC_PTMGR_PIVOTCACHES = SCTAB_MAX;
1801 :
1802 : /** Record wrapper class to write the pivot caches or pivot tables. */
1803 46 : class XclExpPivotRecWrapper : public XclExpRecordBase
1804 : {
1805 : public:
1806 : explicit XclExpPivotRecWrapper( XclExpPivotTableManager& rPTMgr, SCTAB nScTab );
1807 : virtual void Save( XclExpStream& rStrm );
1808 : virtual void SaveXml( XclExpXmlStream& rStrm );
1809 : private:
1810 : XclExpPivotTableManager& mrPTMgr;
1811 : SCTAB mnScTab;
1812 : };
1813 :
1814 23 : XclExpPivotRecWrapper::XclExpPivotRecWrapper( XclExpPivotTableManager& rPTMgr, SCTAB nScTab ) :
1815 : mrPTMgr( rPTMgr ),
1816 23 : mnScTab( nScTab )
1817 : {
1818 23 : }
1819 :
1820 8 : void XclExpPivotRecWrapper::Save( XclExpStream& rStrm )
1821 : {
1822 8 : if( mnScTab == EXC_PTMGR_PIVOTCACHES )
1823 3 : mrPTMgr.WritePivotCaches( rStrm );
1824 : else
1825 5 : mrPTMgr.WritePivotTables( rStrm, mnScTab );
1826 8 : }
1827 :
1828 15 : void XclExpPivotRecWrapper::SaveXml( XclExpXmlStream& rStrm )
1829 : {
1830 15 : if( mnScTab == EXC_PTMGR_PIVOTCACHES )
1831 6 : mrPTMgr.WritePivotCachesXml( rStrm );
1832 : else
1833 9 : mrPTMgr.WritePivotTablesXml( rStrm, mnScTab );
1834 15 : }
1835 :
1836 : } // namespace
1837 :
1838 : // ----------------------------------------------------------------------------
1839 :
1840 9 : XclExpPivotTableManager::XclExpPivotTableManager( const XclExpRoot& rRoot ) :
1841 : XclExpRoot( rRoot ),
1842 9 : mbShareCaches( true )
1843 : {
1844 9 : }
1845 :
1846 9 : void XclExpPivotTableManager::CreatePivotTables()
1847 : {
1848 9 : if( ScDPCollection* pDPColl = GetDoc().GetDPCollection() )
1849 9 : for( size_t nDPObj = 0, nCount = pDPColl->GetCount(); nDPObj < nCount; ++nDPObj )
1850 0 : if( ScDPObject* pDPObj = (*pDPColl)[ nDPObj ] )
1851 0 : if( const XclExpPivotCache* pPCache = CreatePivotCache( *pDPObj ) )
1852 0 : maPTableList.AppendNewRecord( new XclExpPivotTable( GetRoot(), *pDPObj, *pPCache ) );
1853 9 : }
1854 :
1855 9 : XclExpRecordRef XclExpPivotTableManager::CreatePivotCachesRecord()
1856 : {
1857 9 : return XclExpRecordRef( new XclExpPivotRecWrapper( *this, EXC_PTMGR_PIVOTCACHES ) );
1858 : }
1859 :
1860 14 : XclExpRecordRef XclExpPivotTableManager::CreatePivotTablesRecord( SCTAB nScTab )
1861 : {
1862 14 : return XclExpRecordRef( new XclExpPivotRecWrapper( *this, nScTab ) );
1863 : }
1864 :
1865 3 : void XclExpPivotTableManager::WritePivotCaches( XclExpStream& rStrm )
1866 : {
1867 3 : maPCacheList.Save( rStrm );
1868 3 : }
1869 :
1870 6 : void XclExpPivotTableManager::WritePivotCachesXml( XclExpXmlStream&
1871 : #ifdef XLSX_PIVOT_CACHE
1872 : rStrm
1873 : #endif
1874 : )
1875 : {
1876 : #ifdef XLSX_PIVOT_CACHE /* <pivotCache> without xl/pivotCaches/ cacheStream
1877 : results in a broken .xlsx */
1878 : if( maPCacheList.IsEmpty() )
1879 : return;
1880 : sax_fastparser::FSHelperPtr& rWorkbook = rStrm.GetCurrentStream();
1881 : rWorkbook->startElement( XML_pivotCaches, FSEND );
1882 : maPCacheList.SaveXml( rStrm );
1883 : rWorkbook->endElement( XML_pivotCaches );
1884 : #endif /* XLSX_PIVOT_CACHE */
1885 6 : }
1886 :
1887 5 : void XclExpPivotTableManager::WritePivotTables( XclExpStream& rStrm, SCTAB nScTab )
1888 : {
1889 5 : for( size_t nPos = 0, nSize = maPTableList.GetSize(); nPos < nSize; ++nPos )
1890 : {
1891 0 : XclExpPivotTableRef xPTable = maPTableList.GetRecord( nPos );
1892 0 : if( xPTable->GetScTab() == nScTab )
1893 0 : xPTable->Save( rStrm );
1894 0 : }
1895 5 : }
1896 :
1897 9 : void XclExpPivotTableManager::WritePivotTablesXml( XclExpXmlStream& rStrm, SCTAB nScTab )
1898 : {
1899 9 : for( size_t nPos = 0, nSize = maPTableList.GetSize(); nPos < nSize; ++nPos )
1900 : {
1901 0 : XclExpPivotTableRef xPTable = maPTableList.GetRecord( nPos );
1902 0 : if( xPTable->GetScTab() == nScTab )
1903 0 : xPTable->SaveXml( rStrm );
1904 0 : }
1905 9 : }
1906 :
1907 : // private --------------------------------------------------------------------
1908 :
1909 0 : const XclExpPivotCache* XclExpPivotTableManager::CreatePivotCache( const ScDPObject& rDPObj )
1910 : {
1911 : // try to find a pivot cache with the same data source
1912 : /* #i25110# In Excel, the pivot cache contains additional fields
1913 : (i.e. grouping info, calculated fields). If the passed DataPilot object
1914 : or the found cache contains this data, do not share the cache with
1915 : multiple pivot tables. */
1916 0 : if( mbShareCaches )
1917 : {
1918 0 : if( const ScDPSaveData* pSaveData = rDPObj.GetSaveData() )
1919 : {
1920 0 : const ScDPDimensionSaveData* pDimSaveData = pSaveData->GetExistingDimensionData();
1921 : // no dimension save data at all or save data does not contain grouping info
1922 0 : if( !pDimSaveData || !pDimSaveData->HasGroupDimensions() )
1923 : {
1924 : // check all existing pivot caches
1925 0 : for( size_t nPos = 0, nSize = maPCacheList.GetSize(); nPos < nSize; ++nPos )
1926 : {
1927 0 : XclExpPivotCacheRef xPCache = maPCacheList.GetRecord( nPos );
1928 : // pivot cache does not have grouping info and source data is equal
1929 0 : if( !xPCache->HasAddFields() && xPCache->HasEqualDataSource( rDPObj ) )
1930 0 : return xPCache.get();
1931 0 : }
1932 : }
1933 : }
1934 : }
1935 :
1936 : // create a new pivot cache
1937 0 : sal_uInt16 nNewCacheIdx = static_cast< sal_uInt16 >( maPCacheList.GetSize() );
1938 0 : XclExpPivotCacheRef xNewPCache( new XclExpPivotCache( GetRoot(), rDPObj, nNewCacheIdx ) );
1939 0 : if( xNewPCache->IsValid() )
1940 : {
1941 0 : maPCacheList.AppendRecord( xNewPCache );
1942 0 : return xNewPCache.get();
1943 : }
1944 :
1945 0 : return 0;
1946 15 : }
1947 :
1948 : // ============================================================================
1949 :
1950 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|