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