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 .
20 #include "xipivot.hxx"
22 #include <com/sun/star/sheet/DataPilotFieldSortInfo.hpp>
23 #include <com/sun/star/sheet/DataPilotFieldAutoShowInfo.hpp>
24 #include <com/sun/star/sheet/DataPilotFieldLayoutInfo.hpp>
25 #include <com/sun/star/sheet/DataPilotFieldReference.hpp>
27 #include <tools/datetime.hxx>
28 #include <svl/zformat.hxx>
29 #include <svl/intitem.hxx>
31 #include "document.hxx"
32 #include "formulacell.hxx"
34 #include "dpdimsave.hxx"
35 #include "dpobject.hxx"
36 #include "dpshttab.hxx"
37 #include "dpoutputgeometry.hxx"
38 #include "scitems.hxx"
41 #include "xltracer.hxx"
42 #include "xistream.hxx"
43 #include "xihelper.hxx"
45 #include "xiescher.hxx"
47 //TODO ExcelToSc usage
48 #include "excform.hxx"
49 #include "xltable.hxx"
50 #include "documentimport.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
;
66 XclImpPCItem::XclImpPCItem( XclImpStream
& rStrm
)
68 switch( rStrm
.GetRecId() )
70 case EXC_ID_SXDOUBLE
: ReadSxdouble( rStrm
); break;
71 case EXC_ID_SXBOOLEAN
: ReadSxboolean( rStrm
); break;
72 case EXC_ID_SXERROR
: ReadSxerror( rStrm
); break;
73 case EXC_ID_SXINTEGER
: ReadSxinteger( rStrm
); break;
74 case EXC_ID_SXSTRING
: ReadSxstring( rStrm
); break;
75 case EXC_ID_SXDATETIME
: ReadSxdatetime( rStrm
); break;
76 case EXC_ID_SXEMPTY
: ReadSxempty( rStrm
); break;
77 default: OSL_FAIL( "XclImpPCItem::XclImpPCItem - unknown record id" );
83 void lclSetValue( XclImpRoot
& rRoot
, const ScAddress
& rScPos
, double fValue
, short nFormatType
)
85 ScDocumentImport
& rDoc
= rRoot
.GetDocImport();
86 rDoc
.setNumericCell(rScPos
, fValue
);
87 sal_uInt32 nScNumFmt
= rRoot
.GetFormatter().GetStandardFormat( nFormatType
, rRoot
.GetDocLanguage() );
88 rDoc
.getDoc().ApplyAttr(
89 rScPos
.Col(), rScPos
.Row(), rScPos
.Tab(), SfxUInt32Item(ATTR_VALUE_FORMAT
, nScNumFmt
));
94 void XclImpPCItem::WriteToSource( XclImpRoot
& rRoot
, const ScAddress
& rScPos
) const
96 ScDocumentImport
& rDoc
= rRoot
.GetDocImport();
97 if( const OUString
* pText
= GetText() )
98 rDoc
.setStringCell(rScPos
, *pText
);
99 else if( const double* pfValue
= GetDouble() )
100 rDoc
.setNumericCell(rScPos
, *pfValue
);
101 else if( const sal_Int16
* pnValue
= GetInteger() )
102 rDoc
.setNumericCell(rScPos
, *pnValue
);
103 else if( const bool* pbValue
= GetBool() )
104 lclSetValue( rRoot
, rScPos
, *pbValue
? 1.0 : 0.0, css::util::NumberFormat::LOGICAL
);
105 else if( const DateTime
* pDateTime
= GetDateTime() )
107 // set number format date, time, or date/time, depending on the value
108 double fValue
= rRoot
.GetDoubleFromDateTime( *pDateTime
);
110 double fFrac
= modf( fValue
, &fInt
);
111 short nFormatType
= ((fFrac
== 0.0) && (fInt
!= 0.0)) ? css::util::NumberFormat::DATE
:
112 ((fInt
== 0.0) ? css::util::NumberFormat::TIME
: css::util::NumberFormat::DATETIME
);
113 lclSetValue( rRoot
, rScPos
, fValue
, nFormatType
);
115 else if( const sal_uInt16
* pnError
= GetError() )
118 sal_uInt8 nErrCode
= static_cast< sal_uInt8
>( *pnError
);
119 const ScTokenArray
* pScTokArr
= rRoot
.GetOldFmlaConverter().GetBoolErr(
120 XclTools::ErrorToEnum( fValue
, true, nErrCode
) );
121 ScFormulaCell
* pCell
= pScTokArr
? new ScFormulaCell(&rDoc
.getDoc(), rScPos
, *pScTokArr
) : new ScFormulaCell(&rDoc
.getDoc(), rScPos
);
122 pCell
->SetHybridDouble( fValue
);
123 rDoc
.setFormulaCell(rScPos
, pCell
);
127 void XclImpPCItem::ReadSxdouble( XclImpStream
& rStrm
)
129 OSL_ENSURE( rStrm
.GetRecSize() == 8, "XclImpPCItem::ReadSxdouble - wrong record size" );
130 SetDouble( rStrm
.ReadDouble() );
133 void XclImpPCItem::ReadSxboolean( XclImpStream
& rStrm
)
135 OSL_ENSURE( rStrm
.GetRecSize() == 2, "XclImpPCItem::ReadSxboolean - wrong record size" );
136 SetBool( rStrm
.ReaduInt16() != 0 );
139 void XclImpPCItem::ReadSxerror( XclImpStream
& rStrm
)
141 OSL_ENSURE( rStrm
.GetRecSize() == 2, "XclImpPCItem::ReadSxerror - wrong record size" );
142 SetError( rStrm
.ReaduInt16() );
145 void XclImpPCItem::ReadSxinteger( XclImpStream
& rStrm
)
147 OSL_ENSURE( rStrm
.GetRecSize() == 2, "XclImpPCItem::ReadSxinteger - wrong record size" );
148 SetInteger( rStrm
.ReadInt16() );
151 void XclImpPCItem::ReadSxstring( XclImpStream
& rStrm
)
153 OSL_ENSURE( rStrm
.GetRecSize() >= 3, "XclImpPCItem::ReadSxstring - wrong record size" );
154 SetText( rStrm
.ReadUniString() );
157 void XclImpPCItem::ReadSxdatetime( XclImpStream
& rStrm
)
159 OSL_ENSURE( rStrm
.GetRecSize() == 8, "XclImpPCItem::ReadSxdatetime - wrong record size" );
160 sal_uInt16 nYear
, nMonth
;
161 sal_uInt8 nDay
, nHour
, nMin
, nSec
;
162 nYear
= rStrm
.ReaduInt16();
163 nMonth
= rStrm
.ReaduInt16();
164 nDay
= rStrm
.ReaduInt8();
165 nHour
= rStrm
.ReaduInt8();
166 nMin
= rStrm
.ReaduInt8();
167 nSec
= rStrm
.ReaduInt8();
168 SetDateTime( DateTime( Date( nDay
, nMonth
, nYear
), tools::Time( nHour
, nMin
, nSec
) ) );
171 void XclImpPCItem::ReadSxempty( XclImpStream
& rStrm
)
173 (void)rStrm
; // avoid compiler warning
174 OSL_ENSURE( rStrm
.GetRecSize() == 0, "XclImpPCItem::ReadSxempty - wrong record size" );
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 OUString
& XclImpPCField::GetFieldName( const ScfStringVec
& rVisNames
) const
195 if( IsGroupChildField() && (mnFieldIdx
< rVisNames
.size()) )
197 const 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
)
224 OSL_ENSURE( HasOrigItems(), "XclImpPCField::WriteFieldNameToSource - only for standard fields" );
225 GetDocImport().setStringCell(ScAddress(nScCol
, 0, nScTab
), maFieldInfo
.maName
);
226 mnSourceScCol
= nScCol
;
229 void XclImpPCField::WriteOrigItemToSource( SCROW nScRow
, SCTAB nScTab
, sal_uInt16 nItemIdx
)
231 if( nItemIdx
< maOrigItems
.size() )
232 maOrigItems
[ nItemIdx
]->WriteToSource( GetRoot(), ScAddress( mnSourceScCol
, nScRow
, nScTab
) );
235 void XclImpPCField::WriteLastOrigItemToSource( SCROW nScRow
, SCTAB nScTab
)
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 maGroupOrder
[ nIdx
] = rStrm
.ReaduInt16();
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 OUString
& rBaseFieldName
= pBaseField
->GetFieldName( rVisNames
);
410 if( !rBaseFieldName
.isEmpty() )
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 OUString
& rBaseFieldName
= pBaseField
->GetFieldName( rVisNames
);
473 if( !rBaseFieldName
.isEmpty() )
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
= true;
492 aNumInfo
.mbDateValues
= false;
493 aNumInfo
.mbAutoStart
= true;
494 aNumInfo
.mbAutoEnd
= 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
= true;
516 aDateInfo
.mbDateValues
= false;
517 aDateInfo
.mbAutoStart
= true;
518 aDateInfo
.mbAutoEnd
= 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
= 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 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
)
614 mnStrmId
= rStrm
.ReaduInt16();
617 void XclImpPivotCache::ReadSxvs( XclImpStream
& rStrm
)
619 mnSrcType
= rStrm
.ReaduInt16();
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
.isEmpty() || (mnSrcType
!= EXC_SXVS_SHEET
) )
631 XclRange
aXclRange( ScAddress::UNINITIALIZED
);
632 aXclRange
.Read( rStrm
, false );
633 OUString 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.
653 nFlag
= rStrm
.ReaduInt16();
654 mbSelfRef
= (nFlag
== 0);
657 // External name is not supported yet.
658 maSrcRangeName
.clear();
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("DPCache");
707 if( maTabName
.getLength() > 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 tools::SvRef
<SotStorage
> xSvStrg
= OpenStorage( EXC_STORAGE_PTCACHE
);
719 tools::SvRef
<SotStorageStream
> 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();
883 XclImpPTItem::XclImpPTItem( const XclImpPCField
* pCacheField
) :
884 mpCacheField( pCacheField
)
888 const OUString
* XclImpPTItem::GetItemName() const
891 if( const XclImpPCItem
* pCacheItem
= mpCacheField
->GetItem( maItemInfo
.mnCacheIdx
) )
892 //TODO: use XclImpPCItem::ConvertToText(), if all conversions are available
893 return pCacheItem
->IsEmpty() ? NULL
: pCacheItem
->GetText();
897 void XclImpPTItem::ReadSxvi( XclImpStream
& rStrm
)
902 void XclImpPTItem::ConvertItem( ScDPSaveDimension
& rSaveDim
) const
904 if (const OUString
* pItemName
= GetItemName())
906 ScDPSaveMember
& rMember
= *rSaveDim
.GetMemberByName( *pItemName
);
907 rMember
.SetIsVisible( !::get_flag( maItemInfo
.mnFlags
, EXC_SXVI_HIDDEN
) );
908 rMember
.SetShowDetails( !::get_flag( maItemInfo
.mnFlags
, EXC_SXVI_HIDEDETAIL
) );
909 if (maItemInfo
.HasVisName())
910 rMember
.SetLayoutName(*maItemInfo
.GetVisName());
914 XclImpPTField::XclImpPTField( const XclImpPivotTable
& rPTable
, sal_uInt16 nCacheIdx
) :
917 maFieldInfo
.mnCacheIdx
= nCacheIdx
;
920 // general field/item access --------------------------------------------------
922 const XclImpPCField
* XclImpPTField::GetCacheField() const
924 XclImpPivotCacheRef xPCache
= mrPTable
.GetPivotCache();
925 return xPCache
? xPCache
->GetField( maFieldInfo
.mnCacheIdx
) : 0;
928 OUString
XclImpPTField::GetFieldName() const
930 const XclImpPCField
* pField
= GetCacheField();
931 return pField
? pField
->GetFieldName( mrPTable
.GetVisFieldNames() ) : OUString();
934 OUString
XclImpPTField::GetVisFieldName() const
936 const OUString
* pVisName
= maFieldInfo
.GetVisName();
937 return pVisName
? *pVisName
: OUString();
940 const XclImpPTItem
* XclImpPTField::GetItem( sal_uInt16 nItemIdx
) const
942 return (nItemIdx
< maItems
.size()) ? maItems
[ nItemIdx
].get() : 0;
945 const OUString
* XclImpPTField::GetItemName( sal_uInt16 nItemIdx
) const
947 const XclImpPTItem
* pItem
= GetItem( nItemIdx
);
948 return pItem
? pItem
->GetItemName() : 0;
951 // records --------------------------------------------------------------------
953 void XclImpPTField::ReadSxvd( XclImpStream
& rStrm
)
955 rStrm
>> maFieldInfo
;
958 void XclImpPTField::ReadSxvdex( XclImpStream
& rStrm
)
960 rStrm
>> maFieldExtInfo
;
963 void XclImpPTField::ReadSxvi( XclImpStream
& rStrm
)
965 XclImpPTItemRef
xItem( new XclImpPTItem( GetCacheField() ) );
966 maItems
.push_back( xItem
);
967 xItem
->ReadSxvi( rStrm
);
970 // row/column fields ----------------------------------------------------------
972 void XclImpPTField::ConvertRowColField( ScDPSaveData
& rSaveData
) const
974 OSL_ENSURE( maFieldInfo
.mnAxes
& EXC_SXVD_AXIS_ROWCOL
, "XclImpPTField::ConvertRowColField - no row/column field" );
975 // special data orientation field?
976 if( maFieldInfo
.mnCacheIdx
== EXC_SXIVD_DATA
)
977 rSaveData
.GetDataLayoutDimension()->SetOrientation( static_cast< sal_uInt16
>( maFieldInfo
.GetApiOrient( EXC_SXVD_AXIS_ROWCOL
) ) );
979 ConvertRCPField( rSaveData
);
982 // page fields ----------------------------------------------------------------
984 void XclImpPTField::SetPageFieldInfo( const XclPTPageFieldInfo
& rPageInfo
)
986 maPageInfo
= rPageInfo
;
989 void XclImpPTField::ConvertPageField( ScDPSaveData
& rSaveData
) const
991 OSL_ENSURE( maFieldInfo
.mnAxes
& EXC_SXVD_AXIS_PAGE
, "XclImpPTField::ConvertPageField - no page field" );
992 if( ScDPSaveDimension
* pSaveDim
= ConvertRCPField( rSaveData
) )
994 const OUString
* pName
= GetItemName( maPageInfo
.mnSelItem
);
996 pSaveDim
->SetCurrentPage(pName
);
1000 // hidden fields --------------------------------------------------------------
1002 void XclImpPTField::ConvertHiddenField( ScDPSaveData
& rSaveData
) const
1004 OSL_ENSURE( (maFieldInfo
.mnAxes
& EXC_SXVD_AXIS_ROWCOLPAGE
) == 0, "XclImpPTField::ConvertHiddenField - field not hidden" );
1005 ConvertRCPField( rSaveData
);
1008 // data fields ----------------------------------------------------------------
1010 bool XclImpPTField::HasDataFieldInfo() const
1012 return !maDataInfoList
.empty();
1015 void XclImpPTField::AddDataFieldInfo( const XclPTDataFieldInfo
& rDataInfo
)
1017 OSL_ENSURE( maFieldInfo
.mnAxes
& EXC_SXVD_AXIS_DATA
, "XclImpPTField::AddDataFieldInfo - no data field" );
1018 maDataInfoList
.push_back( rDataInfo
);
1021 void XclImpPTField::ConvertDataField( ScDPSaveData
& rSaveData
) const
1023 OSL_ENSURE( maFieldInfo
.mnAxes
& EXC_SXVD_AXIS_DATA
, "XclImpPTField::ConvertDataField - no data field" );
1024 OSL_ENSURE( !maDataInfoList
.empty(), "XclImpPTField::ConvertDataField - no data field info" );
1025 if (maDataInfoList
.empty())
1028 OUString aFieldName
= GetFieldName();
1029 if (aFieldName
.isEmpty())
1032 XclPTDataFieldInfoList::const_iterator aIt
= maDataInfoList
.begin(), aEnd
= maDataInfoList
.end();
1034 ScDPSaveDimension
* pSaveDim
= rSaveData
.GetNewDimensionByName(aFieldName
);
1037 SAL_WARN("sc.filter","XclImpPTField::ConvertDataField - field name not found: " << aFieldName
);
1041 ConvertDataField( *pSaveDim
, *aIt
);
1043 // multiple data fields -> clone dimension
1044 for( ++aIt
; aIt
!= aEnd
; ++aIt
)
1046 ScDPSaveDimension
& rDupDim
= rSaveData
.DuplicateDimension( *pSaveDim
);
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
];
1072 return aBuf
.makeStringAndClear();
1075 ScDPSaveDimension
* XclImpPTField::ConvertRCPField( ScDPSaveData
& rSaveData
) const
1077 const OUString
& rFieldName
= GetFieldName();
1078 if( rFieldName
.isEmpty() )
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 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 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 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 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
;
1300 nFieldIdx
= rStrm
.ReaduInt16();
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 void XclImpPivotTable::Convert()
1359 if( !mxPCache
|| !mxPCache
->IsValid() )
1362 ScDPSaveData aSaveData
;
1364 // *** global settings ***
1366 aSaveData
.SetRowGrand( ::get_flag( maPTInfo
.mnFlags
, EXC_SXVIEW_ROWGRAND
) );
1367 aSaveData
.SetColumnGrand( ::get_flag( maPTInfo
.mnFlags
, EXC_SXVIEW_COLGRAND
) );
1368 aSaveData
.SetFilterButton( false );
1369 aSaveData
.SetDrillDown( ::get_flag( maPTExtInfo
.mnFlags
, EXC_SXEX_DRILLDOWN
) );
1373 ScfUInt16Vec::const_iterator aIt
, aEnd
;
1376 for( aIt
= maRowFields
.begin(), aEnd
= maRowFields
.end(); aIt
!= aEnd
; ++aIt
)
1377 if( const XclImpPTField
* pField
= GetField( *aIt
) )
1378 pField
->ConvertRowColField( aSaveData
);
1381 for( aIt
= maColFields
.begin(), aEnd
= maColFields
.end(); aIt
!= aEnd
; ++aIt
)
1382 if( const XclImpPTField
* pField
= GetField( *aIt
) )
1383 pField
->ConvertRowColField( aSaveData
);
1386 for( aIt
= maPageFields
.begin(), aEnd
= maPageFields
.end(); aIt
!= aEnd
; ++aIt
)
1387 if( const XclImpPTField
* pField
= GetField( *aIt
) )
1388 pField
->ConvertPageField( aSaveData
);
1390 // We need to import hidden fields because hidden fields may contain
1391 // special settings for subtotals (aggregation function, filters, custom
1392 // name etc.) and members (hidden, custom name etc.).
1395 for( sal_uInt16 nField
= 0, nCount
= GetFieldCount(); nField
< nCount
; ++nField
)
1396 if( const XclImpPTField
* pField
= GetField( nField
) )
1397 if (!pField
->GetAxes())
1398 pField
->ConvertHiddenField( aSaveData
);
1401 for( aIt
= maFiltDataFields
.begin(), aEnd
= maFiltDataFields
.end(); aIt
!= aEnd
; ++aIt
)
1402 if( const XclImpPTField
* pField
= GetField( *aIt
) )
1403 pField
->ConvertDataField( aSaveData
);
1405 // *** insert into Calc document ***
1407 // create source descriptor
1408 ScSheetSourceDesc
aDesc(GetDocPtr());
1409 const OUString
& rSrcName
= mxPCache
->GetSourceRangeName();
1410 if (!rSrcName
.isEmpty())
1411 // Range name is the data source.
1412 aDesc
.SetRangeName(rSrcName
);
1414 // Normal cell range.
1415 aDesc
.SetSourceRange(mxPCache
->GetSourceRange());
1417 // adjust output range to include the page fields
1418 ScRange
aOutRange( maOutScRange
);
1419 if( !maPageFields
.empty() )
1421 SCsROW nDecRows
= ::std::min
< SCsROW
>( aOutRange
.aStart
.Row(), maPageFields
.size() + 1 );
1422 aOutRange
.aStart
.IncRow( -nDecRows
);
1425 // create the DataPilot
1426 ScDPObject
* pDPObj
= new ScDPObject( GetDocPtr() );
1427 pDPObj
->SetName( maPTInfo
.maTableName
);
1428 if (!maPTInfo
.maDataName
.isEmpty())
1429 aSaveData
.GetDataLayoutDimension()->SetLayoutName(maPTInfo
.maDataName
);
1431 if (!maPTViewEx9Info
.maGrandTotalName
.isEmpty())
1432 aSaveData
.SetGrandTotalName(maPTViewEx9Info
.maGrandTotalName
);
1434 pDPObj
->SetSaveData( aSaveData
);
1435 pDPObj
->SetSheetDesc( aDesc
);
1436 pDPObj
->SetOutRange( aOutRange
);
1437 pDPObj
->SetHeaderLayout( maPTViewEx9Info
.mnGridLayout
== 0 );
1439 GetDoc().GetDPCollection()->InsertNewTable(pDPObj
);
1442 ApplyMergeFlags(aOutRange
, aSaveData
);
1445 void XclImpPivotTable::MaybeRefresh()
1447 if (mpDPObj
&& mxPCache
->IsRefreshOnLoad())
1449 // 'refresh table on load' flag is set. Refresh the table now. Some
1450 // Excel files contain partial table output when this flag is set.
1451 ScRange aOutRange
= mpDPObj
->GetOutRange();
1452 mpDPObj
->Output(aOutRange
.aStart
);
1456 void XclImpPivotTable::ApplyMergeFlags(const ScRange
& rOutRange
, const ScDPSaveData
& rSaveData
)
1458 // Apply merge flags for varoius datapilot controls.
1460 ScDPOutputGeometry
aGeometry(rOutRange
, false);
1461 aGeometry
.setColumnFieldCount(maPTInfo
.mnColFields
);
1462 aGeometry
.setPageFieldCount(maPTInfo
.mnPageFields
);
1463 aGeometry
.setDataFieldCount(maPTInfo
.mnDataFields
);
1464 aGeometry
.setRowFieldCount(maPTInfo
.mnRowFields
);
1466 ScDocument
& rDoc
= GetDoc();
1468 vector
<const ScDPSaveDimension
*> aFieldDims
;
1469 vector
<ScAddress
> aFieldBtns
;
1471 aGeometry
.getPageFieldPositions(aFieldBtns
);
1472 vector
<ScAddress
>::const_iterator itr
= aFieldBtns
.begin(), itrEnd
= aFieldBtns
.end();
1473 for (; itr
!= itrEnd
; ++itr
)
1475 rDoc
.ApplyFlagsTab(itr
->Col(), itr
->Row(), itr
->Col(), itr
->Row(), itr
->Tab(), SC_MF_BUTTON
);
1477 sal_uInt16 nMFlag
= SC_MF_BUTTON_POPUP
;
1478 OUString aName
= rDoc
.GetString(itr
->Col(), itr
->Row(), itr
->Tab());
1479 if (rSaveData
.HasInvisibleMember(aName
))
1480 nMFlag
|= SC_MF_HIDDEN_MEMBER
;
1482 rDoc
.ApplyFlagsTab(itr
->Col()+1, itr
->Row(), itr
->Col()+1, itr
->Row(), itr
->Tab(), nMFlag
);
1485 aGeometry
.getColumnFieldPositions(aFieldBtns
);
1486 rSaveData
.GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_COLUMN
, aFieldDims
);
1487 if (aFieldBtns
.size() == aFieldDims
.size())
1489 itr
= aFieldBtns
.begin();
1490 itrEnd
= aFieldBtns
.end();
1491 vector
<const ScDPSaveDimension
*>::const_iterator itDim
= aFieldDims
.begin();
1492 for (; itr
!= itrEnd
; ++itr
, ++itDim
)
1494 sal_Int16 nMFlag
= SC_MF_BUTTON
;
1495 const ScDPSaveDimension
* pDim
= *itDim
;
1496 if (pDim
->HasInvisibleMember())
1497 nMFlag
|= SC_MF_HIDDEN_MEMBER
;
1498 if (!pDim
->IsDataLayout())
1499 nMFlag
|= SC_MF_BUTTON_POPUP
;
1500 rDoc
.ApplyFlagsTab(itr
->Col(), itr
->Row(), itr
->Col(), itr
->Row(), itr
->Tab(), nMFlag
);
1504 aGeometry
.getRowFieldPositions(aFieldBtns
);
1505 rSaveData
.GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_ROW
, aFieldDims
);
1506 if (aFieldBtns
.size() == aFieldDims
.size())
1508 itr
= aFieldBtns
.begin();
1509 itrEnd
= aFieldBtns
.end();
1510 vector
<const ScDPSaveDimension
*>::const_iterator itDim
= aFieldDims
.begin();
1511 for (; itr
!= itrEnd
; ++itr
, ++itDim
)
1513 sal_Int16 nMFlag
= SC_MF_BUTTON
;
1514 const ScDPSaveDimension
* pDim
= *itDim
;
1515 if (pDim
->HasInvisibleMember())
1516 nMFlag
|= SC_MF_HIDDEN_MEMBER
;
1517 if (!pDim
->IsDataLayout())
1518 nMFlag
|= SC_MF_BUTTON_POPUP
;
1519 rDoc
.ApplyFlagsTab(itr
->Col(), itr
->Row(), itr
->Col(), itr
->Row(), itr
->Tab(), nMFlag
);
1524 XclImpPivotTableManager::XclImpPivotTableManager( const XclImpRoot
& rRoot
) :
1529 XclImpPivotTableManager::~XclImpPivotTableManager()
1533 // pivot cache records --------------------------------------------------------
1535 XclImpPivotCacheRef
XclImpPivotTableManager::GetPivotCache( sal_uInt16 nCacheIdx
)
1537 XclImpPivotCacheRef xPCache
;
1538 if( nCacheIdx
< maPCaches
.size() )
1539 xPCache
= maPCaches
[ nCacheIdx
];
1543 void XclImpPivotTableManager::ReadSxidstm( XclImpStream
& rStrm
)
1545 XclImpPivotCacheRef
xPCache( new XclImpPivotCache( GetRoot() ) );
1546 maPCaches
.push_back( xPCache
);
1547 xPCache
->ReadSxidstm( rStrm
);
1550 void XclImpPivotTableManager::ReadSxvs( XclImpStream
& rStrm
)
1552 if( !maPCaches
.empty() )
1553 maPCaches
.back()->ReadSxvs( rStrm
);
1556 void XclImpPivotTableManager::ReadDconref( XclImpStream
& rStrm
)
1558 if( !maPCaches
.empty() )
1559 maPCaches
.back()->ReadDconref( rStrm
);
1562 void XclImpPivotTableManager::ReadDConName( XclImpStream
& rStrm
)
1564 if( !maPCaches
.empty() )
1565 maPCaches
.back()->ReadDConName( rStrm
);
1568 // pivot table records --------------------------------------------------------
1570 void XclImpPivotTableManager::ReadSxview( XclImpStream
& rStrm
)
1572 XclImpPivotTableRef
xPTable( new XclImpPivotTable( GetRoot() ) );
1573 maPTables
.push_back( xPTable
);
1574 xPTable
->ReadSxview( rStrm
);
1577 void XclImpPivotTableManager::ReadSxvd( XclImpStream
& rStrm
)
1579 if( !maPTables
.empty() )
1580 maPTables
.back()->ReadSxvd( rStrm
);
1583 void XclImpPivotTableManager::ReadSxvdex( XclImpStream
& rStrm
)
1585 if( !maPTables
.empty() )
1586 maPTables
.back()->ReadSxvdex( rStrm
);
1589 void XclImpPivotTableManager::ReadSxivd( XclImpStream
& rStrm
)
1591 if( !maPTables
.empty() )
1592 maPTables
.back()->ReadSxivd( rStrm
);
1595 void XclImpPivotTableManager::ReadSxpi( XclImpStream
& rStrm
)
1597 if( !maPTables
.empty() )
1598 maPTables
.back()->ReadSxpi( rStrm
);
1601 void XclImpPivotTableManager::ReadSxdi( XclImpStream
& rStrm
)
1603 if( !maPTables
.empty() )
1604 maPTables
.back()->ReadSxdi( rStrm
);
1607 void XclImpPivotTableManager::ReadSxvi( XclImpStream
& rStrm
)
1609 if( !maPTables
.empty() )
1610 maPTables
.back()->ReadSxvi( rStrm
);
1613 void XclImpPivotTableManager::ReadSxex( XclImpStream
& rStrm
)
1615 if( !maPTables
.empty() )
1616 maPTables
.back()->ReadSxex( rStrm
);
1619 void XclImpPivotTableManager::ReadSxViewEx9( XclImpStream
& rStrm
)
1621 if( !maPTables
.empty() )
1622 maPTables
.back()->ReadSxViewEx9( rStrm
);
1625 void XclImpPivotTableManager::ReadPivotCaches( XclImpStream
& rStrm
)
1627 for( XclImpPivotCacheVec::iterator aIt
= maPCaches
.begin(), aEnd
= maPCaches
.end(); aIt
!= aEnd
; ++aIt
)
1628 (*aIt
)->ReadPivotCacheStream( rStrm
);
1631 void XclImpPivotTableManager::ConvertPivotTables()
1633 for( XclImpPivotTableVec::iterator aIt
= maPTables
.begin(), aEnd
= maPTables
.end(); aIt
!= aEnd
; ++aIt
)
1637 void XclImpPivotTableManager::MaybeRefreshPivotTables()
1639 for( XclImpPivotTableVec::iterator aIt
= maPTables
.begin(), aEnd
= maPTables
.end(); aIt
!= aEnd
; ++aIt
)
1640 (*aIt
)->MaybeRefresh();
1643 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */