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_DATA
;
57 using ::com::sun::star::sheet::DataPilotFieldSortInfo
;
58 using ::com::sun::star::sheet::DataPilotFieldAutoShowInfo
;
59 using ::com::sun::star::sheet::DataPilotFieldLayoutInfo
;
60 using ::com::sun::star::sheet::DataPilotFieldReference
;
65 XclImpPCItem::XclImpPCItem( XclImpStream
& rStrm
)
67 switch( rStrm
.GetRecId() )
69 case EXC_ID_SXDOUBLE
: ReadSxdouble( rStrm
); break;
70 case EXC_ID_SXBOOLEAN
: ReadSxboolean( rStrm
); break;
71 case EXC_ID_SXERROR
: ReadSxerror( rStrm
); break;
72 case EXC_ID_SXINTEGER
: ReadSxinteger( rStrm
); break;
73 case EXC_ID_SXSTRING
: ReadSxstring( rStrm
); break;
74 case EXC_ID_SXDATETIME
: ReadSxdatetime( rStrm
); break;
75 case EXC_ID_SXEMPTY
: ReadSxempty( rStrm
); break;
76 default: OSL_FAIL( "XclImpPCItem::XclImpPCItem - unknown record id" );
82 void lclSetValue( XclImpRoot
& rRoot
, const ScAddress
& rScPos
, double fValue
, short nFormatType
)
84 ScDocumentImport
& rDoc
= rRoot
.GetDocImport();
85 rDoc
.setNumericCell(rScPos
, fValue
);
86 sal_uInt32 nScNumFmt
= rRoot
.GetFormatter().GetStandardFormat( nFormatType
, rRoot
.GetDocLanguage() );
87 rDoc
.getDoc().ApplyAttr(
88 rScPos
.Col(), rScPos
.Row(), rScPos
.Tab(), SfxUInt32Item(ATTR_VALUE_FORMAT
, nScNumFmt
));
93 void XclImpPCItem::WriteToSource( XclImpRoot
& rRoot
, const ScAddress
& rScPos
) const
95 ScDocumentImport
& rDoc
= rRoot
.GetDocImport();
96 if( const OUString
* pText
= GetText() )
97 rDoc
.setStringCell(rScPos
, *pText
);
98 else if( const double* pfValue
= GetDouble() )
99 rDoc
.setNumericCell(rScPos
, *pfValue
);
100 else if( const sal_Int16
* pnValue
= GetInteger() )
101 rDoc
.setNumericCell(rScPos
, *pnValue
);
102 else if( const bool* pbValue
= GetBool() )
103 lclSetValue( rRoot
, rScPos
, *pbValue
? 1.0 : 0.0, css::util::NumberFormat::LOGICAL
);
104 else if( const DateTime
* pDateTime
= GetDateTime() )
106 // set number format date, time, or date/time, depending on the value
107 double fValue
= rRoot
.GetDoubleFromDateTime( *pDateTime
);
109 double fFrac
= modf( fValue
, &fInt
);
110 short nFormatType
= ((fFrac
== 0.0) && (fInt
!= 0.0)) ? css::util::NumberFormat::DATE
:
111 ((fInt
== 0.0) ? css::util::NumberFormat::TIME
: css::util::NumberFormat::DATETIME
);
112 lclSetValue( rRoot
, rScPos
, fValue
, nFormatType
);
114 else if( const sal_uInt16
* pnError
= GetError() )
117 sal_uInt8 nErrCode
= static_cast< sal_uInt8
>( *pnError
);
118 const ScTokenArray
* pScTokArr
= rRoot
.GetOldFmlaConverter().GetBoolErr(
119 XclTools::ErrorToEnum( fValue
, true, nErrCode
) );
120 ScFormulaCell
* pCell
= pScTokArr
? new ScFormulaCell(&rDoc
.getDoc(), rScPos
, *pScTokArr
) : new ScFormulaCell(&rDoc
.getDoc(), rScPos
);
121 pCell
->SetHybridDouble( fValue
);
122 rDoc
.setFormulaCell(rScPos
, pCell
);
126 void XclImpPCItem::ReadSxdouble( XclImpStream
& rStrm
)
128 OSL_ENSURE( rStrm
.GetRecSize() == 8, "XclImpPCItem::ReadSxdouble - wrong record size" );
129 SetDouble( rStrm
.ReadDouble() );
132 void XclImpPCItem::ReadSxboolean( XclImpStream
& rStrm
)
134 OSL_ENSURE( rStrm
.GetRecSize() == 2, "XclImpPCItem::ReadSxboolean - wrong record size" );
135 SetBool( rStrm
.ReaduInt16() != 0 );
138 void XclImpPCItem::ReadSxerror( XclImpStream
& rStrm
)
140 OSL_ENSURE( rStrm
.GetRecSize() == 2, "XclImpPCItem::ReadSxerror - wrong record size" );
141 SetError( rStrm
.ReaduInt16() );
144 void XclImpPCItem::ReadSxinteger( XclImpStream
& rStrm
)
146 OSL_ENSURE( rStrm
.GetRecSize() == 2, "XclImpPCItem::ReadSxinteger - wrong record size" );
147 SetInteger( rStrm
.ReadInt16() );
150 void XclImpPCItem::ReadSxstring( XclImpStream
& rStrm
)
152 OSL_ENSURE( rStrm
.GetRecSize() >= 3, "XclImpPCItem::ReadSxstring - wrong record size" );
153 SetText( rStrm
.ReadUniString() );
156 void XclImpPCItem::ReadSxdatetime( XclImpStream
& rStrm
)
158 OSL_ENSURE( rStrm
.GetRecSize() == 8, "XclImpPCItem::ReadSxdatetime - wrong record size" );
159 sal_uInt16 nYear
, nMonth
;
160 sal_uInt8 nDay
, nHour
, nMin
, nSec
;
161 nYear
= rStrm
.ReaduInt16();
162 nMonth
= rStrm
.ReaduInt16();
163 nDay
= rStrm
.ReaduInt8();
164 nHour
= rStrm
.ReaduInt8();
165 nMin
= rStrm
.ReaduInt8();
166 nSec
= rStrm
.ReaduInt8();
167 SetDateTime( DateTime( Date( nDay
, nMonth
, nYear
), tools::Time( nHour
, nMin
, nSec
) ) );
170 void XclImpPCItem::ReadSxempty( XclImpStream
& rStrm
)
172 (void)rStrm
; // avoid compiler warning
173 OSL_ENSURE( rStrm
.GetRecSize() == 0, "XclImpPCItem::ReadSxempty - wrong record size" );
177 XclImpPCField::XclImpPCField( const XclImpRoot
& rRoot
, XclImpPivotCache
& rPCache
, sal_uInt16 nFieldIdx
) :
178 XclPCField( EXC_PCFIELD_UNKNOWN
, nFieldIdx
),
182 mbNumGroupInfoRead( false )
186 XclImpPCField::~XclImpPCField()
190 // general field/item access --------------------------------------------------
192 const OUString
& XclImpPCField::GetFieldName( const ScfStringVec
& rVisNames
) const
194 if( IsGroupChildField() && (mnFieldIdx
< rVisNames
.size()) )
196 const OUString
& rVisName
= rVisNames
[ mnFieldIdx
];
197 if (!rVisName
.isEmpty())
200 return maFieldInfo
.maName
;
203 const XclImpPCField
* XclImpPCField::GetGroupBaseField() const
205 OSL_ENSURE( IsGroupChildField(), "XclImpPCField::GetGroupBaseField - this field type does not have a base field" );
206 return IsGroupChildField() ? mrPCache
.GetField( maFieldInfo
.mnGroupBase
) : nullptr;
209 const XclImpPCItem
* XclImpPCField::GetItem( sal_uInt16 nItemIdx
) const
211 return (nItemIdx
< maItems
.size()) ? maItems
[ nItemIdx
].get() : nullptr;
214 const XclImpPCItem
* XclImpPCField::GetLimitItem( sal_uInt16 nItemIdx
) const
216 OSL_ENSURE( nItemIdx
< 3, "XclImpPCField::GetLimitItem - invalid item index" );
217 OSL_ENSURE( nItemIdx
< maNumGroupItems
.size(), "XclImpPCField::GetLimitItem - no item found" );
218 return (nItemIdx
< maNumGroupItems
.size()) ? maNumGroupItems
[ nItemIdx
].get() : nullptr;
221 void XclImpPCField::WriteFieldNameToSource( SCCOL nScCol
, SCTAB nScTab
)
223 OSL_ENSURE( HasOrigItems(), "XclImpPCField::WriteFieldNameToSource - only for standard fields" );
224 GetDocImport().setStringCell(ScAddress(nScCol
, 0, nScTab
), maFieldInfo
.maName
);
225 mnSourceScCol
= nScCol
;
228 void XclImpPCField::WriteOrigItemToSource( SCROW nScRow
, SCTAB nScTab
, sal_uInt16 nItemIdx
)
230 if( nItemIdx
< maOrigItems
.size() )
231 maOrigItems
[ nItemIdx
]->WriteToSource( GetRoot(), ScAddress( mnSourceScCol
, nScRow
, nScTab
) );
234 void XclImpPCField::WriteLastOrigItemToSource( SCROW nScRow
, SCTAB nScTab
)
236 if( !maOrigItems
.empty() )
237 maOrigItems
.back()->WriteToSource( GetRoot(), ScAddress( mnSourceScCol
, nScRow
, nScTab
) );
240 // records --------------------------------------------------------------------
242 void XclImpPCField::ReadSxfield( XclImpStream
& rStrm
)
244 rStrm
>> maFieldInfo
;
246 /* Detect the type of this field. This is done very restrictive to detect
247 any unexpected state. */
248 meFieldType
= EXC_PCFIELD_UNKNOWN
;
250 bool bItems
= ::get_flag( maFieldInfo
.mnFlags
, EXC_SXFIELD_HASITEMS
);
251 bool bPostp
= ::get_flag( maFieldInfo
.mnFlags
, EXC_SXFIELD_POSTPONE
);
252 bool bCalced
= ::get_flag( maFieldInfo
.mnFlags
, EXC_SXFIELD_CALCED
);
253 bool bChild
= ::get_flag( maFieldInfo
.mnFlags
, EXC_SXFIELD_HASCHILD
);
254 bool bNum
= ::get_flag( maFieldInfo
.mnFlags
, EXC_SXFIELD_NUMGROUP
);
256 sal_uInt16 nVisC
= maFieldInfo
.mnVisItems
;
257 sal_uInt16 nGroupC
= maFieldInfo
.mnGroupItems
;
258 sal_uInt16 nBaseC
= maFieldInfo
.mnBaseItems
;
259 sal_uInt16 nOrigC
= maFieldInfo
.mnOrigItems
;
260 OSL_ENSURE( nVisC
> 0, "XclImpPCField::ReadSxfield - field without visible items" );
262 sal_uInt16 nType
= maFieldInfo
.mnFlags
& EXC_SXFIELD_DATA_MASK
;
264 (nType
== EXC_SXFIELD_DATA_STR
) ||
265 (nType
== EXC_SXFIELD_DATA_INT
) ||
266 (nType
== EXC_SXFIELD_DATA_DBL
) ||
267 (nType
== EXC_SXFIELD_DATA_STR_INT
) ||
268 (nType
== EXC_SXFIELD_DATA_STR_DBL
) ||
269 (nType
== EXC_SXFIELD_DATA_DATE
) ||
270 (nType
== EXC_SXFIELD_DATA_DATE_EMP
) ||
271 (nType
== EXC_SXFIELD_DATA_DATE_NUM
) ||
272 (nType
== EXC_SXFIELD_DATA_DATE_STR
);
274 (nType
== EXC_SXFIELD_DATA_NONE
);
275 // for now, ignore data type of calculated fields
276 OSL_ENSURE( bCalced
|| bType
|| bTypeNone
, "XclImpPCField::ReadSxfield - unknown item data type" );
278 if( nVisC
> 0 || bPostp
)
280 if( bItems
&& !bPostp
)
284 // 1) standard fields and standard grouping fields
287 // 1a) standard field without grouping
288 if( bType
&& (nGroupC
== 0) && (nBaseC
== 0) && (nOrigC
== nVisC
) )
289 meFieldType
= EXC_PCFIELD_STANDARD
;
291 // 1b) standard grouping field
292 else if( bTypeNone
&& (nGroupC
== nVisC
) && (nBaseC
> 0) && (nOrigC
== 0) )
293 meFieldType
= EXC_PCFIELD_STDGROUP
;
295 // 2) numerical grouping fields
296 else if( (nGroupC
== nVisC
) && (nBaseC
== 0) )
298 // 2a) single num/date grouping field without child grouping field
299 if( !bChild
&& bType
&& (nOrigC
> 0) )
303 case EXC_SXFIELD_DATA_INT
:
304 case EXC_SXFIELD_DATA_DBL
: meFieldType
= EXC_PCFIELD_NUMGROUP
; break;
305 case EXC_SXFIELD_DATA_DATE
: meFieldType
= EXC_PCFIELD_DATEGROUP
; break;
306 default: OSL_FAIL( "XclImpPCField::ReadSxfield - numeric group with wrong data type" );
310 // 2b) first date grouping field with child grouping field
311 else if( bChild
&& (nType
== EXC_SXFIELD_DATA_DATE
) && (nOrigC
> 0) )
312 meFieldType
= EXC_PCFIELD_DATEGROUP
;
314 // 2c) additional date grouping field
315 else if( bTypeNone
&& (nOrigC
== 0) )
316 meFieldType
= EXC_PCFIELD_DATECHILD
;
318 OSL_ENSURE( meFieldType
!= EXC_PCFIELD_UNKNOWN
, "XclImpPCField::ReadSxfield - invalid standard or grouped field" );
321 // 3) calculated field
324 if( !bChild
&& !bNum
&& (nGroupC
== 0) && (nBaseC
== 0) && (nOrigC
== 0) )
325 meFieldType
= EXC_PCFIELD_CALCED
;
326 OSL_ENSURE( meFieldType
== EXC_PCFIELD_CALCED
, "XclImpPCField::ReadSxfield - invalid calculated field" );
330 else if( !bItems
&& bPostp
)
332 // 4) standard field with postponed items
333 if( !bCalced
&& !bChild
&& !bNum
&& bType
&& (nGroupC
== 0) && (nBaseC
== 0) && (nOrigC
== 0) )
334 meFieldType
= EXC_PCFIELD_STANDARD
;
335 OSL_ENSURE( meFieldType
== EXC_PCFIELD_STANDARD
, "XclImpPCField::ReadSxfield - invalid postponed field" );
340 void XclImpPCField::ReadItem( XclImpStream
& rStrm
)
342 OSL_ENSURE( HasInlineItems() || HasPostponedItems(), "XclImpPCField::ReadItem - field does not expect items" );
345 XclImpPCItemRef
xItem( new XclImpPCItem( rStrm
) );
347 // try to insert into an item list
348 if( mbNumGroupInfoRead
)
350 // there are 3 items after SXNUMGROUP that contain grouping limits and step count
351 if( maNumGroupItems
.size() < 3 )
352 maNumGroupItems
.push_back( xItem
);
354 maOrigItems
.push_back( xItem
);
356 else if( HasInlineItems() || HasPostponedItems() )
358 maItems
.push_back( xItem
);
359 // visible item is original item in standard fields
360 if( IsStandardField() )
361 maOrigItems
.push_back( xItem
);
365 void XclImpPCField::ReadSxnumgroup( XclImpStream
& rStrm
)
367 OSL_ENSURE( IsNumGroupField() || IsDateGroupField(), "XclImpPCField::ReadSxnumgroup - SXNUMGROUP outside numeric grouping field" );
368 OSL_ENSURE( !mbNumGroupInfoRead
, "XclImpPCField::ReadSxnumgroup - multiple SXNUMGROUP records" );
369 OSL_ENSURE( maItems
.size() == maFieldInfo
.mnGroupItems
, "XclImpPCField::ReadSxnumgroup - SXNUMGROUP out of record order" );
370 rStrm
>> maNumGroupInfo
;
371 mbNumGroupInfoRead
= IsNumGroupField() || IsDateGroupField();
374 void XclImpPCField::ReadSxgroupinfo( XclImpStream
& rStrm
)
376 OSL_ENSURE( IsStdGroupField(), "XclImpPCField::ReadSxgroupinfo - SXGROUPINFO outside grouping field" );
377 OSL_ENSURE( maGroupOrder
.empty(), "XclImpPCField::ReadSxgroupinfo - multiple SXGROUPINFO records" );
378 OSL_ENSURE( maItems
.size() == maFieldInfo
.mnGroupItems
, "XclImpPCField::ReadSxgroupinfo - SXGROUPINFO out of record order" );
379 OSL_ENSURE( (rStrm
.GetRecLeft() / 2) == maFieldInfo
.mnBaseItems
, "XclImpPCField::ReadSxgroupinfo - wrong SXGROUPINFO size" );
380 maGroupOrder
.clear();
381 size_t nSize
= rStrm
.GetRecLeft() / 2;
382 maGroupOrder
.resize( nSize
, 0 );
383 for( size_t nIdx
= 0; nIdx
< nSize
; ++nIdx
)
384 maGroupOrder
[ nIdx
] = rStrm
.ReaduInt16();
387 // grouping -------------------------------------------------------------------
389 void XclImpPCField::ConvertGroupField( ScDPSaveData
& rSaveData
, const ScfStringVec
& rVisNames
) const
391 if (!GetFieldName(rVisNames
).isEmpty())
393 if( IsStdGroupField() )
394 ConvertStdGroupField( rSaveData
, rVisNames
);
395 else if( IsNumGroupField() )
396 ConvertNumGroupField( rSaveData
, rVisNames
);
397 else if( IsDateGroupField() )
398 ConvertDateGroupField( rSaveData
, rVisNames
);
402 // private --------------------------------------------------------------------
404 void XclImpPCField::ConvertStdGroupField( ScDPSaveData
& rSaveData
, const ScfStringVec
& rVisNames
) const
406 if( const XclImpPCField
* pBaseField
= GetGroupBaseField() )
408 const OUString
& rBaseFieldName
= pBaseField
->GetFieldName( rVisNames
);
409 if( !rBaseFieldName
.isEmpty() )
411 // *** create a ScDPSaveGroupItem for each own item, they collect base item names ***
412 ScDPSaveGroupItemVec aGroupItems
;
413 aGroupItems
.reserve( maItems
.size() );
414 // initialize with own item names
415 for( XclImpPCItemVec::const_iterator aIt
= maItems
.begin(), aEnd
= maItems
.end(); aIt
!= aEnd
; ++aIt
)
416 aGroupItems
.push_back( ScDPSaveGroupItem( (*aIt
)->ConvertToText() ) );
418 // *** iterate over all base items, set their names at corresponding own items ***
419 for( sal_uInt16 nItemIdx
= 0, nItemCount
= static_cast< sal_uInt16
>( maGroupOrder
.size() ); nItemIdx
< nItemCount
; ++nItemIdx
)
420 if( maGroupOrder
[ nItemIdx
] < aGroupItems
.size() )
421 if( const XclImpPCItem
* pBaseItem
= pBaseField
->GetItem( nItemIdx
) )
422 if( const XclImpPCItem
* pGroupItem
= GetItem( maGroupOrder
[ nItemIdx
] ) )
423 if( *pBaseItem
!= *pGroupItem
)
424 aGroupItems
[ maGroupOrder
[ nItemIdx
] ].AddElement( pBaseItem
->ConvertToText() );
426 // *** create the ScDPSaveGroupDimension object, fill with grouping info ***
427 ScDPSaveGroupDimension
aGroupDim( rBaseFieldName
, GetFieldName( rVisNames
) );
428 for( ScDPSaveGroupItemVec::const_iterator aIt
= aGroupItems
.begin(), aEnd
= aGroupItems
.end(); aIt
!= aEnd
; ++aIt
)
429 if( !aIt
->IsEmpty() )
430 aGroupDim
.AddGroupItem( *aIt
);
431 rSaveData
.GetDimensionData()->AddGroupDimension( aGroupDim
);
436 void XclImpPCField::ConvertNumGroupField( ScDPSaveData
& rSaveData
, const ScfStringVec
& rVisNames
) const
438 ScDPNumGroupInfo
aNumInfo( GetScNumGroupInfo() );
439 ScDPSaveNumGroupDimension
aNumGroupDim( GetFieldName( rVisNames
), aNumInfo
);
440 rSaveData
.GetDimensionData()->AddNumGroupDimension( aNumGroupDim
);
443 void XclImpPCField::ConvertDateGroupField( ScDPSaveData
& rSaveData
, const ScfStringVec
& rVisNames
) const
445 ScDPNumGroupInfo
aDateInfo( GetScDateGroupInfo() );
446 sal_Int32 nScDateType
= maNumGroupInfo
.GetScDateType();
448 switch( meFieldType
)
450 case EXC_PCFIELD_DATEGROUP
:
452 if( aDateInfo
.mbDateValues
)
454 // special case for days only with step value - create numeric grouping
455 ScDPSaveNumGroupDimension
aNumGroupDim( GetFieldName( rVisNames
), aDateInfo
);
456 rSaveData
.GetDimensionData()->AddNumGroupDimension( aNumGroupDim
);
460 ScDPSaveNumGroupDimension
aNumGroupDim( GetFieldName( rVisNames
), ScDPNumGroupInfo() );
461 aNumGroupDim
.SetDateInfo( aDateInfo
, nScDateType
);
462 rSaveData
.GetDimensionData()->AddNumGroupDimension( aNumGroupDim
);
467 case EXC_PCFIELD_DATECHILD
:
469 if( const XclImpPCField
* pBaseField
= GetGroupBaseField() )
471 const OUString
& rBaseFieldName
= pBaseField
->GetFieldName( rVisNames
);
472 if( !rBaseFieldName
.isEmpty() )
474 ScDPSaveGroupDimension
aGroupDim( rBaseFieldName
, GetFieldName( rVisNames
) );
475 aGroupDim
.SetDateInfo( aDateInfo
, nScDateType
);
476 rSaveData
.GetDimensionData()->AddGroupDimension( aGroupDim
);
483 OSL_FAIL( "XclImpPCField::ConvertDateGroupField - unknown date field type" );
487 ScDPNumGroupInfo
XclImpPCField::GetScNumGroupInfo() const
489 ScDPNumGroupInfo aNumInfo
;
490 aNumInfo
.mbEnable
= true;
491 aNumInfo
.mbDateValues
= false;
492 aNumInfo
.mbAutoStart
= true;
493 aNumInfo
.mbAutoEnd
= true;
495 if( const double* pfMinValue
= GetNumGroupLimit( EXC_SXFIELD_INDEX_MIN
) )
497 aNumInfo
.mfStart
= *pfMinValue
;
498 aNumInfo
.mbAutoStart
= ::get_flag( maNumGroupInfo
.mnFlags
, EXC_SXNUMGROUP_AUTOMIN
);
500 if( const double* pfMaxValue
= GetNumGroupLimit( EXC_SXFIELD_INDEX_MAX
) )
502 aNumInfo
.mfEnd
= *pfMaxValue
;
503 aNumInfo
.mbAutoEnd
= ::get_flag( maNumGroupInfo
.mnFlags
, EXC_SXNUMGROUP_AUTOMAX
);
505 if( const double* pfStepValue
= GetNumGroupLimit( EXC_SXFIELD_INDEX_STEP
) )
506 aNumInfo
.mfStep
= *pfStepValue
;
511 ScDPNumGroupInfo
XclImpPCField::GetScDateGroupInfo() const
513 ScDPNumGroupInfo aDateInfo
;
514 aDateInfo
.mbEnable
= true;
515 aDateInfo
.mbDateValues
= false;
516 aDateInfo
.mbAutoStart
= true;
517 aDateInfo
.mbAutoEnd
= true;
519 if( const DateTime
* pMinDate
= GetDateGroupLimit( EXC_SXFIELD_INDEX_MIN
) )
521 aDateInfo
.mfStart
= GetDoubleFromDateTime( *pMinDate
);
522 aDateInfo
.mbAutoStart
= ::get_flag( maNumGroupInfo
.mnFlags
, EXC_SXNUMGROUP_AUTOMIN
);
524 if( const DateTime
* pMaxDate
= GetDateGroupLimit( EXC_SXFIELD_INDEX_MAX
) )
526 aDateInfo
.mfEnd
= GetDoubleFromDateTime( *pMaxDate
);
527 aDateInfo
.mbAutoEnd
= ::get_flag( maNumGroupInfo
.mnFlags
, EXC_SXNUMGROUP_AUTOMAX
);
529 // GetDateGroupStep() returns a value for date type "day" in single date groups only
530 if( const sal_Int16
* pnStepValue
= GetDateGroupStep() )
532 aDateInfo
.mfStep
= *pnStepValue
;
533 aDateInfo
.mbDateValues
= true;
539 const double* XclImpPCField::GetNumGroupLimit( sal_uInt16 nLimitIdx
) const
541 OSL_ENSURE( IsNumGroupField(), "XclImpPCField::GetNumGroupLimit - only for numeric grouping fields" );
542 if( const XclImpPCItem
* pItem
= GetLimitItem( nLimitIdx
) )
544 OSL_ENSURE( pItem
->GetDouble(), "XclImpPCField::GetNumGroupLimit - SXDOUBLE item expected" );
545 return pItem
->GetDouble();
550 const DateTime
* XclImpPCField::GetDateGroupLimit( sal_uInt16 nLimitIdx
) const
552 OSL_ENSURE( IsDateGroupField(), "XclImpPCField::GetDateGroupLimit - only for date grouping fields" );
553 if( const XclImpPCItem
* pItem
= GetLimitItem( nLimitIdx
) )
555 OSL_ENSURE( pItem
->GetDateTime(), "XclImpPCField::GetDateGroupLimit - SXDATETIME item expected" );
556 return pItem
->GetDateTime();
561 const sal_Int16
* XclImpPCField::GetDateGroupStep() const
563 // only for single date grouping fields, not for grouping chains
564 if( !IsGroupBaseField() && !IsGroupChildField() )
566 // only days may have a step value, return 0 for all other date types
567 if( maNumGroupInfo
.GetXclDataType() == EXC_SXNUMGROUP_TYPE_DAY
)
569 if( const XclImpPCItem
* pItem
= GetLimitItem( EXC_SXFIELD_INDEX_STEP
) )
571 OSL_ENSURE( pItem
->GetInteger(), "XclImpPCField::GetDateGroupStep - SXINTEGER item expected" );
572 if( const sal_Int16
* pnStep
= pItem
->GetInteger() )
574 OSL_ENSURE( *pnStep
> 0, "XclImpPCField::GetDateGroupStep - invalid step count" );
575 // return nothing for step count 1 - this is also a standard date group in Excel
576 return (*pnStep
> 1) ? pnStep
: nullptr;
584 XclImpPivotCache::XclImpPivotCache( const XclImpRoot
& rRoot
) :
586 maSrcRange( ScAddress::INITIALIZE_INVALID
),
588 mnSrcType( EXC_SXVS_UNKNOWN
),
593 XclImpPivotCache::~XclImpPivotCache()
597 // data access ----------------------------------------------------------------
599 sal_uInt16
XclImpPivotCache::GetFieldCount() const
601 return static_cast< sal_uInt16
>( maFields
.size() );
604 const XclImpPCField
* XclImpPivotCache::GetField( sal_uInt16 nFieldIdx
) const
606 return (nFieldIdx
< maFields
.size()) ? maFields
[ nFieldIdx
].get() : nullptr;
609 // records --------------------------------------------------------------------
611 void XclImpPivotCache::ReadSxidstm( XclImpStream
& rStrm
)
613 mnStrmId
= rStrm
.ReaduInt16();
616 void XclImpPivotCache::ReadSxvs( XclImpStream
& rStrm
)
618 mnSrcType
= rStrm
.ReaduInt16();
619 GetTracer().TracePivotDataSource( mnSrcType
!= EXC_SXVS_SHEET
);
622 void XclImpPivotCache::ReadDconref( XclImpStream
& rStrm
)
624 /* Read DCONREF only once (by checking maTabName), there may be other
625 DCONREF records in another context. Read reference only if a leading
626 SXVS record is present (by checking mnSrcType). */
627 if( !maTabName
.isEmpty() || (mnSrcType
!= EXC_SXVS_SHEET
) )
630 XclRange
aXclRange( ScAddress::UNINITIALIZED
);
631 aXclRange
.Read( rStrm
, false );
632 OUString aEncUrl
= rStrm
.ReadUniString();
634 XclImpUrlHelper::DecodeUrl( maUrl
, maTabName
, mbSelfRef
, GetRoot(), aEncUrl
);
636 /* Do not convert maTabName to Calc sheet name -> original name is used to
637 find the sheet in the document. Sheet index of source range will be
638 found later in XclImpPivotCache::ReadPivotCacheStream(), because sheet
639 may not exist yet. */
641 GetAddressConverter().ConvertRange( maSrcRange
, aXclRange
, 0, 0, true );
644 void XclImpPivotCache::ReadDConName( XclImpStream
& rStrm
)
646 maSrcRangeName
= rStrm
.ReadUniString();
648 // This 2-byte value equals the length of string that follows, or if 0 it
649 // indicates that the name has a workbook scope. For now, we only support
650 // internal defined name with a workbook scope.
652 nFlag
= rStrm
.ReaduInt16();
653 mbSelfRef
= (nFlag
== 0);
656 // External name is not supported yet.
657 maSrcRangeName
.clear();
660 void XclImpPivotCache::ReadPivotCacheStream( XclImpStream
& rStrm
)
662 if( (mnSrcType
!= EXC_SXVS_SHEET
) && (mnSrcType
!= EXC_SXVS_EXTERN
) )
665 ScDocument
& rDoc
= GetDoc();
666 SCCOL nFieldScCol
= 0; // column index of source data for next field
667 SCROW nItemScRow
= 0; // row index of source data for current items
668 SCTAB nScTab
= 0; // sheet index of source data
669 bool bGenerateSource
= false; // true = write source data from cache to dummy table
673 if (maSrcRangeName
.isEmpty())
675 // try to find internal sheet containing the source data
676 nScTab
= GetTabInfo().GetScTabFromXclName( maTabName
);
677 if( rDoc
.HasTable( nScTab
) )
679 // set sheet index to source range
680 maSrcRange
.aStart
.SetTab( nScTab
);
681 maSrcRange
.aEnd
.SetTab( nScTab
);
685 // create dummy sheet for deleted internal sheet
686 bGenerateSource
= true;
692 // create dummy sheet for external sheet
693 bGenerateSource
= true;
696 // create dummy sheet for source data from external or deleted sheet
697 if( bGenerateSource
)
699 if( rDoc
.GetTableCount() >= MAXTABCOUNT
)
700 // cannot create more sheets -> exit
703 nScTab
= rDoc
.GetTableCount();
704 rDoc
.MakeTable( nScTab
);
705 OUStringBuffer
aDummyName("DPCache");
706 if( maTabName
.getLength() > 0 )
707 aDummyName
.append( '_' ).append( maTabName
);
708 OUString aName
= aDummyName
.makeStringAndClear();
709 rDoc
.CreateValidTabName( aName
);
710 rDoc
.RenameTab( nScTab
, aName
);
711 // set sheet index to source range
712 maSrcRange
.aStart
.SetTab( nScTab
);
713 maSrcRange
.aEnd
.SetTab( nScTab
);
716 // open pivot cache storage stream
717 tools::SvRef
<SotStorage
> xSvStrg
= OpenStorage( EXC_STORAGE_PTCACHE
);
718 tools::SvRef
<SotStorageStream
> xSvStrm
= OpenStream( xSvStrg
, ScfTools::GetHexStr( mnStrmId
) );
722 // create Excel record stream object
723 XclImpStream
aPCStrm( *xSvStrm
, GetRoot() );
724 aPCStrm
.CopyDecrypterFrom( rStrm
); // pivot cache streams are encrypted
726 XclImpPCFieldRef xCurrField
; // current field for new items
727 XclImpPCFieldVec aOrigFields
; // all standard fields with inline original items
728 XclImpPCFieldVec aPostpFields
; // all standard fields with postponed original items
729 size_t nPostpIdx
= 0; // index to current field with postponed items
730 bool bLoop
= true; // true = continue loop
732 while( bLoop
&& aPCStrm
.StartNextRecord() )
734 switch( aPCStrm
.GetRecId() )
747 sal_uInt16 nNewFieldIdx
= GetFieldCount();
748 if( nNewFieldIdx
< EXC_PC_MAXFIELDCOUNT
)
750 xCurrField
.reset( new XclImpPCField( GetRoot(), *this, nNewFieldIdx
) );
751 maFields
.push_back( xCurrField
);
752 xCurrField
->ReadSxfield( aPCStrm
);
753 if( xCurrField
->HasOrigItems() )
755 if( xCurrField
->HasPostponedItems() )
756 aPostpFields
.push_back( xCurrField
);
758 aOrigFields
.push_back( xCurrField
);
759 // insert field name into generated source data, field remembers its column index
760 if( bGenerateSource
&& (nFieldScCol
<= MAXCOL
) )
761 xCurrField
->WriteFieldNameToSource( nFieldScCol
++, nScTab
);
763 // do not read items into invalid/postponed fields
764 if( !xCurrField
->HasInlineItems() )
770 case EXC_ID_SXINDEXLIST
:
771 // read index list and insert all items into generated source data
772 if( bGenerateSource
&& (nItemScRow
<= MAXROW
) && (++nItemScRow
<= MAXROW
) )
774 for( XclImpPCFieldVec::const_iterator aIt
= aOrigFields
.begin(), aEnd
= aOrigFields
.end(); aIt
!= aEnd
; ++aIt
)
776 sal_uInt16 nItemIdx
= (*aIt
)->Has16BitIndexes() ? aPCStrm
.ReaduInt16() : aPCStrm
.ReaduInt8();
777 (*aIt
)->WriteOrigItemToSource( nItemScRow
, nScTab
, nItemIdx
);
783 case EXC_ID_SXDOUBLE
:
784 case EXC_ID_SXBOOLEAN
:
786 case EXC_ID_SXINTEGER
:
787 case EXC_ID_SXSTRING
:
788 case EXC_ID_SXDATETIME
:
790 if( xCurrField
) // inline items
792 xCurrField
->ReadItem( aPCStrm
);
794 else if( !aPostpFields
.empty() ) // postponed items
796 // read postponed item
797 aPostpFields
[ nPostpIdx
]->ReadItem( aPCStrm
);
798 // write item to source
799 if( bGenerateSource
&& (nItemScRow
<= MAXROW
) )
801 // start new row, if there are only postponed fields
802 if( aOrigFields
.empty() && (nPostpIdx
== 0) )
804 if( nItemScRow
<= MAXROW
)
805 aPostpFields
[ nPostpIdx
]->WriteLastOrigItemToSource( nItemScRow
, nScTab
);
807 // get index of next postponed field
809 if( nPostpIdx
>= aPostpFields
.size() )
814 case EXC_ID_SXNUMGROUP
:
816 xCurrField
->ReadSxnumgroup( aPCStrm
);
819 case EXC_ID_SXGROUPINFO
:
821 xCurrField
->ReadSxgroupinfo( aPCStrm
);
824 // known but ignored records
831 case EXC_ID_SXFORMULA
:
833 case EXC_ID_SXFDBTYPE
:
837 OSL_TRACE( "XclImpPivotCache::ReadPivotCacheStream - unknown record 0x%04hX", aPCStrm
.GetRecId() );
841 OSL_ENSURE( maPCInfo
.mnTotalFields
== maFields
.size(),
842 "XclImpPivotCache::ReadPivotCacheStream - field count mismatch" );
844 if (HasCacheRecords())
846 SCROW nNewEnd
= maSrcRange
.aStart
.Row() + maPCInfo
.mnSrcRecs
;
847 maSrcRange
.aEnd
.SetRow(nNewEnd
);
850 // set source range for external source data
851 if( bGenerateSource
&& (nFieldScCol
> 0) )
853 maSrcRange
.aStart
.SetCol( 0 );
854 maSrcRange
.aStart
.SetRow( 0 );
855 // nFieldScCol points to first unused column
856 maSrcRange
.aEnd
.SetCol( nFieldScCol
- 1 );
857 // nItemScRow points to last used row
858 maSrcRange
.aEnd
.SetRow( nItemScRow
);
862 bool XclImpPivotCache::HasCacheRecords() const
864 return static_cast<bool>(maPCInfo
.mnFlags
& EXC_SXDB_SAVEDATA
);
867 bool XclImpPivotCache::IsRefreshOnLoad() const
869 return static_cast<bool>(maPCInfo
.mnFlags
& EXC_SXDB_REFRESH_LOAD
);
872 bool XclImpPivotCache::IsValid() const
874 if (!maSrcRangeName
.isEmpty())
877 return maSrcRange
.IsValid();
882 XclImpPTItem::XclImpPTItem( const XclImpPCField
* pCacheField
) :
883 mpCacheField( pCacheField
)
887 const OUString
* XclImpPTItem::GetItemName() const
890 if( const XclImpPCItem
* pCacheItem
= mpCacheField
->GetItem( maItemInfo
.mnCacheIdx
) )
891 //TODO: use XclImpPCItem::ConvertToText(), if all conversions are available
892 return pCacheItem
->IsEmpty() ? nullptr : pCacheItem
->GetText();
896 void XclImpPTItem::ReadSxvi( XclImpStream
& rStrm
)
901 void XclImpPTItem::ConvertItem( ScDPSaveDimension
& rSaveDim
) const
903 if (const OUString
* pItemName
= GetItemName())
905 ScDPSaveMember
& rMember
= *rSaveDim
.GetMemberByName( *pItemName
);
906 rMember
.SetIsVisible( !::get_flag( maItemInfo
.mnFlags
, EXC_SXVI_HIDDEN
) );
907 rMember
.SetShowDetails( !::get_flag( maItemInfo
.mnFlags
, EXC_SXVI_HIDEDETAIL
) );
908 if (maItemInfo
.HasVisName())
909 rMember
.SetLayoutName(*maItemInfo
.GetVisName());
913 XclImpPTField::XclImpPTField( const XclImpPivotTable
& rPTable
, sal_uInt16 nCacheIdx
) :
916 maFieldInfo
.mnCacheIdx
= nCacheIdx
;
919 // general field/item access --------------------------------------------------
921 const XclImpPCField
* XclImpPTField::GetCacheField() const
923 XclImpPivotCacheRef xPCache
= mrPTable
.GetPivotCache();
924 return xPCache
? xPCache
->GetField( maFieldInfo
.mnCacheIdx
) : nullptr;
927 OUString
XclImpPTField::GetFieldName() const
929 const XclImpPCField
* pField
= GetCacheField();
930 return pField
? pField
->GetFieldName( mrPTable
.GetVisFieldNames() ) : OUString();
933 OUString
XclImpPTField::GetVisFieldName() const
935 const OUString
* pVisName
= maFieldInfo
.GetVisName();
936 return pVisName
? *pVisName
: OUString();
939 const XclImpPTItem
* XclImpPTField::GetItem( sal_uInt16 nItemIdx
) const
941 return (nItemIdx
< maItems
.size()) ? maItems
[ nItemIdx
].get() : nullptr;
944 const OUString
* XclImpPTField::GetItemName( sal_uInt16 nItemIdx
) const
946 const XclImpPTItem
* pItem
= GetItem( nItemIdx
);
947 return pItem
? pItem
->GetItemName() : nullptr;
950 // records --------------------------------------------------------------------
952 void XclImpPTField::ReadSxvd( XclImpStream
& rStrm
)
954 rStrm
>> maFieldInfo
;
957 void XclImpPTField::ReadSxvdex( XclImpStream
& rStrm
)
959 rStrm
>> maFieldExtInfo
;
962 void XclImpPTField::ReadSxvi( XclImpStream
& rStrm
)
964 XclImpPTItemRef
xItem( new XclImpPTItem( GetCacheField() ) );
965 maItems
.push_back( xItem
);
966 xItem
->ReadSxvi( rStrm
);
969 // row/column fields ----------------------------------------------------------
971 void XclImpPTField::ConvertRowColField( ScDPSaveData
& rSaveData
) const
973 OSL_ENSURE( maFieldInfo
.mnAxes
& EXC_SXVD_AXIS_ROWCOL
, "XclImpPTField::ConvertRowColField - no row/column field" );
974 // special data orientation field?
975 if( maFieldInfo
.mnCacheIdx
== EXC_SXIVD_DATA
)
976 rSaveData
.GetDataLayoutDimension()->SetOrientation( static_cast< sal_uInt16
>( maFieldInfo
.GetApiOrient( EXC_SXVD_AXIS_ROWCOL
) ) );
978 ConvertRCPField( rSaveData
);
981 // page fields ----------------------------------------------------------------
983 void XclImpPTField::SetPageFieldInfo( const XclPTPageFieldInfo
& rPageInfo
)
985 maPageInfo
= rPageInfo
;
988 void XclImpPTField::ConvertPageField( ScDPSaveData
& rSaveData
) const
990 OSL_ENSURE( maFieldInfo
.mnAxes
& EXC_SXVD_AXIS_PAGE
, "XclImpPTField::ConvertPageField - no page field" );
991 if( ScDPSaveDimension
* pSaveDim
= ConvertRCPField( rSaveData
) )
993 const OUString
* pName
= GetItemName( maPageInfo
.mnSelItem
);
995 pSaveDim
->SetCurrentPage(pName
);
999 // hidden fields --------------------------------------------------------------
1001 void XclImpPTField::ConvertHiddenField( ScDPSaveData
& rSaveData
) const
1003 OSL_ENSURE( (maFieldInfo
.mnAxes
& EXC_SXVD_AXIS_ROWCOLPAGE
) == 0, "XclImpPTField::ConvertHiddenField - field not hidden" );
1004 ConvertRCPField( rSaveData
);
1007 // data fields ----------------------------------------------------------------
1009 bool XclImpPTField::HasDataFieldInfo() const
1011 return !maDataInfoList
.empty();
1014 void XclImpPTField::AddDataFieldInfo( const XclPTDataFieldInfo
& rDataInfo
)
1016 OSL_ENSURE( maFieldInfo
.mnAxes
& EXC_SXVD_AXIS_DATA
, "XclImpPTField::AddDataFieldInfo - no data field" );
1017 maDataInfoList
.push_back( rDataInfo
);
1020 void XclImpPTField::ConvertDataField( ScDPSaveData
& rSaveData
) const
1022 OSL_ENSURE( maFieldInfo
.mnAxes
& EXC_SXVD_AXIS_DATA
, "XclImpPTField::ConvertDataField - no data field" );
1023 OSL_ENSURE( !maDataInfoList
.empty(), "XclImpPTField::ConvertDataField - no data field info" );
1024 if (maDataInfoList
.empty())
1027 OUString aFieldName
= GetFieldName();
1028 if (aFieldName
.isEmpty())
1031 ScDPSaveDimension
* pSaveDim
= rSaveData
.GetNewDimensionByName(aFieldName
);
1034 SAL_WARN("sc.filter","XclImpPTField::ConvertDataField - field name not found: " << aFieldName
);
1038 XclPTDataFieldInfoList::const_iterator aIt
= maDataInfoList
.begin(), aEnd
= maDataInfoList
.end();
1040 ConvertDataField( *pSaveDim
, *aIt
);
1042 // multiple data fields -> clone dimension
1043 for( ++aIt
; aIt
!= aEnd
; ++aIt
)
1045 ScDPSaveDimension
& rDupDim
= rSaveData
.DuplicateDimension( *pSaveDim
);
1046 ConvertDataFieldInfo( rDupDim
, *aIt
);
1050 // private --------------------------------------------------------------------
1053 * Convert Excel-encoded subtotal name to a Calc-encoded one.
1055 static OUString
lcl_convertExcelSubtotalName(const OUString
& rName
)
1057 OUStringBuffer aBuf
;
1058 const sal_Unicode
* p
= rName
.getStr();
1059 sal_Int32 n
= rName
.getLength();
1060 for (sal_Int32 i
= 0; i
< n
; ++i
)
1062 const sal_Unicode c
= p
[i
];
1071 return aBuf
.makeStringAndClear();
1074 ScDPSaveDimension
* XclImpPTField::ConvertRCPField( ScDPSaveData
& rSaveData
) const
1076 const OUString
& rFieldName
= GetFieldName();
1077 if( rFieldName
.isEmpty() )
1080 const XclImpPCField
* pCacheField
= GetCacheField();
1081 if( !pCacheField
|| !pCacheField
->IsSupportedField() )
1084 ScDPSaveDimension
* pTest
= rSaveData
.GetNewDimensionByName(rFieldName
);
1088 ScDPSaveDimension
& rSaveDim
= *pTest
;
1091 rSaveDim
.SetOrientation( static_cast< sal_uInt16
>( maFieldInfo
.GetApiOrient( EXC_SXVD_AXIS_ROWCOLPAGE
) ) );
1093 // general field info
1094 ConvertFieldInfo( rSaveDim
);
1097 if (const OUString
* pVisName
= maFieldInfo
.GetVisName())
1098 if (!pVisName
->isEmpty())
1099 rSaveDim
.SetLayoutName( *pVisName
);
1101 // subtotal function(s)
1102 XclPTSubtotalVec aSubtotalVec
;
1103 maFieldInfo
.GetSubtotals( aSubtotalVec
);
1104 if( !aSubtotalVec
.empty() )
1105 rSaveDim
.SetSubTotals( static_cast< long >( aSubtotalVec
.size() ), &aSubtotalVec
[ 0 ] );
1108 DataPilotFieldSortInfo aSortInfo
;
1109 aSortInfo
.Field
= mrPTable
.GetDataFieldName( maFieldExtInfo
.mnSortField
);
1110 aSortInfo
.IsAscending
= ::get_flag( maFieldExtInfo
.mnFlags
, EXC_SXVDEX_SORT_ASC
);
1111 aSortInfo
.Mode
= maFieldExtInfo
.GetApiSortMode();
1112 rSaveDim
.SetSortInfo( &aSortInfo
);
1115 DataPilotFieldAutoShowInfo aShowInfo
;
1116 aShowInfo
.IsEnabled
= ::get_flag( maFieldExtInfo
.mnFlags
, EXC_SXVDEX_AUTOSHOW
);
1117 aShowInfo
.ShowItemsMode
= maFieldExtInfo
.GetApiAutoShowMode();
1118 aShowInfo
.ItemCount
= maFieldExtInfo
.GetApiAutoShowCount();
1119 aShowInfo
.DataField
= mrPTable
.GetDataFieldName( maFieldExtInfo
.mnShowField
);
1120 rSaveDim
.SetAutoShowInfo( &aShowInfo
);
1123 DataPilotFieldLayoutInfo aLayoutInfo
;
1124 aLayoutInfo
.LayoutMode
= maFieldExtInfo
.GetApiLayoutMode();
1125 aLayoutInfo
.AddEmptyLines
= ::get_flag( maFieldExtInfo
.mnFlags
, EXC_SXVDEX_LAYOUT_BLANK
);
1126 rSaveDim
.SetLayoutInfo( &aLayoutInfo
);
1129 pCacheField
->ConvertGroupField( rSaveData
, mrPTable
.GetVisFieldNames() );
1131 // custom subtotal name
1132 if (maFieldExtInfo
.mpFieldTotalName
.get())
1134 OUString aSubName
= lcl_convertExcelSubtotalName(*maFieldExtInfo
.mpFieldTotalName
);
1135 rSaveDim
.SetSubtotalName(aSubName
);
1141 void XclImpPTField::ConvertFieldInfo( ScDPSaveDimension
& rSaveDim
) const
1143 rSaveDim
.SetShowEmpty( ::get_flag( maFieldExtInfo
.mnFlags
, EXC_SXVDEX_SHOWALL
) );
1144 ConvertItems( rSaveDim
);
1147 void XclImpPTField::ConvertDataField( ScDPSaveDimension
& rSaveDim
, const XclPTDataFieldInfo
& rDataInfo
) const
1150 rSaveDim
.SetOrientation( DataPilotFieldOrientation_DATA
);
1151 // general field info
1152 ConvertFieldInfo( rSaveDim
);
1153 // extended data field info
1154 ConvertDataFieldInfo( rSaveDim
, rDataInfo
);
1157 void XclImpPTField::ConvertDataFieldInfo( ScDPSaveDimension
& rSaveDim
, const XclPTDataFieldInfo
& rDataInfo
) const
1160 const OUString
* pVisName
= rDataInfo
.GetVisName();
1161 if (pVisName
&& !pVisName
->isEmpty())
1162 rSaveDim
.SetLayoutName(*pVisName
);
1164 // aggregation function
1165 rSaveDim
.SetFunction( static_cast< sal_uInt16
>( rDataInfo
.GetApiAggFunc() ) );
1167 // result field reference
1168 sal_Int32 nRefType
= rDataInfo
.GetApiRefType();
1169 DataPilotFieldReference aFieldRef
;
1170 aFieldRef
.ReferenceType
= nRefType
;
1171 const XclImpPTField
* pRefField
= mrPTable
.GetField(rDataInfo
.mnRefField
);
1174 aFieldRef
.ReferenceField
= pRefField
->GetFieldName();
1175 aFieldRef
.ReferenceItemType
= rDataInfo
.GetApiRefItemType();
1176 if (aFieldRef
.ReferenceItemType
== sheet::DataPilotFieldReferenceItemType::NAMED
)
1178 const OUString
* pRefItemName
= pRefField
->GetItemName(rDataInfo
.mnRefItem
);
1180 aFieldRef
.ReferenceItemName
= *pRefItemName
;
1184 rSaveDim
.SetReferenceValue(&aFieldRef
);
1187 void XclImpPTField::ConvertItems( ScDPSaveDimension
& rSaveDim
) const
1189 for( XclImpPTItemVec::const_iterator aIt
= maItems
.begin(), aEnd
= maItems
.end(); aIt
!= aEnd
; ++aIt
)
1190 (*aIt
)->ConvertItem( rSaveDim
);
1193 XclImpPivotTable::XclImpPivotTable( const XclImpRoot
& rRoot
) :
1194 XclImpRoot( rRoot
),
1195 maDataOrientField( *this, EXC_SXIVD_DATA
),
1200 XclImpPivotTable::~XclImpPivotTable()
1204 // cache/field access, misc. --------------------------------------------------
1206 sal_uInt16
XclImpPivotTable::GetFieldCount() const
1208 return static_cast< sal_uInt16
>( maFields
.size() );
1211 const XclImpPTField
* XclImpPivotTable::GetField( sal_uInt16 nFieldIdx
) const
1213 return (nFieldIdx
== EXC_SXIVD_DATA
) ? &maDataOrientField
:
1214 ((nFieldIdx
< maFields
.size()) ? maFields
[ nFieldIdx
].get() : nullptr);
1217 XclImpPTField
* XclImpPivotTable::GetFieldAcc( sal_uInt16 nFieldIdx
)
1219 // do not return maDataOrientField
1220 return (nFieldIdx
< maFields
.size()) ? maFields
[ nFieldIdx
].get() : nullptr;
1223 const XclImpPTField
* XclImpPivotTable::GetDataField( sal_uInt16 nDataFieldIdx
) const
1225 if( nDataFieldIdx
< maOrigDataFields
.size() )
1226 return GetField( maOrigDataFields
[ nDataFieldIdx
] );
1230 OUString
XclImpPivotTable::GetDataFieldName( sal_uInt16 nDataFieldIdx
) const
1232 if( const XclImpPTField
* pField
= GetDataField( nDataFieldIdx
) )
1233 return pField
->GetFieldName();
1237 // records --------------------------------------------------------------------
1239 void XclImpPivotTable::ReadSxview( XclImpStream
& rStrm
)
1243 GetAddressConverter().ConvertRange(
1244 maOutScRange
, maPTInfo
.maOutXclRange
, GetCurrScTab(), GetCurrScTab(), true );
1246 mxPCache
= GetPivotTableManager().GetPivotCache( maPTInfo
.mnCacheIdx
);
1247 mxCurrField
.reset();
1250 void XclImpPivotTable::ReadSxvd( XclImpStream
& rStrm
)
1252 sal_uInt16 nFieldCount
= GetFieldCount();
1253 if( nFieldCount
< EXC_PT_MAXFIELDCOUNT
)
1255 // cache index for the field is equal to the SXVD record index
1256 mxCurrField
.reset( new XclImpPTField( *this, nFieldCount
) );
1257 maFields
.push_back( mxCurrField
);
1258 mxCurrField
->ReadSxvd( rStrm
);
1259 // add visible name of new field to list of visible names
1260 maVisFieldNames
.push_back( mxCurrField
->GetVisFieldName() );
1261 OSL_ENSURE( maFields
.size() == maVisFieldNames
.size(),
1262 "XclImpPivotTable::ReadSxvd - wrong size of visible name array" );
1265 mxCurrField
.reset();
1268 void XclImpPivotTable::ReadSxvi( XclImpStream
& rStrm
)
1271 mxCurrField
->ReadSxvi( rStrm
);
1274 void XclImpPivotTable::ReadSxvdex( XclImpStream
& rStrm
)
1277 mxCurrField
->ReadSxvdex( rStrm
);
1280 void XclImpPivotTable::ReadSxivd( XclImpStream
& rStrm
)
1282 mxCurrField
.reset();
1284 // find the index vector to fill (row SXIVD doesn't exist without row fields)
1285 ScfUInt16Vec
* pFieldVec
= nullptr;
1286 if( maRowFields
.empty() && (maPTInfo
.mnRowFields
> 0) )
1287 pFieldVec
= &maRowFields
;
1288 else if( maColFields
.empty() && (maPTInfo
.mnColFields
> 0) )
1289 pFieldVec
= &maColFields
;
1291 // fill the vector from record data
1294 sal_uInt16 nSize
= ulimit_cast
< sal_uInt16
>( rStrm
.GetRecSize() / 2, EXC_PT_MAXROWCOLCOUNT
);
1295 pFieldVec
->reserve( nSize
);
1296 for( sal_uInt16 nIdx
= 0; nIdx
< nSize
; ++nIdx
)
1298 sal_uInt16 nFieldIdx
;
1299 nFieldIdx
= rStrm
.ReaduInt16();
1300 pFieldVec
->push_back( nFieldIdx
);
1302 // set orientation at special data orientation field
1303 if( nFieldIdx
== EXC_SXIVD_DATA
)
1305 sal_uInt16 nAxis
= (pFieldVec
== &maRowFields
) ? EXC_SXVD_AXIS_ROW
: EXC_SXVD_AXIS_COL
;
1306 maDataOrientField
.SetAxes( nAxis
);
1312 void XclImpPivotTable::ReadSxpi( XclImpStream
& rStrm
)
1314 mxCurrField
.reset();
1316 sal_uInt16 nSize
= ulimit_cast
< sal_uInt16
>( rStrm
.GetRecSize() / 6 );
1317 for( sal_uInt16 nEntry
= 0; nEntry
< nSize
; ++nEntry
)
1319 XclPTPageFieldInfo aPageInfo
;
1321 if( XclImpPTField
* pField
= GetFieldAcc( aPageInfo
.mnField
) )
1323 maPageFields
.push_back( aPageInfo
.mnField
);
1324 pField
->SetPageFieldInfo( aPageInfo
);
1326 GetCurrSheetDrawing().SetSkipObj( aPageInfo
.mnObjId
);
1330 void XclImpPivotTable::ReadSxdi( XclImpStream
& rStrm
)
1332 mxCurrField
.reset();
1334 XclPTDataFieldInfo aDataInfo
;
1336 if( XclImpPTField
* pField
= GetFieldAcc( aDataInfo
.mnField
) )
1338 maOrigDataFields
.push_back( aDataInfo
.mnField
);
1339 // DataPilot does not support double data fields -> add first appearance to index list only
1340 if( !pField
->HasDataFieldInfo() )
1341 maFiltDataFields
.push_back( aDataInfo
.mnField
);
1342 pField
->AddDataFieldInfo( aDataInfo
);
1346 void XclImpPivotTable::ReadSxex( XclImpStream
& rStrm
)
1348 rStrm
>> maPTExtInfo
;
1351 void XclImpPivotTable::ReadSxViewEx9( XclImpStream
& rStrm
)
1353 rStrm
>> maPTViewEx9Info
;
1356 void XclImpPivotTable::Convert()
1358 if( !mxPCache
|| !mxPCache
->IsValid() )
1361 ScDPSaveData aSaveData
;
1363 // *** global settings ***
1365 aSaveData
.SetRowGrand( ::get_flag( maPTInfo
.mnFlags
, EXC_SXVIEW_ROWGRAND
) );
1366 aSaveData
.SetColumnGrand( ::get_flag( maPTInfo
.mnFlags
, EXC_SXVIEW_COLGRAND
) );
1367 aSaveData
.SetFilterButton( false );
1368 aSaveData
.SetDrillDown( ::get_flag( maPTExtInfo
.mnFlags
, EXC_SXEX_DRILLDOWN
) );
1372 ScfUInt16Vec::const_iterator aIt
, aEnd
;
1375 for( aIt
= maRowFields
.begin(), aEnd
= maRowFields
.end(); aIt
!= aEnd
; ++aIt
)
1376 if( const XclImpPTField
* pField
= GetField( *aIt
) )
1377 pField
->ConvertRowColField( aSaveData
);
1380 for( aIt
= maColFields
.begin(), aEnd
= maColFields
.end(); aIt
!= aEnd
; ++aIt
)
1381 if( const XclImpPTField
* pField
= GetField( *aIt
) )
1382 pField
->ConvertRowColField( aSaveData
);
1385 for( aIt
= maPageFields
.begin(), aEnd
= maPageFields
.end(); aIt
!= aEnd
; ++aIt
)
1386 if( const XclImpPTField
* pField
= GetField( *aIt
) )
1387 pField
->ConvertPageField( aSaveData
);
1389 // We need to import hidden fields because hidden fields may contain
1390 // special settings for subtotals (aggregation function, filters, custom
1391 // name etc.) and members (hidden, custom name etc.).
1394 for( sal_uInt16 nField
= 0, nCount
= GetFieldCount(); nField
< nCount
; ++nField
)
1395 if( const XclImpPTField
* pField
= GetField( nField
) )
1396 if (!pField
->GetAxes())
1397 pField
->ConvertHiddenField( aSaveData
);
1400 for( aIt
= maFiltDataFields
.begin(), aEnd
= maFiltDataFields
.end(); aIt
!= aEnd
; ++aIt
)
1401 if( const XclImpPTField
* pField
= GetField( *aIt
) )
1402 pField
->ConvertDataField( aSaveData
);
1404 // *** insert into Calc document ***
1406 // create source descriptor
1407 ScSheetSourceDesc
aDesc(&GetDocRef());
1408 const OUString
& rSrcName
= mxPCache
->GetSourceRangeName();
1409 if (!rSrcName
.isEmpty())
1410 // Range name is the data source.
1411 aDesc
.SetRangeName(rSrcName
);
1413 // Normal cell range.
1414 aDesc
.SetSourceRange(mxPCache
->GetSourceRange());
1416 // adjust output range to include the page fields
1417 ScRange
aOutRange( maOutScRange
);
1418 if( !maPageFields
.empty() )
1420 SCsROW nDecRows
= ::std::min
< SCsROW
>( aOutRange
.aStart
.Row(), maPageFields
.size() + 1 );
1421 aOutRange
.aStart
.IncRow( -nDecRows
);
1424 // create the DataPilot
1425 ScDPObject
* pDPObj
= new ScDPObject( &GetDocRef() );
1426 pDPObj
->SetName( maPTInfo
.maTableName
);
1427 if (!maPTInfo
.maDataName
.isEmpty())
1428 aSaveData
.GetDataLayoutDimension()->SetLayoutName(maPTInfo
.maDataName
);
1430 if (!maPTViewEx9Info
.maGrandTotalName
.isEmpty())
1431 aSaveData
.SetGrandTotalName(maPTViewEx9Info
.maGrandTotalName
);
1433 pDPObj
->SetSaveData( aSaveData
);
1434 pDPObj
->SetSheetDesc( aDesc
);
1435 pDPObj
->SetOutRange( aOutRange
);
1436 pDPObj
->SetHeaderLayout( maPTViewEx9Info
.mnGridLayout
== 0 );
1438 GetDoc().GetDPCollection()->InsertNewTable(pDPObj
);
1441 ApplyMergeFlags(aOutRange
, aSaveData
);
1444 void XclImpPivotTable::MaybeRefresh()
1446 if (mpDPObj
&& mxPCache
->IsRefreshOnLoad())
1448 // 'refresh table on load' flag is set. Refresh the table now. Some
1449 // Excel files contain partial table output when this flag is set.
1450 ScRange aOutRange
= mpDPObj
->GetOutRange();
1451 mpDPObj
->Output(aOutRange
.aStart
);
1455 void XclImpPivotTable::ApplyMergeFlags(const ScRange
& rOutRange
, const ScDPSaveData
& rSaveData
)
1457 // Apply merge flags for various datapilot controls.
1459 ScDPOutputGeometry
aGeometry(rOutRange
, false);
1460 aGeometry
.setColumnFieldCount(maPTInfo
.mnColFields
);
1461 aGeometry
.setPageFieldCount(maPTInfo
.mnPageFields
);
1462 aGeometry
.setDataFieldCount(maPTInfo
.mnDataFields
);
1463 aGeometry
.setRowFieldCount(maPTInfo
.mnRowFields
);
1465 ScDocument
& rDoc
= GetDoc();
1467 vector
<const ScDPSaveDimension
*> aFieldDims
;
1468 vector
<ScAddress
> aFieldBtns
;
1470 aGeometry
.getPageFieldPositions(aFieldBtns
);
1471 vector
<ScAddress
>::const_iterator itr
= aFieldBtns
.begin(), itrEnd
= aFieldBtns
.end();
1472 for (; itr
!= itrEnd
; ++itr
)
1474 rDoc
.ApplyFlagsTab(itr
->Col(), itr
->Row(), itr
->Col(), itr
->Row(), itr
->Tab(), ScMF::Button
);
1476 ScMF nMFlag
= ScMF::ButtonPopup
;
1477 OUString aName
= rDoc
.GetString(itr
->Col(), itr
->Row(), itr
->Tab());
1478 if (rSaveData
.HasInvisibleMember(aName
))
1479 nMFlag
|= ScMF::HiddenMember
;
1481 rDoc
.ApplyFlagsTab(itr
->Col()+1, itr
->Row(), itr
->Col()+1, itr
->Row(), itr
->Tab(), nMFlag
);
1484 aGeometry
.getColumnFieldPositions(aFieldBtns
);
1485 rSaveData
.GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_COLUMN
, aFieldDims
);
1486 if (aFieldBtns
.size() == aFieldDims
.size())
1488 itr
= aFieldBtns
.begin();
1489 itrEnd
= aFieldBtns
.end();
1490 vector
<const ScDPSaveDimension
*>::const_iterator itDim
= aFieldDims
.begin();
1491 for (; itr
!= itrEnd
; ++itr
, ++itDim
)
1493 ScMF nMFlag
= ScMF::Button
;
1494 const ScDPSaveDimension
* pDim
= *itDim
;
1495 if (pDim
->HasInvisibleMember())
1496 nMFlag
|= ScMF::HiddenMember
;
1497 if (!pDim
->IsDataLayout())
1498 nMFlag
|= ScMF::ButtonPopup
;
1499 rDoc
.ApplyFlagsTab(itr
->Col(), itr
->Row(), itr
->Col(), itr
->Row(), itr
->Tab(), nMFlag
);
1503 aGeometry
.getRowFieldPositions(aFieldBtns
);
1504 rSaveData
.GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_ROW
, aFieldDims
);
1505 if (aFieldBtns
.size() == aFieldDims
.size())
1507 itr
= aFieldBtns
.begin();
1508 itrEnd
= aFieldBtns
.end();
1509 vector
<const ScDPSaveDimension
*>::const_iterator itDim
= aFieldDims
.begin();
1510 for (; itr
!= itrEnd
; ++itr
, ++itDim
)
1512 ScMF nMFlag
= ScMF::Button
;
1513 const ScDPSaveDimension
* pDim
= *itDim
;
1514 if (pDim
->HasInvisibleMember())
1515 nMFlag
|= ScMF::HiddenMember
;
1516 if (!pDim
->IsDataLayout())
1517 nMFlag
|= ScMF::ButtonPopup
;
1518 rDoc
.ApplyFlagsTab(itr
->Col(), itr
->Row(), itr
->Col(), itr
->Row(), itr
->Tab(), nMFlag
);
1523 XclImpPivotTableManager::XclImpPivotTableManager( const XclImpRoot
& rRoot
) :
1528 XclImpPivotTableManager::~XclImpPivotTableManager()
1532 // pivot cache records --------------------------------------------------------
1534 XclImpPivotCacheRef
XclImpPivotTableManager::GetPivotCache( sal_uInt16 nCacheIdx
)
1536 XclImpPivotCacheRef xPCache
;
1537 if( nCacheIdx
< maPCaches
.size() )
1538 xPCache
= maPCaches
[ nCacheIdx
];
1542 void XclImpPivotTableManager::ReadSxidstm( XclImpStream
& rStrm
)
1544 XclImpPivotCacheRef
xPCache( new XclImpPivotCache( GetRoot() ) );
1545 maPCaches
.push_back( xPCache
);
1546 xPCache
->ReadSxidstm( rStrm
);
1549 void XclImpPivotTableManager::ReadSxvs( XclImpStream
& rStrm
)
1551 if( !maPCaches
.empty() )
1552 maPCaches
.back()->ReadSxvs( rStrm
);
1555 void XclImpPivotTableManager::ReadDconref( XclImpStream
& rStrm
)
1557 if( !maPCaches
.empty() )
1558 maPCaches
.back()->ReadDconref( rStrm
);
1561 void XclImpPivotTableManager::ReadDConName( XclImpStream
& rStrm
)
1563 if( !maPCaches
.empty() )
1564 maPCaches
.back()->ReadDConName( rStrm
);
1567 // pivot table records --------------------------------------------------------
1569 void XclImpPivotTableManager::ReadSxview( XclImpStream
& rStrm
)
1571 XclImpPivotTableRef
xPTable( new XclImpPivotTable( GetRoot() ) );
1572 maPTables
.push_back( xPTable
);
1573 xPTable
->ReadSxview( rStrm
);
1576 void XclImpPivotTableManager::ReadSxvd( XclImpStream
& rStrm
)
1578 if( !maPTables
.empty() )
1579 maPTables
.back()->ReadSxvd( rStrm
);
1582 void XclImpPivotTableManager::ReadSxvdex( XclImpStream
& rStrm
)
1584 if( !maPTables
.empty() )
1585 maPTables
.back()->ReadSxvdex( rStrm
);
1588 void XclImpPivotTableManager::ReadSxivd( XclImpStream
& rStrm
)
1590 if( !maPTables
.empty() )
1591 maPTables
.back()->ReadSxivd( rStrm
);
1594 void XclImpPivotTableManager::ReadSxpi( XclImpStream
& rStrm
)
1596 if( !maPTables
.empty() )
1597 maPTables
.back()->ReadSxpi( rStrm
);
1600 void XclImpPivotTableManager::ReadSxdi( XclImpStream
& rStrm
)
1602 if( !maPTables
.empty() )
1603 maPTables
.back()->ReadSxdi( rStrm
);
1606 void XclImpPivotTableManager::ReadSxvi( XclImpStream
& rStrm
)
1608 if( !maPTables
.empty() )
1609 maPTables
.back()->ReadSxvi( rStrm
);
1612 void XclImpPivotTableManager::ReadSxex( XclImpStream
& rStrm
)
1614 if( !maPTables
.empty() )
1615 maPTables
.back()->ReadSxex( rStrm
);
1618 void XclImpPivotTableManager::ReadSxViewEx9( XclImpStream
& rStrm
)
1620 if( !maPTables
.empty() )
1621 maPTables
.back()->ReadSxViewEx9( rStrm
);
1624 void XclImpPivotTableManager::ReadPivotCaches( XclImpStream
& rStrm
)
1626 for( XclImpPivotCacheVec::iterator aIt
= maPCaches
.begin(), aEnd
= maPCaches
.end(); aIt
!= aEnd
; ++aIt
)
1627 (*aIt
)->ReadPivotCacheStream( rStrm
);
1630 void XclImpPivotTableManager::ConvertPivotTables()
1632 for( XclImpPivotTableVec::iterator aIt
= maPTables
.begin(), aEnd
= maPTables
.end(); aIt
!= aEnd
; ++aIt
)
1636 void XclImpPivotTableManager::MaybeRefreshPivotTables()
1638 for( XclImpPivotTableVec::iterator aIt
= maPTables
.begin(), aEnd
= maPTables
.end(); aIt
!= aEnd
; ++aIt
)
1639 (*aIt
)->MaybeRefresh();
1642 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */