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