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