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