xref: /trunk/main/sc/source/filter/excel/xipivot.cxx (revision b77af630)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_scfilt.hxx"
24 
25 #include "xipivot.hxx"
26 
27 #include <com/sun/star/sheet/DataPilotFieldSortInfo.hpp>
28 #include <com/sun/star/sheet/DataPilotFieldAutoShowInfo.hpp>
29 #include <com/sun/star/sheet/DataPilotFieldLayoutInfo.hpp>
30 #include <com/sun/star/sheet/DataPilotFieldReference.hpp>
31 
32 #include <tools/datetime.hxx>
33 #include <svl/zformat.hxx>
34 #include <svl/intitem.hxx>
35 
36 #include "document.hxx"
37 #include "cell.hxx"
38 #include "dpsave.hxx"
39 #include "dpdimsave.hxx"
40 #include "dpobject.hxx"
41 #include "dpshttab.hxx"
42 #include "dpoutputgeometry.hxx"
43 #include "scitems.hxx"
44 #include "attrib.hxx"
45 
46 #include "xltracer.hxx"
47 #include "xistream.hxx"
48 #include "xihelper.hxx"
49 #include "xilink.hxx"
50 #include "xiescher.hxx"
51 
52 //! TODO ExcelToSc usage
53 #include "excform.hxx"
54 #include "xltable.hxx"
55 
56 #include <vector>
57 
58 using ::rtl::OUString;
59 using ::rtl::OUStringBuffer;
60 using ::com::sun::star::sheet::DataPilotFieldOrientation;
61 using ::com::sun::star::sheet::DataPilotFieldOrientation_DATA;
62 using ::com::sun::star::sheet::DataPilotFieldSortInfo;
63 using ::com::sun::star::sheet::DataPilotFieldAutoShowInfo;
64 using ::com::sun::star::sheet::DataPilotFieldLayoutInfo;
65 using ::com::sun::star::sheet::DataPilotFieldReference;
66 using ::std::vector;
67 
68 // ============================================================================
69 // Pivot cache
70 // ============================================================================
71 
XclImpPCItem(XclImpStream & rStrm)72 XclImpPCItem::XclImpPCItem( XclImpStream& rStrm )
73 {
74     switch( rStrm.GetRecId() )
75     {
76         case EXC_ID_SXDOUBLE:   ReadSxdouble( rStrm );      break;
77         case EXC_ID_SXBOOLEAN:  ReadSxboolean( rStrm );     break;
78         case EXC_ID_SXERROR:    ReadSxerror( rStrm );       break;
79         case EXC_ID_SXINTEGER:  ReadSxinteger( rStrm );     break;
80         case EXC_ID_SXSTRING:   ReadSxstring( rStrm );      break;
81         case EXC_ID_SXDATETIME: ReadSxdatetime( rStrm );    break;
82         case EXC_ID_SXEMPTY:    ReadSxempty( rStrm );       break;
83         default:    DBG_ERRORFILE( "XclImpPCItem::XclImpPCItem - unknown record id" );
84     }
85 }
86 
87 namespace {
88 
lclSetValue(const XclImpRoot & rRoot,const ScAddress & rScPos,double fValue,short nFormatType)89 void lclSetValue( const XclImpRoot& rRoot, const ScAddress& rScPos, double fValue, short nFormatType )
90 {
91     ScDocument& rDoc = rRoot.GetDoc();
92     rDoc.SetValue( rScPos.Col(), rScPos.Row(), rScPos.Tab(), fValue );
93     sal_uInt32 nScNumFmt = rRoot.GetFormatter().GetStandardFormat( nFormatType, rRoot.GetDocLanguage() );
94     rDoc.ApplyAttr( rScPos.Col(), rScPos.Row(), rScPos.Tab(), SfxUInt32Item( ATTR_VALUE_FORMAT, nScNumFmt ) );
95 }
96 
97 } // namespace
98 
WriteToSource(const XclImpRoot & rRoot,const ScAddress & rScPos) const99 void XclImpPCItem::WriteToSource( const XclImpRoot& rRoot, const ScAddress& rScPos ) const
100 {
101     ScDocument& rDoc = rRoot.GetDoc();
102     if( const String* pText = GetText() )
103         rDoc.SetString( rScPos.Col(), rScPos.Row(), rScPos.Tab(), *pText );
104     else if( const double* pfValue = GetDouble() )
105         rDoc.SetValue( rScPos.Col(), rScPos.Row(), rScPos.Tab(), *pfValue );
106     else if( const sal_Int16* pnValue = GetInteger() )
107         rDoc.SetValue( rScPos.Col(), rScPos.Row(), rScPos.Tab(), *pnValue );
108     else if( const bool* pbValue = GetBool() )
109         lclSetValue( rRoot, rScPos, *pbValue ? 1.0 : 0.0, NUMBERFORMAT_LOGICAL );
110     else if( const DateTime* pDateTime = GetDateTime() )
111     {
112         // set number format date, time, or date/time, depending on the value
113         double fValue = rRoot.GetDoubleFromDateTime( *pDateTime );
114         double fInt = 0.0;
115         double fFrac = modf( fValue, &fInt );
116         short nFormatType = ((fFrac == 0.0) && (fInt != 0.0)) ? NUMBERFORMAT_DATE :
117             ((fInt == 0.0) ? NUMBERFORMAT_TIME : NUMBERFORMAT_DATETIME);
118         lclSetValue( rRoot, rScPos, fValue, nFormatType );
119     }
120     else if( const sal_uInt16* pnError = GetError() )
121     {
122         double fValue;
123         sal_uInt8 nErrCode = static_cast< sal_uInt8 >( *pnError );
124         const ScTokenArray* pScTokArr = rRoot.GetOldFmlaConverter().GetBoolErr(
125             XclTools::ErrorToEnum( fValue, EXC_BOOLERR_ERROR, nErrCode ) );
126         ScFormulaCell* pCell = new ScFormulaCell( &rDoc, rScPos, pScTokArr );
127         pCell->SetHybridDouble( fValue );
128         rDoc.PutCell( rScPos, pCell );
129     }
130 }
131 
ReadSxdouble(XclImpStream & rStrm)132 void XclImpPCItem::ReadSxdouble( XclImpStream& rStrm )
133 {
134     DBG_ASSERT( rStrm.GetRecSize() == 8, "XclImpPCItem::ReadSxdouble - wrong record size" );
135     SetDouble( rStrm.ReadDouble() );
136 }
137 
ReadSxboolean(XclImpStream & rStrm)138 void XclImpPCItem::ReadSxboolean( XclImpStream& rStrm )
139 {
140     DBG_ASSERT( rStrm.GetRecSize() == 2, "XclImpPCItem::ReadSxboolean - wrong record size" );
141     SetBool( rStrm.ReaduInt16() != 0 );
142 }
143 
ReadSxerror(XclImpStream & rStrm)144 void XclImpPCItem::ReadSxerror( XclImpStream& rStrm )
145 {
146     DBG_ASSERT( rStrm.GetRecSize() == 2, "XclImpPCItem::ReadSxerror - wrong record size" );
147     SetError( rStrm.ReaduInt16() );
148 }
149 
ReadSxinteger(XclImpStream & rStrm)150 void XclImpPCItem::ReadSxinteger( XclImpStream& rStrm )
151 {
152     DBG_ASSERT( rStrm.GetRecSize() == 2, "XclImpPCItem::ReadSxinteger - wrong record size" );
153     SetInteger( rStrm.ReadInt16() );
154 }
155 
ReadSxstring(XclImpStream & rStrm)156 void XclImpPCItem::ReadSxstring( XclImpStream& rStrm )
157 {
158     DBG_ASSERT( rStrm.GetRecSize() >= 3, "XclImpPCItem::ReadSxstring - wrong record size" );
159     SetText( rStrm.ReadUniString() );
160 }
161 
ReadSxdatetime(XclImpStream & rStrm)162 void XclImpPCItem::ReadSxdatetime( XclImpStream& rStrm )
163 {
164     DBG_ASSERT( rStrm.GetRecSize() == 8, "XclImpPCItem::ReadSxdatetime - wrong record size" );
165     sal_uInt16 nYear, nMonth;
166     sal_uInt8 nDay, nHour, nMin, nSec;
167     rStrm >> nYear >> nMonth >> nDay >> nHour >> nMin >> nSec;
168     SetDateTime( DateTime( Date( nDay, nMonth, nYear ), Time( nHour, nMin, nSec ) ) );
169 }
170 
ReadSxempty(XclImpStream & rStrm)171 void XclImpPCItem::ReadSxempty( XclImpStream& rStrm )
172 {
173     (void)rStrm;    // avoid compiler warning
174     DBG_ASSERT( rStrm.GetRecSize() == 0, "XclImpPCItem::ReadSxempty - wrong record size" );
175     SetEmpty();
176 }
177 
178 // ============================================================================
179 
XclImpPCField(const XclImpRoot & rRoot,XclImpPivotCache & rPCache,sal_uInt16 nFieldIdx)180 XclImpPCField::XclImpPCField( const XclImpRoot& rRoot, XclImpPivotCache& rPCache, sal_uInt16 nFieldIdx ) :
181     XclPCField( EXC_PCFIELD_UNKNOWN, nFieldIdx ),
182     XclImpRoot( rRoot ),
183     mrPCache( rPCache ),
184     mnSourceScCol( -1 ),
185     mbNumGroupInfoRead( false )
186 {
187 }
188 
~XclImpPCField()189 XclImpPCField::~XclImpPCField()
190 {
191 }
192 
193 // general field/item access --------------------------------------------------
194 
GetFieldName(const ScfStringVec & rVisNames) const195 const String& XclImpPCField::GetFieldName( const ScfStringVec& rVisNames ) const
196 {
197     if( IsGroupChildField() && (mnFieldIdx < rVisNames.size()) )
198     {
199         const String& rVisName = rVisNames[ mnFieldIdx ];
200         if( rVisName.Len() > 0 )
201             return rVisName;
202     }
203     return maFieldInfo.maName;
204 }
205 
GetGroupBaseField() const206 const XclImpPCField* XclImpPCField::GetGroupBaseField() const
207 {
208     DBG_ASSERT( IsGroupChildField(), "XclImpPCField::GetGroupBaseField - this field type does not have a base field" );
209     return IsGroupChildField() ? mrPCache.GetField( maFieldInfo.mnGroupBase ) : 0;
210 }
211 
GetItemCount() const212 sal_uInt16 XclImpPCField::GetItemCount() const
213 {
214     return static_cast< sal_uInt16 >( maItems.size() );
215 }
216 
GetItem(sal_uInt16 nItemIdx) const217 const XclImpPCItem* XclImpPCField::GetItem( sal_uInt16 nItemIdx ) const
218 {
219     return (nItemIdx < maItems.size()) ? maItems[ nItemIdx ].get() : 0;
220 }
221 
GetLimitItem(sal_uInt16 nItemIdx) const222 const XclImpPCItem* XclImpPCField::GetLimitItem( sal_uInt16 nItemIdx ) const
223 {
224     DBG_ASSERT( nItemIdx < 3, "XclImpPCField::GetLimitItem - invalid item index" );
225     DBG_ASSERT( nItemIdx < maNumGroupItems.size(), "XclImpPCField::GetLimitItem - no item found" );
226     return (nItemIdx < maNumGroupItems.size()) ? maNumGroupItems[ nItemIdx ].get() : 0;
227 }
228 
WriteFieldNameToSource(SCCOL nScCol,SCTAB nScTab) const229 void XclImpPCField::WriteFieldNameToSource( SCCOL nScCol, SCTAB nScTab ) const
230 {
231     DBG_ASSERT( HasOrigItems(), "XclImpPCField::WriteFieldNameToSource - only for standard fields" );
232     GetDoc().SetString( nScCol, 0, nScTab, maFieldInfo.maName );
233     mnSourceScCol = nScCol;
234 }
235 
WriteOrigItemToSource(SCROW nScRow,SCTAB nScTab,sal_uInt16 nItemIdx) const236 void XclImpPCField::WriteOrigItemToSource( SCROW nScRow, SCTAB nScTab, sal_uInt16 nItemIdx ) const
237 {
238     if( nItemIdx < maOrigItems.size() )
239         maOrigItems[ nItemIdx ]->WriteToSource( GetRoot(), ScAddress( mnSourceScCol, nScRow, nScTab ) );
240 }
241 
WriteLastOrigItemToSource(SCROW nScRow,SCTAB nScTab) const242 void XclImpPCField::WriteLastOrigItemToSource( SCROW nScRow, SCTAB nScTab ) const
243 {
244     if( !maOrigItems.empty() )
245         maOrigItems.back()->WriteToSource( GetRoot(), ScAddress( mnSourceScCol, nScRow, nScTab ) );
246 }
247 
248 // records --------------------------------------------------------------------
249 
ReadSxfield(XclImpStream & rStrm)250 void XclImpPCField::ReadSxfield( XclImpStream& rStrm )
251 {
252     rStrm >> maFieldInfo;
253 
254     /*  Detect the type of this field. This is done very restrictive to detect
255         any unexpected state. */
256     meFieldType = EXC_PCFIELD_UNKNOWN;
257 
258     bool bItems  = ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_HASITEMS );
259     bool bPostp  = ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_POSTPONE );
260     bool bCalced = ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_CALCED );
261     bool bChild  = ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_HASCHILD );
262     bool bNum    = ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_NUMGROUP );
263 
264     sal_uInt16 nVisC   = maFieldInfo.mnVisItems;
265     sal_uInt16 nGroupC = maFieldInfo.mnGroupItems;
266     sal_uInt16 nBaseC  = maFieldInfo.mnBaseItems;
267     sal_uInt16 nOrigC  = maFieldInfo.mnOrigItems;
268     DBG_ASSERT( nVisC > 0, "XclImpPCField::ReadSxfield - field without visible items" );
269 
270     sal_uInt16 nType = maFieldInfo.mnFlags & EXC_SXFIELD_DATA_MASK;
271     bool bType =
272         (nType == EXC_SXFIELD_DATA_STR) ||
273         (nType == EXC_SXFIELD_DATA_INT) ||
274         (nType == EXC_SXFIELD_DATA_DBL) ||
275         (nType == EXC_SXFIELD_DATA_STR_INT) ||
276         (nType == EXC_SXFIELD_DATA_STR_DBL) ||
277         (nType == EXC_SXFIELD_DATA_DATE) ||
278         (nType == EXC_SXFIELD_DATA_DATE_EMP) ||
279         (nType == EXC_SXFIELD_DATA_DATE_NUM) ||
280         (nType == EXC_SXFIELD_DATA_DATE_STR);
281     bool bTypeNone =
282         (nType == EXC_SXFIELD_DATA_NONE);
283     // for now, ignore data type of calculated fields
284     DBG_ASSERT( bCalced || bType || bTypeNone, "XclImpPCField::ReadSxfield - unknown item data type" );
285 
286     if( nVisC > 0 || bPostp )
287     {
288         if( bItems && !bPostp )
289         {
290             if( !bCalced )
291             {
292                 // 1) standard fields and standard grouping fields
293                 if( !bNum )
294                 {
295                     // 1a) standard field without grouping
296                     if( bType && (nGroupC == 0) && (nBaseC == 0) && (nOrigC == nVisC) )
297                         meFieldType = EXC_PCFIELD_STANDARD;
298 
299                     // 1b) standard grouping field
300                     else if( bTypeNone && (nGroupC == nVisC) && (nBaseC > 0) && (nOrigC == 0) )
301                         meFieldType = EXC_PCFIELD_STDGROUP;
302                 }
303                 // 2) numerical grouping fields
304                 else if( (nGroupC == nVisC) && (nBaseC == 0) )
305                 {
306                     // 2a) single num/date grouping field without child grouping field
307                     if( !bChild && bType && (nOrigC > 0) )
308                     {
309                         switch( nType )
310                         {
311                             case EXC_SXFIELD_DATA_INT:
312                             case EXC_SXFIELD_DATA_DBL:  meFieldType = EXC_PCFIELD_NUMGROUP;     break;
313                             case EXC_SXFIELD_DATA_DATE: meFieldType = EXC_PCFIELD_DATEGROUP;    break;
314                             default:    DBG_ERRORFILE( "XclImpPCField::ReadSxfield - numeric group with wrong data type" );
315                         }
316                     }
317 
318                     // 2b) first date grouping field with child grouping field
319                     else if( bChild && (nType == EXC_SXFIELD_DATA_DATE) && (nOrigC > 0) )
320                         meFieldType = EXC_PCFIELD_DATEGROUP;
321 
322                     // 2c) additional date grouping field
323                     else if( bTypeNone && (nOrigC == 0) )
324                         meFieldType = EXC_PCFIELD_DATECHILD;
325                 }
326                 DBG_ASSERT( meFieldType != EXC_PCFIELD_UNKNOWN, "XclImpPCField::ReadSxfield - invalid standard or grouped field" );
327             }
328 
329             // 3) calculated field
330             else
331             {
332                 if( !bChild && !bNum && (nGroupC == 0) && (nBaseC == 0) && (nOrigC == 0) )
333                     meFieldType = EXC_PCFIELD_CALCED;
334                 DBG_ASSERT( meFieldType == EXC_PCFIELD_CALCED, "XclImpPCField::ReadSxfield - invalid calculated field" );
335             }
336         }
337 
338         else if( !bItems && bPostp )
339         {
340             // 4) standard field with postponed items
341             if( !bCalced && !bChild && !bNum && bType && (nGroupC == 0) && (nBaseC == 0) && (nOrigC == 0) )
342                 meFieldType = EXC_PCFIELD_STANDARD;
343             DBG_ASSERT( meFieldType == EXC_PCFIELD_STANDARD, "XclImpPCField::ReadSxfield - invalid postponed field" );
344         }
345     }
346 }
347 
ReadItem(XclImpStream & rStrm)348 void XclImpPCField::ReadItem( XclImpStream& rStrm )
349 {
350     DBG_ASSERT( HasInlineItems() || HasPostponedItems(), "XclImpPCField::ReadItem - field does not expect items" );
351 
352     // read the item
353     XclImpPCItemRef xItem( new XclImpPCItem( rStrm ) );
354 
355     // try to insert into an item list
356     if( mbNumGroupInfoRead )
357     {
358         // there are 3 items after SXNUMGROUP that contain grouping limits and step count
359         if( maNumGroupItems.size() < 3 )
360             maNumGroupItems.push_back( xItem );
361         else
362             maOrigItems.push_back( xItem );
363     }
364     else if( HasInlineItems() || HasPostponedItems() )
365     {
366         maItems.push_back( xItem );
367         // visible item is original item in standard fields
368         if( IsStandardField() )
369             maOrigItems.push_back( xItem );
370     }
371 }
372 
ReadSxnumgroup(XclImpStream & rStrm)373 void XclImpPCField::ReadSxnumgroup( XclImpStream& rStrm )
374 {
375     DBG_ASSERT( IsNumGroupField() || IsDateGroupField(), "XclImpPCField::ReadSxnumgroup - SXNUMGROUP outside numeric grouping field" );
376     DBG_ASSERT( !mbNumGroupInfoRead, "XclImpPCField::ReadSxnumgroup - multiple SXNUMGROUP records" );
377     DBG_ASSERT( maItems.size() == maFieldInfo.mnGroupItems, "XclImpPCField::ReadSxnumgroup - SXNUMGROUP out of record order" );
378     rStrm >> maNumGroupInfo;
379     mbNumGroupInfoRead = IsNumGroupField() || IsDateGroupField();
380 }
381 
ReadSxgroupinfo(XclImpStream & rStrm)382 void XclImpPCField::ReadSxgroupinfo( XclImpStream& rStrm )
383 {
384     DBG_ASSERT( IsStdGroupField(), "XclImpPCField::ReadSxgroupinfo - SXGROUPINFO outside grouping field" );
385     DBG_ASSERT( maGroupOrder.empty(), "XclImpPCField::ReadSxgroupinfo - multiple SXGROUPINFO records" );
386     DBG_ASSERT( maItems.size() == maFieldInfo.mnGroupItems, "XclImpPCField::ReadSxgroupinfo - SXGROUPINFO out of record order" );
387     DBG_ASSERT( (rStrm.GetRecLeft() / 2) == maFieldInfo.mnBaseItems, "XclImpPCField::ReadSxgroupinfo - wrong SXGROUPINFO size" );
388     maGroupOrder.clear();
389     size_t nSize = rStrm.GetRecLeft() / 2;
390     maGroupOrder.resize( nSize, 0 );
391     for( size_t nIdx = 0; nIdx < nSize; ++nIdx )
392         rStrm >> maGroupOrder[ nIdx ];
393 }
394 
395 // grouping -------------------------------------------------------------------
396 
ConvertGroupField(ScDPSaveData & rSaveData,const ScfStringVec & rVisNames) const397 void XclImpPCField::ConvertGroupField( ScDPSaveData& rSaveData, const ScfStringVec& rVisNames ) const
398 {
399     if( GetFieldName( rVisNames ).Len() > 0 )
400     {
401         if( IsStdGroupField() )
402             ConvertStdGroupField( rSaveData, rVisNames );
403         else if( IsNumGroupField() )
404             ConvertNumGroupField( rSaveData, rVisNames );
405         else if( IsDateGroupField() )
406             ConvertDateGroupField( rSaveData, rVisNames );
407     }
408 }
409 
410 // private --------------------------------------------------------------------
411 
ConvertStdGroupField(ScDPSaveData & rSaveData,const ScfStringVec & rVisNames) const412 void XclImpPCField::ConvertStdGroupField( ScDPSaveData& rSaveData, const ScfStringVec& rVisNames ) const
413 {
414     if( const XclImpPCField* pBaseField = GetGroupBaseField() )
415     {
416         const String& rBaseFieldName = pBaseField->GetFieldName( rVisNames );
417         if( rBaseFieldName.Len() > 0 )
418         {
419             // *** create a ScDPSaveGroupItem for each own item, they collect base item names ***
420             typedef ::std::vector< ScDPSaveGroupItem > ScDPSaveGroupItemVec;
421             ScDPSaveGroupItemVec aGroupItems;
422             aGroupItems.reserve( maItems.size() );
423             // initialize with own item names
424             for( XclImpPCItemVec::const_iterator aIt = maItems.begin(), aEnd = maItems.end(); aIt != aEnd; ++aIt )
425                 aGroupItems.push_back( ScDPSaveGroupItem( (*aIt)->ConvertToText() ) );
426 
427             // *** iterate over all base items, set their names at corresponding own items ***
428             for( sal_uInt16 nItemIdx = 0, nItemCount = static_cast< sal_uInt16 >( maGroupOrder.size() ); nItemIdx < nItemCount; ++nItemIdx )
429                 if( maGroupOrder[ nItemIdx ] < aGroupItems.size() )
430                     if( const XclImpPCItem* pBaseItem = pBaseField->GetItem( nItemIdx ) )
431                         if( const XclImpPCItem* pGroupItem = GetItem( maGroupOrder[ nItemIdx ] ) )
432                             if( *pBaseItem != *pGroupItem )
433                                 aGroupItems[ maGroupOrder[ nItemIdx ] ].AddElement( pBaseItem->ConvertToText() );
434 
435             // *** create the ScDPSaveGroupDimension object, fill with grouping info ***
436             ScDPSaveGroupDimension aGroupDim( rBaseFieldName, GetFieldName( rVisNames ) );
437             for( ScDPSaveGroupItemVec::const_iterator aIt = aGroupItems.begin(), aEnd = aGroupItems.end(); aIt != aEnd; ++aIt )
438                 if( !aIt->IsEmpty() )
439                     aGroupDim.AddGroupItem( *aIt );
440             rSaveData.GetDimensionData()->AddGroupDimension( aGroupDim );
441         }
442     }
443 }
444 
ConvertNumGroupField(ScDPSaveData & rSaveData,const ScfStringVec & rVisNames) const445 void XclImpPCField::ConvertNumGroupField( ScDPSaveData& rSaveData, const ScfStringVec& rVisNames ) const
446 {
447     ScDPNumGroupInfo aNumInfo( GetScNumGroupInfo() );
448     ScDPSaveNumGroupDimension aNumGroupDim( GetFieldName( rVisNames ), aNumInfo );
449     rSaveData.GetDimensionData()->AddNumGroupDimension( aNumGroupDim );
450 }
451 
ConvertDateGroupField(ScDPSaveData & rSaveData,const ScfStringVec & rVisNames) const452 void XclImpPCField::ConvertDateGroupField( ScDPSaveData& rSaveData, const ScfStringVec& rVisNames ) const
453 {
454     ScDPNumGroupInfo aDateInfo( GetScDateGroupInfo() );
455     sal_Int32 nScDateType = maNumGroupInfo.GetScDateType();
456 
457     switch( meFieldType )
458     {
459         case EXC_PCFIELD_DATEGROUP:
460         {
461             if( aDateInfo.DateValues )
462             {
463                 // special case for days only with step value - create numeric grouping
464                 ScDPSaveNumGroupDimension aNumGroupDim( GetFieldName( rVisNames ), aDateInfo );
465                 rSaveData.GetDimensionData()->AddNumGroupDimension( aNumGroupDim );
466             }
467             else
468             {
469                 ScDPSaveNumGroupDimension aNumGroupDim( GetFieldName( rVisNames ), ScDPNumGroupInfo() );
470                 aNumGroupDim.SetDateInfo( aDateInfo, nScDateType );
471                 rSaveData.GetDimensionData()->AddNumGroupDimension( aNumGroupDim );
472             }
473         }
474         break;
475 
476         case EXC_PCFIELD_DATECHILD:
477         {
478             if( const XclImpPCField* pBaseField = GetGroupBaseField() )
479             {
480                 const String& rBaseFieldName = pBaseField->GetFieldName( rVisNames );
481                 if( rBaseFieldName.Len() > 0 )
482                 {
483                     ScDPSaveGroupDimension aGroupDim( rBaseFieldName, GetFieldName( rVisNames ) );
484                     aGroupDim.SetDateInfo( aDateInfo, nScDateType );
485                     rSaveData.GetDimensionData()->AddGroupDimension( aGroupDim );
486                 }
487             }
488         }
489         break;
490 
491         default:
492             DBG_ERRORFILE( "XclImpPCField::ConvertDateGroupField - unknown date field type" );
493     }
494 }
495 
GetScNumGroupInfo() const496 ScDPNumGroupInfo XclImpPCField::GetScNumGroupInfo() const
497 {
498     ScDPNumGroupInfo aNumInfo;
499     aNumInfo.Enable = sal_True;
500     aNumInfo.DateValues = sal_False;
501     aNumInfo.AutoStart = sal_True;
502     aNumInfo.AutoEnd = sal_True;
503 
504     if( const double* pfMinValue = GetNumGroupLimit( EXC_SXFIELD_INDEX_MIN ) )
505     {
506         aNumInfo.Start = *pfMinValue;
507         aNumInfo.AutoStart = ::get_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMIN );
508     }
509     if( const double* pfMaxValue = GetNumGroupLimit( EXC_SXFIELD_INDEX_MAX ) )
510     {
511         aNumInfo.End = *pfMaxValue;
512         aNumInfo.AutoEnd = ::get_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMAX );
513     }
514     if( const double* pfStepValue = GetNumGroupLimit( EXC_SXFIELD_INDEX_STEP ) )
515         aNumInfo.Step = *pfStepValue;
516 
517     return aNumInfo;
518 }
519 
GetScDateGroupInfo() const520 ScDPNumGroupInfo XclImpPCField::GetScDateGroupInfo() const
521 {
522     ScDPNumGroupInfo aDateInfo;
523     aDateInfo.Enable = sal_True;
524     aDateInfo.DateValues = sal_False;
525     aDateInfo.AutoStart = sal_True;
526     aDateInfo.AutoEnd = sal_True;
527 
528     if( const DateTime* pMinDate = GetDateGroupLimit( EXC_SXFIELD_INDEX_MIN ) )
529     {
530         aDateInfo.Start = GetDoubleFromDateTime( *pMinDate );
531         aDateInfo.AutoStart = ::get_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMIN );
532     }
533     if( const DateTime* pMaxDate = GetDateGroupLimit( EXC_SXFIELD_INDEX_MAX ) )
534     {
535         aDateInfo.End = GetDoubleFromDateTime( *pMaxDate );
536         aDateInfo.AutoEnd = ::get_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMAX );
537     }
538     // GetDateGroupStep() returns a value for date type "day" in single date groups only
539     if( const sal_Int16* pnStepValue = GetDateGroupStep() )
540     {
541         aDateInfo.Step = *pnStepValue;
542         aDateInfo.DateValues = sal_True;
543     }
544 
545     return aDateInfo;
546 }
547 
GetNumGroupLimit(sal_uInt16 nLimitIdx) const548 const double* XclImpPCField::GetNumGroupLimit( sal_uInt16 nLimitIdx ) const
549 {
550     DBG_ASSERT( IsNumGroupField(), "XclImpPCField::GetNumGroupLimit - only for numeric grouping fields" );
551     if( const XclImpPCItem* pItem = GetLimitItem( nLimitIdx ) )
552     {
553         DBG_ASSERT( pItem->GetDouble(), "XclImpPCField::GetNumGroupLimit - SXDOUBLE item expected" );
554         return pItem->GetDouble();
555     }
556     return 0;
557 }
558 
GetDateGroupLimit(sal_uInt16 nLimitIdx) const559 const DateTime* XclImpPCField::GetDateGroupLimit( sal_uInt16 nLimitIdx ) const
560 {
561     DBG_ASSERT( IsDateGroupField(), "XclImpPCField::GetDateGroupLimit - only for date grouping fields" );
562     if( const XclImpPCItem* pItem = GetLimitItem( nLimitIdx ) )
563     {
564         DBG_ASSERT( pItem->GetDateTime(), "XclImpPCField::GetDateGroupLimit - SXDATETIME item expected" );
565         return pItem->GetDateTime();
566     }
567     return 0;
568 }
569 
GetDateGroupStep() const570 const sal_Int16* XclImpPCField::GetDateGroupStep() const
571 {
572     // only for single date grouping fields, not for grouping chains
573     if( !IsGroupBaseField() && !IsGroupChildField() )
574     {
575         // only days may have a step value, return 0 for all other date types
576         if( maNumGroupInfo.GetXclDataType() == EXC_SXNUMGROUP_TYPE_DAY )
577         {
578             if( const XclImpPCItem* pItem = GetLimitItem( EXC_SXFIELD_INDEX_STEP ) )
579             {
580                 DBG_ASSERT( pItem->GetInteger(), "XclImpPCField::GetDateGroupStep - SXINTEGER item expected" );
581                 if( const sal_Int16* pnStep = pItem->GetInteger() )
582                 {
583                     DBG_ASSERT( *pnStep > 0, "XclImpPCField::GetDateGroupStep - invalid step count" );
584                     // return nothing for step count 1 - this is also a standard date group in Excel
585                     return (*pnStep > 1) ? pnStep : 0;
586                 }
587             }
588         }
589     }
590     return 0;
591 }
592 
593 // ============================================================================
594 
XclImpPivotCache(const XclImpRoot & rRoot)595 XclImpPivotCache::XclImpPivotCache( const XclImpRoot& rRoot ) :
596     XclImpRoot( rRoot ),
597     maSrcRange( ScAddress::INITIALIZE_INVALID ),
598     mnStrmId( 0 ),
599     mnSrcType( EXC_SXVS_UNKNOWN ),
600     mbSelfRef( false )
601 {
602 }
603 
~XclImpPivotCache()604 XclImpPivotCache::~XclImpPivotCache()
605 {
606 }
607 
608 // data access ----------------------------------------------------------------
609 
GetFieldCount() const610 sal_uInt16 XclImpPivotCache::GetFieldCount() const
611 {
612     return static_cast< sal_uInt16 >( maFields.size() );
613 }
614 
GetField(sal_uInt16 nFieldIdx) const615 const XclImpPCField* XclImpPivotCache::GetField( sal_uInt16 nFieldIdx ) const
616 {
617     return (nFieldIdx < maFields.size()) ? maFields[ nFieldIdx ].get() : 0;
618 }
619 
620 // records --------------------------------------------------------------------
621 
ReadSxidstm(XclImpStream & rStrm)622 void XclImpPivotCache::ReadSxidstm( XclImpStream& rStrm )
623 {
624     rStrm >> mnStrmId;
625 }
626 
ReadSxvs(XclImpStream & rStrm)627 void XclImpPivotCache::ReadSxvs( XclImpStream& rStrm )
628 {
629     rStrm >> mnSrcType;
630     GetTracer().TracePivotDataSource( mnSrcType != EXC_SXVS_SHEET );
631 }
632 
ReadDconref(XclImpStream & rStrm)633 void XclImpPivotCache::ReadDconref( XclImpStream& rStrm )
634 {
635     /*  Read DCONREF only once (by checking maTabName), there may be other
636         DCONREF records in another context. Read reference only if a leading
637         SXVS record is present (by checking mnSrcType). */
638     if( (maTabName.Len() > 0) || (mnSrcType != EXC_SXVS_SHEET) )
639         return;
640 
641     XclRange aXclRange( ScAddress::UNINITIALIZED );
642     aXclRange.Read( rStrm, false );
643     String aEncUrl = rStrm.ReadUniString();
644 
645     XclImpUrlHelper::DecodeUrl( maUrl, maTabName, mbSelfRef, GetRoot(), aEncUrl );
646 
647     /*  Do not convert maTabName to Calc sheet name -> original name is used to
648         find the sheet in the document. Sheet index of source range will be
649         found later in XclImpPivotCache::ReadPivotCacheStream(), because sheet
650         may not exist yet. */
651     if( mbSelfRef )
652         GetAddressConverter().ConvertRange( maSrcRange, aXclRange, 0, 0, true );
653 }
654 
ReadPivotCacheStream(XclImpStream & rStrm)655 void XclImpPivotCache::ReadPivotCacheStream( XclImpStream& rStrm )
656 {
657     if( (mnSrcType != EXC_SXVS_SHEET) && (mnSrcType != EXC_SXVS_EXTERN) )
658         return;
659 
660     ScDocument& rDoc = GetDoc();
661     SCCOL nFieldScCol = 0;              // column index of source data for next field
662     SCROW nItemScRow = 0;               // row index of source data for current items
663     SCTAB nScTab = 0;                   // sheet index of source data
664     bool bGenerateSource = false;       // true = write source data from cache to dummy table
665 
666     if( mbSelfRef )
667     {
668         // try to find internal sheet containing the source data
669         nScTab = GetTabInfo().GetScTabFromXclName( maTabName );
670         if( rDoc.HasTable( nScTab ) )
671         {
672             // set sheet index to source range
673             maSrcRange.aStart.SetTab( nScTab );
674             maSrcRange.aEnd.SetTab( nScTab );
675         }
676         else
677         {
678             // create dummy sheet for deleted internal sheet
679             bGenerateSource = true;
680         }
681     }
682     else
683     {
684         // create dummy sheet for external sheet
685         bGenerateSource = true;
686     }
687 
688     // create dummy sheet for source data from external or deleted sheet
689     if( bGenerateSource )
690     {
691         if( rDoc.GetTableCount() >= MAXTABCOUNT )
692             // cannot create more sheets -> exit
693             return;
694 
695         nScTab = rDoc.GetTableCount();
696         rDoc.MakeTable( nScTab );
697         String aDummyName = CREATE_STRING( "DPCache" );
698         if( maTabName.Len() > 0 )
699             aDummyName.Append( '_' ).Append( maTabName );
700         rDoc.CreateValidTabName( aDummyName );
701         rDoc.RenameTab( nScTab, aDummyName );
702         // set sheet index to source range
703         maSrcRange.aStart.SetTab( nScTab );
704         maSrcRange.aEnd.SetTab( nScTab );
705     }
706 
707     // open pivot cache storage stream
708     SotStorageRef xSvStrg = OpenStorage( EXC_STORAGE_PTCACHE );
709     SotStorageStreamRef xSvStrm = OpenStream( xSvStrg, ScfTools::GetHexStr( mnStrmId ) );
710     if( !xSvStrm.Is() )
711         return;
712 
713     // create Excel record stream object
714     XclImpStream aPCStrm( *xSvStrm, GetRoot() );
715     aPCStrm.CopyDecrypterFrom( rStrm );     // pivot cache streams are encrypted
716 
717     XclImpPCFieldRef xCurrField;    // current field for new items
718     XclImpPCFieldVec aOrigFields;   // all standard fields with inline original  items
719     XclImpPCFieldVec aPostpFields;  // all standard fields with postponed original items
720     size_t nPostpIdx = 0;           // index to current field with postponed items
721     bool bLoop = true;              // true = continue loop
722 
723     while( bLoop && aPCStrm.StartNextRecord() )
724     {
725         switch( aPCStrm.GetRecId() )
726         {
727             case EXC_ID_EOF:
728                 bLoop = false;
729             break;
730 
731             case EXC_ID_SXDB:
732                 aPCStrm >> maPCInfo;
733             break;
734 
735             case EXC_ID_SXFIELD:
736             {
737                 xCurrField.reset();
738                 sal_uInt16 nNewFieldIdx = GetFieldCount();
739                 if( nNewFieldIdx < EXC_PC_MAXFIELDCOUNT )
740                 {
741                     xCurrField.reset( new XclImpPCField( GetRoot(), *this, nNewFieldIdx ) );
742                     maFields.push_back( xCurrField );
743                     xCurrField->ReadSxfield( aPCStrm );
744                     if( xCurrField->HasOrigItems() )
745                     {
746                         if( xCurrField->HasPostponedItems() )
747                             aPostpFields.push_back( xCurrField );
748                         else
749                             aOrigFields.push_back( xCurrField );
750                         // insert field name into generated source data, field remembers its column index
751                         if( bGenerateSource && (nFieldScCol <= MAXCOL) )
752                             xCurrField->WriteFieldNameToSource( nFieldScCol++, nScTab );
753                     }
754                     // do not read items into invalid/postponed fields
755                     if( !xCurrField->HasInlineItems() )
756                         xCurrField.reset();
757                 }
758             }
759             break;
760 
761             case EXC_ID_SXINDEXLIST:
762                 // read index list and insert all items into generated source data
763                 if( bGenerateSource && (nItemScRow <= MAXROW) && (++nItemScRow <= MAXROW) )
764                 {
765                     for( XclImpPCFieldVec::const_iterator aIt = aOrigFields.begin(), aEnd = aOrigFields.end(); aIt != aEnd; ++aIt )
766                     {
767                         sal_uInt16 nItemIdx = (*aIt)->Has16BitIndexes() ? aPCStrm.ReaduInt16() : aPCStrm.ReaduInt8();
768                         (*aIt)->WriteOrigItemToSource( nItemScRow, nScTab, nItemIdx );
769                     }
770                 }
771                 xCurrField.reset();
772             break;
773 
774             case EXC_ID_SXDOUBLE:
775             case EXC_ID_SXBOOLEAN:
776             case EXC_ID_SXERROR:
777             case EXC_ID_SXINTEGER:
778             case EXC_ID_SXSTRING:
779             case EXC_ID_SXDATETIME:
780             case EXC_ID_SXEMPTY:
781                 if( xCurrField.is() )                   // inline items
782                 {
783                     xCurrField->ReadItem( aPCStrm );
784                 }
785                 else if( !aPostpFields.empty() )        // postponed items
786                 {
787                     // read postponed item
788                     aPostpFields[ nPostpIdx ]->ReadItem( aPCStrm );
789                     // write item to source
790                     if( bGenerateSource && (nItemScRow <= MAXROW) )
791                     {
792                         // start new row, if there are only postponed fields
793                         if( aOrigFields.empty() && (nPostpIdx == 0) )
794                             ++nItemScRow;
795                         if( nItemScRow <= MAXROW )
796                             aPostpFields[ nPostpIdx ]->WriteLastOrigItemToSource( nItemScRow, nScTab );
797                     }
798                     // get index of next postponed field
799                     ++nPostpIdx;
800                     if( nPostpIdx >= aPostpFields.size() )
801                         nPostpIdx = 0;
802                 }
803             break;
804 
805             case EXC_ID_SXNUMGROUP:
806                 if( xCurrField.is() )
807                     xCurrField->ReadSxnumgroup( aPCStrm );
808             break;
809 
810             case EXC_ID_SXGROUPINFO:
811                 if( xCurrField.is() )
812                     xCurrField->ReadSxgroupinfo( aPCStrm );
813             break;
814 
815             // known but ignored records
816             case EXC_ID_SXRULE:
817             case EXC_ID_SXFILT:
818             case EXC_ID_00F5:
819             case EXC_ID_SXNAME:
820             case EXC_ID_SXPAIR:
821             case EXC_ID_SXFMLA:
822             case EXC_ID_SXFORMULA:
823             case EXC_ID_SXDBEX:
824             case EXC_ID_SXFDBTYPE:
825             break;
826 
827             default:
828                 DBG_ERROR1( "XclImpPivotCache::ReadPivotCacheStream - unknown record 0x%04hX", aPCStrm.GetRecId() );
829         }
830     }
831 
832     DBG_ASSERT( maPCInfo.mnTotalFields == maFields.size(),
833         "XclImpPivotCache::ReadPivotCacheStream - field count mismatch" );
834 
835     // set source range for external source data
836     if( bGenerateSource && (nFieldScCol > 0) )
837     {
838         maSrcRange.aStart.SetCol( 0 );
839         maSrcRange.aStart.SetRow( 0 );
840         // nFieldScCol points to first unused column
841         maSrcRange.aEnd.SetCol( nFieldScCol - 1 );
842         // nItemScRow points to last used row
843         maSrcRange.aEnd.SetRow( nItemScRow );
844     }
845 }
846 
IsRefreshOnLoad() const847 bool XclImpPivotCache::IsRefreshOnLoad() const
848 {
849     return static_cast<bool>(maPCInfo.mnFlags & 0x0004);
850 }
851 
852 // ============================================================================
853 // Pivot table
854 // ============================================================================
855 
XclImpPTItem(const XclImpPTField & rPTField)856 XclImpPTItem::XclImpPTItem( const XclImpPTField& rPTField ) :
857     mrPTField( rPTField )
858 {
859 }
860 
GetItemName() const861 const String* XclImpPTItem::GetItemName() const
862 {
863     if( const XclImpPCField * mpCacheField = mrPTField.GetCacheField() )
864     {
865         if( const XclImpPCItem* pCacheItem = mpCacheField->GetItem( maItemInfo.mnCacheIdx ) )
866         {
867             return pCacheItem->GetItemName();
868         }
869     }
870     return 0;
871 }
872 
GetVisItemName() const873 const String* XclImpPTItem::GetVisItemName() const
874 {
875     return maItemInfo.HasVisName() ? maItemInfo.GetVisName() : GetItemName();
876 }
877 
ReadSxvi(XclImpStream & rStrm)878 void XclImpPTItem::ReadSxvi( XclImpStream& rStrm )
879 {
880     rStrm >> maItemInfo;
881 }
882 
ConvertItem(ScDPSaveDimension & rSaveDim) const883 void XclImpPTItem::ConvertItem( ScDPSaveDimension& rSaveDim ) const
884 {
885     if( const String* pItemName = GetItemName() )
886     {
887         ScDPSaveMember& rMember = *rSaveDim.GetMemberByName( *pItemName );
888         rMember.SetIsVisible( !::get_flag( maItemInfo.mnFlags, EXC_SXVI_HIDDEN ) );
889         rMember.SetShowDetails( !::get_flag( maItemInfo.mnFlags, EXC_SXVI_HIDEDETAIL ) );
890         if (maItemInfo.HasVisName())
891             rMember.SetLayoutName(*maItemInfo.GetVisName());
892     }
893 }
894 
895 // ============================================================================
896 
XclImpPTField(const XclImpPivotTable & rPTable,sal_uInt16 nCacheIdx)897 XclImpPTField::XclImpPTField( const XclImpPivotTable& rPTable, sal_uInt16 nCacheIdx ) :
898     mrPTable( rPTable )
899 {
900     maFieldInfo.mnCacheIdx = nCacheIdx;
901 }
902 
903 // general field/item access --------------------------------------------------
904 
GetCacheField() const905 const XclImpPCField* XclImpPTField::GetCacheField() const
906 {
907     XclImpPivotCacheRef xPCache = mrPTable.GetPivotCache();
908     return xPCache.is() ? xPCache->GetField( maFieldInfo.mnCacheIdx ) : 0;
909 }
910 
GetFieldName() const911 const String& XclImpPTField::GetFieldName() const
912 {
913     const XclImpPCField* pField = GetCacheField();
914     return pField ? pField->GetFieldName( mrPTable.GetVisFieldNames() ) : String::EmptyString();
915 }
916 
GetVisFieldName() const917 const String& XclImpPTField::GetVisFieldName() const
918 {
919     const String* pVisName = maFieldInfo.GetVisName();
920     return pVisName ? *pVisName : String::EmptyString();
921 }
922 
GetItem(sal_uInt16 nItemIdx) const923 const XclImpPTItem* XclImpPTField::GetItem( sal_uInt16 nItemIdx ) const
924 {
925     return (nItemIdx < maItems.size()) ? maItems[ nItemIdx ].get() : 0;
926 }
927 
GetItemName(sal_uInt16 nItemIdx) const928 const String* XclImpPTField::GetItemName( sal_uInt16 nItemIdx ) const
929 {
930     const XclImpPTItem* pItem = GetItem( nItemIdx );
931     return pItem ? pItem->GetItemName() : 0;
932 }
933 
GetVisItemName(sal_uInt16 nItemIdx) const934 const String* XclImpPTField::GetVisItemName( sal_uInt16 nItemIdx ) const
935 {
936     const XclImpPTItem* pItem = GetItem( nItemIdx );
937     return pItem ? pItem->GetVisItemName() : 0;
938 }
939 
940 // records --------------------------------------------------------------------
941 
ReadSxvd(XclImpStream & rStrm)942 void XclImpPTField::ReadSxvd( XclImpStream& rStrm )
943 {
944     rStrm >> maFieldInfo;
945 }
946 
ReadSxvdex(XclImpStream & rStrm)947 void XclImpPTField::ReadSxvdex( XclImpStream& rStrm )
948 {
949     rStrm >> maFieldExtInfo;
950 }
951 
ReadSxvi(XclImpStream & rStrm)952 void XclImpPTField::ReadSxvi( XclImpStream& rStrm )
953 {
954     XclImpPTItemRef xItem( new XclImpPTItem( *this ) );
955     maItems.push_back( xItem );
956     xItem->ReadSxvi( rStrm );
957 }
958 
959 // row/column fields ----------------------------------------------------------
960 
ConvertRowColField(ScDPSaveData & rSaveData) const961 void XclImpPTField::ConvertRowColField( ScDPSaveData& rSaveData ) const
962 {
963     DBG_ASSERT( maFieldInfo.mnAxes & EXC_SXVD_AXIS_ROWCOL, "XclImpPTField::ConvertRowColField - no row/column field" );
964     // special data orientation field?
965     if( maFieldInfo.mnCacheIdx == EXC_SXIVD_DATA )
966         rSaveData.GetDataLayoutDimension()->SetOrientation( static_cast< sal_uInt16 >( maFieldInfo.GetApiOrient( EXC_SXVD_AXIS_ROWCOL ) ) );
967     else
968         ConvertRCPField( rSaveData );
969 }
970 
971 // page fields ----------------------------------------------------------------
972 
SetPageFieldInfo(const XclPTPageFieldInfo & rPageInfo)973 void XclImpPTField::SetPageFieldInfo( const XclPTPageFieldInfo& rPageInfo )
974 {
975     maPageInfo = rPageInfo;
976 }
977 
ConvertPageField(ScDPSaveData & rSaveData) const978 void XclImpPTField::ConvertPageField( ScDPSaveData& rSaveData ) const
979 {
980     DBG_ASSERT( maFieldInfo.mnAxes & EXC_SXVD_AXIS_PAGE, "XclImpPTField::ConvertPageField - no page field" );
981     if( ScDPSaveDimension* pSaveDim = ConvertRCPField( rSaveData ) )
982         pSaveDim->SetCurrentPage( GetItemName( maPageInfo.mnSelItem ) );
983 }
984 
985 // hidden fields --------------------------------------------------------------
986 
ConvertHiddenField(ScDPSaveData & rSaveData) const987 void XclImpPTField::ConvertHiddenField( ScDPSaveData& rSaveData ) const
988 {
989     DBG_ASSERT( (maFieldInfo.mnAxes & EXC_SXVD_AXIS_ROWCOLPAGE) == 0, "XclImpPTField::ConvertHiddenField - field not hidden" );
990     ConvertRCPField( rSaveData );
991 }
992 
993 // data fields ----------------------------------------------------------------
994 
HasDataFieldInfo() const995 bool XclImpPTField::HasDataFieldInfo() const
996 {
997     return !maDataInfoList.empty();
998 }
999 
AddDataFieldInfo(const XclPTDataFieldInfo & rDataInfo)1000 void XclImpPTField::AddDataFieldInfo( const XclPTDataFieldInfo& rDataInfo )
1001 {
1002     DBG_ASSERT( maFieldInfo.mnAxes & EXC_SXVD_AXIS_DATA, "XclImpPTField::AddDataFieldInfo - no data field" );
1003     maDataInfoList.push_back( rDataInfo );
1004 }
1005 
ConvertDataField(ScDPSaveData & rSaveData) const1006 void XclImpPTField::ConvertDataField( ScDPSaveData& rSaveData ) const
1007 {
1008     DBG_ASSERT( maFieldInfo.mnAxes & EXC_SXVD_AXIS_DATA, "XclImpPTField::ConvertDataField - no data field" );
1009     DBG_ASSERT( !maDataInfoList.empty(), "XclImpPTField::ConvertDataField - no data field info" );
1010     if( !maDataInfoList.empty() )
1011     {
1012         const String& rFieldName = GetFieldName();
1013         if( rFieldName.Len() > 0 )
1014         {
1015             XclPTDataFieldInfoList::const_iterator aIt = maDataInfoList.begin(), aEnd = maDataInfoList.end();
1016 
1017             ScDPSaveDimension& rSaveDim = *rSaveData.GetNewDimensionByName( rFieldName );
1018             ConvertDataField( rSaveDim, *aIt );
1019 
1020             // multiple data fields -> clone dimension
1021             for( ++aIt; aIt != aEnd; ++aIt )
1022             {
1023                 ScDPSaveDimension& rDupDim = rSaveData.DuplicateDimension( rSaveDim );
1024                 ConvertDataFieldInfo( rDupDim, *aIt );
1025             }
1026         }
1027     }
1028 }
1029 
1030 // private --------------------------------------------------------------------
1031 
1032 /**
1033  * Convert Excel-encoded subtotal name to a Calc-encoded one.
1034  */
lcl_convertExcelSubtotalName(const OUString & rName)1035 static OUString lcl_convertExcelSubtotalName(const OUString& rName)
1036 {
1037     OUStringBuffer aBuf;
1038     const sal_Unicode* p = rName.getStr();
1039     sal_Int32 n = rName.getLength();
1040     for (sal_Int32 i = 0; i < n; ++i)
1041     {
1042         const sal_Unicode c = p[i];
1043         if (c == sal_Unicode('\\'))
1044         {
1045             aBuf.append(c);
1046             aBuf.append(c);
1047         }
1048         else
1049             aBuf.append(c);
1050     }
1051     return aBuf.makeStringAndClear();
1052 }
1053 
ConvertRCPField(ScDPSaveData & rSaveData) const1054 ScDPSaveDimension* XclImpPTField::ConvertRCPField( ScDPSaveData& rSaveData ) const
1055 {
1056     const String& rFieldName = GetFieldName();
1057     if( rFieldName.Len() == 0 )
1058         return 0;
1059 
1060     const XclImpPCField* pCacheField = GetCacheField();
1061     if( !pCacheField || !pCacheField->IsSupportedField() )
1062         return 0;
1063 
1064     ScDPSaveDimension& rSaveDim = *rSaveData.GetNewDimensionByName( rFieldName );
1065 
1066     // orientation
1067     rSaveDim.SetOrientation( static_cast< sal_uInt16 >( maFieldInfo.GetApiOrient( EXC_SXVD_AXIS_ROWCOLPAGE ) ) );
1068 
1069     // general field info
1070     ConvertFieldInfo( rSaveDim );
1071 
1072     // visible name
1073     if( const String* pVisName = maFieldInfo.GetVisName() )
1074         if( pVisName->Len() > 0 )
1075             rSaveDim.SetLayoutName( *pVisName );
1076 
1077     // subtotal function(s)
1078     XclPTSubtotalVec aSubtotalVec;
1079     maFieldInfo.GetSubtotals( aSubtotalVec );
1080     if( !aSubtotalVec.empty() )
1081         rSaveDim.SetSubTotals( static_cast< long >( aSubtotalVec.size() ), &aSubtotalVec[ 0 ] );
1082 
1083     // sorting
1084     DataPilotFieldSortInfo aSortInfo;
1085     aSortInfo.Field = mrPTable.GetDataFieldName( maFieldExtInfo.mnSortField );
1086     aSortInfo.IsAscending = ::get_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_SORT_ASC );
1087     aSortInfo.Mode = maFieldExtInfo.GetApiSortMode();
1088     rSaveDim.SetSortInfo( &aSortInfo );
1089 
1090     // auto show
1091     DataPilotFieldAutoShowInfo aShowInfo;
1092     aShowInfo.IsEnabled = ::get_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_AUTOSHOW );
1093     aShowInfo.ShowItemsMode = maFieldExtInfo.GetApiAutoShowMode();
1094     aShowInfo.ItemCount = maFieldExtInfo.GetApiAutoShowCount();
1095     aShowInfo.DataField = mrPTable.GetDataFieldName( maFieldExtInfo.mnShowField );
1096     rSaveDim.SetAutoShowInfo( &aShowInfo );
1097 
1098     // layout
1099     DataPilotFieldLayoutInfo aLayoutInfo;
1100     aLayoutInfo.LayoutMode = maFieldExtInfo.GetApiLayoutMode();
1101     aLayoutInfo.AddEmptyLines = ::get_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_LAYOUT_BLANK );
1102     rSaveDim.SetLayoutInfo( &aLayoutInfo );
1103 
1104     // grouping info
1105     pCacheField->ConvertGroupField( rSaveData, mrPTable.GetVisFieldNames() );
1106 
1107     // custom subtotal name
1108     if (maFieldExtInfo.mpFieldTotalName.get())
1109     {
1110         OUString aSubName = lcl_convertExcelSubtotalName(*maFieldExtInfo.mpFieldTotalName);
1111         rSaveDim.SetSubtotalName(aSubName);
1112     }
1113 
1114     return &rSaveDim;
1115 }
1116 
ConvertFieldInfo(ScDPSaveDimension & rSaveDim) const1117 void XclImpPTField::ConvertFieldInfo( ScDPSaveDimension& rSaveDim ) const
1118 {
1119     rSaveDim.SetShowEmpty( ::get_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_SHOWALL ) );
1120     ConvertItems( rSaveDim );
1121 }
1122 
ConvertDataField(ScDPSaveDimension & rSaveDim,const XclPTDataFieldInfo & rDataInfo) const1123 void XclImpPTField::ConvertDataField( ScDPSaveDimension& rSaveDim, const XclPTDataFieldInfo& rDataInfo ) const
1124 {
1125     // orientation
1126     rSaveDim.SetOrientation( DataPilotFieldOrientation_DATA );
1127     // general field info
1128     ConvertFieldInfo( rSaveDim );
1129     // extended data field info
1130     ConvertDataFieldInfo( rSaveDim, rDataInfo );
1131 }
1132 
ConvertDataFieldInfo(ScDPSaveDimension & rSaveDim,const XclPTDataFieldInfo & rDataInfo) const1133 void XclImpPTField::ConvertDataFieldInfo( ScDPSaveDimension& rSaveDim, const XclPTDataFieldInfo& rDataInfo ) const
1134 {
1135     // visible name
1136     if( const String* pVisName = rDataInfo.GetVisName() )
1137         if( pVisName->Len() > 0 )
1138             rSaveDim.SetLayoutName( *pVisName );
1139 
1140     // aggregation function
1141     rSaveDim.SetFunction( static_cast< sal_uInt16 >( rDataInfo.GetApiAggFunc() ) );
1142 
1143     // result field reference
1144     sal_Int32 nRefType = rDataInfo.GetApiRefType();
1145     if( nRefType != ::com::sun::star::sheet::DataPilotFieldReferenceType::NONE )
1146     {
1147         DataPilotFieldReference aFieldRef;
1148         aFieldRef.ReferenceType = nRefType;
1149 
1150         if( const XclImpPTField* pRefField = mrPTable.GetField( rDataInfo.mnRefField ) )
1151         {
1152             aFieldRef.ReferenceField = pRefField->GetFieldName();
1153             aFieldRef.ReferenceItemType = rDataInfo.GetApiRefItemType();
1154             if( aFieldRef.ReferenceItemType == ::com::sun::star::sheet::DataPilotFieldReferenceItemType::NAMED )
1155                 if( const String* pRefItemName = pRefField->GetItemName( rDataInfo.mnRefItem ) )
1156                     aFieldRef.ReferenceItemName = *pRefItemName;
1157         }
1158 
1159         rSaveDim.SetReferenceValue( &aFieldRef );
1160     }
1161 }
1162 
ConvertItems(ScDPSaveDimension & rSaveDim) const1163 void XclImpPTField::ConvertItems( ScDPSaveDimension& rSaveDim ) const
1164 {
1165     for( XclImpPTItemVec::const_iterator aIt = maItems.begin(), aEnd = maItems.end(); aIt != aEnd; ++aIt )
1166         (*aIt)->ConvertItem( rSaveDim );
1167 }
1168 
1169 // ============================================================================
1170 
XclImpPivotTable(const XclImpRoot & rRoot)1171 XclImpPivotTable::XclImpPivotTable( const XclImpRoot& rRoot ) :
1172     XclImpRoot( rRoot ),
1173     maDataOrientField( *this, EXC_SXIVD_DATA ),
1174     mpDPObj(NULL)
1175 {
1176 }
1177 
~XclImpPivotTable()1178 XclImpPivotTable::~XclImpPivotTable()
1179 {
1180 }
1181 
1182 // cache/field access, misc. --------------------------------------------------
1183 
GetFieldCount() const1184 sal_uInt16 XclImpPivotTable::GetFieldCount() const
1185 {
1186     return static_cast< sal_uInt16 >( maFields.size() );
1187 }
1188 
GetField(sal_uInt16 nFieldIdx) const1189 const XclImpPTField* XclImpPivotTable::GetField( sal_uInt16 nFieldIdx ) const
1190 {
1191     return (nFieldIdx == EXC_SXIVD_DATA) ? &maDataOrientField :
1192         ((nFieldIdx < maFields.size()) ? maFields[ nFieldIdx ].get() : 0);
1193 }
1194 
GetFieldAcc(sal_uInt16 nFieldIdx)1195 XclImpPTField* XclImpPivotTable::GetFieldAcc( sal_uInt16 nFieldIdx )
1196 {
1197     // do not return maDataOrientField
1198     return (nFieldIdx < maFields.size()) ? maFields[ nFieldIdx ].get() : 0;
1199 }
1200 
GetFieldName(sal_uInt16 nFieldIdx) const1201 const String& XclImpPivotTable::GetFieldName( sal_uInt16 nFieldIdx ) const
1202 {
1203     if( const XclImpPTField* pField = GetField( nFieldIdx ) )
1204         return pField->GetFieldName();
1205     return EMPTY_STRING;
1206 }
1207 
GetDataField(sal_uInt16 nDataFieldIdx) const1208 const XclImpPTField* XclImpPivotTable::GetDataField( sal_uInt16 nDataFieldIdx ) const
1209 {
1210     if( nDataFieldIdx < maOrigDataFields.size() )
1211         return GetField( maOrigDataFields[ nDataFieldIdx ] );
1212     return 0;
1213 }
1214 
GetDataFieldName(sal_uInt16 nDataFieldIdx) const1215 const String& XclImpPivotTable::GetDataFieldName( sal_uInt16 nDataFieldIdx ) const
1216 {
1217     if( const XclImpPTField* pField = GetDataField( nDataFieldIdx ) )
1218         return pField->GetFieldName();
1219     return EMPTY_STRING;
1220 }
1221 
1222 // records --------------------------------------------------------------------
1223 
ReadSxview(XclImpStream & rStrm)1224 void XclImpPivotTable::ReadSxview( XclImpStream& rStrm )
1225 {
1226     rStrm >> maPTInfo;
1227 
1228     GetAddressConverter().ConvertRange(
1229         maOutScRange, maPTInfo.maOutXclRange, GetCurrScTab(), GetCurrScTab(), true );
1230 
1231     mxPCache = GetPivotTableManager().GetPivotCache( maPTInfo.mnCacheIdx );
1232     mxCurrField.reset();
1233 }
1234 
ReadSxvd(XclImpStream & rStrm)1235 void XclImpPivotTable::ReadSxvd( XclImpStream& rStrm )
1236 {
1237     sal_uInt16 nFieldCount = GetFieldCount();
1238     if( nFieldCount < EXC_PT_MAXFIELDCOUNT )
1239     {
1240         // cache index for the field is equal to the SXVD record index
1241         mxCurrField.reset( new XclImpPTField( *this, nFieldCount ) );
1242         maFields.push_back( mxCurrField );
1243         mxCurrField->ReadSxvd( rStrm );
1244         // add visible name of new field to list of visible names
1245         maVisFieldNames.push_back( mxCurrField->GetVisFieldName() );
1246         DBG_ASSERT( maFields.size() == maVisFieldNames.size(),
1247             "XclImpPivotTable::ReadSxvd - wrong size of visible name array" );
1248     }
1249     else
1250         mxCurrField.reset();
1251 }
1252 
ReadSxvi(XclImpStream & rStrm)1253 void XclImpPivotTable::ReadSxvi( XclImpStream& rStrm )
1254 {
1255     if( mxCurrField.is() )
1256         mxCurrField->ReadSxvi( rStrm );
1257 }
1258 
ReadSxvdex(XclImpStream & rStrm)1259 void XclImpPivotTable::ReadSxvdex( XclImpStream& rStrm )
1260 {
1261     if( mxCurrField.is() )
1262         mxCurrField->ReadSxvdex( rStrm );
1263 }
1264 
ReadSxivd(XclImpStream & rStrm)1265 void XclImpPivotTable::ReadSxivd( XclImpStream& rStrm )
1266 {
1267     mxCurrField.reset();
1268 
1269     // find the index vector to fill (row SXIVD doesn't exist without row fields)
1270     ScfUInt16Vec* pFieldVec = 0;
1271     if( maRowFields.empty() && (maPTInfo.mnRowFields > 0) )
1272         pFieldVec = &maRowFields;
1273     else if( maColFields.empty() && (maPTInfo.mnColFields > 0) )
1274         pFieldVec = &maColFields;
1275 
1276     // fill the vector from record data
1277     if( pFieldVec )
1278     {
1279         sal_uInt16 nSize = ulimit_cast< sal_uInt16 >( rStrm.GetRecSize() / 2, EXC_PT_MAXROWCOLCOUNT );
1280         pFieldVec->reserve( nSize );
1281         for( sal_uInt16 nIdx = 0; nIdx < nSize; ++nIdx )
1282         {
1283             sal_uInt16 nFieldIdx;
1284             rStrm >> nFieldIdx;
1285             pFieldVec->push_back( nFieldIdx );
1286 
1287             // set orientation at special data orientation field
1288             if( nFieldIdx == EXC_SXIVD_DATA )
1289             {
1290                 sal_uInt16 nAxis = (pFieldVec == &maRowFields) ? EXC_SXVD_AXIS_ROW : EXC_SXVD_AXIS_COL;
1291                 maDataOrientField.SetAxes( nAxis );
1292             }
1293         }
1294     }
1295 }
1296 
ReadSxpi(XclImpStream & rStrm)1297 void XclImpPivotTable::ReadSxpi( XclImpStream& rStrm )
1298 {
1299     mxCurrField.reset();
1300 
1301     sal_uInt16 nSize = ulimit_cast< sal_uInt16 >( rStrm.GetRecSize() / 6 );
1302     for( sal_uInt16 nEntry = 0; nEntry < nSize; ++nEntry )
1303     {
1304         XclPTPageFieldInfo aPageInfo;
1305         rStrm >> aPageInfo;
1306         if( XclImpPTField* pField = GetFieldAcc( aPageInfo.mnField ) )
1307         {
1308             maPageFields.push_back( aPageInfo.mnField );
1309             pField->SetPageFieldInfo( aPageInfo );
1310         }
1311         GetCurrSheetDrawing().SetSkipObj( aPageInfo.mnObjId );
1312     }
1313 }
1314 
ReadSxdi(XclImpStream & rStrm)1315 void XclImpPivotTable::ReadSxdi( XclImpStream& rStrm )
1316 {
1317     mxCurrField.reset();
1318 
1319     XclPTDataFieldInfo aDataInfo;
1320     rStrm >> aDataInfo;
1321     if( XclImpPTField* pField = GetFieldAcc( aDataInfo.mnField ) )
1322     {
1323         maOrigDataFields.push_back( aDataInfo.mnField );
1324         // DataPilot does not support double data fields -> add first appearance to index list only
1325         if( !pField->HasDataFieldInfo() )
1326             maFiltDataFields.push_back( aDataInfo.mnField );
1327         pField->AddDataFieldInfo( aDataInfo );
1328     }
1329 }
1330 
ReadSxex(XclImpStream & rStrm)1331 void XclImpPivotTable::ReadSxex( XclImpStream& rStrm )
1332 {
1333     rStrm >> maPTExtInfo;
1334 }
1335 
ReadSxViewEx9(XclImpStream & rStrm)1336 void XclImpPivotTable::ReadSxViewEx9( XclImpStream& rStrm )
1337 {
1338     rStrm >> maPTViewEx9Info;
1339 }
1340 
1341 // ----------------------------------------------------------------------------
1342 
Convert()1343 void XclImpPivotTable::Convert()
1344 {
1345     if( !mxPCache || !mxPCache->GetSourceRange().IsValid() )
1346 		return;
1347 
1348 	ScDPSaveData aSaveData;
1349 
1350     // *** global settings ***
1351 
1352     aSaveData.SetRowGrand( ::get_flag( maPTInfo.mnFlags, EXC_SXVIEW_ROWGRAND ) );
1353     aSaveData.SetColumnGrand( ::get_flag( maPTInfo.mnFlags, EXC_SXVIEW_COLGRAND ) );
1354     aSaveData.SetFilterButton( sal_False );
1355     aSaveData.SetDrillDown( ::get_flag( maPTExtInfo.mnFlags, EXC_SXEX_DRILLDOWN ) );
1356 
1357     // *** fields ***
1358 
1359     ScfUInt16Vec::const_iterator aIt, aEnd;
1360 
1361     // row fields
1362     for( aIt = maRowFields.begin(), aEnd = maRowFields.end(); aIt != aEnd; ++aIt )
1363         if( const XclImpPTField* pField = GetField( *aIt ) )
1364             pField->ConvertRowColField( aSaveData );
1365 
1366     // column fields
1367     for( aIt = maColFields.begin(), aEnd = maColFields.end(); aIt != aEnd; ++aIt )
1368         if( const XclImpPTField* pField = GetField( *aIt ) )
1369             pField->ConvertRowColField( aSaveData );
1370 
1371     // page fields
1372     for( aIt = maPageFields.begin(), aEnd = maPageFields.end(); aIt != aEnd; ++aIt )
1373         if( const XclImpPTField* pField = GetField( *aIt ) )
1374             pField->ConvertPageField( aSaveData );
1375 
1376     // We need to import hidden fields because hidden fields may contain
1377     // special settings for subtotals (aggregation function, filters, custom
1378     // name etc.) and members (hidden, custom name etc.).
1379 
1380     // hidden fields
1381     for( sal_uInt16 nField = 0, nCount = GetFieldCount(); nField < nCount; ++nField )
1382         if( const XclImpPTField* pField = GetField( nField ) )
1383             if( (pField->GetAxes() & EXC_SXVD_AXIS_ROWCOLPAGE) == 0 )
1384                 pField->ConvertHiddenField( aSaveData );
1385 
1386     // data fields
1387     for( aIt = maFiltDataFields.begin(), aEnd = maFiltDataFields.end(); aIt != aEnd; ++aIt )
1388         if( const XclImpPTField* pField = GetField( *aIt ) )
1389             pField->ConvertDataField( aSaveData );
1390 
1391     // *** insert into Calc document ***
1392 
1393     // create source descriptor
1394     ScSheetSourceDesc aDesc;
1395     aDesc.aSourceRange = mxPCache->GetSourceRange();
1396 
1397     // adjust output range to include the page fields
1398     ScRange aOutRange( maOutScRange );
1399     if( !maPageFields.empty() )
1400     {
1401         SCsROW nDecRows = ::std::min< SCsROW >( aOutRange.aStart.Row(), maPageFields.size() + 1 );
1402         aOutRange.aStart.IncRow( -nDecRows );
1403     }
1404 
1405     // create the DataPilot
1406     ScDPObject* pDPObj = new ScDPObject( GetDocPtr() );
1407     pDPObj->SetName( maPTInfo.maTableName );
1408     if (maPTInfo.maDataName.Len() > 0)
1409         aSaveData.GetDataLayoutDimension()->SetLayoutName(maPTInfo.maDataName);
1410 
1411     if (maPTViewEx9Info.maGrandTotalName.Len() > 0)
1412         aSaveData.SetGrandTotalName(maPTViewEx9Info.maGrandTotalName);
1413 
1414     pDPObj->SetSaveData( aSaveData );
1415     pDPObj->SetSheetDesc( aDesc );
1416     pDPObj->SetOutRange( aOutRange );
1417     pDPObj->SetAlive( sal_True );
1418     pDPObj->SetHeaderLayout( maPTViewEx9Info.mnGridLayout == 0 );
1419 
1420     GetDoc().GetDPCollection()->InsertNewTable(pDPObj);
1421     mpDPObj = pDPObj;
1422 
1423     ApplyMergeFlags(aOutRange, aSaveData);
1424     MaybeRefresh();	// refresh after convert immediately
1425     mxPCache = XclImpPivotCacheRef();	// release memory
1426 }
1427 
MaybeRefresh()1428 void XclImpPivotTable::MaybeRefresh()
1429 {
1430     if (mpDPObj && mxPCache->IsRefreshOnLoad())
1431     {
1432         // 'refresh table on load' flag is set.  Refresh the table now.  Some
1433         // Excel files contain partial table output when this flag is set.
1434         ScRange aOutRange = mpDPObj->GetOutRange();
1435         mpDPObj->Output(aOutRange.aStart);
1436     }
1437 }
1438 
ApplyMergeFlags(const ScRange & rOutRange,const ScDPSaveData & rSaveData)1439 void XclImpPivotTable::ApplyMergeFlags(const ScRange& rOutRange, const ScDPSaveData& rSaveData)
1440 {
1441     // Apply merge flags for varoius datapilot controls.
1442 
1443     ScDPOutputGeometry aGeometry(rOutRange, false, ScDPOutputGeometry::XLS);
1444     aGeometry.setColumnFieldCount(maPTInfo.mnColFields);
1445     aGeometry.setPageFieldCount(maPTInfo.mnPageFields);
1446     aGeometry.setDataFieldCount(maPTInfo.mnDataFields);
1447 
1448     // Excel includes data layout field in the row field count.  We need to
1449     // subtract it.
1450     bool bDataLayout = maPTInfo.mnDataFields > 1;
1451     aGeometry.setRowFieldCount(maPTInfo.mnRowFields - static_cast<sal_uInt32>(bDataLayout));
1452 
1453     ScDocument& rDoc = GetDoc();
1454 
1455     vector<ScAddress> aPageBtns;
1456     aGeometry.getPageFieldPositions(aPageBtns);
1457     vector<ScAddress>::const_iterator itr = aPageBtns.begin(), itrEnd = aPageBtns.end();
1458     for (; itr != itrEnd; ++itr)
1459     {
1460         sal_uInt16 nMFlag = SC_MF_BUTTON;
1461         String aName;
1462         rDoc.GetString(itr->Col(), itr->Row(), itr->Tab(), aName);
1463         if (rSaveData.HasInvisibleMember(aName))
1464             nMFlag |= SC_MF_HIDDEN_MEMBER;
1465 
1466         rDoc.ApplyFlagsTab(itr->Col(), itr->Row(), itr->Col(), itr->Row(), itr->Tab(), nMFlag);
1467         rDoc.ApplyFlagsTab(itr->Col()+1, itr->Row(), itr->Col()+1, itr->Row(), itr->Tab(), SC_MF_AUTO);
1468     }
1469 
1470     vector<ScAddress> aColBtns;
1471     aGeometry.getColumnFieldPositions(aColBtns);
1472     itr    = aColBtns.begin();
1473     itrEnd = aColBtns.end();
1474     for (; itr != itrEnd; ++itr)
1475     {
1476         sal_Int16 nMFlag = SC_MF_BUTTON | SC_MF_BUTTON_POPUP;
1477         String aName;
1478         rDoc.GetString(itr->Col(), itr->Row(), itr->Tab(), aName);
1479         if (rSaveData.HasInvisibleMember(aName))
1480             nMFlag |= SC_MF_HIDDEN_MEMBER;
1481         rDoc.ApplyFlagsTab(itr->Col(), itr->Row(), itr->Col(), itr->Row(), itr->Tab(), nMFlag);
1482     }
1483 
1484     vector<ScAddress> aRowBtns;
1485     aGeometry.getRowFieldPositions(aRowBtns);
1486     if (aRowBtns.empty())
1487     {
1488         if (bDataLayout)
1489         {
1490             // No row fields, but the data layout button exists.
1491             SCROW nRow = aGeometry.getRowFieldHeaderRow();
1492             SCCOL nCol = rOutRange.aStart.Col();
1493             SCTAB nTab = rOutRange.aStart.Tab();
1494             rDoc.ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, SC_MF_BUTTON);
1495         }
1496     }
1497     else
1498     {
1499         itr    = aRowBtns.begin();
1500         itrEnd = aRowBtns.end();
1501         for (; itr != itrEnd; ++itr)
1502         {
1503             sal_Int16 nMFlag = SC_MF_BUTTON | SC_MF_BUTTON_POPUP;
1504             String aName;
1505             rDoc.GetString(itr->Col(), itr->Row(), itr->Tab(), aName);
1506             if (rSaveData.HasInvisibleMember(aName))
1507                 nMFlag |= SC_MF_HIDDEN_MEMBER;
1508             rDoc.ApplyFlagsTab(itr->Col(), itr->Row(), itr->Col(), itr->Row(), itr->Tab(), nMFlag);
1509         }
1510         if (bDataLayout)
1511         {
1512             --itr; // move back to the last row field position.
1513             rDoc.ApplyFlagsTab(itr->Col(), itr->Row(), itr->Col(), itr->Row(), itr->Tab(), SC_MF_BUTTON);
1514         }
1515     }
1516 }
1517 
1518 // ============================================================================
1519 // ============================================================================
1520 
XclImpPivotTableManager(const XclImpRoot & rRoot)1521 XclImpPivotTableManager::XclImpPivotTableManager( const XclImpRoot& rRoot ) :
1522     XclImpRoot( rRoot )
1523 {
1524 }
1525 
~XclImpPivotTableManager()1526 XclImpPivotTableManager::~XclImpPivotTableManager()
1527 {
1528 }
1529 
1530 // pivot cache records --------------------------------------------------------
1531 
GetPivotCache(sal_uInt16 nCacheIdx)1532 XclImpPivotCacheRef XclImpPivotTableManager::GetPivotCache( sal_uInt16 nCacheIdx )
1533 {
1534     XclImpPivotCacheRef xPCache;
1535     if( nCacheIdx < maPCaches.size() )
1536         xPCache = maPCaches[ nCacheIdx ];
1537     return xPCache;
1538 }
1539 
ReadSxidstm(XclImpStream & rStrm)1540 void XclImpPivotTableManager::ReadSxidstm( XclImpStream& rStrm )
1541 {
1542     XclImpPivotCacheRef xPCache( new XclImpPivotCache( GetRoot() ) );
1543     maPCaches.push_back( xPCache );
1544     xPCache->ReadSxidstm( rStrm );
1545 }
1546 
ReadSxvs(XclImpStream & rStrm)1547 void XclImpPivotTableManager::ReadSxvs( XclImpStream& rStrm )
1548 {
1549     if( !maPCaches.empty() )
1550         maPCaches.back()->ReadSxvs( rStrm );
1551 }
1552 
ReadDconref(XclImpStream & rStrm)1553 void XclImpPivotTableManager::ReadDconref( XclImpStream& rStrm )
1554 {
1555     if( !maPCaches.empty() )
1556         maPCaches.back()->ReadDconref( rStrm );
1557 }
1558 
1559 // pivot table records --------------------------------------------------------
1560 
ReadSxview(XclImpStream & rStrm)1561 void XclImpPivotTableManager::ReadSxview( XclImpStream& rStrm )
1562 {
1563     XclImpPivotTableRef xPTable( new XclImpPivotTable( GetRoot() ) );
1564     maPTables.push_back( xPTable );
1565     xPTable->ReadSxview( rStrm );
1566 }
1567 
ReadSxvd(XclImpStream & rStrm)1568 void XclImpPivotTableManager::ReadSxvd( XclImpStream& rStrm )
1569 {
1570     if( !maPTables.empty() )
1571         maPTables.back()->ReadSxvd( rStrm );
1572 }
1573 
ReadSxvdex(XclImpStream & rStrm)1574 void XclImpPivotTableManager::ReadSxvdex( XclImpStream& rStrm )
1575 {
1576     if( !maPTables.empty() )
1577         maPTables.back()->ReadSxvdex( rStrm );
1578 }
1579 
ReadSxivd(XclImpStream & rStrm)1580 void XclImpPivotTableManager::ReadSxivd( XclImpStream& rStrm )
1581 {
1582     if( !maPTables.empty() )
1583         maPTables.back()->ReadSxivd( rStrm );
1584 }
1585 
ReadSxpi(XclImpStream & rStrm)1586 void XclImpPivotTableManager::ReadSxpi( XclImpStream& rStrm )
1587 {
1588     if( !maPTables.empty() )
1589         maPTables.back()->ReadSxpi( rStrm );
1590 }
1591 
ReadSxdi(XclImpStream & rStrm)1592 void XclImpPivotTableManager::ReadSxdi( XclImpStream& rStrm )
1593 {
1594     if( !maPTables.empty() )
1595         maPTables.back()->ReadSxdi( rStrm );
1596 }
1597 
ReadSxvi(XclImpStream & rStrm)1598 void XclImpPivotTableManager::ReadSxvi( XclImpStream& rStrm )
1599 {
1600     if( !maPTables.empty() )
1601         maPTables.back()->ReadSxvi( rStrm );
1602 }
1603 
ReadSxex(XclImpStream & rStrm)1604 void XclImpPivotTableManager::ReadSxex( XclImpStream& rStrm )
1605 {
1606     if( !maPTables.empty() )
1607         maPTables.back()->ReadSxex( rStrm );
1608 }
1609 
ReadSxViewEx9(XclImpStream & rStrm)1610 void XclImpPivotTableManager::ReadSxViewEx9( XclImpStream& rStrm )
1611 {
1612     if( !maPTables.empty() )
1613         maPTables.back()->ReadSxViewEx9( rStrm );
1614 }
1615 
1616 // ----------------------------------------------------------------------------
1617 
1618 // Reading all used pivot caches at one time and then converting all pivot tables together will consume too much memory, forbid this action
1619 // ConvertPivotTables will change to read cache one by one and convert it then release the memory
1620 /*void XclImpPivotTableManager::ReadPivotCaches( XclImpStream& rStrm )
1621 {
1622     for( XclImpPivotCacheVec::iterator aIt = maPCaches.begin(), aEnd = maPCaches.end(); aIt != aEnd; ++aIt )
1623         (*aIt)->ReadPivotCacheStream( rStrm );
1624 }*/
1625 
ConvertPivotTables(XclImpStream & rStm)1626 void XclImpPivotTableManager::ConvertPivotTables( XclImpStream & rStm/* guoyanp: for DP memory */ )
1627 {
1628 //    for( XclImpPivotTableVec::iterator aIt = maPTables.begin(), aEnd = maPTables.end(); aIt != aEnd; ++aIt )
1629 //        (*aIt)->Convert();
1630 
1631     std::map< sal_uInt16, std::list< XclImpPivotTableRef > > aMap;
1632 
1633     for( XclImpPivotTableVec::iterator aIt = maPTables.begin(), aEnd = maPTables.end(); aIt != aEnd; ++aIt )
1634         aMap[(*aIt)->GetCacheId()].push_back( *aIt );
1635 
1636     size_t iCache = 0;
1637 
1638     for( std::map< sal_uInt16, std::list< XclImpPivotTableRef > >::iterator i = aMap.begin(); i != aMap.end(); i++, iCache++ )
1639     {
1640         if( i->first >= maPCaches.size() ) continue;
1641 
1642         maPCaches[iCache]->ReadPivotCacheStream( rStm );
1643 
1644         for( std::list< XclImpPivotTableRef >::iterator j = i->second.begin(); j != i->second.end(); j++ )
1645             (*j)->Convert();
1646 
1647         maPCaches[iCache] = XclImpPivotCacheRef();
1648     }
1649 }
1650 
1651 // Reading all used pivot caches at one time and then converting all pivot tables together will consume too much memory, forbid that action
1652 // ConvertPivotTables will change to read cache one by one and convert it then release the memory
1653 // So refreshing all pivot tables at one time is forbidden too because the cache already released
1654 // Need to refresh one by one after convert every pivot table
1655 /*void XclImpPivotTableManager::MaybeRefreshPivotTables()
1656 {
1657     for( XclImpPivotTableVec::iterator aIt = maPTables.begin(), aEnd = maPTables.end(); aIt != aEnd; ++aIt )
1658         (*aIt)->MaybeRefresh();
1659 }*/
1660 
1661 // ============================================================================
1662 
1663