1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 "formulacell.hxx"
35 #include "dpdimsave.hxx"
36 #include "dpobject.hxx"
37 #include "dpshttab.hxx"
38 #include "dpoutputgeometry.hxx"
39 #include "scitems.hxx"
42 #include "xltracer.hxx"
43 #include "xistream.hxx"
44 #include "xihelper.hxx"
46 #include "xiescher.hxx"
48 //! TODO ExcelToSc usage
49 #include "excform.hxx"
50 #include "xltable.hxx"
54 using namespace com::sun::star
;
56 using ::com::sun::star::sheet::DataPilotFieldOrientation
;
57 using ::com::sun::star::sheet::DataPilotFieldOrientation_DATA
;
58 using ::com::sun::star::sheet::DataPilotFieldSortInfo
;
59 using ::com::sun::star::sheet::DataPilotFieldAutoShowInfo
;
60 using ::com::sun::star::sheet::DataPilotFieldLayoutInfo
;
61 using ::com::sun::star::sheet::DataPilotFieldReference
;
64 // ============================================================================
66 // ============================================================================
68 XclImpPCItem::XclImpPCItem( XclImpStream
& rStrm
)
70 switch( rStrm
.GetRecId() )
72 case EXC_ID_SXDOUBLE
: ReadSxdouble( rStrm
); break;
73 case EXC_ID_SXBOOLEAN
: ReadSxboolean( rStrm
); break;
74 case EXC_ID_SXERROR
: ReadSxerror( rStrm
); break;
75 case EXC_ID_SXINTEGER
: ReadSxinteger( rStrm
); break;
76 case EXC_ID_SXSTRING
: ReadSxstring( rStrm
); break;
77 case EXC_ID_SXDATETIME
: ReadSxdatetime( rStrm
); break;
78 case EXC_ID_SXEMPTY
: ReadSxempty( rStrm
); break;
79 default: OSL_FAIL( "XclImpPCItem::XclImpPCItem - unknown record id" );
85 void lclSetValue( const XclImpRoot
& rRoot
, const ScAddress
& rScPos
, double fValue
, short nFormatType
)
87 ScDocument
& rDoc
= rRoot
.GetDoc();
88 rDoc
.SetValue( rScPos
.Col(), rScPos
.Row(), rScPos
.Tab(), fValue
);
89 sal_uInt32 nScNumFmt
= rRoot
.GetFormatter().GetStandardFormat( nFormatType
, rRoot
.GetDocLanguage() );
90 rDoc
.ApplyAttr( rScPos
.Col(), rScPos
.Row(), rScPos
.Tab(), SfxUInt32Item( ATTR_VALUE_FORMAT
, nScNumFmt
) );
95 void XclImpPCItem::WriteToSource( const XclImpRoot
& rRoot
, const ScAddress
& rScPos
) const
97 ScDocument
& rDoc
= rRoot
.GetDoc();
98 if( const OUString
* pText
= GetText() )
99 rDoc
.SetString( rScPos
.Col(), rScPos
.Row(), rScPos
.Tab(), *pText
);
100 else if( const double* pfValue
= GetDouble() )
101 rDoc
.SetValue( rScPos
.Col(), rScPos
.Row(), rScPos
.Tab(), *pfValue
);
102 else if( const sal_Int16
* pnValue
= GetInteger() )
103 rDoc
.SetValue( rScPos
.Col(), rScPos
.Row(), rScPos
.Tab(), *pnValue
);
104 else if( const bool* pbValue
= GetBool() )
105 lclSetValue( rRoot
, rScPos
, *pbValue
? 1.0 : 0.0, NUMBERFORMAT_LOGICAL
);
106 else if( const DateTime
* pDateTime
= GetDateTime() )
108 // set number format date, time, or date/time, depending on the value
109 double fValue
= rRoot
.GetDoubleFromDateTime( *pDateTime
);
111 double fFrac
= modf( fValue
, &fInt
);
112 short nFormatType
= ((fFrac
== 0.0) && (fInt
!= 0.0)) ? NUMBERFORMAT_DATE
:
113 ((fInt
== 0.0) ? NUMBERFORMAT_TIME
: NUMBERFORMAT_DATETIME
);
114 lclSetValue( rRoot
, rScPos
, fValue
, nFormatType
);
116 else if( const sal_uInt16
* pnError
= GetError() )
119 sal_uInt8 nErrCode
= static_cast< sal_uInt8
>( *pnError
);
120 const ScTokenArray
* pScTokArr
= rRoot
.GetOldFmlaConverter().GetBoolErr(
121 XclTools::ErrorToEnum( fValue
, EXC_BOOLERR_ERROR
, nErrCode
) );
122 ScFormulaCell
* pCell
= new ScFormulaCell( &rDoc
, rScPos
, pScTokArr
);
123 pCell
->SetHybridDouble( fValue
);
124 rDoc
.SetFormulaCell(rScPos
, pCell
);
128 void XclImpPCItem::ReadSxdouble( XclImpStream
& rStrm
)
130 OSL_ENSURE( rStrm
.GetRecSize() == 8, "XclImpPCItem::ReadSxdouble - wrong record size" );
131 SetDouble( rStrm
.ReadDouble() );
134 void XclImpPCItem::ReadSxboolean( XclImpStream
& rStrm
)
136 OSL_ENSURE( rStrm
.GetRecSize() == 2, "XclImpPCItem::ReadSxboolean - wrong record size" );
137 SetBool( rStrm
.ReaduInt16() != 0 );
140 void XclImpPCItem::ReadSxerror( XclImpStream
& rStrm
)
142 OSL_ENSURE( rStrm
.GetRecSize() == 2, "XclImpPCItem::ReadSxerror - wrong record size" );
143 SetError( rStrm
.ReaduInt16() );
146 void XclImpPCItem::ReadSxinteger( XclImpStream
& rStrm
)
148 OSL_ENSURE( rStrm
.GetRecSize() == 2, "XclImpPCItem::ReadSxinteger - wrong record size" );
149 SetInteger( rStrm
.ReadInt16() );
152 void XclImpPCItem::ReadSxstring( XclImpStream
& rStrm
)
154 OSL_ENSURE( rStrm
.GetRecSize() >= 3, "XclImpPCItem::ReadSxstring - wrong record size" );
155 SetText( rStrm
.ReadUniString() );
158 void XclImpPCItem::ReadSxdatetime( XclImpStream
& rStrm
)
160 OSL_ENSURE( rStrm
.GetRecSize() == 8, "XclImpPCItem::ReadSxdatetime - wrong record size" );
161 sal_uInt16 nYear
, nMonth
;
162 sal_uInt8 nDay
, nHour
, nMin
, nSec
;
163 rStrm
>> nYear
>> nMonth
>> nDay
>> nHour
>> nMin
>> nSec
;
164 SetDateTime( DateTime( Date( nDay
, nMonth
, nYear
), Time( nHour
, nMin
, nSec
) ) );
167 void XclImpPCItem::ReadSxempty( XclImpStream
& rStrm
)
169 (void)rStrm
; // avoid compiler warning
170 OSL_ENSURE( rStrm
.GetRecSize() == 0, "XclImpPCItem::ReadSxempty - wrong record size" );
174 // ============================================================================
176 XclImpPCField::XclImpPCField( const XclImpRoot
& rRoot
, XclImpPivotCache
& rPCache
, sal_uInt16 nFieldIdx
) :
177 XclPCField( EXC_PCFIELD_UNKNOWN
, nFieldIdx
),
181 mbNumGroupInfoRead( false )
185 XclImpPCField::~XclImpPCField()
189 // general field/item access --------------------------------------------------
191 const OUString
& XclImpPCField::GetFieldName( const ScfStringVec
& rVisNames
) const
193 if( IsGroupChildField() && (mnFieldIdx
< rVisNames
.size()) )
195 const OUString
& rVisName
= rVisNames
[ mnFieldIdx
];
196 if (!rVisName
.isEmpty())
199 return maFieldInfo
.maName
;
202 const XclImpPCField
* XclImpPCField::GetGroupBaseField() const
204 OSL_ENSURE( IsGroupChildField(), "XclImpPCField::GetGroupBaseField - this field type does not have a base field" );
205 return IsGroupChildField() ? mrPCache
.GetField( maFieldInfo
.mnGroupBase
) : 0;
208 const XclImpPCItem
* XclImpPCField::GetItem( sal_uInt16 nItemIdx
) const
210 return (nItemIdx
< maItems
.size()) ? maItems
[ nItemIdx
].get() : 0;
213 const XclImpPCItem
* XclImpPCField::GetLimitItem( sal_uInt16 nItemIdx
) const
215 OSL_ENSURE( nItemIdx
< 3, "XclImpPCField::GetLimitItem - invalid item index" );
216 OSL_ENSURE( nItemIdx
< maNumGroupItems
.size(), "XclImpPCField::GetLimitItem - no item found" );
217 return (nItemIdx
< maNumGroupItems
.size()) ? maNumGroupItems
[ nItemIdx
].get() : 0;
220 void XclImpPCField::WriteFieldNameToSource( SCCOL nScCol
, SCTAB nScTab
) const
222 OSL_ENSURE( HasOrigItems(), "XclImpPCField::WriteFieldNameToSource - only for standard fields" );
223 GetDoc().SetString( nScCol
, 0, nScTab
, maFieldInfo
.maName
);
224 mnSourceScCol
= nScCol
;
227 void XclImpPCField::WriteOrigItemToSource( SCROW nScRow
, SCTAB nScTab
, sal_uInt16 nItemIdx
) const
229 if( nItemIdx
< maOrigItems
.size() )
230 maOrigItems
[ nItemIdx
]->WriteToSource( GetRoot(), ScAddress( mnSourceScCol
, nScRow
, nScTab
) );
233 void XclImpPCField::WriteLastOrigItemToSource( SCROW nScRow
, SCTAB nScTab
) const
235 if( !maOrigItems
.empty() )
236 maOrigItems
.back()->WriteToSource( GetRoot(), ScAddress( mnSourceScCol
, nScRow
, nScTab
) );
239 // records --------------------------------------------------------------------
241 void XclImpPCField::ReadSxfield( XclImpStream
& rStrm
)
243 rStrm
>> maFieldInfo
;
245 /* Detect the type of this field. This is done very restrictive to detect
246 any unexpected state. */
247 meFieldType
= EXC_PCFIELD_UNKNOWN
;
249 bool bItems
= ::get_flag( maFieldInfo
.mnFlags
, EXC_SXFIELD_HASITEMS
);
250 bool bPostp
= ::get_flag( maFieldInfo
.mnFlags
, EXC_SXFIELD_POSTPONE
);
251 bool bCalced
= ::get_flag( maFieldInfo
.mnFlags
, EXC_SXFIELD_CALCED
);
252 bool bChild
= ::get_flag( maFieldInfo
.mnFlags
, EXC_SXFIELD_HASCHILD
);
253 bool bNum
= ::get_flag( maFieldInfo
.mnFlags
, EXC_SXFIELD_NUMGROUP
);
255 sal_uInt16 nVisC
= maFieldInfo
.mnVisItems
;
256 sal_uInt16 nGroupC
= maFieldInfo
.mnGroupItems
;
257 sal_uInt16 nBaseC
= maFieldInfo
.mnBaseItems
;
258 sal_uInt16 nOrigC
= maFieldInfo
.mnOrigItems
;
259 OSL_ENSURE( nVisC
> 0, "XclImpPCField::ReadSxfield - field without visible items" );
261 sal_uInt16 nType
= maFieldInfo
.mnFlags
& EXC_SXFIELD_DATA_MASK
;
263 (nType
== EXC_SXFIELD_DATA_STR
) ||
264 (nType
== EXC_SXFIELD_DATA_INT
) ||
265 (nType
== EXC_SXFIELD_DATA_DBL
) ||
266 (nType
== EXC_SXFIELD_DATA_STR_INT
) ||
267 (nType
== EXC_SXFIELD_DATA_STR_DBL
) ||
268 (nType
== EXC_SXFIELD_DATA_DATE
) ||
269 (nType
== EXC_SXFIELD_DATA_DATE_EMP
) ||
270 (nType
== EXC_SXFIELD_DATA_DATE_NUM
) ||
271 (nType
== EXC_SXFIELD_DATA_DATE_STR
);
273 (nType
== EXC_SXFIELD_DATA_NONE
);
274 // for now, ignore data type of calculated fields
275 OSL_ENSURE( bCalced
|| bType
|| bTypeNone
, "XclImpPCField::ReadSxfield - unknown item data type" );
277 if( nVisC
> 0 || bPostp
)
279 if( bItems
&& !bPostp
)
283 // 1) standard fields and standard grouping fields
286 // 1a) standard field without grouping
287 if( bType
&& (nGroupC
== 0) && (nBaseC
== 0) && (nOrigC
== nVisC
) )
288 meFieldType
= EXC_PCFIELD_STANDARD
;
290 // 1b) standard grouping field
291 else if( bTypeNone
&& (nGroupC
== nVisC
) && (nBaseC
> 0) && (nOrigC
== 0) )
292 meFieldType
= EXC_PCFIELD_STDGROUP
;
294 // 2) numerical grouping fields
295 else if( (nGroupC
== nVisC
) && (nBaseC
== 0) )
297 // 2a) single num/date grouping field without child grouping field
298 if( !bChild
&& bType
&& (nOrigC
> 0) )
302 case EXC_SXFIELD_DATA_INT
:
303 case EXC_SXFIELD_DATA_DBL
: meFieldType
= EXC_PCFIELD_NUMGROUP
; break;
304 case EXC_SXFIELD_DATA_DATE
: meFieldType
= EXC_PCFIELD_DATEGROUP
; break;
305 default: OSL_FAIL( "XclImpPCField::ReadSxfield - numeric group with wrong data type" );
309 // 2b) first date grouping field with child grouping field
310 else if( bChild
&& (nType
== EXC_SXFIELD_DATA_DATE
) && (nOrigC
> 0) )
311 meFieldType
= EXC_PCFIELD_DATEGROUP
;
313 // 2c) additional date grouping field
314 else if( bTypeNone
&& (nOrigC
== 0) )
315 meFieldType
= EXC_PCFIELD_DATECHILD
;
317 OSL_ENSURE( meFieldType
!= EXC_PCFIELD_UNKNOWN
, "XclImpPCField::ReadSxfield - invalid standard or grouped field" );
320 // 3) calculated field
323 if( !bChild
&& !bNum
&& (nGroupC
== 0) && (nBaseC
== 0) && (nOrigC
== 0) )
324 meFieldType
= EXC_PCFIELD_CALCED
;
325 OSL_ENSURE( meFieldType
== EXC_PCFIELD_CALCED
, "XclImpPCField::ReadSxfield - invalid calculated field" );
329 else if( !bItems
&& bPostp
)
331 // 4) standard field with postponed items
332 if( !bCalced
&& !bChild
&& !bNum
&& bType
&& (nGroupC
== 0) && (nBaseC
== 0) && (nOrigC
== 0) )
333 meFieldType
= EXC_PCFIELD_STANDARD
;
334 OSL_ENSURE( meFieldType
== EXC_PCFIELD_STANDARD
, "XclImpPCField::ReadSxfield - invalid postponed field" );
339 void XclImpPCField::ReadItem( XclImpStream
& rStrm
)
341 OSL_ENSURE( HasInlineItems() || HasPostponedItems(), "XclImpPCField::ReadItem - field does not expect items" );
344 XclImpPCItemRef
xItem( new XclImpPCItem( rStrm
) );
346 // try to insert into an item list
347 if( mbNumGroupInfoRead
)
349 // there are 3 items after SXNUMGROUP that contain grouping limits and step count
350 if( maNumGroupItems
.size() < 3 )
351 maNumGroupItems
.push_back( xItem
);
353 maOrigItems
.push_back( xItem
);
355 else if( HasInlineItems() || HasPostponedItems() )
357 maItems
.push_back( xItem
);
358 // visible item is original item in standard fields
359 if( IsStandardField() )
360 maOrigItems
.push_back( xItem
);
364 void XclImpPCField::ReadSxnumgroup( XclImpStream
& rStrm
)
366 OSL_ENSURE( IsNumGroupField() || IsDateGroupField(), "XclImpPCField::ReadSxnumgroup - SXNUMGROUP outside numeric grouping field" );
367 OSL_ENSURE( !mbNumGroupInfoRead
, "XclImpPCField::ReadSxnumgroup - multiple SXNUMGROUP records" );
368 OSL_ENSURE( maItems
.size() == maFieldInfo
.mnGroupItems
, "XclImpPCField::ReadSxnumgroup - SXNUMGROUP out of record order" );
369 rStrm
>> maNumGroupInfo
;
370 mbNumGroupInfoRead
= IsNumGroupField() || IsDateGroupField();
373 void XclImpPCField::ReadSxgroupinfo( XclImpStream
& rStrm
)
375 OSL_ENSURE( IsStdGroupField(), "XclImpPCField::ReadSxgroupinfo - SXGROUPINFO outside grouping field" );
376 OSL_ENSURE( maGroupOrder
.empty(), "XclImpPCField::ReadSxgroupinfo - multiple SXGROUPINFO records" );
377 OSL_ENSURE( maItems
.size() == maFieldInfo
.mnGroupItems
, "XclImpPCField::ReadSxgroupinfo - SXGROUPINFO out of record order" );
378 OSL_ENSURE( (rStrm
.GetRecLeft() / 2) == maFieldInfo
.mnBaseItems
, "XclImpPCField::ReadSxgroupinfo - wrong SXGROUPINFO size" );
379 maGroupOrder
.clear();
380 size_t nSize
= rStrm
.GetRecLeft() / 2;
381 maGroupOrder
.resize( nSize
, 0 );
382 for( size_t nIdx
= 0; nIdx
< nSize
; ++nIdx
)
383 rStrm
>> maGroupOrder
[ nIdx
];
386 // grouping -------------------------------------------------------------------
388 void XclImpPCField::ConvertGroupField( ScDPSaveData
& rSaveData
, const ScfStringVec
& rVisNames
) const
390 if (!GetFieldName(rVisNames
).isEmpty())
392 if( IsStdGroupField() )
393 ConvertStdGroupField( rSaveData
, rVisNames
);
394 else if( IsNumGroupField() )
395 ConvertNumGroupField( rSaveData
, rVisNames
);
396 else if( IsDateGroupField() )
397 ConvertDateGroupField( rSaveData
, rVisNames
);
401 // private --------------------------------------------------------------------
403 void XclImpPCField::ConvertStdGroupField( ScDPSaveData
& rSaveData
, const ScfStringVec
& rVisNames
) const
405 if( const XclImpPCField
* pBaseField
= GetGroupBaseField() )
407 const String
& rBaseFieldName
= pBaseField
->GetFieldName( rVisNames
);
408 if( rBaseFieldName
.Len() > 0 )
410 // *** create a ScDPSaveGroupItem for each own item, they collect base item names ***
411 ScDPSaveGroupItemVec aGroupItems
;
412 aGroupItems
.reserve( maItems
.size() );
413 // initialize with own item names
414 for( XclImpPCItemVec::const_iterator aIt
= maItems
.begin(), aEnd
= maItems
.end(); aIt
!= aEnd
; ++aIt
)
415 aGroupItems
.push_back( ScDPSaveGroupItem( (*aIt
)->ConvertToText() ) );
417 // *** iterate over all base items, set their names at corresponding own items ***
418 for( sal_uInt16 nItemIdx
= 0, nItemCount
= static_cast< sal_uInt16
>( maGroupOrder
.size() ); nItemIdx
< nItemCount
; ++nItemIdx
)
419 if( maGroupOrder
[ nItemIdx
] < aGroupItems
.size() )
420 if( const XclImpPCItem
* pBaseItem
= pBaseField
->GetItem( nItemIdx
) )
421 if( const XclImpPCItem
* pGroupItem
= GetItem( maGroupOrder
[ nItemIdx
] ) )
422 if( *pBaseItem
!= *pGroupItem
)
423 aGroupItems
[ maGroupOrder
[ nItemIdx
] ].AddElement( pBaseItem
->ConvertToText() );
425 // *** create the ScDPSaveGroupDimension object, fill with grouping info ***
426 ScDPSaveGroupDimension
aGroupDim( rBaseFieldName
, GetFieldName( rVisNames
) );
427 for( ScDPSaveGroupItemVec::const_iterator aIt
= aGroupItems
.begin(), aEnd
= aGroupItems
.end(); aIt
!= aEnd
; ++aIt
)
428 if( !aIt
->IsEmpty() )
429 aGroupDim
.AddGroupItem( *aIt
);
430 rSaveData
.GetDimensionData()->AddGroupDimension( aGroupDim
);
435 void XclImpPCField::ConvertNumGroupField( ScDPSaveData
& rSaveData
, const ScfStringVec
& rVisNames
) const
437 ScDPNumGroupInfo
aNumInfo( GetScNumGroupInfo() );
438 ScDPSaveNumGroupDimension
aNumGroupDim( GetFieldName( rVisNames
), aNumInfo
);
439 rSaveData
.GetDimensionData()->AddNumGroupDimension( aNumGroupDim
);
442 void XclImpPCField::ConvertDateGroupField( ScDPSaveData
& rSaveData
, const ScfStringVec
& rVisNames
) const
444 ScDPNumGroupInfo
aDateInfo( GetScDateGroupInfo() );
445 sal_Int32 nScDateType
= maNumGroupInfo
.GetScDateType();
447 switch( meFieldType
)
449 case EXC_PCFIELD_DATEGROUP
:
451 if( aDateInfo
.mbDateValues
)
453 // special case for days only with step value - create numeric grouping
454 ScDPSaveNumGroupDimension
aNumGroupDim( GetFieldName( rVisNames
), aDateInfo
);
455 rSaveData
.GetDimensionData()->AddNumGroupDimension( aNumGroupDim
);
459 ScDPSaveNumGroupDimension
aNumGroupDim( GetFieldName( rVisNames
), ScDPNumGroupInfo() );
460 aNumGroupDim
.SetDateInfo( aDateInfo
, nScDateType
);
461 rSaveData
.GetDimensionData()->AddNumGroupDimension( aNumGroupDim
);
466 case EXC_PCFIELD_DATECHILD
:
468 if( const XclImpPCField
* pBaseField
= GetGroupBaseField() )
470 const String
& rBaseFieldName
= pBaseField
->GetFieldName( rVisNames
);
471 if( rBaseFieldName
.Len() > 0 )
473 ScDPSaveGroupDimension
aGroupDim( rBaseFieldName
, GetFieldName( rVisNames
) );
474 aGroupDim
.SetDateInfo( aDateInfo
, nScDateType
);
475 rSaveData
.GetDimensionData()->AddGroupDimension( aGroupDim
);
482 OSL_FAIL( "XclImpPCField::ConvertDateGroupField - unknown date field type" );
486 ScDPNumGroupInfo
XclImpPCField::GetScNumGroupInfo() const
488 ScDPNumGroupInfo aNumInfo
;
489 aNumInfo
.mbEnable
= sal_True
;
490 aNumInfo
.mbDateValues
= false;
491 aNumInfo
.mbAutoStart
= sal_True
;
492 aNumInfo
.mbAutoEnd
= sal_True
;
494 if( const double* pfMinValue
= GetNumGroupLimit( EXC_SXFIELD_INDEX_MIN
) )
496 aNumInfo
.mfStart
= *pfMinValue
;
497 aNumInfo
.mbAutoStart
= ::get_flag( maNumGroupInfo
.mnFlags
, EXC_SXNUMGROUP_AUTOMIN
);
499 if( const double* pfMaxValue
= GetNumGroupLimit( EXC_SXFIELD_INDEX_MAX
) )
501 aNumInfo
.mfEnd
= *pfMaxValue
;
502 aNumInfo
.mbAutoEnd
= ::get_flag( maNumGroupInfo
.mnFlags
, EXC_SXNUMGROUP_AUTOMAX
);
504 if( const double* pfStepValue
= GetNumGroupLimit( EXC_SXFIELD_INDEX_STEP
) )
505 aNumInfo
.mfStep
= *pfStepValue
;
510 ScDPNumGroupInfo
XclImpPCField::GetScDateGroupInfo() const
512 ScDPNumGroupInfo aDateInfo
;
513 aDateInfo
.mbEnable
= sal_True
;
514 aDateInfo
.mbDateValues
= false;
515 aDateInfo
.mbAutoStart
= sal_True
;
516 aDateInfo
.mbAutoEnd
= sal_True
;
518 if( const DateTime
* pMinDate
= GetDateGroupLimit( EXC_SXFIELD_INDEX_MIN
) )
520 aDateInfo
.mfStart
= GetDoubleFromDateTime( *pMinDate
);
521 aDateInfo
.mbAutoStart
= ::get_flag( maNumGroupInfo
.mnFlags
, EXC_SXNUMGROUP_AUTOMIN
);
523 if( const DateTime
* pMaxDate
= GetDateGroupLimit( EXC_SXFIELD_INDEX_MAX
) )
525 aDateInfo
.mfEnd
= GetDoubleFromDateTime( *pMaxDate
);
526 aDateInfo
.mbAutoEnd
= ::get_flag( maNumGroupInfo
.mnFlags
, EXC_SXNUMGROUP_AUTOMAX
);
528 // GetDateGroupStep() returns a value for date type "day" in single date groups only
529 if( const sal_Int16
* pnStepValue
= GetDateGroupStep() )
531 aDateInfo
.mfStep
= *pnStepValue
;
532 aDateInfo
.mbDateValues
= sal_True
;
538 const double* XclImpPCField::GetNumGroupLimit( sal_uInt16 nLimitIdx
) const
540 OSL_ENSURE( IsNumGroupField(), "XclImpPCField::GetNumGroupLimit - only for numeric grouping fields" );
541 if( const XclImpPCItem
* pItem
= GetLimitItem( nLimitIdx
) )
543 OSL_ENSURE( pItem
->GetDouble(), "XclImpPCField::GetNumGroupLimit - SXDOUBLE item expected" );
544 return pItem
->GetDouble();
549 const DateTime
* XclImpPCField::GetDateGroupLimit( sal_uInt16 nLimitIdx
) const
551 OSL_ENSURE( IsDateGroupField(), "XclImpPCField::GetDateGroupLimit - only for date grouping fields" );
552 if( const XclImpPCItem
* pItem
= GetLimitItem( nLimitIdx
) )
554 OSL_ENSURE( pItem
->GetDateTime(), "XclImpPCField::GetDateGroupLimit - SXDATETIME item expected" );
555 return pItem
->GetDateTime();
560 const sal_Int16
* XclImpPCField::GetDateGroupStep() const
562 // only for single date grouping fields, not for grouping chains
563 if( !IsGroupBaseField() && !IsGroupChildField() )
565 // only days may have a step value, return 0 for all other date types
566 if( maNumGroupInfo
.GetXclDataType() == EXC_SXNUMGROUP_TYPE_DAY
)
568 if( const XclImpPCItem
* pItem
= GetLimitItem( EXC_SXFIELD_INDEX_STEP
) )
570 OSL_ENSURE( pItem
->GetInteger(), "XclImpPCField::GetDateGroupStep - SXINTEGER item expected" );
571 if( const sal_Int16
* pnStep
= pItem
->GetInteger() )
573 OSL_ENSURE( *pnStep
> 0, "XclImpPCField::GetDateGroupStep - invalid step count" );
574 // return nothing for step count 1 - this is also a standard date group in Excel
575 return (*pnStep
> 1) ? pnStep
: 0;
583 // ============================================================================
585 XclImpPivotCache::XclImpPivotCache( const XclImpRoot
& rRoot
) :
587 maSrcRange( ScAddress::INITIALIZE_INVALID
),
589 mnSrcType( EXC_SXVS_UNKNOWN
),
594 XclImpPivotCache::~XclImpPivotCache()
598 // data access ----------------------------------------------------------------
600 sal_uInt16
XclImpPivotCache::GetFieldCount() const
602 return static_cast< sal_uInt16
>( maFields
.size() );
605 const XclImpPCField
* XclImpPivotCache::GetField( sal_uInt16 nFieldIdx
) const
607 return (nFieldIdx
< maFields
.size()) ? maFields
[ nFieldIdx
].get() : 0;
610 // records --------------------------------------------------------------------
612 void XclImpPivotCache::ReadSxidstm( XclImpStream
& rStrm
)
617 void XclImpPivotCache::ReadSxvs( XclImpStream
& rStrm
)
620 GetTracer().TracePivotDataSource( mnSrcType
!= EXC_SXVS_SHEET
);
623 void XclImpPivotCache::ReadDconref( XclImpStream
& rStrm
)
625 /* Read DCONREF only once (by checking maTabName), there may be other
626 DCONREF records in another context. Read reference only if a leading
627 SXVS record is present (by checking mnSrcType). */
628 if( (maTabName
.Len() > 0) || (mnSrcType
!= EXC_SXVS_SHEET
) )
631 XclRange
aXclRange( ScAddress::UNINITIALIZED
);
632 aXclRange
.Read( rStrm
, false );
633 String aEncUrl
= rStrm
.ReadUniString();
635 XclImpUrlHelper::DecodeUrl( maUrl
, maTabName
, mbSelfRef
, GetRoot(), aEncUrl
);
637 /* Do not convert maTabName to Calc sheet name -> original name is used to
638 find the sheet in the document. Sheet index of source range will be
639 found later in XclImpPivotCache::ReadPivotCacheStream(), because sheet
640 may not exist yet. */
642 GetAddressConverter().ConvertRange( maSrcRange
, aXclRange
, 0, 0, true );
645 void XclImpPivotCache::ReadDConName( XclImpStream
& rStrm
)
647 maSrcRangeName
= rStrm
.ReadUniString();
649 // This 2-byte value equals the length of string that follows, or if 0 it
650 // indicates that the name has a workbook scope. For now, we only support
651 // internal defined name with a workbook scope.
654 mbSelfRef
= (nFlag
== 0);
657 // External name is not supported yet.
658 maSrcRangeName
= OUString();
661 void XclImpPivotCache::ReadPivotCacheStream( XclImpStream
& rStrm
)
663 if( (mnSrcType
!= EXC_SXVS_SHEET
) && (mnSrcType
!= EXC_SXVS_EXTERN
) )
666 ScDocument
& rDoc
= GetDoc();
667 SCCOL nFieldScCol
= 0; // column index of source data for next field
668 SCROW nItemScRow
= 0; // row index of source data for current items
669 SCTAB nScTab
= 0; // sheet index of source data
670 bool bGenerateSource
= false; // true = write source data from cache to dummy table
674 if (maSrcRangeName
.isEmpty())
676 // try to find internal sheet containing the source data
677 nScTab
= GetTabInfo().GetScTabFromXclName( maTabName
);
678 if( rDoc
.HasTable( nScTab
) )
680 // set sheet index to source range
681 maSrcRange
.aStart
.SetTab( nScTab
);
682 maSrcRange
.aEnd
.SetTab( nScTab
);
686 // create dummy sheet for deleted internal sheet
687 bGenerateSource
= true;
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
704 nScTab
= rDoc
.GetTableCount();
705 rDoc
.MakeTable( nScTab
);
706 OUStringBuffer
aDummyName(OUString("DPCache"));
707 if( maTabName
.Len() > 0 )
708 aDummyName
.append( '_' ).append( maTabName
);
709 OUString aName
= aDummyName
.makeStringAndClear();
710 rDoc
.CreateValidTabName( aName
);
711 rDoc
.RenameTab( nScTab
, aName
);
712 // set sheet index to source range
713 maSrcRange
.aStart
.SetTab( nScTab
);
714 maSrcRange
.aEnd
.SetTab( nScTab
);
717 // open pivot cache storage stream
718 SotStorageRef xSvStrg
= OpenStorage( EXC_STORAGE_PTCACHE
);
719 SotStorageStreamRef xSvStrm
= OpenStream( xSvStrg
, ScfTools::GetHexStr( mnStrmId
) );
723 // create Excel record stream object
724 XclImpStream
aPCStrm( *xSvStrm
, GetRoot() );
725 aPCStrm
.CopyDecrypterFrom( rStrm
); // pivot cache streams are encrypted
727 XclImpPCFieldRef xCurrField
; // current field for new items
728 XclImpPCFieldVec aOrigFields
; // all standard fields with inline original items
729 XclImpPCFieldVec aPostpFields
; // all standard fields with postponed original items
730 size_t nPostpIdx
= 0; // index to current field with postponed items
731 bool bLoop
= true; // true = continue loop
733 while( bLoop
&& aPCStrm
.StartNextRecord() )
735 switch( aPCStrm
.GetRecId() )
748 sal_uInt16 nNewFieldIdx
= GetFieldCount();
749 if( nNewFieldIdx
< EXC_PC_MAXFIELDCOUNT
)
751 xCurrField
.reset( new XclImpPCField( GetRoot(), *this, nNewFieldIdx
) );
752 maFields
.push_back( xCurrField
);
753 xCurrField
->ReadSxfield( aPCStrm
);
754 if( xCurrField
->HasOrigItems() )
756 if( xCurrField
->HasPostponedItems() )
757 aPostpFields
.push_back( xCurrField
);
759 aOrigFields
.push_back( xCurrField
);
760 // insert field name into generated source data, field remembers its column index
761 if( bGenerateSource
&& (nFieldScCol
<= MAXCOL
) )
762 xCurrField
->WriteFieldNameToSource( nFieldScCol
++, nScTab
);
764 // do not read items into invalid/postponed fields
765 if( !xCurrField
->HasInlineItems() )
771 case EXC_ID_SXINDEXLIST
:
772 // read index list and insert all items into generated source data
773 if( bGenerateSource
&& (nItemScRow
<= MAXROW
) && (++nItemScRow
<= MAXROW
) )
775 for( XclImpPCFieldVec::const_iterator aIt
= aOrigFields
.begin(), aEnd
= aOrigFields
.end(); aIt
!= aEnd
; ++aIt
)
777 sal_uInt16 nItemIdx
= (*aIt
)->Has16BitIndexes() ? aPCStrm
.ReaduInt16() : aPCStrm
.ReaduInt8();
778 (*aIt
)->WriteOrigItemToSource( nItemScRow
, nScTab
, nItemIdx
);
784 case EXC_ID_SXDOUBLE
:
785 case EXC_ID_SXBOOLEAN
:
787 case EXC_ID_SXINTEGER
:
788 case EXC_ID_SXSTRING
:
789 case EXC_ID_SXDATETIME
:
791 if( xCurrField
) // inline items
793 xCurrField
->ReadItem( aPCStrm
);
795 else if( !aPostpFields
.empty() ) // postponed items
797 // read postponed item
798 aPostpFields
[ nPostpIdx
]->ReadItem( aPCStrm
);
799 // write item to source
800 if( bGenerateSource
&& (nItemScRow
<= MAXROW
) )
802 // start new row, if there are only postponed fields
803 if( aOrigFields
.empty() && (nPostpIdx
== 0) )
805 if( nItemScRow
<= MAXROW
)
806 aPostpFields
[ nPostpIdx
]->WriteLastOrigItemToSource( nItemScRow
, nScTab
);
808 // get index of next postponed field
810 if( nPostpIdx
>= aPostpFields
.size() )
815 case EXC_ID_SXNUMGROUP
:
817 xCurrField
->ReadSxnumgroup( aPCStrm
);
820 case EXC_ID_SXGROUPINFO
:
822 xCurrField
->ReadSxgroupinfo( aPCStrm
);
825 // known but ignored records
832 case EXC_ID_SXFORMULA
:
834 case EXC_ID_SXFDBTYPE
:
838 OSL_TRACE( "XclImpPivotCache::ReadPivotCacheStream - unknown record 0x%04hX", aPCStrm
.GetRecId() );
842 OSL_ENSURE( maPCInfo
.mnTotalFields
== maFields
.size(),
843 "XclImpPivotCache::ReadPivotCacheStream - field count mismatch" );
845 if (HasCacheRecords())
847 SCROW nNewEnd
= maSrcRange
.aStart
.Row() + maPCInfo
.mnSrcRecs
;
848 maSrcRange
.aEnd
.SetRow(nNewEnd
);
851 // set source range for external source data
852 if( bGenerateSource
&& (nFieldScCol
> 0) )
854 maSrcRange
.aStart
.SetCol( 0 );
855 maSrcRange
.aStart
.SetRow( 0 );
856 // nFieldScCol points to first unused column
857 maSrcRange
.aEnd
.SetCol( nFieldScCol
- 1 );
858 // nItemScRow points to last used row
859 maSrcRange
.aEnd
.SetRow( nItemScRow
);
863 bool XclImpPivotCache::HasCacheRecords() const
865 return static_cast<bool>(maPCInfo
.mnFlags
& EXC_SXDB_SAVEDATA
);
868 bool XclImpPivotCache::IsRefreshOnLoad() const
870 return static_cast<bool>(maPCInfo
.mnFlags
& EXC_SXDB_REFRESH_LOAD
);
873 bool XclImpPivotCache::IsValid() const
875 if (!maSrcRangeName
.isEmpty())
878 return maSrcRange
.IsValid();
881 // ============================================================================
883 // ============================================================================
885 XclImpPTItem::XclImpPTItem( const XclImpPCField
* pCacheField
) :
886 mpCacheField( pCacheField
)
890 const OUString
* XclImpPTItem::GetItemName() const
893 if( const XclImpPCItem
* pCacheItem
= mpCacheField
->GetItem( maItemInfo
.mnCacheIdx
) )
894 //! TODO: use XclImpPCItem::ConvertToText(), if all conversions are available
895 return pCacheItem
->IsEmpty() ? NULL
: pCacheItem
->GetText();
899 void XclImpPTItem::ReadSxvi( XclImpStream
& rStrm
)
904 void XclImpPTItem::ConvertItem( ScDPSaveDimension
& rSaveDim
) const
906 if (const OUString
* pItemName
= GetItemName())
908 ScDPSaveMember
& rMember
= *rSaveDim
.GetMemberByName( *pItemName
);
909 rMember
.SetIsVisible( !::get_flag( maItemInfo
.mnFlags
, EXC_SXVI_HIDDEN
) );
910 rMember
.SetShowDetails( !::get_flag( maItemInfo
.mnFlags
, EXC_SXVI_HIDEDETAIL
) );
911 if (maItemInfo
.HasVisName())
912 rMember
.SetLayoutName(*maItemInfo
.GetVisName());
916 // ============================================================================
918 XclImpPTField::XclImpPTField( const XclImpPivotTable
& rPTable
, sal_uInt16 nCacheIdx
) :
921 maFieldInfo
.mnCacheIdx
= nCacheIdx
;
924 // general field/item access --------------------------------------------------
926 const XclImpPCField
* XclImpPTField::GetCacheField() const
928 XclImpPivotCacheRef xPCache
= mrPTable
.GetPivotCache();
929 return xPCache
? xPCache
->GetField( maFieldInfo
.mnCacheIdx
) : 0;
932 OUString
XclImpPTField::GetFieldName() const
934 const XclImpPCField
* pField
= GetCacheField();
935 return pField
? pField
->GetFieldName( mrPTable
.GetVisFieldNames() ) : OUString();
938 OUString
XclImpPTField::GetVisFieldName() const
940 const OUString
* pVisName
= maFieldInfo
.GetVisName();
941 return pVisName
? *pVisName
: OUString();
944 const XclImpPTItem
* XclImpPTField::GetItem( sal_uInt16 nItemIdx
) const
946 return (nItemIdx
< maItems
.size()) ? maItems
[ nItemIdx
].get() : 0;
949 const OUString
* XclImpPTField::GetItemName( sal_uInt16 nItemIdx
) const
951 const XclImpPTItem
* pItem
= GetItem( nItemIdx
);
952 return pItem
? pItem
->GetItemName() : 0;
955 // records --------------------------------------------------------------------
957 void XclImpPTField::ReadSxvd( XclImpStream
& rStrm
)
959 rStrm
>> maFieldInfo
;
962 void XclImpPTField::ReadSxvdex( XclImpStream
& rStrm
)
964 rStrm
>> maFieldExtInfo
;
967 void XclImpPTField::ReadSxvi( XclImpStream
& rStrm
)
969 XclImpPTItemRef
xItem( new XclImpPTItem( GetCacheField() ) );
970 maItems
.push_back( xItem
);
971 xItem
->ReadSxvi( rStrm
);
974 // row/column fields ----------------------------------------------------------
976 void XclImpPTField::ConvertRowColField( ScDPSaveData
& rSaveData
) const
978 OSL_ENSURE( maFieldInfo
.mnAxes
& EXC_SXVD_AXIS_ROWCOL
, "XclImpPTField::ConvertRowColField - no row/column field" );
979 // special data orientation field?
980 if( maFieldInfo
.mnCacheIdx
== EXC_SXIVD_DATA
)
981 rSaveData
.GetDataLayoutDimension()->SetOrientation( static_cast< sal_uInt16
>( maFieldInfo
.GetApiOrient( EXC_SXVD_AXIS_ROWCOL
) ) );
983 ConvertRCPField( rSaveData
);
986 // page fields ----------------------------------------------------------------
988 void XclImpPTField::SetPageFieldInfo( const XclPTPageFieldInfo
& rPageInfo
)
990 maPageInfo
= rPageInfo
;
993 void XclImpPTField::ConvertPageField( ScDPSaveData
& rSaveData
) const
995 OSL_ENSURE( maFieldInfo
.mnAxes
& EXC_SXVD_AXIS_PAGE
, "XclImpPTField::ConvertPageField - no page field" );
996 if( ScDPSaveDimension
* pSaveDim
= ConvertRCPField( rSaveData
) )
998 const OUString
* pName
= GetItemName( maPageInfo
.mnSelItem
);
1000 pSaveDim
->SetCurrentPage(pName
);
1004 // hidden fields --------------------------------------------------------------
1006 void XclImpPTField::ConvertHiddenField( ScDPSaveData
& rSaveData
) const
1008 OSL_ENSURE( (maFieldInfo
.mnAxes
& EXC_SXVD_AXIS_ROWCOLPAGE
) == 0, "XclImpPTField::ConvertHiddenField - field not hidden" );
1009 ConvertRCPField( rSaveData
);
1012 // data fields ----------------------------------------------------------------
1014 bool XclImpPTField::HasDataFieldInfo() const
1016 return !maDataInfoList
.empty();
1019 void XclImpPTField::AddDataFieldInfo( const XclPTDataFieldInfo
& rDataInfo
)
1021 OSL_ENSURE( maFieldInfo
.mnAxes
& EXC_SXVD_AXIS_DATA
, "XclImpPTField::AddDataFieldInfo - no data field" );
1022 maDataInfoList
.push_back( rDataInfo
);
1025 void XclImpPTField::ConvertDataField( ScDPSaveData
& rSaveData
) const
1027 OSL_ENSURE( maFieldInfo
.mnAxes
& EXC_SXVD_AXIS_DATA
, "XclImpPTField::ConvertDataField - no data field" );
1028 OSL_ENSURE( !maDataInfoList
.empty(), "XclImpPTField::ConvertDataField - no data field info" );
1029 if (maDataInfoList
.empty())
1032 OUString aFieldName
= GetFieldName();
1033 if (aFieldName
.isEmpty())
1036 XclPTDataFieldInfoList::const_iterator aIt
= maDataInfoList
.begin(), aEnd
= maDataInfoList
.end();
1038 ScDPSaveDimension
& rSaveDim
= *rSaveData
.GetNewDimensionByName(aFieldName
);
1039 ConvertDataField( rSaveDim
, *aIt
);
1041 // multiple data fields -> clone dimension
1042 for( ++aIt
; aIt
!= aEnd
; ++aIt
)
1044 ScDPSaveDimension
& rDupDim
= rSaveData
.DuplicateDimension( rSaveDim
);
1045 ConvertDataFieldInfo( rDupDim
, *aIt
);
1049 // private --------------------------------------------------------------------
1052 * Convert Excel-encoded subtotal name to a Calc-encoded one.
1054 static OUString
lcl_convertExcelSubtotalName(const OUString
& rName
)
1056 OUStringBuffer aBuf
;
1057 const sal_Unicode
* p
= rName
.getStr();
1058 sal_Int32 n
= rName
.getLength();
1059 for (sal_Int32 i
= 0; i
< n
; ++i
)
1061 const sal_Unicode c
= p
[i
];
1062 if (c
== sal_Unicode('\\'))
1070 return aBuf
.makeStringAndClear();
1073 ScDPSaveDimension
* XclImpPTField::ConvertRCPField( ScDPSaveData
& rSaveData
) const
1075 const String
& rFieldName
= GetFieldName();
1076 if( rFieldName
.Len() == 0 )
1079 const XclImpPCField
* pCacheField
= GetCacheField();
1080 if( !pCacheField
|| !pCacheField
->IsSupportedField() )
1083 ScDPSaveDimension
* pTest
= rSaveData
.GetNewDimensionByName(rFieldName
);
1087 ScDPSaveDimension
& rSaveDim
= *pTest
;
1090 rSaveDim
.SetOrientation( static_cast< sal_uInt16
>( maFieldInfo
.GetApiOrient( EXC_SXVD_AXIS_ROWCOLPAGE
) ) );
1092 // general field info
1093 ConvertFieldInfo( rSaveDim
);
1096 if (const OUString
* pVisName
= maFieldInfo
.GetVisName())
1097 if (!pVisName
->isEmpty())
1098 rSaveDim
.SetLayoutName( *pVisName
);
1100 // subtotal function(s)
1101 XclPTSubtotalVec aSubtotalVec
;
1102 maFieldInfo
.GetSubtotals( aSubtotalVec
);
1103 if( !aSubtotalVec
.empty() )
1104 rSaveDim
.SetSubTotals( static_cast< long >( aSubtotalVec
.size() ), &aSubtotalVec
[ 0 ] );
1107 DataPilotFieldSortInfo aSortInfo
;
1108 aSortInfo
.Field
= mrPTable
.GetDataFieldName( maFieldExtInfo
.mnSortField
);
1109 aSortInfo
.IsAscending
= ::get_flag( maFieldExtInfo
.mnFlags
, EXC_SXVDEX_SORT_ASC
);
1110 aSortInfo
.Mode
= maFieldExtInfo
.GetApiSortMode();
1111 rSaveDim
.SetSortInfo( &aSortInfo
);
1114 DataPilotFieldAutoShowInfo aShowInfo
;
1115 aShowInfo
.IsEnabled
= ::get_flag( maFieldExtInfo
.mnFlags
, EXC_SXVDEX_AUTOSHOW
);
1116 aShowInfo
.ShowItemsMode
= maFieldExtInfo
.GetApiAutoShowMode();
1117 aShowInfo
.ItemCount
= maFieldExtInfo
.GetApiAutoShowCount();
1118 aShowInfo
.DataField
= mrPTable
.GetDataFieldName( maFieldExtInfo
.mnShowField
);
1119 rSaveDim
.SetAutoShowInfo( &aShowInfo
);
1122 DataPilotFieldLayoutInfo aLayoutInfo
;
1123 aLayoutInfo
.LayoutMode
= maFieldExtInfo
.GetApiLayoutMode();
1124 aLayoutInfo
.AddEmptyLines
= ::get_flag( maFieldExtInfo
.mnFlags
, EXC_SXVDEX_LAYOUT_BLANK
);
1125 rSaveDim
.SetLayoutInfo( &aLayoutInfo
);
1128 pCacheField
->ConvertGroupField( rSaveData
, mrPTable
.GetVisFieldNames() );
1130 // custom subtotal name
1131 if (maFieldExtInfo
.mpFieldTotalName
.get())
1133 OUString aSubName
= lcl_convertExcelSubtotalName(*maFieldExtInfo
.mpFieldTotalName
);
1134 rSaveDim
.SetSubtotalName(aSubName
);
1140 void XclImpPTField::ConvertFieldInfo( ScDPSaveDimension
& rSaveDim
) const
1142 rSaveDim
.SetShowEmpty( ::get_flag( maFieldExtInfo
.mnFlags
, EXC_SXVDEX_SHOWALL
) );
1143 ConvertItems( rSaveDim
);
1146 void XclImpPTField::ConvertDataField( ScDPSaveDimension
& rSaveDim
, const XclPTDataFieldInfo
& rDataInfo
) const
1149 rSaveDim
.SetOrientation( DataPilotFieldOrientation_DATA
);
1150 // general field info
1151 ConvertFieldInfo( rSaveDim
);
1152 // extended data field info
1153 ConvertDataFieldInfo( rSaveDim
, rDataInfo
);
1156 void XclImpPTField::ConvertDataFieldInfo( ScDPSaveDimension
& rSaveDim
, const XclPTDataFieldInfo
& rDataInfo
) const
1159 const OUString
* pVisName
= rDataInfo
.GetVisName();
1160 if (pVisName
&& !pVisName
->isEmpty())
1161 rSaveDim
.SetLayoutName(*pVisName
);
1163 // aggregation function
1164 rSaveDim
.SetFunction( static_cast< sal_uInt16
>( rDataInfo
.GetApiAggFunc() ) );
1166 // result field reference
1167 sal_Int32 nRefType
= rDataInfo
.GetApiRefType();
1168 DataPilotFieldReference aFieldRef
;
1169 aFieldRef
.ReferenceType
= nRefType
;
1170 const XclImpPTField
* pRefField
= mrPTable
.GetField(rDataInfo
.mnRefField
);
1173 aFieldRef
.ReferenceField
= pRefField
->GetFieldName();
1174 aFieldRef
.ReferenceItemType
= rDataInfo
.GetApiRefItemType();
1175 if (aFieldRef
.ReferenceItemType
== sheet::DataPilotFieldReferenceItemType::NAMED
)
1177 const OUString
* pRefItemName
= pRefField
->GetItemName(rDataInfo
.mnRefItem
);
1179 aFieldRef
.ReferenceItemName
= *pRefItemName
;
1183 rSaveDim
.SetReferenceValue(&aFieldRef
);
1186 void XclImpPTField::ConvertItems( ScDPSaveDimension
& rSaveDim
) const
1188 for( XclImpPTItemVec::const_iterator aIt
= maItems
.begin(), aEnd
= maItems
.end(); aIt
!= aEnd
; ++aIt
)
1189 (*aIt
)->ConvertItem( rSaveDim
);
1192 // ============================================================================
1194 XclImpPivotTable::XclImpPivotTable( const XclImpRoot
& rRoot
) :
1195 XclImpRoot( rRoot
),
1196 maDataOrientField( *this, EXC_SXIVD_DATA
),
1201 XclImpPivotTable::~XclImpPivotTable()
1205 // cache/field access, misc. --------------------------------------------------
1207 sal_uInt16
XclImpPivotTable::GetFieldCount() const
1209 return static_cast< sal_uInt16
>( maFields
.size() );
1212 const XclImpPTField
* XclImpPivotTable::GetField( sal_uInt16 nFieldIdx
) const
1214 return (nFieldIdx
== EXC_SXIVD_DATA
) ? &maDataOrientField
:
1215 ((nFieldIdx
< maFields
.size()) ? maFields
[ nFieldIdx
].get() : 0);
1218 XclImpPTField
* XclImpPivotTable::GetFieldAcc( sal_uInt16 nFieldIdx
)
1220 // do not return maDataOrientField
1221 return (nFieldIdx
< maFields
.size()) ? maFields
[ nFieldIdx
].get() : 0;
1224 const XclImpPTField
* XclImpPivotTable::GetDataField( sal_uInt16 nDataFieldIdx
) const
1226 if( nDataFieldIdx
< maOrigDataFields
.size() )
1227 return GetField( maOrigDataFields
[ nDataFieldIdx
] );
1231 OUString
XclImpPivotTable::GetDataFieldName( sal_uInt16 nDataFieldIdx
) const
1233 if( const XclImpPTField
* pField
= GetDataField( nDataFieldIdx
) )
1234 return pField
->GetFieldName();
1238 // records --------------------------------------------------------------------
1240 void XclImpPivotTable::ReadSxview( XclImpStream
& rStrm
)
1244 GetAddressConverter().ConvertRange(
1245 maOutScRange
, maPTInfo
.maOutXclRange
, GetCurrScTab(), GetCurrScTab(), true );
1247 mxPCache
= GetPivotTableManager().GetPivotCache( maPTInfo
.mnCacheIdx
);
1248 mxCurrField
.reset();
1251 void XclImpPivotTable::ReadSxvd( XclImpStream
& rStrm
)
1253 sal_uInt16 nFieldCount
= GetFieldCount();
1254 if( nFieldCount
< EXC_PT_MAXFIELDCOUNT
)
1256 // cache index for the field is equal to the SXVD record index
1257 mxCurrField
.reset( new XclImpPTField( *this, nFieldCount
) );
1258 maFields
.push_back( mxCurrField
);
1259 mxCurrField
->ReadSxvd( rStrm
);
1260 // add visible name of new field to list of visible names
1261 maVisFieldNames
.push_back( mxCurrField
->GetVisFieldName() );
1262 OSL_ENSURE( maFields
.size() == maVisFieldNames
.size(),
1263 "XclImpPivotTable::ReadSxvd - wrong size of visible name array" );
1266 mxCurrField
.reset();
1269 void XclImpPivotTable::ReadSxvi( XclImpStream
& rStrm
)
1272 mxCurrField
->ReadSxvi( rStrm
);
1275 void XclImpPivotTable::ReadSxvdex( XclImpStream
& rStrm
)
1278 mxCurrField
->ReadSxvdex( rStrm
);
1281 void XclImpPivotTable::ReadSxivd( XclImpStream
& rStrm
)
1283 mxCurrField
.reset();
1285 // find the index vector to fill (row SXIVD doesn't exist without row fields)
1286 ScfUInt16Vec
* pFieldVec
= 0;
1287 if( maRowFields
.empty() && (maPTInfo
.mnRowFields
> 0) )
1288 pFieldVec
= &maRowFields
;
1289 else if( maColFields
.empty() && (maPTInfo
.mnColFields
> 0) )
1290 pFieldVec
= &maColFields
;
1292 // fill the vector from record data
1295 sal_uInt16 nSize
= ulimit_cast
< sal_uInt16
>( rStrm
.GetRecSize() / 2, EXC_PT_MAXROWCOLCOUNT
);
1296 pFieldVec
->reserve( nSize
);
1297 for( sal_uInt16 nIdx
= 0; nIdx
< nSize
; ++nIdx
)
1299 sal_uInt16 nFieldIdx
;
1301 pFieldVec
->push_back( nFieldIdx
);
1303 // set orientation at special data orientation field
1304 if( nFieldIdx
== EXC_SXIVD_DATA
)
1306 sal_uInt16 nAxis
= (pFieldVec
== &maRowFields
) ? EXC_SXVD_AXIS_ROW
: EXC_SXVD_AXIS_COL
;
1307 maDataOrientField
.SetAxes( nAxis
);
1313 void XclImpPivotTable::ReadSxpi( XclImpStream
& rStrm
)
1315 mxCurrField
.reset();
1317 sal_uInt16 nSize
= ulimit_cast
< sal_uInt16
>( rStrm
.GetRecSize() / 6 );
1318 for( sal_uInt16 nEntry
= 0; nEntry
< nSize
; ++nEntry
)
1320 XclPTPageFieldInfo aPageInfo
;
1322 if( XclImpPTField
* pField
= GetFieldAcc( aPageInfo
.mnField
) )
1324 maPageFields
.push_back( aPageInfo
.mnField
);
1325 pField
->SetPageFieldInfo( aPageInfo
);
1327 GetCurrSheetDrawing().SetSkipObj( aPageInfo
.mnObjId
);
1331 void XclImpPivotTable::ReadSxdi( XclImpStream
& rStrm
)
1333 mxCurrField
.reset();
1335 XclPTDataFieldInfo aDataInfo
;
1337 if( XclImpPTField
* pField
= GetFieldAcc( aDataInfo
.mnField
) )
1339 maOrigDataFields
.push_back( aDataInfo
.mnField
);
1340 // DataPilot does not support double data fields -> add first appearance to index list only
1341 if( !pField
->HasDataFieldInfo() )
1342 maFiltDataFields
.push_back( aDataInfo
.mnField
);
1343 pField
->AddDataFieldInfo( aDataInfo
);
1347 void XclImpPivotTable::ReadSxex( XclImpStream
& rStrm
)
1349 rStrm
>> maPTExtInfo
;
1352 void XclImpPivotTable::ReadSxViewEx9( XclImpStream
& rStrm
)
1354 rStrm
>> maPTViewEx9Info
;
1357 // ----------------------------------------------------------------------------
1359 void XclImpPivotTable::Convert()
1361 if( !mxPCache
|| !mxPCache
->IsValid() )
1364 ScDPSaveData aSaveData
;
1366 // *** global settings ***
1368 aSaveData
.SetRowGrand( ::get_flag( maPTInfo
.mnFlags
, EXC_SXVIEW_ROWGRAND
) );
1369 aSaveData
.SetColumnGrand( ::get_flag( maPTInfo
.mnFlags
, EXC_SXVIEW_COLGRAND
) );
1370 aSaveData
.SetFilterButton( false );
1371 aSaveData
.SetDrillDown( ::get_flag( maPTExtInfo
.mnFlags
, EXC_SXEX_DRILLDOWN
) );
1375 ScfUInt16Vec::const_iterator aIt
, aEnd
;
1378 for( aIt
= maRowFields
.begin(), aEnd
= maRowFields
.end(); aIt
!= aEnd
; ++aIt
)
1379 if( const XclImpPTField
* pField
= GetField( *aIt
) )
1380 pField
->ConvertRowColField( aSaveData
);
1383 for( aIt
= maColFields
.begin(), aEnd
= maColFields
.end(); aIt
!= aEnd
; ++aIt
)
1384 if( const XclImpPTField
* pField
= GetField( *aIt
) )
1385 pField
->ConvertRowColField( aSaveData
);
1388 for( aIt
= maPageFields
.begin(), aEnd
= maPageFields
.end(); aIt
!= aEnd
; ++aIt
)
1389 if( const XclImpPTField
* pField
= GetField( *aIt
) )
1390 pField
->ConvertPageField( aSaveData
);
1392 // We need to import hidden fields because hidden fields may contain
1393 // special settings for subtotals (aggregation function, filters, custom
1394 // name etc.) and members (hidden, custom name etc.).
1397 for( sal_uInt16 nField
= 0, nCount
= GetFieldCount(); nField
< nCount
; ++nField
)
1398 if( const XclImpPTField
* pField
= GetField( nField
) )
1399 if (!pField
->GetAxes())
1400 pField
->ConvertHiddenField( aSaveData
);
1403 for( aIt
= maFiltDataFields
.begin(), aEnd
= maFiltDataFields
.end(); aIt
!= aEnd
; ++aIt
)
1404 if( const XclImpPTField
* pField
= GetField( *aIt
) )
1405 pField
->ConvertDataField( aSaveData
);
1407 // *** insert into Calc document ***
1409 // create source descriptor
1410 ScSheetSourceDesc
aDesc(GetDocPtr());
1411 const OUString
& rSrcName
= mxPCache
->GetSourceRangeName();
1412 if (!rSrcName
.isEmpty())
1413 // Range name is the data source.
1414 aDesc
.SetRangeName(rSrcName
);
1416 // Normal cell range.
1417 aDesc
.SetSourceRange(mxPCache
->GetSourceRange());
1419 // adjust output range to include the page fields
1420 ScRange
aOutRange( maOutScRange
);
1421 if( !maPageFields
.empty() )
1423 SCsROW nDecRows
= ::std::min
< SCsROW
>( aOutRange
.aStart
.Row(), maPageFields
.size() + 1 );
1424 aOutRange
.aStart
.IncRow( -nDecRows
);
1427 // create the DataPilot
1428 ScDPObject
* pDPObj
= new ScDPObject( GetDocPtr() );
1429 pDPObj
->SetName( maPTInfo
.maTableName
);
1430 if (!maPTInfo
.maDataName
.isEmpty())
1431 aSaveData
.GetDataLayoutDimension()->SetLayoutName(maPTInfo
.maDataName
);
1433 if (!maPTViewEx9Info
.maGrandTotalName
.isEmpty())
1434 aSaveData
.SetGrandTotalName(maPTViewEx9Info
.maGrandTotalName
);
1436 pDPObj
->SetSaveData( aSaveData
);
1437 pDPObj
->SetSheetDesc( aDesc
);
1438 pDPObj
->SetOutRange( aOutRange
);
1439 pDPObj
->SetHeaderLayout( maPTViewEx9Info
.mnGridLayout
== 0 );
1441 GetDoc().GetDPCollection()->InsertNewTable(pDPObj
);
1444 ApplyMergeFlags(aOutRange
, aSaveData
);
1447 void XclImpPivotTable::MaybeRefresh()
1449 if (mpDPObj
&& mxPCache
->IsRefreshOnLoad())
1451 // 'refresh table on load' flag is set. Refresh the table now. Some
1452 // Excel files contain partial table output when this flag is set.
1453 ScRange aOutRange
= mpDPObj
->GetOutRange();
1454 mpDPObj
->Output(aOutRange
.aStart
);
1458 void XclImpPivotTable::ApplyMergeFlags(const ScRange
& rOutRange
, const ScDPSaveData
& rSaveData
)
1460 // Apply merge flags for varoius datapilot controls.
1462 ScDPOutputGeometry
aGeometry(rOutRange
, false);
1463 aGeometry
.setColumnFieldCount(maPTInfo
.mnColFields
);
1464 aGeometry
.setPageFieldCount(maPTInfo
.mnPageFields
);
1465 aGeometry
.setDataFieldCount(maPTInfo
.mnDataFields
);
1466 aGeometry
.setRowFieldCount(maPTInfo
.mnRowFields
);
1468 ScDocument
& rDoc
= GetDoc();
1470 vector
<const ScDPSaveDimension
*> aFieldDims
;
1471 vector
<ScAddress
> aFieldBtns
;
1473 aGeometry
.getPageFieldPositions(aFieldBtns
);
1474 vector
<ScAddress
>::const_iterator itr
= aFieldBtns
.begin(), itrEnd
= aFieldBtns
.end();
1475 for (; itr
!= itrEnd
; ++itr
)
1477 rDoc
.ApplyFlagsTab(itr
->Col(), itr
->Row(), itr
->Col(), itr
->Row(), itr
->Tab(), SC_MF_BUTTON
);
1479 sal_uInt16 nMFlag
= SC_MF_BUTTON_POPUP
;
1480 OUString aName
= rDoc
.GetString(itr
->Col(), itr
->Row(), itr
->Tab());
1481 if (rSaveData
.HasInvisibleMember(aName
))
1482 nMFlag
|= SC_MF_HIDDEN_MEMBER
;
1484 rDoc
.ApplyFlagsTab(itr
->Col()+1, itr
->Row(), itr
->Col()+1, itr
->Row(), itr
->Tab(), nMFlag
);
1487 aGeometry
.getColumnFieldPositions(aFieldBtns
);
1488 rSaveData
.GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_COLUMN
, aFieldDims
);
1489 if (aFieldBtns
.size() == aFieldDims
.size())
1491 itr
= aFieldBtns
.begin();
1492 itrEnd
= aFieldBtns
.end();
1493 vector
<const ScDPSaveDimension
*>::const_iterator itDim
= aFieldDims
.begin();
1494 for (; itr
!= itrEnd
; ++itr
, ++itDim
)
1496 sal_Int16 nMFlag
= SC_MF_BUTTON
;
1497 const ScDPSaveDimension
* pDim
= *itDim
;
1498 if (pDim
->HasInvisibleMember())
1499 nMFlag
|= SC_MF_HIDDEN_MEMBER
;
1500 if (!pDim
->IsDataLayout())
1501 nMFlag
|= SC_MF_BUTTON_POPUP
;
1502 rDoc
.ApplyFlagsTab(itr
->Col(), itr
->Row(), itr
->Col(), itr
->Row(), itr
->Tab(), nMFlag
);
1506 aGeometry
.getRowFieldPositions(aFieldBtns
);
1507 rSaveData
.GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_ROW
, aFieldDims
);
1508 if (aFieldBtns
.size() == aFieldDims
.size())
1510 itr
= aFieldBtns
.begin();
1511 itrEnd
= aFieldBtns
.end();
1512 vector
<const ScDPSaveDimension
*>::const_iterator itDim
= aFieldDims
.begin();
1513 for (; itr
!= itrEnd
; ++itr
, ++itDim
)
1515 sal_Int16 nMFlag
= SC_MF_BUTTON
;
1516 const ScDPSaveDimension
* pDim
= *itDim
;
1517 if (pDim
->HasInvisibleMember())
1518 nMFlag
|= SC_MF_HIDDEN_MEMBER
;
1519 if (!pDim
->IsDataLayout())
1520 nMFlag
|= SC_MF_BUTTON_POPUP
;
1521 rDoc
.ApplyFlagsTab(itr
->Col(), itr
->Row(), itr
->Col(), itr
->Row(), itr
->Tab(), nMFlag
);
1526 // ============================================================================
1528 XclImpPivotTableManager::XclImpPivotTableManager( const XclImpRoot
& rRoot
) :
1533 XclImpPivotTableManager::~XclImpPivotTableManager()
1537 // pivot cache records --------------------------------------------------------
1539 XclImpPivotCacheRef
XclImpPivotTableManager::GetPivotCache( sal_uInt16 nCacheIdx
)
1541 XclImpPivotCacheRef xPCache
;
1542 if( nCacheIdx
< maPCaches
.size() )
1543 xPCache
= maPCaches
[ nCacheIdx
];
1547 void XclImpPivotTableManager::ReadSxidstm( XclImpStream
& rStrm
)
1549 XclImpPivotCacheRef
xPCache( new XclImpPivotCache( GetRoot() ) );
1550 maPCaches
.push_back( xPCache
);
1551 xPCache
->ReadSxidstm( rStrm
);
1554 void XclImpPivotTableManager::ReadSxvs( XclImpStream
& rStrm
)
1556 if( !maPCaches
.empty() )
1557 maPCaches
.back()->ReadSxvs( rStrm
);
1560 void XclImpPivotTableManager::ReadDconref( XclImpStream
& rStrm
)
1562 if( !maPCaches
.empty() )
1563 maPCaches
.back()->ReadDconref( rStrm
);
1566 void XclImpPivotTableManager::ReadDConName( XclImpStream
& rStrm
)
1568 if( !maPCaches
.empty() )
1569 maPCaches
.back()->ReadDConName( rStrm
);
1572 // pivot table records --------------------------------------------------------
1574 void XclImpPivotTableManager::ReadSxview( XclImpStream
& rStrm
)
1576 XclImpPivotTableRef
xPTable( new XclImpPivotTable( GetRoot() ) );
1577 maPTables
.push_back( xPTable
);
1578 xPTable
->ReadSxview( rStrm
);
1581 void XclImpPivotTableManager::ReadSxvd( XclImpStream
& rStrm
)
1583 if( !maPTables
.empty() )
1584 maPTables
.back()->ReadSxvd( rStrm
);
1587 void XclImpPivotTableManager::ReadSxvdex( XclImpStream
& rStrm
)
1589 if( !maPTables
.empty() )
1590 maPTables
.back()->ReadSxvdex( rStrm
);
1593 void XclImpPivotTableManager::ReadSxivd( XclImpStream
& rStrm
)
1595 if( !maPTables
.empty() )
1596 maPTables
.back()->ReadSxivd( rStrm
);
1599 void XclImpPivotTableManager::ReadSxpi( XclImpStream
& rStrm
)
1601 if( !maPTables
.empty() )
1602 maPTables
.back()->ReadSxpi( rStrm
);
1605 void XclImpPivotTableManager::ReadSxdi( XclImpStream
& rStrm
)
1607 if( !maPTables
.empty() )
1608 maPTables
.back()->ReadSxdi( rStrm
);
1611 void XclImpPivotTableManager::ReadSxvi( XclImpStream
& rStrm
)
1613 if( !maPTables
.empty() )
1614 maPTables
.back()->ReadSxvi( rStrm
);
1617 void XclImpPivotTableManager::ReadSxex( XclImpStream
& rStrm
)
1619 if( !maPTables
.empty() )
1620 maPTables
.back()->ReadSxex( rStrm
);
1623 void XclImpPivotTableManager::ReadSxViewEx9( XclImpStream
& rStrm
)
1625 if( !maPTables
.empty() )
1626 maPTables
.back()->ReadSxViewEx9( rStrm
);
1629 // ----------------------------------------------------------------------------
1631 void XclImpPivotTableManager::ReadPivotCaches( XclImpStream
& rStrm
)
1633 for( XclImpPivotCacheVec::iterator aIt
= maPCaches
.begin(), aEnd
= maPCaches
.end(); aIt
!= aEnd
; ++aIt
)
1634 (*aIt
)->ReadPivotCacheStream( rStrm
);
1637 void XclImpPivotTableManager::ConvertPivotTables()
1639 for( XclImpPivotTableVec::iterator aIt
= maPTables
.begin(), aEnd
= maPTables
.end(); aIt
!= aEnd
; ++aIt
)
1643 void XclImpPivotTableManager::MaybeRefreshPivotTables()
1645 for( XclImpPivotTableVec::iterator aIt
= maPTables
.begin(), aEnd
= maPTables
.end(); aIt
!= aEnd
; ++aIt
)
1646 (*aIt
)->MaybeRefresh();
1649 // ============================================================================
1651 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */