Update ooo320-m1
[ooovba.git] / sc / source / filter / excel / xipivot.cxx
blobbae219208c696eb23703874eec43a33203a89bd5
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: xipivot.cxx,v $
10 * $Revision: 1.20.4.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 #include "xipivot.hxx"
36 #include <com/sun/star/sheet/DataPilotFieldSortInfo.hpp>
37 #include <com/sun/star/sheet/DataPilotFieldAutoShowInfo.hpp>
38 #include <com/sun/star/sheet/DataPilotFieldLayoutInfo.hpp>
39 #include <com/sun/star/sheet/DataPilotFieldReference.hpp>
41 #include <tools/datetime.hxx>
42 #include <svtools/zformat.hxx>
43 #include <svtools/intitem.hxx>
45 #include "document.hxx"
46 #include "cell.hxx"
47 #include "dpsave.hxx"
48 #include "dpdimsave.hxx"
49 #include "dpobject.hxx"
50 #include "dpshttab.hxx"
51 #include "dpoutputgeometry.hxx"
52 #include "scitems.hxx"
53 #include "attrib.hxx"
55 #include "xltracer.hxx"
56 #include "xistream.hxx"
57 #include "xihelper.hxx"
58 #include "xilink.hxx"
59 #include "xiescher.hxx"
61 //! TODO ExcelToSc usage
62 #include "excform.hxx"
63 #include "xltable.hxx"
65 #include <vector>
67 using ::rtl::OUString;
68 using ::rtl::OUStringBuffer;
69 using ::com::sun::star::sheet::DataPilotFieldOrientation;
70 using ::com::sun::star::sheet::DataPilotFieldOrientation_DATA;
71 using ::com::sun::star::sheet::DataPilotFieldSortInfo;
72 using ::com::sun::star::sheet::DataPilotFieldAutoShowInfo;
73 using ::com::sun::star::sheet::DataPilotFieldLayoutInfo;
74 using ::com::sun::star::sheet::DataPilotFieldReference;
75 using ::std::vector;
77 // ============================================================================
78 // Pivot cache
79 // ============================================================================
81 XclImpPCItem::XclImpPCItem( XclImpStream& rStrm )
83 switch( rStrm.GetRecId() )
85 case EXC_ID_SXDOUBLE: ReadSxdouble( rStrm ); break;
86 case EXC_ID_SXBOOLEAN: ReadSxboolean( rStrm ); break;
87 case EXC_ID_SXERROR: ReadSxerror( rStrm ); break;
88 case EXC_ID_SXINTEGER: ReadSxinteger( rStrm ); break;
89 case EXC_ID_SXSTRING: ReadSxstring( rStrm ); break;
90 case EXC_ID_SXDATETIME: ReadSxdatetime( rStrm ); break;
91 case EXC_ID_SXEMPTY: ReadSxempty( rStrm ); break;
92 default: DBG_ERRORFILE( "XclImpPCItem::XclImpPCItem - unknown record id" );
96 namespace {
98 void lclSetValue( const XclImpRoot& rRoot, const ScAddress& rScPos, double fValue, short nFormatType )
100 ScDocument& rDoc = rRoot.GetDoc();
101 rDoc.SetValue( rScPos.Col(), rScPos.Row(), rScPos.Tab(), fValue );
102 sal_uInt32 nScNumFmt = rRoot.GetFormatter().GetStandardFormat( nFormatType, rRoot.GetDocLanguage() );
103 rDoc.ApplyAttr( rScPos.Col(), rScPos.Row(), rScPos.Tab(), SfxUInt32Item( ATTR_VALUE_FORMAT, nScNumFmt ) );
106 } // namespace
108 void XclImpPCItem::WriteToSource( const XclImpRoot& rRoot, const ScAddress& rScPos ) const
110 ScDocument& rDoc = rRoot.GetDoc();
111 if( const String* pText = GetText() )
112 rDoc.SetString( rScPos.Col(), rScPos.Row(), rScPos.Tab(), *pText );
113 else if( const double* pfValue = GetDouble() )
114 rDoc.SetValue( rScPos.Col(), rScPos.Row(), rScPos.Tab(), *pfValue );
115 else if( const sal_Int16* pnValue = GetInteger() )
116 rDoc.SetValue( rScPos.Col(), rScPos.Row(), rScPos.Tab(), *pnValue );
117 else if( const bool* pbValue = GetBool() )
118 lclSetValue( rRoot, rScPos, *pbValue ? 1.0 : 0.0, NUMBERFORMAT_LOGICAL );
119 else if( const DateTime* pDateTime = GetDateTime() )
121 // set number format date, time, or date/time, depending on the value
122 double fValue = rRoot.GetDoubleFromDateTime( *pDateTime );
123 double fInt = 0.0;
124 double fFrac = modf( fValue, &fInt );
125 short nFormatType = ((fFrac == 0.0) && (fInt != 0.0)) ? NUMBERFORMAT_DATE :
126 ((fInt == 0.0) ? NUMBERFORMAT_TIME : NUMBERFORMAT_DATETIME);
127 lclSetValue( rRoot, rScPos, fValue, nFormatType );
129 else if( const sal_uInt16* pnError = GetError() )
131 double fValue;
132 sal_uInt8 nErrCode = static_cast< sal_uInt8 >( *pnError );
133 const ScTokenArray* pScTokArr = rRoot.GetOldFmlaConverter().GetBoolErr(
134 XclTools::ErrorToEnum( fValue, EXC_BOOLERR_ERROR, nErrCode ) );
135 ScFormulaCell* pCell = new ScFormulaCell( &rDoc, rScPos, pScTokArr );
136 pCell->SetHybridDouble( fValue );
137 rDoc.PutCell( rScPos, pCell );
141 void XclImpPCItem::ReadSxdouble( XclImpStream& rStrm )
143 DBG_ASSERT( rStrm.GetRecSize() == 8, "XclImpPCItem::ReadSxdouble - wrong record size" );
144 SetDouble( rStrm.ReadDouble() );
147 void XclImpPCItem::ReadSxboolean( XclImpStream& rStrm )
149 DBG_ASSERT( rStrm.GetRecSize() == 2, "XclImpPCItem::ReadSxboolean - wrong record size" );
150 SetBool( rStrm.ReaduInt16() != 0 );
153 void XclImpPCItem::ReadSxerror( XclImpStream& rStrm )
155 DBG_ASSERT( rStrm.GetRecSize() == 2, "XclImpPCItem::ReadSxerror - wrong record size" );
156 SetError( rStrm.ReaduInt16() );
159 void XclImpPCItem::ReadSxinteger( XclImpStream& rStrm )
161 DBG_ASSERT( rStrm.GetRecSize() == 2, "XclImpPCItem::ReadSxinteger - wrong record size" );
162 SetInteger( rStrm.ReadInt16() );
165 void XclImpPCItem::ReadSxstring( XclImpStream& rStrm )
167 DBG_ASSERT( rStrm.GetRecSize() >= 3, "XclImpPCItem::ReadSxstring - wrong record size" );
168 SetText( rStrm.ReadUniString() );
171 void XclImpPCItem::ReadSxdatetime( XclImpStream& rStrm )
173 DBG_ASSERT( rStrm.GetRecSize() == 8, "XclImpPCItem::ReadSxdatetime - wrong record size" );
174 sal_uInt16 nYear, nMonth;
175 sal_uInt8 nDay, nHour, nMin, nSec;
176 rStrm >> nYear >> nMonth >> nDay >> nHour >> nMin >> nSec;
177 SetDateTime( DateTime( Date( nDay, nMonth, nYear ), Time( nHour, nMin, nSec ) ) );
180 void XclImpPCItem::ReadSxempty( XclImpStream& rStrm )
182 (void)rStrm; // avoid compiler warning
183 DBG_ASSERT( rStrm.GetRecSize() == 0, "XclImpPCItem::ReadSxempty - wrong record size" );
184 SetEmpty();
187 // ============================================================================
189 XclImpPCField::XclImpPCField( const XclImpRoot& rRoot, XclImpPivotCache& rPCache, sal_uInt16 nFieldIdx ) :
190 XclPCField( EXC_PCFIELD_UNKNOWN, nFieldIdx ),
191 XclImpRoot( rRoot ),
192 mrPCache( rPCache ),
193 mnSourceScCol( -1 ),
194 mbNumGroupInfoRead( false )
198 XclImpPCField::~XclImpPCField()
202 // general field/item access --------------------------------------------------
204 const String& XclImpPCField::GetFieldName( const ScfStringVec& rVisNames ) const
206 if( IsGroupChildField() && (mnFieldIdx < rVisNames.size()) )
208 const String& rVisName = rVisNames[ mnFieldIdx ];
209 if( rVisName.Len() > 0 )
210 return rVisName;
212 return maFieldInfo.maName;
215 const XclImpPCField* XclImpPCField::GetGroupBaseField() const
217 DBG_ASSERT( IsGroupChildField(), "XclImpPCField::GetGroupBaseField - this field type does not have a base field" );
218 return IsGroupChildField() ? mrPCache.GetField( maFieldInfo.mnGroupBase ) : 0;
221 sal_uInt16 XclImpPCField::GetItemCount() const
223 return static_cast< sal_uInt16 >( maItems.size() );
226 const XclImpPCItem* XclImpPCField::GetItem( sal_uInt16 nItemIdx ) const
228 return (nItemIdx < maItems.size()) ? maItems[ nItemIdx ].get() : 0;
231 const XclImpPCItem* XclImpPCField::GetLimitItem( sal_uInt16 nItemIdx ) const
233 DBG_ASSERT( nItemIdx < 3, "XclImpPCField::GetLimitItem - invalid item index" );
234 DBG_ASSERT( nItemIdx < maNumGroupItems.size(), "XclImpPCField::GetLimitItem - no item found" );
235 return (nItemIdx < maNumGroupItems.size()) ? maNumGroupItems[ nItemIdx ].get() : 0;
238 void XclImpPCField::WriteFieldNameToSource( SCCOL nScCol, SCTAB nScTab ) const
240 DBG_ASSERT( HasOrigItems(), "XclImpPCField::WriteFieldNameToSource - only for standard fields" );
241 GetDoc().SetString( nScCol, 0, nScTab, maFieldInfo.maName );
242 mnSourceScCol = nScCol;
245 void XclImpPCField::WriteOrigItemToSource( SCROW nScRow, SCTAB nScTab, sal_uInt16 nItemIdx ) const
247 if( nItemIdx < maOrigItems.size() )
248 maOrigItems[ nItemIdx ]->WriteToSource( GetRoot(), ScAddress( mnSourceScCol, nScRow, nScTab ) );
251 void XclImpPCField::WriteLastOrigItemToSource( SCROW nScRow, SCTAB nScTab ) const
253 if( !maOrigItems.empty() )
254 maOrigItems.back()->WriteToSource( GetRoot(), ScAddress( mnSourceScCol, nScRow, nScTab ) );
257 // records --------------------------------------------------------------------
259 void XclImpPCField::ReadSxfield( XclImpStream& rStrm )
261 rStrm >> maFieldInfo;
263 /* Detect the type of this field. This is done very restrictive to detect
264 any unexpected state. */
265 meFieldType = EXC_PCFIELD_UNKNOWN;
267 bool bItems = ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_HASITEMS );
268 bool bPostp = ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_POSTPONE );
269 bool bCalced = ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_CALCED );
270 bool bChild = ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_HASCHILD );
271 bool bNum = ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_NUMGROUP );
273 sal_uInt16 nVisC = maFieldInfo.mnVisItems;
274 sal_uInt16 nGroupC = maFieldInfo.mnGroupItems;
275 sal_uInt16 nBaseC = maFieldInfo.mnBaseItems;
276 sal_uInt16 nOrigC = maFieldInfo.mnOrigItems;
277 DBG_ASSERT( nVisC > 0, "XclImpPCField::ReadSxfield - field without visible items" );
279 sal_uInt16 nType = maFieldInfo.mnFlags & EXC_SXFIELD_DATA_MASK;
280 bool bType =
281 (nType == EXC_SXFIELD_DATA_STR) ||
282 (nType == EXC_SXFIELD_DATA_INT) ||
283 (nType == EXC_SXFIELD_DATA_DBL) ||
284 (nType == EXC_SXFIELD_DATA_STR_INT) ||
285 (nType == EXC_SXFIELD_DATA_STR_DBL) ||
286 (nType == EXC_SXFIELD_DATA_DATE) ||
287 (nType == EXC_SXFIELD_DATA_DATE_EMP) ||
288 (nType == EXC_SXFIELD_DATA_DATE_NUM) ||
289 (nType == EXC_SXFIELD_DATA_DATE_STR);
290 bool bTypeNone =
291 (nType == EXC_SXFIELD_DATA_NONE);
292 // for now, ignore data type of calculated fields
293 DBG_ASSERT( bCalced || bType || bTypeNone, "XclImpPCField::ReadSxfield - unknown item data type" );
295 if( nVisC > 0 || bPostp )
297 if( bItems && !bPostp )
299 if( !bCalced )
301 // 1) standard fields and standard grouping fields
302 if( !bNum )
304 // 1a) standard field without grouping
305 if( bType && (nGroupC == 0) && (nBaseC == 0) && (nOrigC == nVisC) )
306 meFieldType = EXC_PCFIELD_STANDARD;
308 // 1b) standard grouping field
309 else if( bTypeNone && (nGroupC == nVisC) && (nBaseC > 0) && (nOrigC == 0) )
310 meFieldType = EXC_PCFIELD_STDGROUP;
312 // 2) numerical grouping fields
313 else if( (nGroupC == nVisC) && (nBaseC == 0) )
315 // 2a) single num/date grouping field without child grouping field
316 if( !bChild && bType && (nOrigC > 0) )
318 switch( nType )
320 case EXC_SXFIELD_DATA_INT:
321 case EXC_SXFIELD_DATA_DBL: meFieldType = EXC_PCFIELD_NUMGROUP; break;
322 case EXC_SXFIELD_DATA_DATE: meFieldType = EXC_PCFIELD_DATEGROUP; break;
323 default: DBG_ERRORFILE( "XclImpPCField::ReadSxfield - numeric group with wrong data type" );
327 // 2b) first date grouping field with child grouping field
328 else if( bChild && (nType == EXC_SXFIELD_DATA_DATE) && (nOrigC > 0) )
329 meFieldType = EXC_PCFIELD_DATEGROUP;
331 // 2c) additional date grouping field
332 else if( bTypeNone && (nOrigC == 0) )
333 meFieldType = EXC_PCFIELD_DATECHILD;
335 DBG_ASSERT( meFieldType != EXC_PCFIELD_UNKNOWN, "XclImpPCField::ReadSxfield - invalid standard or grouped field" );
338 // 3) calculated field
339 else
341 if( !bChild && !bNum && (nGroupC == 0) && (nBaseC == 0) && (nOrigC == 0) )
342 meFieldType = EXC_PCFIELD_CALCED;
343 DBG_ASSERT( meFieldType == EXC_PCFIELD_CALCED, "XclImpPCField::ReadSxfield - invalid calculated field" );
347 else if( !bItems && bPostp )
349 // 4) standard field with postponed items
350 if( !bCalced && !bChild && !bNum && bType && (nGroupC == 0) && (nBaseC == 0) && (nOrigC == 0) )
351 meFieldType = EXC_PCFIELD_STANDARD;
352 DBG_ASSERT( meFieldType == EXC_PCFIELD_STANDARD, "XclImpPCField::ReadSxfield - invalid postponed field" );
357 void XclImpPCField::ReadItem( XclImpStream& rStrm )
359 DBG_ASSERT( HasInlineItems() || HasPostponedItems(), "XclImpPCField::ReadItem - field does not expect items" );
361 // read the item
362 XclImpPCItemRef xItem( new XclImpPCItem( rStrm ) );
364 // try to insert into an item list
365 if( mbNumGroupInfoRead )
367 // there are 3 items after SXNUMGROUP that contain grouping limits and step count
368 if( maNumGroupItems.size() < 3 )
369 maNumGroupItems.push_back( xItem );
370 else
371 maOrigItems.push_back( xItem );
373 else if( HasInlineItems() || HasPostponedItems() )
375 maItems.push_back( xItem );
376 // visible item is original item in standard fields
377 if( IsStandardField() )
378 maOrigItems.push_back( xItem );
382 void XclImpPCField::ReadSxnumgroup( XclImpStream& rStrm )
384 DBG_ASSERT( IsNumGroupField() || IsDateGroupField(), "XclImpPCField::ReadSxnumgroup - SXNUMGROUP outside numeric grouping field" );
385 DBG_ASSERT( !mbNumGroupInfoRead, "XclImpPCField::ReadSxnumgroup - multiple SXNUMGROUP records" );
386 DBG_ASSERT( maItems.size() == maFieldInfo.mnGroupItems, "XclImpPCField::ReadSxnumgroup - SXNUMGROUP out of record order" );
387 rStrm >> maNumGroupInfo;
388 mbNumGroupInfoRead = IsNumGroupField() || IsDateGroupField();
391 void XclImpPCField::ReadSxgroupinfo( XclImpStream& rStrm )
393 DBG_ASSERT( IsStdGroupField(), "XclImpPCField::ReadSxgroupinfo - SXGROUPINFO outside grouping field" );
394 DBG_ASSERT( maGroupOrder.empty(), "XclImpPCField::ReadSxgroupinfo - multiple SXGROUPINFO records" );
395 DBG_ASSERT( maItems.size() == maFieldInfo.mnGroupItems, "XclImpPCField::ReadSxgroupinfo - SXGROUPINFO out of record order" );
396 DBG_ASSERT( (rStrm.GetRecLeft() / 2) == maFieldInfo.mnBaseItems, "XclImpPCField::ReadSxgroupinfo - wrong SXGROUPINFO size" );
397 maGroupOrder.clear();
398 size_t nSize = rStrm.GetRecLeft() / 2;
399 maGroupOrder.resize( nSize, 0 );
400 for( size_t nIdx = 0; nIdx < nSize; ++nIdx )
401 rStrm >> maGroupOrder[ nIdx ];
404 // grouping -------------------------------------------------------------------
406 void XclImpPCField::ConvertGroupField( ScDPSaveData& rSaveData, const ScfStringVec& rVisNames ) const
408 if( GetFieldName( rVisNames ).Len() > 0 )
410 if( IsStdGroupField() )
411 ConvertStdGroupField( rSaveData, rVisNames );
412 else if( IsNumGroupField() )
413 ConvertNumGroupField( rSaveData, rVisNames );
414 else if( IsDateGroupField() )
415 ConvertDateGroupField( rSaveData, rVisNames );
419 // private --------------------------------------------------------------------
421 void XclImpPCField::ConvertStdGroupField( ScDPSaveData& rSaveData, const ScfStringVec& rVisNames ) const
423 if( const XclImpPCField* pBaseField = GetGroupBaseField() )
425 const String& rBaseFieldName = pBaseField->GetFieldName( rVisNames );
426 if( rBaseFieldName.Len() > 0 )
428 // *** create a ScDPSaveGroupItem for each own item, they collect base item names ***
429 typedef ::std::vector< ScDPSaveGroupItem > ScDPSaveGroupItemVec;
430 ScDPSaveGroupItemVec aGroupItems;
431 aGroupItems.reserve( maItems.size() );
432 // initialize with own item names
433 for( XclImpPCItemVec::const_iterator aIt = maItems.begin(), aEnd = maItems.end(); aIt != aEnd; ++aIt )
434 aGroupItems.push_back( ScDPSaveGroupItem( (*aIt)->ConvertToText() ) );
436 // *** iterate over all base items, set their names at corresponding own items ***
437 for( sal_uInt16 nItemIdx = 0, nItemCount = static_cast< sal_uInt16 >( maGroupOrder.size() ); nItemIdx < nItemCount; ++nItemIdx )
438 if( maGroupOrder[ nItemIdx ] < aGroupItems.size() )
439 if( const XclImpPCItem* pBaseItem = pBaseField->GetItem( nItemIdx ) )
440 if( const XclImpPCItem* pGroupItem = GetItem( maGroupOrder[ nItemIdx ] ) )
441 if( *pBaseItem != *pGroupItem )
442 aGroupItems[ maGroupOrder[ nItemIdx ] ].AddElement( pBaseItem->ConvertToText() );
444 // *** create the ScDPSaveGroupDimension object, fill with grouping info ***
445 ScDPSaveGroupDimension aGroupDim( rBaseFieldName, GetFieldName( rVisNames ) );
446 for( ScDPSaveGroupItemVec::const_iterator aIt = aGroupItems.begin(), aEnd = aGroupItems.end(); aIt != aEnd; ++aIt )
447 if( !aIt->IsEmpty() )
448 aGroupDim.AddGroupItem( *aIt );
449 rSaveData.GetDimensionData()->AddGroupDimension( aGroupDim );
454 void XclImpPCField::ConvertNumGroupField( ScDPSaveData& rSaveData, const ScfStringVec& rVisNames ) const
456 ScDPNumGroupInfo aNumInfo( GetScNumGroupInfo() );
457 ScDPSaveNumGroupDimension aNumGroupDim( GetFieldName( rVisNames ), aNumInfo );
458 rSaveData.GetDimensionData()->AddNumGroupDimension( aNumGroupDim );
461 void XclImpPCField::ConvertDateGroupField( ScDPSaveData& rSaveData, const ScfStringVec& rVisNames ) const
463 ScDPNumGroupInfo aDateInfo( GetScDateGroupInfo() );
464 sal_Int32 nScDateType = maNumGroupInfo.GetScDateType();
466 switch( meFieldType )
468 case EXC_PCFIELD_DATEGROUP:
470 if( aDateInfo.DateValues )
472 // special case for days only with step value - create numeric grouping
473 ScDPSaveNumGroupDimension aNumGroupDim( GetFieldName( rVisNames ), aDateInfo );
474 rSaveData.GetDimensionData()->AddNumGroupDimension( aNumGroupDim );
476 else
478 ScDPSaveNumGroupDimension aNumGroupDim( GetFieldName( rVisNames ), ScDPNumGroupInfo() );
479 aNumGroupDim.SetDateInfo( aDateInfo, nScDateType );
480 rSaveData.GetDimensionData()->AddNumGroupDimension( aNumGroupDim );
483 break;
485 case EXC_PCFIELD_DATECHILD:
487 if( const XclImpPCField* pBaseField = GetGroupBaseField() )
489 const String& rBaseFieldName = pBaseField->GetFieldName( rVisNames );
490 if( rBaseFieldName.Len() > 0 )
492 ScDPSaveGroupDimension aGroupDim( rBaseFieldName, GetFieldName( rVisNames ) );
493 aGroupDim.SetDateInfo( aDateInfo, nScDateType );
494 rSaveData.GetDimensionData()->AddGroupDimension( aGroupDim );
498 break;
500 default:
501 DBG_ERRORFILE( "XclImpPCField::ConvertDateGroupField - unknown date field type" );
505 ScDPNumGroupInfo XclImpPCField::GetScNumGroupInfo() const
507 ScDPNumGroupInfo aNumInfo;
508 aNumInfo.Enable = sal_True;
509 aNumInfo.DateValues = sal_False;
510 aNumInfo.AutoStart = sal_True;
511 aNumInfo.AutoEnd = sal_True;
513 if( const double* pfMinValue = GetNumGroupLimit( EXC_SXFIELD_INDEX_MIN ) )
515 aNumInfo.Start = *pfMinValue;
516 aNumInfo.AutoStart = ::get_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMIN );
518 if( const double* pfMaxValue = GetNumGroupLimit( EXC_SXFIELD_INDEX_MAX ) )
520 aNumInfo.End = *pfMaxValue;
521 aNumInfo.AutoEnd = ::get_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMAX );
523 if( const double* pfStepValue = GetNumGroupLimit( EXC_SXFIELD_INDEX_STEP ) )
524 aNumInfo.Step = *pfStepValue;
526 return aNumInfo;
529 ScDPNumGroupInfo XclImpPCField::GetScDateGroupInfo() const
531 ScDPNumGroupInfo aDateInfo;
532 aDateInfo.Enable = sal_True;
533 aDateInfo.DateValues = sal_False;
534 aDateInfo.AutoStart = sal_True;
535 aDateInfo.AutoEnd = sal_True;
537 if( const DateTime* pMinDate = GetDateGroupLimit( EXC_SXFIELD_INDEX_MIN ) )
539 aDateInfo.Start = GetDoubleFromDateTime( *pMinDate );
540 aDateInfo.AutoStart = ::get_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMIN );
542 if( const DateTime* pMaxDate = GetDateGroupLimit( EXC_SXFIELD_INDEX_MAX ) )
544 aDateInfo.End = GetDoubleFromDateTime( *pMaxDate );
545 aDateInfo.AutoEnd = ::get_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMAX );
547 // GetDateGroupStep() returns a value for date type "day" in single date groups only
548 if( const sal_Int16* pnStepValue = GetDateGroupStep() )
550 aDateInfo.Step = *pnStepValue;
551 aDateInfo.DateValues = sal_True;
554 return aDateInfo;
557 const double* XclImpPCField::GetNumGroupLimit( sal_uInt16 nLimitIdx ) const
559 DBG_ASSERT( IsNumGroupField(), "XclImpPCField::GetNumGroupLimit - only for numeric grouping fields" );
560 if( const XclImpPCItem* pItem = GetLimitItem( nLimitIdx ) )
562 DBG_ASSERT( pItem->GetDouble(), "XclImpPCField::GetNumGroupLimit - SXDOUBLE item expected" );
563 return pItem->GetDouble();
565 return 0;
568 const DateTime* XclImpPCField::GetDateGroupLimit( sal_uInt16 nLimitIdx ) const
570 DBG_ASSERT( IsDateGroupField(), "XclImpPCField::GetDateGroupLimit - only for date grouping fields" );
571 if( const XclImpPCItem* pItem = GetLimitItem( nLimitIdx ) )
573 DBG_ASSERT( pItem->GetDateTime(), "XclImpPCField::GetDateGroupLimit - SXDATETIME item expected" );
574 return pItem->GetDateTime();
576 return 0;
579 const sal_Int16* XclImpPCField::GetDateGroupStep() const
581 // only for single date grouping fields, not for grouping chains
582 if( !IsGroupBaseField() && !IsGroupChildField() )
584 // only days may have a step value, return 0 for all other date types
585 if( maNumGroupInfo.GetXclDataType() == EXC_SXNUMGROUP_TYPE_DAY )
587 if( const XclImpPCItem* pItem = GetLimitItem( EXC_SXFIELD_INDEX_STEP ) )
589 DBG_ASSERT( pItem->GetInteger(), "XclImpPCField::GetDateGroupStep - SXINTEGER item expected" );
590 if( const sal_Int16* pnStep = pItem->GetInteger() )
592 DBG_ASSERT( *pnStep > 0, "XclImpPCField::GetDateGroupStep - invalid step count" );
593 // return nothing for step count 1 - this is also a standard date group in Excel
594 return (*pnStep > 1) ? pnStep : 0;
599 return 0;
602 // ============================================================================
604 XclImpPivotCache::XclImpPivotCache( const XclImpRoot& rRoot ) :
605 XclImpRoot( rRoot ),
606 maSrcRange( ScAddress::INITIALIZE_INVALID ),
607 mnStrmId( 0 ),
608 mnSrcType( EXC_SXVS_UNKNOWN ),
609 mbSelfRef( false )
613 XclImpPivotCache::~XclImpPivotCache()
617 // data access ----------------------------------------------------------------
619 sal_uInt16 XclImpPivotCache::GetFieldCount() const
621 return static_cast< sal_uInt16 >( maFields.size() );
624 const XclImpPCField* XclImpPivotCache::GetField( sal_uInt16 nFieldIdx ) const
626 return (nFieldIdx < maFields.size()) ? maFields[ nFieldIdx ].get() : 0;
629 // records --------------------------------------------------------------------
631 void XclImpPivotCache::ReadSxidstm( XclImpStream& rStrm )
633 rStrm >> mnStrmId;
636 void XclImpPivotCache::ReadSxvs( XclImpStream& rStrm )
638 rStrm >> mnSrcType;
639 GetTracer().TracePivotDataSource( mnSrcType != EXC_SXVS_SHEET );
642 void XclImpPivotCache::ReadDconref( XclImpStream& rStrm )
644 /* Read DCONREF only once (by checking maTabName), there may be other
645 DCONREF records in another context. Read reference only if a leading
646 SXVS record is present (by checking mnSrcType). */
647 if( (maTabName.Len() > 0) || (mnSrcType != EXC_SXVS_SHEET) )
648 return;
650 XclRange aXclRange( ScAddress::UNINITIALIZED );
651 aXclRange.Read( rStrm, false );
652 String aEncUrl = rStrm.ReadUniString();
654 XclImpUrlHelper::DecodeUrl( maUrl, maTabName, mbSelfRef, GetRoot(), aEncUrl );
656 /* Do not convert maTabName to Calc sheet name -> original name is used to
657 find the sheet in the document. Sheet index of source range will be
658 found later in XclImpPivotCache::ReadPivotCacheStream(), because sheet
659 may not exist yet. */
660 if( mbSelfRef )
661 GetAddressConverter().ConvertRange( maSrcRange, aXclRange, 0, 0, true );
664 void XclImpPivotCache::ReadPivotCacheStream( XclImpStream& rStrm )
666 if( (mnSrcType != EXC_SXVS_SHEET) && (mnSrcType != EXC_SXVS_EXTERN) )
667 return;
669 ScDocument& rDoc = GetDoc();
670 SCCOL nFieldScCol = 0; // column index of source data for next field
671 SCROW nItemScRow = 0; // row index of source data for current items
672 SCTAB nScTab = 0; // sheet index of source data
673 bool bGenerateSource = false; // true = write source data from cache to dummy table
675 if( mbSelfRef )
677 // try to find internal sheet containing the source data
678 nScTab = GetTabInfo().GetScTabFromXclName( maTabName );
679 if( rDoc.HasTable( nScTab ) )
681 // set sheet index to source range
682 maSrcRange.aStart.SetTab( nScTab );
683 maSrcRange.aEnd.SetTab( nScTab );
685 else
687 // create dummy sheet for deleted internal sheet
688 bGenerateSource = true;
691 else
693 // create dummy sheet for external sheet
694 bGenerateSource = true;
697 // create dummy sheet for source data from external or deleted sheet
698 if( bGenerateSource )
700 if( rDoc.GetTableCount() >= MAXTABCOUNT )
701 // cannot create more sheets -> exit
702 return;
704 nScTab = rDoc.GetTableCount();
705 rDoc.MakeTable( nScTab );
706 String aDummyName = CREATE_STRING( "DPCache" );
707 if( maTabName.Len() > 0 )
708 aDummyName.Append( '_' ).Append( maTabName );
709 rDoc.CreateValidTabName( aDummyName );
710 rDoc.RenameTab( nScTab, aDummyName );
711 // set sheet index to source range
712 maSrcRange.aStart.SetTab( nScTab );
713 maSrcRange.aEnd.SetTab( nScTab );
716 // open pivot cache storage stream
717 SotStorageRef xSvStrg = OpenStorage( EXC_STORAGE_PTCACHE );
718 SotStorageStreamRef xSvStrm = OpenStream( xSvStrg, ScfTools::GetHexStr( mnStrmId ) );
719 if( !xSvStrm.Is() )
720 return;
722 // create Excel record stream object
723 XclImpStream aPCStrm( *xSvStrm, GetRoot() );
724 aPCStrm.CopyDecrypterFrom( rStrm ); // pivot cache streams are encrypted
726 XclImpPCFieldRef xCurrField; // current field for new items
727 XclImpPCFieldVec aOrigFields; // all standard fields with inline original items
728 XclImpPCFieldVec aPostpFields; // all standard fields with postponed original items
729 size_t nPostpIdx = 0; // index to current field with postponed items
730 bool bLoop = true; // true = continue loop
732 while( bLoop && aPCStrm.StartNextRecord() )
734 switch( aPCStrm.GetRecId() )
736 case EXC_ID_EOF:
737 bLoop = false;
738 break;
740 case EXC_ID_SXDB:
741 aPCStrm >> maPCInfo;
742 break;
744 case EXC_ID_SXFIELD:
746 xCurrField.reset();
747 sal_uInt16 nNewFieldIdx = GetFieldCount();
748 if( nNewFieldIdx < EXC_PC_MAXFIELDCOUNT )
750 xCurrField.reset( new XclImpPCField( GetRoot(), *this, nNewFieldIdx ) );
751 maFields.push_back( xCurrField );
752 xCurrField->ReadSxfield( aPCStrm );
753 if( xCurrField->HasOrigItems() )
755 if( xCurrField->HasPostponedItems() )
756 aPostpFields.push_back( xCurrField );
757 else
758 aOrigFields.push_back( xCurrField );
759 // insert field name into generated source data, field remembers its column index
760 if( bGenerateSource && (nFieldScCol <= MAXCOL) )
761 xCurrField->WriteFieldNameToSource( nFieldScCol++, nScTab );
763 // do not read items into invalid/postponed fields
764 if( !xCurrField->HasInlineItems() )
765 xCurrField.reset();
768 break;
770 case EXC_ID_SXINDEXLIST:
771 // read index list and insert all items into generated source data
772 if( bGenerateSource && (nItemScRow <= MAXROW) && (++nItemScRow <= MAXROW) )
774 for( XclImpPCFieldVec::const_iterator aIt = aOrigFields.begin(), aEnd = aOrigFields.end(); aIt != aEnd; ++aIt )
776 sal_uInt16 nItemIdx = (*aIt)->Has16BitIndexes() ? aPCStrm.ReaduInt16() : aPCStrm.ReaduInt8();
777 (*aIt)->WriteOrigItemToSource( nItemScRow, nScTab, nItemIdx );
780 xCurrField.reset();
781 break;
783 case EXC_ID_SXDOUBLE:
784 case EXC_ID_SXBOOLEAN:
785 case EXC_ID_SXERROR:
786 case EXC_ID_SXINTEGER:
787 case EXC_ID_SXSTRING:
788 case EXC_ID_SXDATETIME:
789 case EXC_ID_SXEMPTY:
790 if( xCurrField.is() ) // inline items
792 xCurrField->ReadItem( aPCStrm );
794 else if( !aPostpFields.empty() ) // postponed items
796 // read postponed item
797 aPostpFields[ nPostpIdx ]->ReadItem( aPCStrm );
798 // write item to source
799 if( bGenerateSource && (nItemScRow <= MAXROW) )
801 // start new row, if there are only postponed fields
802 if( aOrigFields.empty() && (nPostpIdx == 0) )
803 ++nItemScRow;
804 if( nItemScRow <= MAXROW )
805 aPostpFields[ nPostpIdx ]->WriteLastOrigItemToSource( nItemScRow, nScTab );
807 // get index of next postponed field
808 ++nPostpIdx;
809 if( nPostpIdx >= aPostpFields.size() )
810 nPostpIdx = 0;
812 break;
814 case EXC_ID_SXNUMGROUP:
815 if( xCurrField.is() )
816 xCurrField->ReadSxnumgroup( aPCStrm );
817 break;
819 case EXC_ID_SXGROUPINFO:
820 if( xCurrField.is() )
821 xCurrField->ReadSxgroupinfo( aPCStrm );
822 break;
824 // known but ignored records
825 case EXC_ID_SXRULE:
826 case EXC_ID_SXFILT:
827 case EXC_ID_00F5:
828 case EXC_ID_SXNAME:
829 case EXC_ID_SXPAIR:
830 case EXC_ID_SXFMLA:
831 case EXC_ID_SXFORMULA:
832 case EXC_ID_SXDBEX:
833 case EXC_ID_SXFDBTYPE:
834 break;
836 default:
837 DBG_ERROR1( "XclImpPivotCache::ReadPivotCacheStream - unknown record 0x%04hX", aPCStrm.GetRecId() );
841 DBG_ASSERT( maPCInfo.mnTotalFields == maFields.size(),
842 "XclImpPivotCache::ReadPivotCacheStream - field count mismatch" );
844 // set source range for external source data
845 if( bGenerateSource && (nFieldScCol > 0) )
847 maSrcRange.aStart.SetCol( 0 );
848 maSrcRange.aStart.SetRow( 0 );
849 // nFieldScCol points to first unused column
850 maSrcRange.aEnd.SetCol( nFieldScCol - 1 );
851 // nItemScRow points to last used row
852 maSrcRange.aEnd.SetRow( nItemScRow );
856 bool XclImpPivotCache::IsRefreshOnLoad() const
858 return static_cast<bool>(maPCInfo.mnFlags & 0x0004);
861 // ============================================================================
862 // Pivot table
863 // ============================================================================
865 XclImpPTItem::XclImpPTItem( const XclImpPCField* pCacheField ) :
866 mpCacheField( pCacheField )
870 const String* XclImpPTItem::GetItemName() const
872 if( mpCacheField )
873 if( const XclImpPCItem* pCacheItem = mpCacheField->GetItem( maItemInfo.mnCacheIdx ) )
874 //! TODO: use XclImpPCItem::ConvertToText(), if all conversions are available
875 return pCacheItem->IsEmpty() ? &String::EmptyString() : pCacheItem->GetText();
876 return 0;
879 const String* XclImpPTItem::GetVisItemName() const
881 return maItemInfo.HasVisName() ? maItemInfo.GetVisName() : GetItemName();
884 void XclImpPTItem::ReadSxvi( XclImpStream& rStrm )
886 rStrm >> maItemInfo;
889 void XclImpPTItem::ConvertItem( ScDPSaveDimension& rSaveDim ) const
891 if( const String* pItemName = GetItemName() )
893 ScDPSaveMember& rMember = *rSaveDim.GetMemberByName( *pItemName );
894 rMember.SetIsVisible( !::get_flag( maItemInfo.mnFlags, EXC_SXVI_HIDDEN ) );
895 rMember.SetShowDetails( !::get_flag( maItemInfo.mnFlags, EXC_SXVI_HIDEDETAIL ) );
896 if (maItemInfo.HasVisName())
897 rMember.SetLayoutName(*maItemInfo.GetVisName());
901 // ============================================================================
903 XclImpPTField::XclImpPTField( const XclImpPivotTable& rPTable, sal_uInt16 nCacheIdx ) :
904 mrPTable( rPTable )
906 maFieldInfo.mnCacheIdx = nCacheIdx;
909 // general field/item access --------------------------------------------------
911 const XclImpPCField* XclImpPTField::GetCacheField() const
913 XclImpPivotCacheRef xPCache = mrPTable.GetPivotCache();
914 return xPCache.is() ? xPCache->GetField( maFieldInfo.mnCacheIdx ) : 0;
917 const String& XclImpPTField::GetFieldName() const
919 const XclImpPCField* pField = GetCacheField();
920 return pField ? pField->GetFieldName( mrPTable.GetVisFieldNames() ) : String::EmptyString();
923 const String& XclImpPTField::GetVisFieldName() const
925 const String* pVisName = maFieldInfo.GetVisName();
926 return pVisName ? *pVisName : String::EmptyString();
929 const XclImpPTItem* XclImpPTField::GetItem( sal_uInt16 nItemIdx ) const
931 return (nItemIdx < maItems.size()) ? maItems[ nItemIdx ].get() : 0;
934 const String* XclImpPTField::GetItemName( sal_uInt16 nItemIdx ) const
936 const XclImpPTItem* pItem = GetItem( nItemIdx );
937 return pItem ? pItem->GetItemName() : 0;
940 const String* XclImpPTField::GetVisItemName( sal_uInt16 nItemIdx ) const
942 const XclImpPTItem* pItem = GetItem( nItemIdx );
943 return pItem ? pItem->GetVisItemName() : 0;
946 // records --------------------------------------------------------------------
948 void XclImpPTField::ReadSxvd( XclImpStream& rStrm )
950 rStrm >> maFieldInfo;
953 void XclImpPTField::ReadSxvdex( XclImpStream& rStrm )
955 rStrm >> maFieldExtInfo;
958 void XclImpPTField::ReadSxvi( XclImpStream& rStrm )
960 XclImpPTItemRef xItem( new XclImpPTItem( GetCacheField() ) );
961 maItems.push_back( xItem );
962 xItem->ReadSxvi( rStrm );
965 // row/column fields ----------------------------------------------------------
967 void XclImpPTField::ConvertRowColField( ScDPSaveData& rSaveData ) const
969 DBG_ASSERT( maFieldInfo.mnAxes & EXC_SXVD_AXIS_ROWCOL, "XclImpPTField::ConvertRowColField - no row/column field" );
970 // special data orientation field?
971 if( maFieldInfo.mnCacheIdx == EXC_SXIVD_DATA )
972 rSaveData.GetDataLayoutDimension()->SetOrientation( static_cast< USHORT >( maFieldInfo.GetApiOrient( EXC_SXVD_AXIS_ROWCOL ) ) );
973 else
974 ConvertRCPField( rSaveData );
977 // page fields ----------------------------------------------------------------
979 void XclImpPTField::SetPageFieldInfo( const XclPTPageFieldInfo& rPageInfo )
981 maPageInfo = rPageInfo;
984 void XclImpPTField::ConvertPageField( ScDPSaveData& rSaveData ) const
986 DBG_ASSERT( maFieldInfo.mnAxes & EXC_SXVD_AXIS_PAGE, "XclImpPTField::ConvertPageField - no page field" );
987 if( ScDPSaveDimension* pSaveDim = ConvertRCPField( rSaveData ) )
988 pSaveDim->SetCurrentPage( GetItemName( maPageInfo.mnSelItem ) );
991 // hidden fields --------------------------------------------------------------
993 void XclImpPTField::ConvertHiddenField( ScDPSaveData& rSaveData ) const
995 DBG_ASSERT( (maFieldInfo.mnAxes & EXC_SXVD_AXIS_ROWCOLPAGE) == 0, "XclImpPTField::ConvertHiddenField - field not hidden" );
996 ConvertRCPField( rSaveData );
999 // data fields ----------------------------------------------------------------
1001 bool XclImpPTField::HasDataFieldInfo() const
1003 return !maDataInfoList.empty();
1006 void XclImpPTField::AddDataFieldInfo( const XclPTDataFieldInfo& rDataInfo )
1008 DBG_ASSERT( maFieldInfo.mnAxes & EXC_SXVD_AXIS_DATA, "XclImpPTField::AddDataFieldInfo - no data field" );
1009 maDataInfoList.push_back( rDataInfo );
1012 void XclImpPTField::ConvertDataField( ScDPSaveData& rSaveData ) const
1014 DBG_ASSERT( maFieldInfo.mnAxes & EXC_SXVD_AXIS_DATA, "XclImpPTField::ConvertDataField - no data field" );
1015 DBG_ASSERT( !maDataInfoList.empty(), "XclImpPTField::ConvertDataField - no data field info" );
1016 if( !maDataInfoList.empty() )
1018 const String& rFieldName = GetFieldName();
1019 if( rFieldName.Len() > 0 )
1021 XclPTDataFieldInfoList::const_iterator aIt = maDataInfoList.begin(), aEnd = maDataInfoList.end();
1023 ScDPSaveDimension& rSaveDim = *rSaveData.GetNewDimensionByName( rFieldName );
1024 ConvertDataField( rSaveDim, *aIt );
1026 // multiple data fields -> clone dimension
1027 for( ++aIt; aIt != aEnd; ++aIt )
1029 ScDPSaveDimension& rDupDim = rSaveData.DuplicateDimension( rSaveDim );
1030 ConvertDataFieldInfo( rDupDim, *aIt );
1036 // private --------------------------------------------------------------------
1038 /**
1039 * Convert Excel-encoded subtotal name to a Calc-encoded one.
1041 static OUString lcl_convertExcelSubtotalName(const OUString& rName)
1043 OUStringBuffer aBuf;
1044 const sal_Unicode* p = rName.getStr();
1045 sal_Int32 n = rName.getLength();
1046 for (sal_Int32 i = 0; i < n; ++i)
1048 const sal_Unicode c = p[i];
1049 if (c == sal_Unicode('\\'))
1051 aBuf.append(c);
1052 aBuf.append(c);
1054 else
1055 aBuf.append(c);
1057 return aBuf.makeStringAndClear();
1060 ScDPSaveDimension* XclImpPTField::ConvertRCPField( ScDPSaveData& rSaveData ) const
1062 const String& rFieldName = GetFieldName();
1063 if( rFieldName.Len() == 0 )
1064 return 0;
1066 const XclImpPCField* pCacheField = GetCacheField();
1067 if( !pCacheField || !pCacheField->IsSupportedField() )
1068 return 0;
1070 ScDPSaveDimension& rSaveDim = *rSaveData.GetNewDimensionByName( rFieldName );
1072 // orientation
1073 rSaveDim.SetOrientation( static_cast< USHORT >( maFieldInfo.GetApiOrient( EXC_SXVD_AXIS_ROWCOLPAGE ) ) );
1075 // general field info
1076 ConvertFieldInfo( rSaveDim );
1078 // visible name
1079 if( const String* pVisName = maFieldInfo.GetVisName() )
1080 if( pVisName->Len() > 0 )
1081 rSaveDim.SetLayoutName( *pVisName );
1083 // subtotal function(s)
1084 XclPTSubtotalVec aSubtotalVec;
1085 maFieldInfo.GetSubtotals( aSubtotalVec );
1086 if( !aSubtotalVec.empty() )
1087 rSaveDim.SetSubTotals( static_cast< long >( aSubtotalVec.size() ), &aSubtotalVec[ 0 ] );
1089 // sorting
1090 DataPilotFieldSortInfo aSortInfo;
1091 aSortInfo.Field = mrPTable.GetDataFieldName( maFieldExtInfo.mnSortField );
1092 aSortInfo.IsAscending = ::get_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_SORT_ASC );
1093 aSortInfo.Mode = maFieldExtInfo.GetApiSortMode();
1094 rSaveDim.SetSortInfo( &aSortInfo );
1096 // auto show
1097 DataPilotFieldAutoShowInfo aShowInfo;
1098 aShowInfo.IsEnabled = ::get_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_AUTOSHOW );
1099 aShowInfo.ShowItemsMode = maFieldExtInfo.GetApiAutoShowMode();
1100 aShowInfo.ItemCount = maFieldExtInfo.GetApiAutoShowCount();
1101 aShowInfo.DataField = mrPTable.GetDataFieldName( maFieldExtInfo.mnShowField );
1102 rSaveDim.SetAutoShowInfo( &aShowInfo );
1104 // layout
1105 DataPilotFieldLayoutInfo aLayoutInfo;
1106 aLayoutInfo.LayoutMode = maFieldExtInfo.GetApiLayoutMode();
1107 aLayoutInfo.AddEmptyLines = ::get_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_LAYOUT_BLANK );
1108 rSaveDim.SetLayoutInfo( &aLayoutInfo );
1110 // grouping info
1111 pCacheField->ConvertGroupField( rSaveData, mrPTable.GetVisFieldNames() );
1113 // custom subtotal name
1114 if (maFieldExtInfo.mpFieldTotalName.get())
1116 OUString aSubName = lcl_convertExcelSubtotalName(*maFieldExtInfo.mpFieldTotalName);
1117 rSaveDim.SetSubtotalName(aSubName);
1120 return &rSaveDim;
1123 void XclImpPTField::ConvertFieldInfo( ScDPSaveDimension& rSaveDim ) const
1125 rSaveDim.SetShowEmpty( ::get_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_SHOWALL ) );
1126 ConvertItems( rSaveDim );
1129 void XclImpPTField::ConvertDataField( ScDPSaveDimension& rSaveDim, const XclPTDataFieldInfo& rDataInfo ) const
1131 // orientation
1132 rSaveDim.SetOrientation( DataPilotFieldOrientation_DATA );
1133 // general field info
1134 ConvertFieldInfo( rSaveDim );
1135 // extended data field info
1136 ConvertDataFieldInfo( rSaveDim, rDataInfo );
1139 void XclImpPTField::ConvertDataFieldInfo( ScDPSaveDimension& rSaveDim, const XclPTDataFieldInfo& rDataInfo ) const
1141 // visible name
1142 if( const String* pVisName = rDataInfo.GetVisName() )
1143 if( pVisName->Len() > 0 )
1144 rSaveDim.SetLayoutName( *pVisName );
1146 // aggregation function
1147 rSaveDim.SetFunction( static_cast< USHORT >( rDataInfo.GetApiAggFunc() ) );
1149 // result field reference
1150 sal_Int32 nRefType = rDataInfo.GetApiRefType();
1151 if( nRefType != ::com::sun::star::sheet::DataPilotFieldReferenceType::NONE )
1153 DataPilotFieldReference aFieldRef;
1154 aFieldRef.ReferenceType = nRefType;
1156 if( const XclImpPTField* pRefField = mrPTable.GetField( rDataInfo.mnRefField ) )
1158 aFieldRef.ReferenceField = pRefField->GetFieldName();
1159 aFieldRef.ReferenceItemType = rDataInfo.GetApiRefItemType();
1160 if( aFieldRef.ReferenceItemType == ::com::sun::star::sheet::DataPilotFieldReferenceItemType::NAMED )
1161 if( const String* pRefItemName = pRefField->GetItemName( rDataInfo.mnRefItem ) )
1162 aFieldRef.ReferenceItemName = *pRefItemName;
1165 rSaveDim.SetReferenceValue( &aFieldRef );
1169 void XclImpPTField::ConvertItems( ScDPSaveDimension& rSaveDim ) const
1171 for( XclImpPTItemVec::const_iterator aIt = maItems.begin(), aEnd = maItems.end(); aIt != aEnd; ++aIt )
1172 (*aIt)->ConvertItem( rSaveDim );
1175 // ============================================================================
1177 XclImpPivotTable::XclImpPivotTable( const XclImpRoot& rRoot ) :
1178 XclImpRoot( rRoot ),
1179 maDataOrientField( *this, EXC_SXIVD_DATA ),
1180 mpDPObj(NULL)
1184 XclImpPivotTable::~XclImpPivotTable()
1188 // cache/field access, misc. --------------------------------------------------
1190 sal_uInt16 XclImpPivotTable::GetFieldCount() const
1192 return static_cast< sal_uInt16 >( maFields.size() );
1195 const XclImpPTField* XclImpPivotTable::GetField( sal_uInt16 nFieldIdx ) const
1197 return (nFieldIdx == EXC_SXIVD_DATA) ? &maDataOrientField :
1198 ((nFieldIdx < maFields.size()) ? maFields[ nFieldIdx ].get() : 0);
1201 XclImpPTField* XclImpPivotTable::GetFieldAcc( sal_uInt16 nFieldIdx )
1203 // do not return maDataOrientField
1204 return (nFieldIdx < maFields.size()) ? maFields[ nFieldIdx ].get() : 0;
1207 const String& XclImpPivotTable::GetFieldName( sal_uInt16 nFieldIdx ) const
1209 if( const XclImpPTField* pField = GetField( nFieldIdx ) )
1210 return pField->GetFieldName();
1211 return EMPTY_STRING;
1214 const XclImpPTField* XclImpPivotTable::GetDataField( sal_uInt16 nDataFieldIdx ) const
1216 if( nDataFieldIdx < maOrigDataFields.size() )
1217 return GetField( maOrigDataFields[ nDataFieldIdx ] );
1218 return 0;
1221 const String& XclImpPivotTable::GetDataFieldName( sal_uInt16 nDataFieldIdx ) const
1223 if( const XclImpPTField* pField = GetDataField( nDataFieldIdx ) )
1224 return pField->GetFieldName();
1225 return EMPTY_STRING;
1228 // records --------------------------------------------------------------------
1230 void XclImpPivotTable::ReadSxview( XclImpStream& rStrm )
1232 rStrm >> maPTInfo;
1234 GetAddressConverter().ConvertRange(
1235 maOutScRange, maPTInfo.maOutXclRange, GetCurrScTab(), GetCurrScTab(), true );
1237 mxPCache = GetPivotTableManager().GetPivotCache( maPTInfo.mnCacheIdx );
1238 mxCurrField.reset();
1241 void XclImpPivotTable::ReadSxvd( XclImpStream& rStrm )
1243 sal_uInt16 nFieldCount = GetFieldCount();
1244 if( nFieldCount < EXC_PT_MAXFIELDCOUNT )
1246 // cache index for the field is equal to the SXVD record index
1247 mxCurrField.reset( new XclImpPTField( *this, nFieldCount ) );
1248 maFields.push_back( mxCurrField );
1249 mxCurrField->ReadSxvd( rStrm );
1250 // add visible name of new field to list of visible names
1251 maVisFieldNames.push_back( mxCurrField->GetVisFieldName() );
1252 DBG_ASSERT( maFields.size() == maVisFieldNames.size(),
1253 "XclImpPivotTable::ReadSxvd - wrong size of visible name array" );
1255 else
1256 mxCurrField.reset();
1259 void XclImpPivotTable::ReadSxvi( XclImpStream& rStrm )
1261 if( mxCurrField.is() )
1262 mxCurrField->ReadSxvi( rStrm );
1265 void XclImpPivotTable::ReadSxvdex( XclImpStream& rStrm )
1267 if( mxCurrField.is() )
1268 mxCurrField->ReadSxvdex( rStrm );
1271 void XclImpPivotTable::ReadSxivd( XclImpStream& rStrm )
1273 mxCurrField.reset();
1275 // find the index vector to fill (row SXIVD doesn't exist without row fields)
1276 ScfUInt16Vec* pFieldVec = 0;
1277 if( maRowFields.empty() && (maPTInfo.mnRowFields > 0) )
1278 pFieldVec = &maRowFields;
1279 else if( maColFields.empty() && (maPTInfo.mnColFields > 0) )
1280 pFieldVec = &maColFields;
1282 // fill the vector from record data
1283 if( pFieldVec )
1285 sal_uInt16 nSize = ulimit_cast< sal_uInt16 >( rStrm.GetRecSize() / 2, EXC_PT_MAXROWCOLCOUNT );
1286 pFieldVec->reserve( nSize );
1287 for( sal_uInt16 nIdx = 0; nIdx < nSize; ++nIdx )
1289 sal_uInt16 nFieldIdx;
1290 rStrm >> nFieldIdx;
1291 pFieldVec->push_back( nFieldIdx );
1293 // set orientation at special data orientation field
1294 if( nFieldIdx == EXC_SXIVD_DATA )
1296 sal_uInt16 nAxis = (pFieldVec == &maRowFields) ? EXC_SXVD_AXIS_ROW : EXC_SXVD_AXIS_COL;
1297 maDataOrientField.SetAxes( nAxis );
1303 void XclImpPivotTable::ReadSxpi( XclImpStream& rStrm )
1305 mxCurrField.reset();
1307 sal_uInt16 nSize = ulimit_cast< sal_uInt16 >( rStrm.GetRecSize() / 6 );
1308 for( sal_uInt16 nEntry = 0; nEntry < nSize; ++nEntry )
1310 XclPTPageFieldInfo aPageInfo;
1311 rStrm >> aPageInfo;
1312 if( XclImpPTField* pField = GetFieldAcc( aPageInfo.mnField ) )
1314 maPageFields.push_back( aPageInfo.mnField );
1315 pField->SetPageFieldInfo( aPageInfo );
1317 GetObjectManager().SetSkipObj( GetCurrScTab(), aPageInfo.mnObjId );
1321 void XclImpPivotTable::ReadSxdi( XclImpStream& rStrm )
1323 mxCurrField.reset();
1325 XclPTDataFieldInfo aDataInfo;
1326 rStrm >> aDataInfo;
1327 if( XclImpPTField* pField = GetFieldAcc( aDataInfo.mnField ) )
1329 maOrigDataFields.push_back( aDataInfo.mnField );
1330 // DataPilot does not support double data fields -> add first appearence to index list only
1331 if( !pField->HasDataFieldInfo() )
1332 maFiltDataFields.push_back( aDataInfo.mnField );
1333 pField->AddDataFieldInfo( aDataInfo );
1337 void XclImpPivotTable::ReadSxex( XclImpStream& rStrm )
1339 rStrm >> maPTExtInfo;
1342 void XclImpPivotTable::ReadSxViewEx9( XclImpStream& rStrm )
1344 rStrm >> maPTViewEx9Info;
1347 // ----------------------------------------------------------------------------
1349 void XclImpPivotTable::Convert()
1351 if( !mxPCache || !mxPCache->GetSourceRange().IsValid() )
1352 return;
1354 ScDPSaveData aSaveData;
1356 // *** global settings ***
1358 aSaveData.SetRowGrand( ::get_flag( maPTInfo.mnFlags, EXC_SXVIEW_ROWGRAND ) );
1359 aSaveData.SetColumnGrand( ::get_flag( maPTInfo.mnFlags, EXC_SXVIEW_COLGRAND ) );
1360 aSaveData.SetFilterButton( FALSE );
1361 aSaveData.SetDrillDown( ::get_flag( maPTExtInfo.mnFlags, EXC_SXEX_DRILLDOWN ) );
1363 // *** fields ***
1365 ScfUInt16Vec::const_iterator aIt, aEnd;
1367 // row fields
1368 for( aIt = maRowFields.begin(), aEnd = maRowFields.end(); aIt != aEnd; ++aIt )
1369 if( const XclImpPTField* pField = GetField( *aIt ) )
1370 pField->ConvertRowColField( aSaveData );
1372 // column fields
1373 for( aIt = maColFields.begin(), aEnd = maColFields.end(); aIt != aEnd; ++aIt )
1374 if( const XclImpPTField* pField = GetField( *aIt ) )
1375 pField->ConvertRowColField( aSaveData );
1377 // page fields
1378 for( aIt = maPageFields.begin(), aEnd = maPageFields.end(); aIt != aEnd; ++aIt )
1379 if( const XclImpPTField* pField = GetField( *aIt ) )
1380 pField->ConvertPageField( aSaveData );
1382 // We need to import hidden fields because hidden fields may contain
1383 // special settings for subtotals (aggregation function, filters, custom
1384 // name etc.) and members (hidden, custom name etc.).
1386 // hidden fields
1387 for( sal_uInt16 nField = 0, nCount = GetFieldCount(); nField < nCount; ++nField )
1388 if( const XclImpPTField* pField = GetField( nField ) )
1389 if( (pField->GetAxes() & EXC_SXVD_AXIS_ROWCOLPAGE) == 0 )
1390 pField->ConvertHiddenField( aSaveData );
1392 // data fields
1393 for( aIt = maFiltDataFields.begin(), aEnd = maFiltDataFields.end(); aIt != aEnd; ++aIt )
1394 if( const XclImpPTField* pField = GetField( *aIt ) )
1395 pField->ConvertDataField( aSaveData );
1397 // *** insert into Calc document ***
1399 // create source descriptor
1400 ScSheetSourceDesc aDesc;
1401 aDesc.aSourceRange = mxPCache->GetSourceRange();
1403 // adjust output range to include the page fields
1404 ScRange aOutRange( maOutScRange );
1405 if( !maPageFields.empty() )
1407 SCsROW nDecRows = ::std::min< SCsROW >( aOutRange.aStart.Row(), maPageFields.size() + 1 );
1408 aOutRange.aStart.IncRow( -nDecRows );
1411 // create the DataPilot
1412 ScDPObject* pDPObj = new ScDPObject( GetDocPtr() );
1413 pDPObj->SetName( maPTInfo.maTableName );
1414 if (maPTInfo.maDataName.Len() > 0)
1415 aSaveData.GetDataLayoutDimension()->SetLayoutName(maPTInfo.maDataName);
1417 if (maPTViewEx9Info.maGrandTotalName.Len() > 0)
1418 aSaveData.SetGrandTotalName(maPTViewEx9Info.maGrandTotalName);
1420 pDPObj->SetSaveData( aSaveData );
1421 pDPObj->SetSheetDesc( aDesc );
1422 pDPObj->SetOutRange( aOutRange );
1423 pDPObj->SetAlive( TRUE );
1424 pDPObj->SetHeaderLayout( maPTViewEx9Info.mnGridLayout == 0 );
1426 GetDoc().GetDPCollection()->InsertNewTable(pDPObj);
1427 mpDPObj = pDPObj;
1429 ApplyMergeFlags(aOutRange, aSaveData);
1432 void XclImpPivotTable::MaybeRefresh()
1434 if (mpDPObj && mxPCache->IsRefreshOnLoad())
1436 // 'refresh table on load' flag is set. Refresh the table now. Some
1437 // Excel files contain partial table output when this flag is set.
1438 mpDPObj->Output(maOutScRange.aStart);
1442 void XclImpPivotTable::ApplyMergeFlags(const ScRange& rOutRange, const ScDPSaveData& rSaveData)
1444 // Apply merge flags for varoius datapilot controls.
1446 ScDPOutputGeometry aGeometry(rOutRange, false, ScDPOutputGeometry::XLS);
1447 aGeometry.setColumnFieldCount(maPTInfo.mnColFields);
1448 aGeometry.setPageFieldCount(maPTInfo.mnPageFields);
1449 aGeometry.setDataFieldCount(maPTInfo.mnDataFields);
1451 // Excel includes data layout field in the row field count. We need to
1452 // subtract it.
1453 bool bDataLayout = maPTInfo.mnDataFields > 1;
1454 aGeometry.setRowFieldCount(maPTInfo.mnRowFields - static_cast<sal_uInt32>(bDataLayout));
1456 ScDocument& rDoc = GetDoc();
1458 vector<ScAddress> aPageBtns;
1459 aGeometry.getPageFieldPositions(aPageBtns);
1460 vector<ScAddress>::const_iterator itr = aPageBtns.begin(), itrEnd = aPageBtns.end();
1461 for (; itr != itrEnd; ++itr)
1463 sal_uInt16 nMFlag = SC_MF_BUTTON;
1464 String aName;
1465 rDoc.GetString(itr->Col(), itr->Row(), itr->Tab(), aName);
1466 if (rSaveData.HasInvisibleMember(aName))
1467 nMFlag |= SC_MF_HIDDEN_MEMBER;
1469 rDoc.ApplyFlagsTab(itr->Col(), itr->Row(), itr->Col(), itr->Row(), itr->Tab(), nMFlag);
1470 rDoc.ApplyFlagsTab(itr->Col()+1, itr->Row(), itr->Col()+1, itr->Row(), itr->Tab(), SC_MF_AUTO);
1473 vector<ScAddress> aColBtns;
1474 aGeometry.getColumnFieldPositions(aColBtns);
1475 itr = aColBtns.begin();
1476 itrEnd = aColBtns.end();
1477 for (; itr != itrEnd; ++itr)
1479 sal_Int16 nMFlag = SC_MF_BUTTON | SC_MF_BUTTON_POPUP;
1480 String aName;
1481 rDoc.GetString(itr->Col(), itr->Row(), itr->Tab(), aName);
1482 if (rSaveData.HasInvisibleMember(aName))
1483 nMFlag |= SC_MF_HIDDEN_MEMBER;
1484 rDoc.ApplyFlagsTab(itr->Col(), itr->Row(), itr->Col(), itr->Row(), itr->Tab(), nMFlag);
1487 vector<ScAddress> aRowBtns;
1488 aGeometry.getRowFieldPositions(aRowBtns);
1489 if (aRowBtns.empty())
1491 if (bDataLayout)
1493 // No row fields, but the data layout button exists.
1494 SCROW nRow = aGeometry.getRowFieldHeaderRow();
1495 SCCOL nCol = rOutRange.aStart.Col();
1496 SCTAB nTab = rOutRange.aStart.Tab();
1497 rDoc.ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, SC_MF_BUTTON);
1500 else
1502 itr = aRowBtns.begin();
1503 itrEnd = aRowBtns.end();
1504 for (; itr != itrEnd; ++itr)
1506 sal_Int16 nMFlag = SC_MF_BUTTON | SC_MF_BUTTON_POPUP;
1507 String aName;
1508 rDoc.GetString(itr->Col(), itr->Row(), itr->Tab(), aName);
1509 if (rSaveData.HasInvisibleMember(aName))
1510 nMFlag |= SC_MF_HIDDEN_MEMBER;
1511 rDoc.ApplyFlagsTab(itr->Col(), itr->Row(), itr->Col(), itr->Row(), itr->Tab(), nMFlag);
1513 if (bDataLayout)
1515 --itr; // move back to the last row field position.
1516 rDoc.ApplyFlagsTab(itr->Col(), itr->Row(), itr->Col(), itr->Row(), itr->Tab(), SC_MF_BUTTON);
1521 // ============================================================================
1522 // ============================================================================
1524 XclImpPivotTableManager::XclImpPivotTableManager( const XclImpRoot& rRoot ) :
1525 XclImpRoot( rRoot )
1529 XclImpPivotTableManager::~XclImpPivotTableManager()
1533 // pivot cache records --------------------------------------------------------
1535 XclImpPivotCacheRef XclImpPivotTableManager::GetPivotCache( sal_uInt16 nCacheIdx )
1537 XclImpPivotCacheRef xPCache;
1538 if( nCacheIdx < maPCaches.size() )
1539 xPCache = maPCaches[ nCacheIdx ];
1540 return xPCache;
1543 void XclImpPivotTableManager::ReadSxidstm( XclImpStream& rStrm )
1545 XclImpPivotCacheRef xPCache( new XclImpPivotCache( GetRoot() ) );
1546 maPCaches.push_back( xPCache );
1547 xPCache->ReadSxidstm( rStrm );
1550 void XclImpPivotTableManager::ReadSxvs( XclImpStream& rStrm )
1552 if( !maPCaches.empty() )
1553 maPCaches.back()->ReadSxvs( rStrm );
1556 void XclImpPivotTableManager::ReadDconref( XclImpStream& rStrm )
1558 if( !maPCaches.empty() )
1559 maPCaches.back()->ReadDconref( rStrm );
1562 // pivot table records --------------------------------------------------------
1564 void XclImpPivotTableManager::ReadSxview( XclImpStream& rStrm )
1566 XclImpPivotTableRef xPTable( new XclImpPivotTable( GetRoot() ) );
1567 maPTables.push_back( xPTable );
1568 xPTable->ReadSxview( rStrm );
1571 void XclImpPivotTableManager::ReadSxvd( XclImpStream& rStrm )
1573 if( !maPTables.empty() )
1574 maPTables.back()->ReadSxvd( rStrm );
1577 void XclImpPivotTableManager::ReadSxvdex( XclImpStream& rStrm )
1579 if( !maPTables.empty() )
1580 maPTables.back()->ReadSxvdex( rStrm );
1583 void XclImpPivotTableManager::ReadSxivd( XclImpStream& rStrm )
1585 if( !maPTables.empty() )
1586 maPTables.back()->ReadSxivd( rStrm );
1589 void XclImpPivotTableManager::ReadSxpi( XclImpStream& rStrm )
1591 if( !maPTables.empty() )
1592 maPTables.back()->ReadSxpi( rStrm );
1595 void XclImpPivotTableManager::ReadSxdi( XclImpStream& rStrm )
1597 if( !maPTables.empty() )
1598 maPTables.back()->ReadSxdi( rStrm );
1601 void XclImpPivotTableManager::ReadSxvi( XclImpStream& rStrm )
1603 if( !maPTables.empty() )
1604 maPTables.back()->ReadSxvi( rStrm );
1607 void XclImpPivotTableManager::ReadSxex( XclImpStream& rStrm )
1609 if( !maPTables.empty() )
1610 maPTables.back()->ReadSxex( rStrm );
1613 void XclImpPivotTableManager::ReadSxViewEx9( XclImpStream& rStrm )
1615 if( !maPTables.empty() )
1616 maPTables.back()->ReadSxViewEx9( rStrm );
1619 // ----------------------------------------------------------------------------
1621 void XclImpPivotTableManager::ReadPivotCaches( XclImpStream& rStrm )
1623 for( XclImpPivotCacheVec::iterator aIt = maPCaches.begin(), aEnd = maPCaches.end(); aIt != aEnd; ++aIt )
1624 (*aIt)->ReadPivotCacheStream( rStrm );
1627 void XclImpPivotTableManager::ConvertPivotTables()
1629 for( XclImpPivotTableVec::iterator aIt = maPTables.begin(), aEnd = maPTables.end(); aIt != aEnd; ++aIt )
1630 (*aIt)->Convert();
1633 void XclImpPivotTableManager::MaybeRefreshPivotTables()
1635 for( XclImpPivotTableVec::iterator aIt = maPTables.begin(), aEnd = maPTables.end(); aIt != aEnd; ++aIt )
1636 (*aIt)->MaybeRefresh();
1639 // ============================================================================