Version 4.0.2.1, tag libreoffice-4.0.2.1
[LibreOffice.git] / sc / source / filter / excel / xipivot.cxx
blobf20550207a89d163cb3117639d0bc5f9344a04e9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "xipivot.hxx"
23 #include <com/sun/star/sheet/DataPilotFieldSortInfo.hpp>
24 #include <com/sun/star/sheet/DataPilotFieldAutoShowInfo.hpp>
25 #include <com/sun/star/sheet/DataPilotFieldLayoutInfo.hpp>
26 #include <com/sun/star/sheet/DataPilotFieldReference.hpp>
28 #include <tools/datetime.hxx>
29 #include <svl/zformat.hxx>
30 #include <svl/intitem.hxx>
32 #include "document.hxx"
33 #include "cell.hxx"
34 #include "dpsave.hxx"
35 #include "dpdimsave.hxx"
36 #include "dpobject.hxx"
37 #include "dpshttab.hxx"
38 #include "dpoutputgeometry.hxx"
39 #include "scitems.hxx"
40 #include "attrib.hxx"
42 #include "xltracer.hxx"
43 #include "xistream.hxx"
44 #include "xihelper.hxx"
45 #include "xilink.hxx"
46 #include "xiescher.hxx"
48 //! TODO ExcelToSc usage
49 #include "excform.hxx"
50 #include "xltable.hxx"
52 #include <vector>
54 using namespace com::sun::star;
56 using ::rtl::OUString;
57 using ::rtl::OUStringBuffer;
58 using ::com::sun::star::sheet::DataPilotFieldOrientation;
59 using ::com::sun::star::sheet::DataPilotFieldOrientation_DATA;
60 using ::com::sun::star::sheet::DataPilotFieldSortInfo;
61 using ::com::sun::star::sheet::DataPilotFieldAutoShowInfo;
62 using ::com::sun::star::sheet::DataPilotFieldLayoutInfo;
63 using ::com::sun::star::sheet::DataPilotFieldReference;
64 using ::std::vector;
66 // ============================================================================
67 // Pivot cache
68 // ============================================================================
70 XclImpPCItem::XclImpPCItem( XclImpStream& rStrm )
72 switch( rStrm.GetRecId() )
74 case EXC_ID_SXDOUBLE: ReadSxdouble( rStrm ); break;
75 case EXC_ID_SXBOOLEAN: ReadSxboolean( rStrm ); break;
76 case EXC_ID_SXERROR: ReadSxerror( rStrm ); break;
77 case EXC_ID_SXINTEGER: ReadSxinteger( rStrm ); break;
78 case EXC_ID_SXSTRING: ReadSxstring( rStrm ); break;
79 case EXC_ID_SXDATETIME: ReadSxdatetime( rStrm ); break;
80 case EXC_ID_SXEMPTY: ReadSxempty( rStrm ); break;
81 default: OSL_FAIL( "XclImpPCItem::XclImpPCItem - unknown record id" );
85 namespace {
87 void lclSetValue( const XclImpRoot& rRoot, const ScAddress& rScPos, double fValue, short nFormatType )
89 ScDocument& rDoc = rRoot.GetDoc();
90 rDoc.SetValue( rScPos.Col(), rScPos.Row(), rScPos.Tab(), fValue );
91 sal_uInt32 nScNumFmt = rRoot.GetFormatter().GetStandardFormat( nFormatType, rRoot.GetDocLanguage() );
92 rDoc.ApplyAttr( rScPos.Col(), rScPos.Row(), rScPos.Tab(), SfxUInt32Item( ATTR_VALUE_FORMAT, nScNumFmt ) );
95 } // namespace
97 void XclImpPCItem::WriteToSource( const XclImpRoot& rRoot, const ScAddress& rScPos ) const
99 ScDocument& rDoc = rRoot.GetDoc();
100 if( const rtl::OUString* pText = GetText() )
101 rDoc.SetString( rScPos.Col(), rScPos.Row(), rScPos.Tab(), *pText );
102 else if( const double* pfValue = GetDouble() )
103 rDoc.SetValue( rScPos.Col(), rScPos.Row(), rScPos.Tab(), *pfValue );
104 else if( const sal_Int16* pnValue = GetInteger() )
105 rDoc.SetValue( rScPos.Col(), rScPos.Row(), rScPos.Tab(), *pnValue );
106 else if( const bool* pbValue = GetBool() )
107 lclSetValue( rRoot, rScPos, *pbValue ? 1.0 : 0.0, NUMBERFORMAT_LOGICAL );
108 else if( const DateTime* pDateTime = GetDateTime() )
110 // set number format date, time, or date/time, depending on the value
111 double fValue = rRoot.GetDoubleFromDateTime( *pDateTime );
112 double fInt = 0.0;
113 double fFrac = modf( fValue, &fInt );
114 short nFormatType = ((fFrac == 0.0) && (fInt != 0.0)) ? NUMBERFORMAT_DATE :
115 ((fInt == 0.0) ? NUMBERFORMAT_TIME : NUMBERFORMAT_DATETIME);
116 lclSetValue( rRoot, rScPos, fValue, nFormatType );
118 else if( const sal_uInt16* pnError = GetError() )
120 double fValue;
121 sal_uInt8 nErrCode = static_cast< sal_uInt8 >( *pnError );
122 const ScTokenArray* pScTokArr = rRoot.GetOldFmlaConverter().GetBoolErr(
123 XclTools::ErrorToEnum( fValue, EXC_BOOLERR_ERROR, nErrCode ) );
124 ScFormulaCell* pCell = new ScFormulaCell( &rDoc, rScPos, pScTokArr );
125 pCell->SetHybridDouble( fValue );
126 rDoc.PutCell( rScPos, pCell );
130 void XclImpPCItem::ReadSxdouble( XclImpStream& rStrm )
132 OSL_ENSURE( rStrm.GetRecSize() == 8, "XclImpPCItem::ReadSxdouble - wrong record size" );
133 SetDouble( rStrm.ReadDouble() );
136 void XclImpPCItem::ReadSxboolean( XclImpStream& rStrm )
138 OSL_ENSURE( rStrm.GetRecSize() == 2, "XclImpPCItem::ReadSxboolean - wrong record size" );
139 SetBool( rStrm.ReaduInt16() != 0 );
142 void XclImpPCItem::ReadSxerror( XclImpStream& rStrm )
144 OSL_ENSURE( rStrm.GetRecSize() == 2, "XclImpPCItem::ReadSxerror - wrong record size" );
145 SetError( rStrm.ReaduInt16() );
148 void XclImpPCItem::ReadSxinteger( XclImpStream& rStrm )
150 OSL_ENSURE( rStrm.GetRecSize() == 2, "XclImpPCItem::ReadSxinteger - wrong record size" );
151 SetInteger( rStrm.ReadInt16() );
154 void XclImpPCItem::ReadSxstring( XclImpStream& rStrm )
156 OSL_ENSURE( rStrm.GetRecSize() >= 3, "XclImpPCItem::ReadSxstring - wrong record size" );
157 SetText( rStrm.ReadUniString() );
160 void XclImpPCItem::ReadSxdatetime( XclImpStream& rStrm )
162 OSL_ENSURE( rStrm.GetRecSize() == 8, "XclImpPCItem::ReadSxdatetime - wrong record size" );
163 sal_uInt16 nYear, nMonth;
164 sal_uInt8 nDay, nHour, nMin, nSec;
165 rStrm >> nYear >> nMonth >> nDay >> nHour >> nMin >> nSec;
166 SetDateTime( DateTime( Date( nDay, nMonth, nYear ), Time( nHour, nMin, nSec ) ) );
169 void XclImpPCItem::ReadSxempty( XclImpStream& rStrm )
171 (void)rStrm; // avoid compiler warning
172 OSL_ENSURE( rStrm.GetRecSize() == 0, "XclImpPCItem::ReadSxempty - wrong record size" );
173 SetEmpty();
176 // ============================================================================
178 XclImpPCField::XclImpPCField( const XclImpRoot& rRoot, XclImpPivotCache& rPCache, sal_uInt16 nFieldIdx ) :
179 XclPCField( EXC_PCFIELD_UNKNOWN, nFieldIdx ),
180 XclImpRoot( rRoot ),
181 mrPCache( rPCache ),
182 mnSourceScCol( -1 ),
183 mbNumGroupInfoRead( false )
187 XclImpPCField::~XclImpPCField()
191 // general field/item access --------------------------------------------------
193 const rtl::OUString& XclImpPCField::GetFieldName( const ScfStringVec& rVisNames ) const
195 if( IsGroupChildField() && (mnFieldIdx < rVisNames.size()) )
197 const rtl::OUString& rVisName = rVisNames[ mnFieldIdx ];
198 if (!rVisName.isEmpty())
199 return rVisName;
201 return maFieldInfo.maName;
204 const XclImpPCField* XclImpPCField::GetGroupBaseField() const
206 OSL_ENSURE( IsGroupChildField(), "XclImpPCField::GetGroupBaseField - this field type does not have a base field" );
207 return IsGroupChildField() ? mrPCache.GetField( maFieldInfo.mnGroupBase ) : 0;
210 const XclImpPCItem* XclImpPCField::GetItem( sal_uInt16 nItemIdx ) const
212 return (nItemIdx < maItems.size()) ? maItems[ nItemIdx ].get() : 0;
215 const XclImpPCItem* XclImpPCField::GetLimitItem( sal_uInt16 nItemIdx ) const
217 OSL_ENSURE( nItemIdx < 3, "XclImpPCField::GetLimitItem - invalid item index" );
218 OSL_ENSURE( nItemIdx < maNumGroupItems.size(), "XclImpPCField::GetLimitItem - no item found" );
219 return (nItemIdx < maNumGroupItems.size()) ? maNumGroupItems[ nItemIdx ].get() : 0;
222 void XclImpPCField::WriteFieldNameToSource( SCCOL nScCol, SCTAB nScTab ) const
224 OSL_ENSURE( HasOrigItems(), "XclImpPCField::WriteFieldNameToSource - only for standard fields" );
225 GetDoc().SetString( nScCol, 0, nScTab, maFieldInfo.maName );
226 mnSourceScCol = nScCol;
229 void XclImpPCField::WriteOrigItemToSource( SCROW nScRow, SCTAB nScTab, sal_uInt16 nItemIdx ) const
231 if( nItemIdx < maOrigItems.size() )
232 maOrigItems[ nItemIdx ]->WriteToSource( GetRoot(), ScAddress( mnSourceScCol, nScRow, nScTab ) );
235 void XclImpPCField::WriteLastOrigItemToSource( SCROW nScRow, SCTAB nScTab ) const
237 if( !maOrigItems.empty() )
238 maOrigItems.back()->WriteToSource( GetRoot(), ScAddress( mnSourceScCol, nScRow, nScTab ) );
241 // records --------------------------------------------------------------------
243 void XclImpPCField::ReadSxfield( XclImpStream& rStrm )
245 rStrm >> maFieldInfo;
247 /* Detect the type of this field. This is done very restrictive to detect
248 any unexpected state. */
249 meFieldType = EXC_PCFIELD_UNKNOWN;
251 bool bItems = ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_HASITEMS );
252 bool bPostp = ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_POSTPONE );
253 bool bCalced = ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_CALCED );
254 bool bChild = ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_HASCHILD );
255 bool bNum = ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_NUMGROUP );
257 sal_uInt16 nVisC = maFieldInfo.mnVisItems;
258 sal_uInt16 nGroupC = maFieldInfo.mnGroupItems;
259 sal_uInt16 nBaseC = maFieldInfo.mnBaseItems;
260 sal_uInt16 nOrigC = maFieldInfo.mnOrigItems;
261 OSL_ENSURE( nVisC > 0, "XclImpPCField::ReadSxfield - field without visible items" );
263 sal_uInt16 nType = maFieldInfo.mnFlags & EXC_SXFIELD_DATA_MASK;
264 bool bType =
265 (nType == EXC_SXFIELD_DATA_STR) ||
266 (nType == EXC_SXFIELD_DATA_INT) ||
267 (nType == EXC_SXFIELD_DATA_DBL) ||
268 (nType == EXC_SXFIELD_DATA_STR_INT) ||
269 (nType == EXC_SXFIELD_DATA_STR_DBL) ||
270 (nType == EXC_SXFIELD_DATA_DATE) ||
271 (nType == EXC_SXFIELD_DATA_DATE_EMP) ||
272 (nType == EXC_SXFIELD_DATA_DATE_NUM) ||
273 (nType == EXC_SXFIELD_DATA_DATE_STR);
274 bool bTypeNone =
275 (nType == EXC_SXFIELD_DATA_NONE);
276 // for now, ignore data type of calculated fields
277 OSL_ENSURE( bCalced || bType || bTypeNone, "XclImpPCField::ReadSxfield - unknown item data type" );
279 if( nVisC > 0 || bPostp )
281 if( bItems && !bPostp )
283 if( !bCalced )
285 // 1) standard fields and standard grouping fields
286 if( !bNum )
288 // 1a) standard field without grouping
289 if( bType && (nGroupC == 0) && (nBaseC == 0) && (nOrigC == nVisC) )
290 meFieldType = EXC_PCFIELD_STANDARD;
292 // 1b) standard grouping field
293 else if( bTypeNone && (nGroupC == nVisC) && (nBaseC > 0) && (nOrigC == 0) )
294 meFieldType = EXC_PCFIELD_STDGROUP;
296 // 2) numerical grouping fields
297 else if( (nGroupC == nVisC) && (nBaseC == 0) )
299 // 2a) single num/date grouping field without child grouping field
300 if( !bChild && bType && (nOrigC > 0) )
302 switch( nType )
304 case EXC_SXFIELD_DATA_INT:
305 case EXC_SXFIELD_DATA_DBL: meFieldType = EXC_PCFIELD_NUMGROUP; break;
306 case EXC_SXFIELD_DATA_DATE: meFieldType = EXC_PCFIELD_DATEGROUP; break;
307 default: OSL_FAIL( "XclImpPCField::ReadSxfield - numeric group with wrong data type" );
311 // 2b) first date grouping field with child grouping field
312 else if( bChild && (nType == EXC_SXFIELD_DATA_DATE) && (nOrigC > 0) )
313 meFieldType = EXC_PCFIELD_DATEGROUP;
315 // 2c) additional date grouping field
316 else if( bTypeNone && (nOrigC == 0) )
317 meFieldType = EXC_PCFIELD_DATECHILD;
319 OSL_ENSURE( meFieldType != EXC_PCFIELD_UNKNOWN, "XclImpPCField::ReadSxfield - invalid standard or grouped field" );
322 // 3) calculated field
323 else
325 if( !bChild && !bNum && (nGroupC == 0) && (nBaseC == 0) && (nOrigC == 0) )
326 meFieldType = EXC_PCFIELD_CALCED;
327 OSL_ENSURE( meFieldType == EXC_PCFIELD_CALCED, "XclImpPCField::ReadSxfield - invalid calculated field" );
331 else if( !bItems && bPostp )
333 // 4) standard field with postponed items
334 if( !bCalced && !bChild && !bNum && bType && (nGroupC == 0) && (nBaseC == 0) && (nOrigC == 0) )
335 meFieldType = EXC_PCFIELD_STANDARD;
336 OSL_ENSURE( meFieldType == EXC_PCFIELD_STANDARD, "XclImpPCField::ReadSxfield - invalid postponed field" );
341 void XclImpPCField::ReadItem( XclImpStream& rStrm )
343 OSL_ENSURE( HasInlineItems() || HasPostponedItems(), "XclImpPCField::ReadItem - field does not expect items" );
345 // read the item
346 XclImpPCItemRef xItem( new XclImpPCItem( rStrm ) );
348 // try to insert into an item list
349 if( mbNumGroupInfoRead )
351 // there are 3 items after SXNUMGROUP that contain grouping limits and step count
352 if( maNumGroupItems.size() < 3 )
353 maNumGroupItems.push_back( xItem );
354 else
355 maOrigItems.push_back( xItem );
357 else if( HasInlineItems() || HasPostponedItems() )
359 maItems.push_back( xItem );
360 // visible item is original item in standard fields
361 if( IsStandardField() )
362 maOrigItems.push_back( xItem );
366 void XclImpPCField::ReadSxnumgroup( XclImpStream& rStrm )
368 OSL_ENSURE( IsNumGroupField() || IsDateGroupField(), "XclImpPCField::ReadSxnumgroup - SXNUMGROUP outside numeric grouping field" );
369 OSL_ENSURE( !mbNumGroupInfoRead, "XclImpPCField::ReadSxnumgroup - multiple SXNUMGROUP records" );
370 OSL_ENSURE( maItems.size() == maFieldInfo.mnGroupItems, "XclImpPCField::ReadSxnumgroup - SXNUMGROUP out of record order" );
371 rStrm >> maNumGroupInfo;
372 mbNumGroupInfoRead = IsNumGroupField() || IsDateGroupField();
375 void XclImpPCField::ReadSxgroupinfo( XclImpStream& rStrm )
377 OSL_ENSURE( IsStdGroupField(), "XclImpPCField::ReadSxgroupinfo - SXGROUPINFO outside grouping field" );
378 OSL_ENSURE( maGroupOrder.empty(), "XclImpPCField::ReadSxgroupinfo - multiple SXGROUPINFO records" );
379 OSL_ENSURE( maItems.size() == maFieldInfo.mnGroupItems, "XclImpPCField::ReadSxgroupinfo - SXGROUPINFO out of record order" );
380 OSL_ENSURE( (rStrm.GetRecLeft() / 2) == maFieldInfo.mnBaseItems, "XclImpPCField::ReadSxgroupinfo - wrong SXGROUPINFO size" );
381 maGroupOrder.clear();
382 size_t nSize = rStrm.GetRecLeft() / 2;
383 maGroupOrder.resize( nSize, 0 );
384 for( size_t nIdx = 0; nIdx < nSize; ++nIdx )
385 rStrm >> maGroupOrder[ nIdx ];
388 // grouping -------------------------------------------------------------------
390 void XclImpPCField::ConvertGroupField( ScDPSaveData& rSaveData, const ScfStringVec& rVisNames ) const
392 if (!GetFieldName(rVisNames).isEmpty())
394 if( IsStdGroupField() )
395 ConvertStdGroupField( rSaveData, rVisNames );
396 else if( IsNumGroupField() )
397 ConvertNumGroupField( rSaveData, rVisNames );
398 else if( IsDateGroupField() )
399 ConvertDateGroupField( rSaveData, rVisNames );
403 // private --------------------------------------------------------------------
405 void XclImpPCField::ConvertStdGroupField( ScDPSaveData& rSaveData, const ScfStringVec& rVisNames ) const
407 if( const XclImpPCField* pBaseField = GetGroupBaseField() )
409 const String& rBaseFieldName = pBaseField->GetFieldName( rVisNames );
410 if( rBaseFieldName.Len() > 0 )
412 // *** create a ScDPSaveGroupItem for each own item, they collect base item names ***
413 ScDPSaveGroupItemVec aGroupItems;
414 aGroupItems.reserve( maItems.size() );
415 // initialize with own item names
416 for( XclImpPCItemVec::const_iterator aIt = maItems.begin(), aEnd = maItems.end(); aIt != aEnd; ++aIt )
417 aGroupItems.push_back( ScDPSaveGroupItem( (*aIt)->ConvertToText() ) );
419 // *** iterate over all base items, set their names at corresponding own items ***
420 for( sal_uInt16 nItemIdx = 0, nItemCount = static_cast< sal_uInt16 >( maGroupOrder.size() ); nItemIdx < nItemCount; ++nItemIdx )
421 if( maGroupOrder[ nItemIdx ] < aGroupItems.size() )
422 if( const XclImpPCItem* pBaseItem = pBaseField->GetItem( nItemIdx ) )
423 if( const XclImpPCItem* pGroupItem = GetItem( maGroupOrder[ nItemIdx ] ) )
424 if( *pBaseItem != *pGroupItem )
425 aGroupItems[ maGroupOrder[ nItemIdx ] ].AddElement( pBaseItem->ConvertToText() );
427 // *** create the ScDPSaveGroupDimension object, fill with grouping info ***
428 ScDPSaveGroupDimension aGroupDim( rBaseFieldName, GetFieldName( rVisNames ) );
429 for( ScDPSaveGroupItemVec::const_iterator aIt = aGroupItems.begin(), aEnd = aGroupItems.end(); aIt != aEnd; ++aIt )
430 if( !aIt->IsEmpty() )
431 aGroupDim.AddGroupItem( *aIt );
432 rSaveData.GetDimensionData()->AddGroupDimension( aGroupDim );
437 void XclImpPCField::ConvertNumGroupField( ScDPSaveData& rSaveData, const ScfStringVec& rVisNames ) const
439 ScDPNumGroupInfo aNumInfo( GetScNumGroupInfo() );
440 ScDPSaveNumGroupDimension aNumGroupDim( GetFieldName( rVisNames ), aNumInfo );
441 rSaveData.GetDimensionData()->AddNumGroupDimension( aNumGroupDim );
444 void XclImpPCField::ConvertDateGroupField( ScDPSaveData& rSaveData, const ScfStringVec& rVisNames ) const
446 ScDPNumGroupInfo aDateInfo( GetScDateGroupInfo() );
447 sal_Int32 nScDateType = maNumGroupInfo.GetScDateType();
449 switch( meFieldType )
451 case EXC_PCFIELD_DATEGROUP:
453 if( aDateInfo.mbDateValues )
455 // special case for days only with step value - create numeric grouping
456 ScDPSaveNumGroupDimension aNumGroupDim( GetFieldName( rVisNames ), aDateInfo );
457 rSaveData.GetDimensionData()->AddNumGroupDimension( aNumGroupDim );
459 else
461 ScDPSaveNumGroupDimension aNumGroupDim( GetFieldName( rVisNames ), ScDPNumGroupInfo() );
462 aNumGroupDim.SetDateInfo( aDateInfo, nScDateType );
463 rSaveData.GetDimensionData()->AddNumGroupDimension( aNumGroupDim );
466 break;
468 case EXC_PCFIELD_DATECHILD:
470 if( const XclImpPCField* pBaseField = GetGroupBaseField() )
472 const String& rBaseFieldName = pBaseField->GetFieldName( rVisNames );
473 if( rBaseFieldName.Len() > 0 )
475 ScDPSaveGroupDimension aGroupDim( rBaseFieldName, GetFieldName( rVisNames ) );
476 aGroupDim.SetDateInfo( aDateInfo, nScDateType );
477 rSaveData.GetDimensionData()->AddGroupDimension( aGroupDim );
481 break;
483 default:
484 OSL_FAIL( "XclImpPCField::ConvertDateGroupField - unknown date field type" );
488 ScDPNumGroupInfo XclImpPCField::GetScNumGroupInfo() const
490 ScDPNumGroupInfo aNumInfo;
491 aNumInfo.mbEnable = sal_True;
492 aNumInfo.mbDateValues = false;
493 aNumInfo.mbAutoStart = sal_True;
494 aNumInfo.mbAutoEnd = sal_True;
496 if( const double* pfMinValue = GetNumGroupLimit( EXC_SXFIELD_INDEX_MIN ) )
498 aNumInfo.mfStart = *pfMinValue;
499 aNumInfo.mbAutoStart = ::get_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMIN );
501 if( const double* pfMaxValue = GetNumGroupLimit( EXC_SXFIELD_INDEX_MAX ) )
503 aNumInfo.mfEnd = *pfMaxValue;
504 aNumInfo.mbAutoEnd = ::get_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMAX );
506 if( const double* pfStepValue = GetNumGroupLimit( EXC_SXFIELD_INDEX_STEP ) )
507 aNumInfo.mfStep = *pfStepValue;
509 return aNumInfo;
512 ScDPNumGroupInfo XclImpPCField::GetScDateGroupInfo() const
514 ScDPNumGroupInfo aDateInfo;
515 aDateInfo.mbEnable = sal_True;
516 aDateInfo.mbDateValues = false;
517 aDateInfo.mbAutoStart = sal_True;
518 aDateInfo.mbAutoEnd = sal_True;
520 if( const DateTime* pMinDate = GetDateGroupLimit( EXC_SXFIELD_INDEX_MIN ) )
522 aDateInfo.mfStart = GetDoubleFromDateTime( *pMinDate );
523 aDateInfo.mbAutoStart = ::get_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMIN );
525 if( const DateTime* pMaxDate = GetDateGroupLimit( EXC_SXFIELD_INDEX_MAX ) )
527 aDateInfo.mfEnd = GetDoubleFromDateTime( *pMaxDate );
528 aDateInfo.mbAutoEnd = ::get_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMAX );
530 // GetDateGroupStep() returns a value for date type "day" in single date groups only
531 if( const sal_Int16* pnStepValue = GetDateGroupStep() )
533 aDateInfo.mfStep = *pnStepValue;
534 aDateInfo.mbDateValues = sal_True;
537 return aDateInfo;
540 const double* XclImpPCField::GetNumGroupLimit( sal_uInt16 nLimitIdx ) const
542 OSL_ENSURE( IsNumGroupField(), "XclImpPCField::GetNumGroupLimit - only for numeric grouping fields" );
543 if( const XclImpPCItem* pItem = GetLimitItem( nLimitIdx ) )
545 OSL_ENSURE( pItem->GetDouble(), "XclImpPCField::GetNumGroupLimit - SXDOUBLE item expected" );
546 return pItem->GetDouble();
548 return 0;
551 const DateTime* XclImpPCField::GetDateGroupLimit( sal_uInt16 nLimitIdx ) const
553 OSL_ENSURE( IsDateGroupField(), "XclImpPCField::GetDateGroupLimit - only for date grouping fields" );
554 if( const XclImpPCItem* pItem = GetLimitItem( nLimitIdx ) )
556 OSL_ENSURE( pItem->GetDateTime(), "XclImpPCField::GetDateGroupLimit - SXDATETIME item expected" );
557 return pItem->GetDateTime();
559 return 0;
562 const sal_Int16* XclImpPCField::GetDateGroupStep() const
564 // only for single date grouping fields, not for grouping chains
565 if( !IsGroupBaseField() && !IsGroupChildField() )
567 // only days may have a step value, return 0 for all other date types
568 if( maNumGroupInfo.GetXclDataType() == EXC_SXNUMGROUP_TYPE_DAY )
570 if( const XclImpPCItem* pItem = GetLimitItem( EXC_SXFIELD_INDEX_STEP ) )
572 OSL_ENSURE( pItem->GetInteger(), "XclImpPCField::GetDateGroupStep - SXINTEGER item expected" );
573 if( const sal_Int16* pnStep = pItem->GetInteger() )
575 OSL_ENSURE( *pnStep > 0, "XclImpPCField::GetDateGroupStep - invalid step count" );
576 // return nothing for step count 1 - this is also a standard date group in Excel
577 return (*pnStep > 1) ? pnStep : 0;
582 return 0;
585 // ============================================================================
587 XclImpPivotCache::XclImpPivotCache( const XclImpRoot& rRoot ) :
588 XclImpRoot( rRoot ),
589 maSrcRange( ScAddress::INITIALIZE_INVALID ),
590 mnStrmId( 0 ),
591 mnSrcType( EXC_SXVS_UNKNOWN ),
592 mbSelfRef( false )
596 XclImpPivotCache::~XclImpPivotCache()
600 // data access ----------------------------------------------------------------
602 sal_uInt16 XclImpPivotCache::GetFieldCount() const
604 return static_cast< sal_uInt16 >( maFields.size() );
607 const XclImpPCField* XclImpPivotCache::GetField( sal_uInt16 nFieldIdx ) const
609 return (nFieldIdx < maFields.size()) ? maFields[ nFieldIdx ].get() : 0;
612 // records --------------------------------------------------------------------
614 void XclImpPivotCache::ReadSxidstm( XclImpStream& rStrm )
616 rStrm >> mnStrmId;
619 void XclImpPivotCache::ReadSxvs( XclImpStream& rStrm )
621 rStrm >> mnSrcType;
622 GetTracer().TracePivotDataSource( mnSrcType != EXC_SXVS_SHEET );
625 void XclImpPivotCache::ReadDconref( XclImpStream& rStrm )
627 /* Read DCONREF only once (by checking maTabName), there may be other
628 DCONREF records in another context. Read reference only if a leading
629 SXVS record is present (by checking mnSrcType). */
630 if( (maTabName.Len() > 0) || (mnSrcType != EXC_SXVS_SHEET) )
631 return;
633 XclRange aXclRange( ScAddress::UNINITIALIZED );
634 aXclRange.Read( rStrm, false );
635 String aEncUrl = rStrm.ReadUniString();
637 XclImpUrlHelper::DecodeUrl( maUrl, maTabName, mbSelfRef, GetRoot(), aEncUrl );
639 /* Do not convert maTabName to Calc sheet name -> original name is used to
640 find the sheet in the document. Sheet index of source range will be
641 found later in XclImpPivotCache::ReadPivotCacheStream(), because sheet
642 may not exist yet. */
643 if( mbSelfRef )
644 GetAddressConverter().ConvertRange( maSrcRange, aXclRange, 0, 0, true );
647 void XclImpPivotCache::ReadDConName( XclImpStream& rStrm )
649 maSrcRangeName = rStrm.ReadUniString();
651 // This 2-byte value equals the length of string that follows, or if 0 it
652 // indicates that the name has a workbook scope. For now, we only support
653 // internal defined name with a workbook scope.
654 sal_uInt16 nFlag;
655 rStrm >> nFlag;
656 mbSelfRef = (nFlag == 0);
658 if (!mbSelfRef)
659 // External name is not supported yet.
660 maSrcRangeName = OUString();
663 void XclImpPivotCache::ReadPivotCacheStream( XclImpStream& rStrm )
665 if( (mnSrcType != EXC_SXVS_SHEET) && (mnSrcType != EXC_SXVS_EXTERN) )
666 return;
668 ScDocument& rDoc = GetDoc();
669 SCCOL nFieldScCol = 0; // column index of source data for next field
670 SCROW nItemScRow = 0; // row index of source data for current items
671 SCTAB nScTab = 0; // sheet index of source data
672 bool bGenerateSource = false; // true = write source data from cache to dummy table
674 if( mbSelfRef )
676 if (maSrcRangeName.isEmpty())
678 // try to find internal sheet containing the source data
679 nScTab = GetTabInfo().GetScTabFromXclName( maTabName );
680 if( rDoc.HasTable( nScTab ) )
682 // set sheet index to source range
683 maSrcRange.aStart.SetTab( nScTab );
684 maSrcRange.aEnd.SetTab( nScTab );
686 else
688 // create dummy sheet for deleted internal sheet
689 bGenerateSource = true;
693 else
695 // create dummy sheet for external sheet
696 bGenerateSource = true;
699 // create dummy sheet for source data from external or deleted sheet
700 if( bGenerateSource )
702 if( rDoc.GetTableCount() >= MAXTABCOUNT )
703 // cannot create more sheets -> exit
704 return;
706 nScTab = rDoc.GetTableCount();
707 rDoc.MakeTable( nScTab );
708 rtl::OUStringBuffer aDummyName(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("DPCache") ));
709 if( maTabName.Len() > 0 )
710 aDummyName.append( '_' ).append( maTabName );
711 rtl::OUString aName = aDummyName.makeStringAndClear();
712 rDoc.CreateValidTabName( aName );
713 rDoc.RenameTab( nScTab, aName );
714 // set sheet index to source range
715 maSrcRange.aStart.SetTab( nScTab );
716 maSrcRange.aEnd.SetTab( nScTab );
719 // open pivot cache storage stream
720 SotStorageRef xSvStrg = OpenStorage( EXC_STORAGE_PTCACHE );
721 SotStorageStreamRef xSvStrm = OpenStream( xSvStrg, ScfTools::GetHexStr( mnStrmId ) );
722 if( !xSvStrm.Is() )
723 return;
725 // create Excel record stream object
726 XclImpStream aPCStrm( *xSvStrm, GetRoot() );
727 aPCStrm.CopyDecrypterFrom( rStrm ); // pivot cache streams are encrypted
729 XclImpPCFieldRef xCurrField; // current field for new items
730 XclImpPCFieldVec aOrigFields; // all standard fields with inline original items
731 XclImpPCFieldVec aPostpFields; // all standard fields with postponed original items
732 size_t nPostpIdx = 0; // index to current field with postponed items
733 bool bLoop = true; // true = continue loop
735 while( bLoop && aPCStrm.StartNextRecord() )
737 switch( aPCStrm.GetRecId() )
739 case EXC_ID_EOF:
740 bLoop = false;
741 break;
743 case EXC_ID_SXDB:
744 aPCStrm >> maPCInfo;
745 break;
747 case EXC_ID_SXFIELD:
749 xCurrField.reset();
750 sal_uInt16 nNewFieldIdx = GetFieldCount();
751 if( nNewFieldIdx < EXC_PC_MAXFIELDCOUNT )
753 xCurrField.reset( new XclImpPCField( GetRoot(), *this, nNewFieldIdx ) );
754 maFields.push_back( xCurrField );
755 xCurrField->ReadSxfield( aPCStrm );
756 if( xCurrField->HasOrigItems() )
758 if( xCurrField->HasPostponedItems() )
759 aPostpFields.push_back( xCurrField );
760 else
761 aOrigFields.push_back( xCurrField );
762 // insert field name into generated source data, field remembers its column index
763 if( bGenerateSource && (nFieldScCol <= MAXCOL) )
764 xCurrField->WriteFieldNameToSource( nFieldScCol++, nScTab );
766 // do not read items into invalid/postponed fields
767 if( !xCurrField->HasInlineItems() )
768 xCurrField.reset();
771 break;
773 case EXC_ID_SXINDEXLIST:
774 // read index list and insert all items into generated source data
775 if( bGenerateSource && (nItemScRow <= MAXROW) && (++nItemScRow <= MAXROW) )
777 for( XclImpPCFieldVec::const_iterator aIt = aOrigFields.begin(), aEnd = aOrigFields.end(); aIt != aEnd; ++aIt )
779 sal_uInt16 nItemIdx = (*aIt)->Has16BitIndexes() ? aPCStrm.ReaduInt16() : aPCStrm.ReaduInt8();
780 (*aIt)->WriteOrigItemToSource( nItemScRow, nScTab, nItemIdx );
783 xCurrField.reset();
784 break;
786 case EXC_ID_SXDOUBLE:
787 case EXC_ID_SXBOOLEAN:
788 case EXC_ID_SXERROR:
789 case EXC_ID_SXINTEGER:
790 case EXC_ID_SXSTRING:
791 case EXC_ID_SXDATETIME:
792 case EXC_ID_SXEMPTY:
793 if( xCurrField ) // inline items
795 xCurrField->ReadItem( aPCStrm );
797 else if( !aPostpFields.empty() ) // postponed items
799 // read postponed item
800 aPostpFields[ nPostpIdx ]->ReadItem( aPCStrm );
801 // write item to source
802 if( bGenerateSource && (nItemScRow <= MAXROW) )
804 // start new row, if there are only postponed fields
805 if( aOrigFields.empty() && (nPostpIdx == 0) )
806 ++nItemScRow;
807 if( nItemScRow <= MAXROW )
808 aPostpFields[ nPostpIdx ]->WriteLastOrigItemToSource( nItemScRow, nScTab );
810 // get index of next postponed field
811 ++nPostpIdx;
812 if( nPostpIdx >= aPostpFields.size() )
813 nPostpIdx = 0;
815 break;
817 case EXC_ID_SXNUMGROUP:
818 if( xCurrField )
819 xCurrField->ReadSxnumgroup( aPCStrm );
820 break;
822 case EXC_ID_SXGROUPINFO:
823 if( xCurrField )
824 xCurrField->ReadSxgroupinfo( aPCStrm );
825 break;
827 // known but ignored records
828 case EXC_ID_SXRULE:
829 case EXC_ID_SXFILT:
830 case EXC_ID_00F5:
831 case EXC_ID_SXNAME:
832 case EXC_ID_SXPAIR:
833 case EXC_ID_SXFMLA:
834 case EXC_ID_SXFORMULA:
835 case EXC_ID_SXDBEX:
836 case EXC_ID_SXFDBTYPE:
837 break;
839 default:
840 OSL_TRACE( "XclImpPivotCache::ReadPivotCacheStream - unknown record 0x%04hX", aPCStrm.GetRecId() );
844 OSL_ENSURE( maPCInfo.mnTotalFields == maFields.size(),
845 "XclImpPivotCache::ReadPivotCacheStream - field count mismatch" );
847 if (HasCacheRecords())
849 SCROW nNewEnd = maSrcRange.aStart.Row() + maPCInfo.mnSrcRecs;
850 maSrcRange.aEnd.SetRow(nNewEnd);
853 // set source range for external source data
854 if( bGenerateSource && (nFieldScCol > 0) )
856 maSrcRange.aStart.SetCol( 0 );
857 maSrcRange.aStart.SetRow( 0 );
858 // nFieldScCol points to first unused column
859 maSrcRange.aEnd.SetCol( nFieldScCol - 1 );
860 // nItemScRow points to last used row
861 maSrcRange.aEnd.SetRow( nItemScRow );
865 bool XclImpPivotCache::HasCacheRecords() const
867 return static_cast<bool>(maPCInfo.mnFlags & EXC_SXDB_SAVEDATA);
870 bool XclImpPivotCache::IsRefreshOnLoad() const
872 return static_cast<bool>(maPCInfo.mnFlags & EXC_SXDB_REFRESH_LOAD);
875 bool XclImpPivotCache::IsValid() const
877 if (!maSrcRangeName.isEmpty())
878 return true;
880 return maSrcRange.IsValid();
883 // ============================================================================
884 // Pivot table
885 // ============================================================================
887 XclImpPTItem::XclImpPTItem( const XclImpPCField* pCacheField ) :
888 mpCacheField( pCacheField )
892 const rtl::OUString* XclImpPTItem::GetItemName() const
894 if( mpCacheField )
895 if( const XclImpPCItem* pCacheItem = mpCacheField->GetItem( maItemInfo.mnCacheIdx ) )
896 //! TODO: use XclImpPCItem::ConvertToText(), if all conversions are available
897 return pCacheItem->IsEmpty() ? NULL : pCacheItem->GetText();
898 return 0;
901 void XclImpPTItem::ReadSxvi( XclImpStream& rStrm )
903 rStrm >> maItemInfo;
906 void XclImpPTItem::ConvertItem( ScDPSaveDimension& rSaveDim ) const
908 if (const rtl::OUString* pItemName = GetItemName())
910 ScDPSaveMember& rMember = *rSaveDim.GetMemberByName( *pItemName );
911 rMember.SetIsVisible( !::get_flag( maItemInfo.mnFlags, EXC_SXVI_HIDDEN ) );
912 rMember.SetShowDetails( !::get_flag( maItemInfo.mnFlags, EXC_SXVI_HIDEDETAIL ) );
913 if (maItemInfo.HasVisName())
914 rMember.SetLayoutName(*maItemInfo.GetVisName());
918 // ============================================================================
920 XclImpPTField::XclImpPTField( const XclImpPivotTable& rPTable, sal_uInt16 nCacheIdx ) :
921 mrPTable( rPTable )
923 maFieldInfo.mnCacheIdx = nCacheIdx;
926 // general field/item access --------------------------------------------------
928 const XclImpPCField* XclImpPTField::GetCacheField() const
930 XclImpPivotCacheRef xPCache = mrPTable.GetPivotCache();
931 return xPCache ? xPCache->GetField( maFieldInfo.mnCacheIdx ) : 0;
934 rtl::OUString XclImpPTField::GetFieldName() const
936 const XclImpPCField* pField = GetCacheField();
937 return pField ? pField->GetFieldName( mrPTable.GetVisFieldNames() ) : rtl::OUString();
940 rtl::OUString XclImpPTField::GetVisFieldName() const
942 const rtl::OUString* pVisName = maFieldInfo.GetVisName();
943 return pVisName ? *pVisName : rtl::OUString();
946 const XclImpPTItem* XclImpPTField::GetItem( sal_uInt16 nItemIdx ) const
948 return (nItemIdx < maItems.size()) ? maItems[ nItemIdx ].get() : 0;
951 const rtl::OUString* XclImpPTField::GetItemName( sal_uInt16 nItemIdx ) const
953 const XclImpPTItem* pItem = GetItem( nItemIdx );
954 return pItem ? pItem->GetItemName() : 0;
957 // records --------------------------------------------------------------------
959 void XclImpPTField::ReadSxvd( XclImpStream& rStrm )
961 rStrm >> maFieldInfo;
964 void XclImpPTField::ReadSxvdex( XclImpStream& rStrm )
966 rStrm >> maFieldExtInfo;
969 void XclImpPTField::ReadSxvi( XclImpStream& rStrm )
971 XclImpPTItemRef xItem( new XclImpPTItem( GetCacheField() ) );
972 maItems.push_back( xItem );
973 xItem->ReadSxvi( rStrm );
976 // row/column fields ----------------------------------------------------------
978 void XclImpPTField::ConvertRowColField( ScDPSaveData& rSaveData ) const
980 OSL_ENSURE( maFieldInfo.mnAxes & EXC_SXVD_AXIS_ROWCOL, "XclImpPTField::ConvertRowColField - no row/column field" );
981 // special data orientation field?
982 if( maFieldInfo.mnCacheIdx == EXC_SXIVD_DATA )
983 rSaveData.GetDataLayoutDimension()->SetOrientation( static_cast< sal_uInt16 >( maFieldInfo.GetApiOrient( EXC_SXVD_AXIS_ROWCOL ) ) );
984 else
985 ConvertRCPField( rSaveData );
988 // page fields ----------------------------------------------------------------
990 void XclImpPTField::SetPageFieldInfo( const XclPTPageFieldInfo& rPageInfo )
992 maPageInfo = rPageInfo;
995 void XclImpPTField::ConvertPageField( ScDPSaveData& rSaveData ) const
997 OSL_ENSURE( maFieldInfo.mnAxes & EXC_SXVD_AXIS_PAGE, "XclImpPTField::ConvertPageField - no page field" );
998 if( ScDPSaveDimension* pSaveDim = ConvertRCPField( rSaveData ) )
1000 const rtl::OUString* pName = GetItemName( maPageInfo.mnSelItem );
1001 if (pName)
1002 pSaveDim->SetCurrentPage(pName);
1006 // hidden fields --------------------------------------------------------------
1008 void XclImpPTField::ConvertHiddenField( ScDPSaveData& rSaveData ) const
1010 OSL_ENSURE( (maFieldInfo.mnAxes & EXC_SXVD_AXIS_ROWCOLPAGE) == 0, "XclImpPTField::ConvertHiddenField - field not hidden" );
1011 ConvertRCPField( rSaveData );
1014 // data fields ----------------------------------------------------------------
1016 bool XclImpPTField::HasDataFieldInfo() const
1018 return !maDataInfoList.empty();
1021 void XclImpPTField::AddDataFieldInfo( const XclPTDataFieldInfo& rDataInfo )
1023 OSL_ENSURE( maFieldInfo.mnAxes & EXC_SXVD_AXIS_DATA, "XclImpPTField::AddDataFieldInfo - no data field" );
1024 maDataInfoList.push_back( rDataInfo );
1027 void XclImpPTField::ConvertDataField( ScDPSaveData& rSaveData ) const
1029 OSL_ENSURE( maFieldInfo.mnAxes & EXC_SXVD_AXIS_DATA, "XclImpPTField::ConvertDataField - no data field" );
1030 OSL_ENSURE( !maDataInfoList.empty(), "XclImpPTField::ConvertDataField - no data field info" );
1031 if (maDataInfoList.empty())
1032 return;
1034 rtl::OUString aFieldName = GetFieldName();
1035 if (aFieldName.isEmpty())
1036 return;
1038 XclPTDataFieldInfoList::const_iterator aIt = maDataInfoList.begin(), aEnd = maDataInfoList.end();
1040 ScDPSaveDimension& rSaveDim = *rSaveData.GetNewDimensionByName(aFieldName);
1041 ConvertDataField( rSaveDim, *aIt );
1043 // multiple data fields -> clone dimension
1044 for( ++aIt; aIt != aEnd; ++aIt )
1046 ScDPSaveDimension& rDupDim = rSaveData.DuplicateDimension( rSaveDim );
1047 ConvertDataFieldInfo( rDupDim, *aIt );
1051 // private --------------------------------------------------------------------
1054 * Convert Excel-encoded subtotal name to a Calc-encoded one.
1056 static OUString lcl_convertExcelSubtotalName(const OUString& rName)
1058 OUStringBuffer aBuf;
1059 const sal_Unicode* p = rName.getStr();
1060 sal_Int32 n = rName.getLength();
1061 for (sal_Int32 i = 0; i < n; ++i)
1063 const sal_Unicode c = p[i];
1064 if (c == sal_Unicode('\\'))
1066 aBuf.append(c);
1067 aBuf.append(c);
1069 else
1070 aBuf.append(c);
1072 return aBuf.makeStringAndClear();
1075 ScDPSaveDimension* XclImpPTField::ConvertRCPField( ScDPSaveData& rSaveData ) const
1077 const String& rFieldName = GetFieldName();
1078 if( rFieldName.Len() == 0 )
1079 return 0;
1081 const XclImpPCField* pCacheField = GetCacheField();
1082 if( !pCacheField || !pCacheField->IsSupportedField() )
1083 return 0;
1085 ScDPSaveDimension* pTest = rSaveData.GetNewDimensionByName(rFieldName);
1086 if (!pTest)
1087 return NULL;
1089 ScDPSaveDimension& rSaveDim = *pTest;
1091 // orientation
1092 rSaveDim.SetOrientation( static_cast< sal_uInt16 >( maFieldInfo.GetApiOrient( EXC_SXVD_AXIS_ROWCOLPAGE ) ) );
1094 // general field info
1095 ConvertFieldInfo( rSaveDim );
1097 // visible name
1098 if (const rtl::OUString* pVisName = maFieldInfo.GetVisName())
1099 if (!pVisName->isEmpty())
1100 rSaveDim.SetLayoutName( *pVisName );
1102 // subtotal function(s)
1103 XclPTSubtotalVec aSubtotalVec;
1104 maFieldInfo.GetSubtotals( aSubtotalVec );
1105 if( !aSubtotalVec.empty() )
1106 rSaveDim.SetSubTotals( static_cast< long >( aSubtotalVec.size() ), &aSubtotalVec[ 0 ] );
1108 // sorting
1109 DataPilotFieldSortInfo aSortInfo;
1110 aSortInfo.Field = mrPTable.GetDataFieldName( maFieldExtInfo.mnSortField );
1111 aSortInfo.IsAscending = ::get_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_SORT_ASC );
1112 aSortInfo.Mode = maFieldExtInfo.GetApiSortMode();
1113 rSaveDim.SetSortInfo( &aSortInfo );
1115 // auto show
1116 DataPilotFieldAutoShowInfo aShowInfo;
1117 aShowInfo.IsEnabled = ::get_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_AUTOSHOW );
1118 aShowInfo.ShowItemsMode = maFieldExtInfo.GetApiAutoShowMode();
1119 aShowInfo.ItemCount = maFieldExtInfo.GetApiAutoShowCount();
1120 aShowInfo.DataField = mrPTable.GetDataFieldName( maFieldExtInfo.mnShowField );
1121 rSaveDim.SetAutoShowInfo( &aShowInfo );
1123 // layout
1124 DataPilotFieldLayoutInfo aLayoutInfo;
1125 aLayoutInfo.LayoutMode = maFieldExtInfo.GetApiLayoutMode();
1126 aLayoutInfo.AddEmptyLines = ::get_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_LAYOUT_BLANK );
1127 rSaveDim.SetLayoutInfo( &aLayoutInfo );
1129 // grouping info
1130 pCacheField->ConvertGroupField( rSaveData, mrPTable.GetVisFieldNames() );
1132 // custom subtotal name
1133 if (maFieldExtInfo.mpFieldTotalName.get())
1135 OUString aSubName = lcl_convertExcelSubtotalName(*maFieldExtInfo.mpFieldTotalName);
1136 rSaveDim.SetSubtotalName(aSubName);
1139 return &rSaveDim;
1142 void XclImpPTField::ConvertFieldInfo( ScDPSaveDimension& rSaveDim ) const
1144 rSaveDim.SetShowEmpty( ::get_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_SHOWALL ) );
1145 ConvertItems( rSaveDim );
1148 void XclImpPTField::ConvertDataField( ScDPSaveDimension& rSaveDim, const XclPTDataFieldInfo& rDataInfo ) const
1150 // orientation
1151 rSaveDim.SetOrientation( DataPilotFieldOrientation_DATA );
1152 // general field info
1153 ConvertFieldInfo( rSaveDim );
1154 // extended data field info
1155 ConvertDataFieldInfo( rSaveDim, rDataInfo );
1158 void XclImpPTField::ConvertDataFieldInfo( ScDPSaveDimension& rSaveDim, const XclPTDataFieldInfo& rDataInfo ) const
1160 // visible name
1161 const rtl::OUString* pVisName = rDataInfo.GetVisName();
1162 if (pVisName && !pVisName->isEmpty())
1163 rSaveDim.SetLayoutName(*pVisName);
1165 // aggregation function
1166 rSaveDim.SetFunction( static_cast< sal_uInt16 >( rDataInfo.GetApiAggFunc() ) );
1168 // result field reference
1169 sal_Int32 nRefType = rDataInfo.GetApiRefType();
1170 DataPilotFieldReference aFieldRef;
1171 aFieldRef.ReferenceType = nRefType;
1172 const XclImpPTField* pRefField = mrPTable.GetField(rDataInfo.mnRefField);
1173 if (pRefField)
1175 aFieldRef.ReferenceField = pRefField->GetFieldName();
1176 aFieldRef.ReferenceItemType = rDataInfo.GetApiRefItemType();
1177 if (aFieldRef.ReferenceItemType == sheet::DataPilotFieldReferenceItemType::NAMED)
1179 const rtl::OUString* pRefItemName = pRefField->GetItemName(rDataInfo.mnRefItem);
1180 if (pRefItemName)
1181 aFieldRef.ReferenceItemName = *pRefItemName;
1185 rSaveDim.SetReferenceValue(&aFieldRef);
1188 void XclImpPTField::ConvertItems( ScDPSaveDimension& rSaveDim ) const
1190 for( XclImpPTItemVec::const_iterator aIt = maItems.begin(), aEnd = maItems.end(); aIt != aEnd; ++aIt )
1191 (*aIt)->ConvertItem( rSaveDim );
1194 // ============================================================================
1196 XclImpPivotTable::XclImpPivotTable( const XclImpRoot& rRoot ) :
1197 XclImpRoot( rRoot ),
1198 maDataOrientField( *this, EXC_SXIVD_DATA ),
1199 mpDPObj(NULL)
1203 XclImpPivotTable::~XclImpPivotTable()
1207 // cache/field access, misc. --------------------------------------------------
1209 sal_uInt16 XclImpPivotTable::GetFieldCount() const
1211 return static_cast< sal_uInt16 >( maFields.size() );
1214 const XclImpPTField* XclImpPivotTable::GetField( sal_uInt16 nFieldIdx ) const
1216 return (nFieldIdx == EXC_SXIVD_DATA) ? &maDataOrientField :
1217 ((nFieldIdx < maFields.size()) ? maFields[ nFieldIdx ].get() : 0);
1220 XclImpPTField* XclImpPivotTable::GetFieldAcc( sal_uInt16 nFieldIdx )
1222 // do not return maDataOrientField
1223 return (nFieldIdx < maFields.size()) ? maFields[ nFieldIdx ].get() : 0;
1226 const XclImpPTField* XclImpPivotTable::GetDataField( sal_uInt16 nDataFieldIdx ) const
1228 if( nDataFieldIdx < maOrigDataFields.size() )
1229 return GetField( maOrigDataFields[ nDataFieldIdx ] );
1230 return 0;
1233 rtl::OUString XclImpPivotTable::GetDataFieldName( sal_uInt16 nDataFieldIdx ) const
1235 if( const XclImpPTField* pField = GetDataField( nDataFieldIdx ) )
1236 return pField->GetFieldName();
1237 return rtl::OUString();
1240 // records --------------------------------------------------------------------
1242 void XclImpPivotTable::ReadSxview( XclImpStream& rStrm )
1244 rStrm >> maPTInfo;
1246 GetAddressConverter().ConvertRange(
1247 maOutScRange, maPTInfo.maOutXclRange, GetCurrScTab(), GetCurrScTab(), true );
1249 mxPCache = GetPivotTableManager().GetPivotCache( maPTInfo.mnCacheIdx );
1250 mxCurrField.reset();
1253 void XclImpPivotTable::ReadSxvd( XclImpStream& rStrm )
1255 sal_uInt16 nFieldCount = GetFieldCount();
1256 if( nFieldCount < EXC_PT_MAXFIELDCOUNT )
1258 // cache index for the field is equal to the SXVD record index
1259 mxCurrField.reset( new XclImpPTField( *this, nFieldCount ) );
1260 maFields.push_back( mxCurrField );
1261 mxCurrField->ReadSxvd( rStrm );
1262 // add visible name of new field to list of visible names
1263 maVisFieldNames.push_back( mxCurrField->GetVisFieldName() );
1264 OSL_ENSURE( maFields.size() == maVisFieldNames.size(),
1265 "XclImpPivotTable::ReadSxvd - wrong size of visible name array" );
1267 else
1268 mxCurrField.reset();
1271 void XclImpPivotTable::ReadSxvi( XclImpStream& rStrm )
1273 if( mxCurrField )
1274 mxCurrField->ReadSxvi( rStrm );
1277 void XclImpPivotTable::ReadSxvdex( XclImpStream& rStrm )
1279 if( mxCurrField )
1280 mxCurrField->ReadSxvdex( rStrm );
1283 void XclImpPivotTable::ReadSxivd( XclImpStream& rStrm )
1285 mxCurrField.reset();
1287 // find the index vector to fill (row SXIVD doesn't exist without row fields)
1288 ScfUInt16Vec* pFieldVec = 0;
1289 if( maRowFields.empty() && (maPTInfo.mnRowFields > 0) )
1290 pFieldVec = &maRowFields;
1291 else if( maColFields.empty() && (maPTInfo.mnColFields > 0) )
1292 pFieldVec = &maColFields;
1294 // fill the vector from record data
1295 if( pFieldVec )
1297 sal_uInt16 nSize = ulimit_cast< sal_uInt16 >( rStrm.GetRecSize() / 2, EXC_PT_MAXROWCOLCOUNT );
1298 pFieldVec->reserve( nSize );
1299 for( sal_uInt16 nIdx = 0; nIdx < nSize; ++nIdx )
1301 sal_uInt16 nFieldIdx;
1302 rStrm >> nFieldIdx;
1303 pFieldVec->push_back( nFieldIdx );
1305 // set orientation at special data orientation field
1306 if( nFieldIdx == EXC_SXIVD_DATA )
1308 sal_uInt16 nAxis = (pFieldVec == &maRowFields) ? EXC_SXVD_AXIS_ROW : EXC_SXVD_AXIS_COL;
1309 maDataOrientField.SetAxes( nAxis );
1315 void XclImpPivotTable::ReadSxpi( XclImpStream& rStrm )
1317 mxCurrField.reset();
1319 sal_uInt16 nSize = ulimit_cast< sal_uInt16 >( rStrm.GetRecSize() / 6 );
1320 for( sal_uInt16 nEntry = 0; nEntry < nSize; ++nEntry )
1322 XclPTPageFieldInfo aPageInfo;
1323 rStrm >> aPageInfo;
1324 if( XclImpPTField* pField = GetFieldAcc( aPageInfo.mnField ) )
1326 maPageFields.push_back( aPageInfo.mnField );
1327 pField->SetPageFieldInfo( aPageInfo );
1329 GetCurrSheetDrawing().SetSkipObj( aPageInfo.mnObjId );
1333 void XclImpPivotTable::ReadSxdi( XclImpStream& rStrm )
1335 mxCurrField.reset();
1337 XclPTDataFieldInfo aDataInfo;
1338 rStrm >> aDataInfo;
1339 if( XclImpPTField* pField = GetFieldAcc( aDataInfo.mnField ) )
1341 maOrigDataFields.push_back( aDataInfo.mnField );
1342 // DataPilot does not support double data fields -> add first appearence to index list only
1343 if( !pField->HasDataFieldInfo() )
1344 maFiltDataFields.push_back( aDataInfo.mnField );
1345 pField->AddDataFieldInfo( aDataInfo );
1349 void XclImpPivotTable::ReadSxex( XclImpStream& rStrm )
1351 rStrm >> maPTExtInfo;
1354 void XclImpPivotTable::ReadSxViewEx9( XclImpStream& rStrm )
1356 rStrm >> maPTViewEx9Info;
1359 // ----------------------------------------------------------------------------
1361 void XclImpPivotTable::Convert()
1363 if( !mxPCache || !mxPCache->IsValid() )
1364 return;
1366 ScDPSaveData aSaveData;
1368 // *** global settings ***
1370 aSaveData.SetRowGrand( ::get_flag( maPTInfo.mnFlags, EXC_SXVIEW_ROWGRAND ) );
1371 aSaveData.SetColumnGrand( ::get_flag( maPTInfo.mnFlags, EXC_SXVIEW_COLGRAND ) );
1372 aSaveData.SetFilterButton( false );
1373 aSaveData.SetDrillDown( ::get_flag( maPTExtInfo.mnFlags, EXC_SXEX_DRILLDOWN ) );
1375 // *** fields ***
1377 ScfUInt16Vec::const_iterator aIt, aEnd;
1379 // row fields
1380 for( aIt = maRowFields.begin(), aEnd = maRowFields.end(); aIt != aEnd; ++aIt )
1381 if( const XclImpPTField* pField = GetField( *aIt ) )
1382 pField->ConvertRowColField( aSaveData );
1384 // column fields
1385 for( aIt = maColFields.begin(), aEnd = maColFields.end(); aIt != aEnd; ++aIt )
1386 if( const XclImpPTField* pField = GetField( *aIt ) )
1387 pField->ConvertRowColField( aSaveData );
1389 // page fields
1390 for( aIt = maPageFields.begin(), aEnd = maPageFields.end(); aIt != aEnd; ++aIt )
1391 if( const XclImpPTField* pField = GetField( *aIt ) )
1392 pField->ConvertPageField( aSaveData );
1394 // We need to import hidden fields because hidden fields may contain
1395 // special settings for subtotals (aggregation function, filters, custom
1396 // name etc.) and members (hidden, custom name etc.).
1398 // hidden fields
1399 for( sal_uInt16 nField = 0, nCount = GetFieldCount(); nField < nCount; ++nField )
1400 if( const XclImpPTField* pField = GetField( nField ) )
1401 if (!pField->GetAxes())
1402 pField->ConvertHiddenField( aSaveData );
1404 // data fields
1405 for( aIt = maFiltDataFields.begin(), aEnd = maFiltDataFields.end(); aIt != aEnd; ++aIt )
1406 if( const XclImpPTField* pField = GetField( *aIt ) )
1407 pField->ConvertDataField( aSaveData );
1409 // *** insert into Calc document ***
1411 // create source descriptor
1412 ScSheetSourceDesc aDesc(GetDocPtr());
1413 const OUString& rSrcName = mxPCache->GetSourceRangeName();
1414 if (!rSrcName.isEmpty())
1415 // Range name is the data source.
1416 aDesc.SetRangeName(rSrcName);
1417 else
1418 // Normal cell range.
1419 aDesc.SetSourceRange(mxPCache->GetSourceRange());
1421 // adjust output range to include the page fields
1422 ScRange aOutRange( maOutScRange );
1423 if( !maPageFields.empty() )
1425 SCsROW nDecRows = ::std::min< SCsROW >( aOutRange.aStart.Row(), maPageFields.size() + 1 );
1426 aOutRange.aStart.IncRow( -nDecRows );
1429 // create the DataPilot
1430 ScDPObject* pDPObj = new ScDPObject( GetDocPtr() );
1431 pDPObj->SetName( maPTInfo.maTableName );
1432 if (!maPTInfo.maDataName.isEmpty())
1433 aSaveData.GetDataLayoutDimension()->SetLayoutName(maPTInfo.maDataName);
1435 if (!maPTViewEx9Info.maGrandTotalName.isEmpty())
1436 aSaveData.SetGrandTotalName(maPTViewEx9Info.maGrandTotalName);
1438 pDPObj->SetSaveData( aSaveData );
1439 pDPObj->SetSheetDesc( aDesc );
1440 pDPObj->SetOutRange( aOutRange );
1441 pDPObj->SetAlive(true);
1442 pDPObj->SetHeaderLayout( maPTViewEx9Info.mnGridLayout == 0 );
1444 GetDoc().GetDPCollection()->InsertNewTable(pDPObj);
1445 mpDPObj = pDPObj;
1447 ApplyMergeFlags(aOutRange, aSaveData);
1450 void XclImpPivotTable::MaybeRefresh()
1452 if (mpDPObj && mxPCache->IsRefreshOnLoad())
1454 // 'refresh table on load' flag is set. Refresh the table now. Some
1455 // Excel files contain partial table output when this flag is set.
1456 ScRange aOutRange = mpDPObj->GetOutRange();
1457 mpDPObj->Output(aOutRange.aStart);
1461 void XclImpPivotTable::ApplyMergeFlags(const ScRange& rOutRange, const ScDPSaveData& rSaveData)
1463 // Apply merge flags for varoius datapilot controls.
1465 ScDPOutputGeometry aGeometry(rOutRange, false);
1466 aGeometry.setColumnFieldCount(maPTInfo.mnColFields);
1467 aGeometry.setPageFieldCount(maPTInfo.mnPageFields);
1468 aGeometry.setDataFieldCount(maPTInfo.mnDataFields);
1469 aGeometry.setRowFieldCount(maPTInfo.mnRowFields);
1471 ScDocument& rDoc = GetDoc();
1473 vector<const ScDPSaveDimension*> aFieldDims;
1474 vector<ScAddress> aFieldBtns;
1476 aGeometry.getPageFieldPositions(aFieldBtns);
1477 vector<ScAddress>::const_iterator itr = aFieldBtns.begin(), itrEnd = aFieldBtns.end();
1478 for (; itr != itrEnd; ++itr)
1480 rDoc.ApplyFlagsTab(itr->Col(), itr->Row(), itr->Col(), itr->Row(), itr->Tab(), SC_MF_BUTTON);
1482 sal_uInt16 nMFlag = SC_MF_BUTTON_POPUP;
1483 rtl::OUString aName;
1484 rDoc.GetString(itr->Col(), itr->Row(), itr->Tab(), aName);
1485 if (rSaveData.HasInvisibleMember(aName))
1486 nMFlag |= SC_MF_HIDDEN_MEMBER;
1488 rDoc.ApplyFlagsTab(itr->Col()+1, itr->Row(), itr->Col()+1, itr->Row(), itr->Tab(), nMFlag);
1491 aGeometry.getColumnFieldPositions(aFieldBtns);
1492 rSaveData.GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_COLUMN, aFieldDims);
1493 if (aFieldBtns.size() == aFieldDims.size())
1495 itr = aFieldBtns.begin();
1496 itrEnd = aFieldBtns.end();
1497 vector<const ScDPSaveDimension*>::const_iterator itDim = aFieldDims.begin();
1498 for (; itr != itrEnd; ++itr, ++itDim)
1500 sal_Int16 nMFlag = SC_MF_BUTTON;
1501 const ScDPSaveDimension* pDim = *itDim;
1502 if (pDim->HasInvisibleMember())
1503 nMFlag |= SC_MF_HIDDEN_MEMBER;
1504 if (!pDim->IsDataLayout())
1505 nMFlag |= SC_MF_BUTTON_POPUP;
1506 rDoc.ApplyFlagsTab(itr->Col(), itr->Row(), itr->Col(), itr->Row(), itr->Tab(), nMFlag);
1510 aGeometry.getRowFieldPositions(aFieldBtns);
1511 rSaveData.GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_ROW, aFieldDims);
1512 if (aFieldBtns.size() == aFieldDims.size())
1514 itr = aFieldBtns.begin();
1515 itrEnd = aFieldBtns.end();
1516 vector<const ScDPSaveDimension*>::const_iterator itDim = aFieldDims.begin();
1517 for (; itr != itrEnd; ++itr, ++itDim)
1519 sal_Int16 nMFlag = SC_MF_BUTTON;
1520 const ScDPSaveDimension* pDim = *itDim;
1521 if (pDim->HasInvisibleMember())
1522 nMFlag |= SC_MF_HIDDEN_MEMBER;
1523 if (!pDim->IsDataLayout())
1524 nMFlag |= SC_MF_BUTTON_POPUP;
1525 rDoc.ApplyFlagsTab(itr->Col(), itr->Row(), itr->Col(), itr->Row(), itr->Tab(), nMFlag);
1530 // ============================================================================
1532 XclImpPivotTableManager::XclImpPivotTableManager( const XclImpRoot& rRoot ) :
1533 XclImpRoot( rRoot )
1537 XclImpPivotTableManager::~XclImpPivotTableManager()
1541 // pivot cache records --------------------------------------------------------
1543 XclImpPivotCacheRef XclImpPivotTableManager::GetPivotCache( sal_uInt16 nCacheIdx )
1545 XclImpPivotCacheRef xPCache;
1546 if( nCacheIdx < maPCaches.size() )
1547 xPCache = maPCaches[ nCacheIdx ];
1548 return xPCache;
1551 void XclImpPivotTableManager::ReadSxidstm( XclImpStream& rStrm )
1553 XclImpPivotCacheRef xPCache( new XclImpPivotCache( GetRoot() ) );
1554 maPCaches.push_back( xPCache );
1555 xPCache->ReadSxidstm( rStrm );
1558 void XclImpPivotTableManager::ReadSxvs( XclImpStream& rStrm )
1560 if( !maPCaches.empty() )
1561 maPCaches.back()->ReadSxvs( rStrm );
1564 void XclImpPivotTableManager::ReadDconref( XclImpStream& rStrm )
1566 if( !maPCaches.empty() )
1567 maPCaches.back()->ReadDconref( rStrm );
1570 void XclImpPivotTableManager::ReadDConName( XclImpStream& rStrm )
1572 if( !maPCaches.empty() )
1573 maPCaches.back()->ReadDConName( rStrm );
1576 // pivot table records --------------------------------------------------------
1578 void XclImpPivotTableManager::ReadSxview( XclImpStream& rStrm )
1580 XclImpPivotTableRef xPTable( new XclImpPivotTable( GetRoot() ) );
1581 maPTables.push_back( xPTable );
1582 xPTable->ReadSxview( rStrm );
1585 void XclImpPivotTableManager::ReadSxvd( XclImpStream& rStrm )
1587 if( !maPTables.empty() )
1588 maPTables.back()->ReadSxvd( rStrm );
1591 void XclImpPivotTableManager::ReadSxvdex( XclImpStream& rStrm )
1593 if( !maPTables.empty() )
1594 maPTables.back()->ReadSxvdex( rStrm );
1597 void XclImpPivotTableManager::ReadSxivd( XclImpStream& rStrm )
1599 if( !maPTables.empty() )
1600 maPTables.back()->ReadSxivd( rStrm );
1603 void XclImpPivotTableManager::ReadSxpi( XclImpStream& rStrm )
1605 if( !maPTables.empty() )
1606 maPTables.back()->ReadSxpi( rStrm );
1609 void XclImpPivotTableManager::ReadSxdi( XclImpStream& rStrm )
1611 if( !maPTables.empty() )
1612 maPTables.back()->ReadSxdi( rStrm );
1615 void XclImpPivotTableManager::ReadSxvi( XclImpStream& rStrm )
1617 if( !maPTables.empty() )
1618 maPTables.back()->ReadSxvi( rStrm );
1621 void XclImpPivotTableManager::ReadSxex( XclImpStream& rStrm )
1623 if( !maPTables.empty() )
1624 maPTables.back()->ReadSxex( rStrm );
1627 void XclImpPivotTableManager::ReadSxViewEx9( XclImpStream& rStrm )
1629 if( !maPTables.empty() )
1630 maPTables.back()->ReadSxViewEx9( rStrm );
1633 // ----------------------------------------------------------------------------
1635 void XclImpPivotTableManager::ReadPivotCaches( XclImpStream& rStrm )
1637 for( XclImpPivotCacheVec::iterator aIt = maPCaches.begin(), aEnd = maPCaches.end(); aIt != aEnd; ++aIt )
1638 (*aIt)->ReadPivotCacheStream( rStrm );
1641 void XclImpPivotTableManager::ConvertPivotTables()
1643 for( XclImpPivotTableVec::iterator aIt = maPTables.begin(), aEnd = maPTables.end(); aIt != aEnd; ++aIt )
1644 (*aIt)->Convert();
1647 void XclImpPivotTableManager::MaybeRefreshPivotTables()
1649 for( XclImpPivotTableVec::iterator aIt = maPTables.begin(), aEnd = maPTables.end(); aIt != aEnd; ++aIt )
1650 (*aIt)->MaybeRefresh();
1653 // ============================================================================
1655 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */