LCOV - code coverage report
Current view: top level - libreoffice/sc/source/filter/excel - xepivot.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 26 918 2.8 %
Date: 2012-12-27 Functions: 12 119 10.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      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 .
      18             :  */
      19             : 
      20             : #include "xepivot.hxx"
      21             : #include <com/sun/star/sheet/DataPilotFieldSortInfo.hpp>
      22             : #include <com/sun/star/sheet/DataPilotFieldAutoShowInfo.hpp>
      23             : #include <com/sun/star/sheet/DataPilotFieldLayoutInfo.hpp>
      24             : #include <com/sun/star/sheet/DataPilotFieldReference.hpp>
      25             : #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
      26             : 
      27             : #include <algorithm>
      28             : #include <math.h>
      29             : 
      30             : #include <rtl/math.hxx>
      31             : #include <tools/date.hxx>
      32             : #include <svl/zformat.hxx>
      33             : #include <sot/storage.hxx>
      34             : #include "document.hxx"
      35             : #include "dpobject.hxx"
      36             : #include "dpsave.hxx"
      37             : #include "dpdimsave.hxx"
      38             : #include "dpshttab.hxx"
      39             : #include "globstr.hrc"
      40             : #include "fapihelper.hxx"
      41             : #include "xestring.hxx"
      42             : #include "xelink.hxx"
      43             : #include "dputil.hxx"
      44             : 
      45             : using namespace ::oox;
      46             : 
      47             : using ::com::sun::star::sheet::DataPilotFieldOrientation;
      48             : using ::com::sun::star::sheet::DataPilotFieldOrientation_HIDDEN;
      49             : using ::com::sun::star::sheet::DataPilotFieldOrientation_ROW;
      50             : using ::com::sun::star::sheet::DataPilotFieldOrientation_COLUMN;
      51             : using ::com::sun::star::sheet::DataPilotFieldOrientation_PAGE;
      52             : using ::com::sun::star::sheet::DataPilotFieldOrientation_DATA;
      53             : using ::com::sun::star::sheet::GeneralFunction;
      54             : using ::com::sun::star::sheet::DataPilotFieldSortInfo;
      55             : using ::com::sun::star::sheet::DataPilotFieldAutoShowInfo;
      56             : using ::com::sun::star::sheet::DataPilotFieldLayoutInfo;
      57             : using ::com::sun::star::sheet::DataPilotFieldReference;
      58             : using ::rtl::OUString;
      59             : 
      60             : using ::rtl::OString;
      61             : using ::rtl::OUString;
      62             : using ::rtl::OUStringBuffer;
      63             : 
      64             : // ============================================================================
      65             : // Pivot cache
      66             : // ============================================================================
      67             : 
      68             : namespace {
      69             : 
      70             : // constants to track occurrence of specific data types
      71             : const sal_uInt16 EXC_PCITEM_DATA_STRING     = 0x0001;   /// String, empty, boolean, error.
      72             : const sal_uInt16 EXC_PCITEM_DATA_DOUBLE     = 0x0002;   /// Double with fraction.
      73             : const sal_uInt16 EXC_PCITEM_DATA_INTEGER    = 0x0004;   /// Integer, double without fraction.
      74             : const sal_uInt16 EXC_PCITEM_DATA_DATE       = 0x0008;   /// Date, time, date/time.
      75             : 
      76             : /** Maps a bitfield consisting of EXC_PCITEM_DATA_* flags above to SXFIELD data type bitfield. */
      77             : static const sal_uInt16 spnPCItemFlags[] =
      78             : {                               // STR DBL INT DAT
      79             :     EXC_SXFIELD_DATA_NONE,      //
      80             :     EXC_SXFIELD_DATA_STR,       //  x
      81             :     EXC_SXFIELD_DATA_INT,       //      x
      82             :     EXC_SXFIELD_DATA_STR_INT,   //  x   x
      83             :     EXC_SXFIELD_DATA_DBL,       //          x
      84             :     EXC_SXFIELD_DATA_STR_DBL,   //  x       x
      85             :     EXC_SXFIELD_DATA_INT,       //      x   x
      86             :     EXC_SXFIELD_DATA_STR_INT,   //  x   x   x
      87             :     EXC_SXFIELD_DATA_DATE,      //              x
      88             :     EXC_SXFIELD_DATA_DATE_STR,  //  x           x
      89             :     EXC_SXFIELD_DATA_DATE_NUM,  //      x       x
      90             :     EXC_SXFIELD_DATA_DATE_STR,  //  x   x       x
      91             :     EXC_SXFIELD_DATA_DATE_NUM,  //          x   x
      92             :     EXC_SXFIELD_DATA_DATE_STR,  //  x       x   x
      93             :     EXC_SXFIELD_DATA_DATE_NUM,  //      x   x   x
      94             :     EXC_SXFIELD_DATA_DATE_STR   //  x   x   x   x
      95             : };
      96             : 
      97             : } // namespace
      98             : 
      99             : // ----------------------------------------------------------------------------
     100             : 
     101           0 : XclExpPCItem::XclExpPCItem( const String& rText ) :
     102           0 :     XclExpRecord( (rText.Len() > 0) ? EXC_ID_SXSTRING : EXC_ID_SXEMPTY, 0 ),
     103           0 :     mnTypeFlag( EXC_PCITEM_DATA_STRING )
     104             : {
     105           0 :     if( rText.Len() )
     106           0 :         SetText( rText );
     107             :     else
     108           0 :         SetEmpty();
     109           0 : }
     110             : 
     111           0 : XclExpPCItem::XclExpPCItem( double fValue ) :
     112           0 :     XclExpRecord( EXC_ID_SXDOUBLE, 8 )
     113             : {
     114           0 :     SetDouble( fValue );
     115           0 :     mnTypeFlag = (fValue - floor( fValue ) == 0.0) ?
     116           0 :         EXC_PCITEM_DATA_INTEGER : EXC_PCITEM_DATA_DOUBLE;
     117           0 : }
     118             : 
     119           0 : XclExpPCItem::XclExpPCItem( const DateTime& rDateTime ) :
     120           0 :     XclExpRecord( EXC_ID_SXDATETIME, 8 )
     121             : {
     122           0 :     SetDateTime( rDateTime );
     123           0 :     mnTypeFlag = EXC_PCITEM_DATA_DATE;
     124           0 : }
     125             : 
     126           0 : XclExpPCItem::XclExpPCItem( sal_Int16 nValue ) :
     127             :     XclExpRecord( EXC_ID_SXINTEGER, 2 ),
     128           0 :     mnTypeFlag( EXC_PCITEM_DATA_INTEGER )
     129             : {
     130           0 :     SetInteger( nValue );
     131           0 : }
     132             : 
     133           0 : XclExpPCItem::XclExpPCItem( bool bValue ) :
     134             :     XclExpRecord( EXC_ID_SXBOOLEAN, 2 ),
     135           0 :     mnTypeFlag( EXC_PCITEM_DATA_STRING )
     136             : {
     137           0 :     SetBool( bValue );
     138           0 : }
     139             : 
     140             : // ----------------------------------------------------------------------------
     141             : 
     142           0 : bool XclExpPCItem::EqualsText( const rtl::OUString& rText ) const
     143             : {
     144           0 :     return rText.isEmpty() ? IsEmpty() : (GetText() && (*GetText() == rText));
     145             : }
     146             : 
     147           0 : bool XclExpPCItem::EqualsDouble( double fValue ) const
     148             : {
     149           0 :     return GetDouble() && (*GetDouble() == fValue);
     150             : }
     151             : 
     152           0 : bool XclExpPCItem::EqualsDateTime( const DateTime& rDateTime ) const
     153             : {
     154           0 :     return GetDateTime() && (*GetDateTime() == rDateTime);
     155             : }
     156             : 
     157           0 : bool XclExpPCItem::EqualsBool( bool bValue ) const
     158             : {
     159           0 :     return GetBool() && (*GetBool() == bValue);
     160             : }
     161             : 
     162             : // ----------------------------------------------------------------------------
     163             : 
     164           0 : void XclExpPCItem::WriteBody( XclExpStream& rStrm )
     165             : {
     166           0 :     if( const rtl::OUString* pText = GetText() )
     167             :     {
     168           0 :         rStrm << XclExpString( *pText );
     169             :     }
     170           0 :     else if( const double* pfValue = GetDouble() )
     171             :     {
     172           0 :         rStrm << *pfValue;
     173             :     }
     174           0 :     else if( const sal_Int16* pnValue = GetInteger() )
     175             :     {
     176           0 :         rStrm << *pnValue;
     177             :     }
     178           0 :     else if( const DateTime* pDateTime = GetDateTime() )
     179             :     {
     180           0 :         sal_uInt16 nYear = static_cast< sal_uInt16 >( pDateTime->GetYear() );
     181           0 :         sal_uInt16 nMonth = static_cast< sal_uInt16 >( pDateTime->GetMonth() );
     182           0 :         sal_uInt8 nDay = static_cast< sal_uInt8 >( pDateTime->GetDay() );
     183           0 :         sal_uInt8 nHour = static_cast< sal_uInt8 >( pDateTime->GetHour() );
     184           0 :         sal_uInt8 nMin = static_cast< sal_uInt8 >( pDateTime->GetMin() );
     185           0 :         sal_uInt8 nSec = static_cast< sal_uInt8 >( pDateTime->GetSec() );
     186           0 :         if( nYear < 1900 ) { nYear = 1900; nMonth = 1; nDay = 0; }
     187           0 :         rStrm << nYear << nMonth << nDay << nHour << nMin << nSec;
     188             :     }
     189           0 :     else if( const bool* pbValue = GetBool() )
     190             :     {
     191           0 :         rStrm << static_cast< sal_uInt16 >( *pbValue ? 1 : 0 );
     192             :     }
     193             :     else
     194             :     {
     195             :         // nothing to do for SXEMPTY
     196             :         OSL_ENSURE( IsEmpty(), "XclExpPCItem::WriteBody - no data found" );
     197             :     }
     198           0 : }
     199             : 
     200             : // ============================================================================
     201             : 
     202           0 : XclExpPCField::XclExpPCField(
     203             :         const XclExpRoot& rRoot, const XclExpPivotCache& rPCache, sal_uInt16 nFieldIdx,
     204             :         const ScDPObject& rDPObj, const ScRange& rRange ) :
     205             :     XclExpRecord( EXC_ID_SXFIELD ),
     206             :     XclPCField( EXC_PCFIELD_STANDARD, nFieldIdx ),
     207             :     XclExpRoot( rRoot ),
     208             :     mrPCache( rPCache ),
     209           0 :     mnTypeFlags( 0 )
     210             : {
     211             :     // general settings for the standard field, insert all items from source range
     212           0 :     InitStandardField( rRange );
     213             : 
     214             :     // add special settings for inplace numeric grouping
     215           0 :     if( const ScDPSaveData* pSaveData = rDPObj.GetSaveData() )
     216             :     {
     217           0 :         if( const ScDPDimensionSaveData* pSaveDimData = pSaveData->GetExistingDimensionData() )
     218             :         {
     219           0 :             if( const ScDPSaveNumGroupDimension* pNumGroupDim = pSaveDimData->GetNumGroupDim( GetFieldName() ) )
     220             :             {
     221           0 :                 const ScDPNumGroupInfo& rNumInfo = pNumGroupDim->GetInfo();
     222           0 :                 const ScDPNumGroupInfo& rDateInfo = pNumGroupDim->GetDateInfo();
     223             :                 OSL_ENSURE( !rNumInfo.mbEnable || !rDateInfo.mbEnable,
     224             :                     "XclExpPCField::XclExpPCField - numeric and date grouping enabled" );
     225             : 
     226           0 :                 if( rNumInfo.mbEnable )
     227           0 :                     InitNumGroupField( rDPObj, rNumInfo );
     228           0 :                 else if( rDateInfo.mbEnable )
     229           0 :                     InitDateGroupField( rDPObj, rDateInfo, pNumGroupDim->GetDatePart() );
     230             :             }
     231             :         }
     232             :     }
     233             : 
     234             :     // final settings (flags, item numbers)
     235           0 :     Finalize();
     236           0 : }
     237             : 
     238           0 : XclExpPCField::XclExpPCField(
     239             :         const XclExpRoot& rRoot, const XclExpPivotCache& rPCache, sal_uInt16 nFieldIdx,
     240             :         const ScDPObject& rDPObj, const ScDPSaveGroupDimension& rGroupDim, const XclExpPCField& rBaseField ) :
     241             :     XclExpRecord( EXC_ID_SXFIELD ),
     242             :     XclPCField( EXC_PCFIELD_STDGROUP, nFieldIdx ),
     243             :     XclExpRoot( rRoot ),
     244             :     mrPCache( rPCache ),
     245           0 :     mnTypeFlags( 0 )
     246             : {
     247             :     // add base field info (always using first base field, not predecessor of this field) ***
     248             :     OSL_ENSURE( rBaseField.GetFieldName() == rGroupDim.GetSourceDimName(),
     249             :         "XclExpPCField::FillFromGroup - wrong base cache field" );
     250           0 :     maFieldInfo.maName = rGroupDim.GetGroupDimName();
     251           0 :     maFieldInfo.mnGroupBase = rBaseField.GetFieldIndex();
     252             : 
     253             :     // add standard group info or date group info
     254           0 :     const ScDPNumGroupInfo& rDateInfo = rGroupDim.GetDateInfo();
     255           0 :     if( rDateInfo.mbEnable && (rGroupDim.GetDatePart() != 0) )
     256           0 :         InitDateGroupField( rDPObj, rDateInfo, rGroupDim.GetDatePart() );
     257             :     else
     258           0 :         InitStdGroupField( rBaseField, rGroupDim );
     259             : 
     260             :     // final settings (flags, item numbers)
     261           0 :     Finalize();
     262           0 : }
     263             : 
     264           0 : XclExpPCField::~XclExpPCField()
     265             : {
     266           0 : }
     267             : 
     268           0 : void XclExpPCField::SetGroupChildField( const XclExpPCField& rChildField )
     269             : {
     270             :     OSL_ENSURE( !::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_HASCHILD ),
     271             :         "XclExpPCField::SetGroupChildIndex - field already has a grouping child field" );
     272           0 :     ::set_flag( maFieldInfo.mnFlags, EXC_SXFIELD_HASCHILD );
     273           0 :     maFieldInfo.mnGroupChild = rChildField.GetFieldIndex();
     274           0 : }
     275             : 
     276           0 : sal_uInt16 XclExpPCField::GetItemCount() const
     277             : {
     278           0 :     return static_cast< sal_uInt16 >( GetVisItemList().GetSize() );
     279             : }
     280             : 
     281           0 : const XclExpPCItem* XclExpPCField::GetItem( sal_uInt16 nItemIdx ) const
     282             : {
     283           0 :     return GetVisItemList().GetRecord( nItemIdx ).get();
     284             : }
     285             : 
     286           0 : sal_uInt16 XclExpPCField::GetItemIndex( const rtl::OUString& rItemName ) const
     287             : {
     288           0 :     const XclExpPCItemList& rItemList = GetVisItemList();
     289           0 :     for( size_t nPos = 0, nSize = rItemList.GetSize(); nPos < nSize; ++nPos )
     290           0 :         if( rItemList.GetRecord( nPos )->ConvertToText() == rItemName )
     291           0 :             return static_cast< sal_uInt16 >( nPos );
     292           0 :     return EXC_PC_NOITEM;
     293             : }
     294             : 
     295           0 : sal_Size XclExpPCField::GetIndexSize() const
     296             : {
     297           0 :     return Has16BitIndexes() ? 2 : 1;
     298             : }
     299             : 
     300           0 : void XclExpPCField::WriteIndex( XclExpStream& rStrm, sal_uInt32 nSrcRow ) const
     301             : {
     302             :     // only standard fields write item indexes
     303           0 :     if( nSrcRow < maIndexVec.size() )
     304             :     {
     305           0 :         sal_uInt16 nIndex = maIndexVec[ nSrcRow ];
     306           0 :         if( Has16BitIndexes() )
     307           0 :             rStrm << nIndex;
     308             :         else
     309           0 :             rStrm << static_cast< sal_uInt8 >( nIndex );
     310             :     }
     311           0 : }
     312             : 
     313           0 : void XclExpPCField::Save( XclExpStream& rStrm )
     314             : {
     315             :     OSL_ENSURE( IsSupportedField(), "XclExpPCField::Save - unknown field type" );
     316             :     // SXFIELD
     317           0 :     XclExpRecord::Save( rStrm );
     318             :     // SXFDBTYPE
     319           0 :     XclExpUInt16Record( EXC_ID_SXFDBTYPE, EXC_SXFDBTYPE_DEFAULT ).Save( rStrm );
     320             :     // list of grouping items
     321           0 :     maGroupItemList.Save( rStrm );
     322             :     // SXGROUPINFO
     323           0 :     WriteSxgroupinfo( rStrm );
     324             :     // SXNUMGROUP and additional grouping items (grouping limit settings)
     325           0 :     WriteSxnumgroup( rStrm );
     326             :     // list of original items
     327           0 :     maOrigItemList.Save( rStrm );
     328           0 : }
     329             : 
     330             : // private --------------------------------------------------------------------
     331             : 
     332           0 : const XclExpPCField::XclExpPCItemList& XclExpPCField::GetVisItemList() const
     333             : {
     334             :     OSL_ENSURE( IsStandardField() == maGroupItemList.IsEmpty(),
     335             :         "XclExpPCField::GetVisItemList - unexpected additional items in standard field" );
     336           0 :     return IsStandardField() ? maOrigItemList : maGroupItemList;
     337             : }
     338             : 
     339           0 : void XclExpPCField::InitStandardField( const ScRange& rRange )
     340             : {
     341             :     OSL_ENSURE( IsStandardField(), "XclExpPCField::InitStandardField - only for standard fields" );
     342             :     OSL_ENSURE( rRange.aStart.Col() == rRange.aEnd.Col(), "XclExpPCField::InitStandardField - cell range with multiple columns" );
     343             : 
     344           0 :     ScDocument& rDoc = GetDoc();
     345           0 :     SvNumberFormatter& rFormatter = GetFormatter();
     346             : 
     347             :     // field name is in top cell of the range
     348           0 :     ScAddress aPos( rRange.aStart );
     349           0 :     rDoc.GetString( aPos.Col(), aPos.Row(), aPos.Tab(), maFieldInfo.maName );
     350             :     // #i76047# maximum field name length in pivot cache is 255
     351           0 :     if (maFieldInfo.maName.getLength() > EXC_PC_MAXSTRLEN)
     352           0 :         maFieldInfo.maName = maFieldInfo.maName.copy(0, EXC_PC_MAXSTRLEN);
     353             : 
     354             :     // loop over all cells, create pivot cache items
     355           0 :     for( aPos.IncRow(); (aPos.Row() <= rRange.aEnd.Row()) && (maOrigItemList.GetSize() < EXC_PC_MAXITEMCOUNT); aPos.IncRow() )
     356             :     {
     357           0 :         if( rDoc.HasValueData( aPos.Col(), aPos.Row(), aPos.Tab() ) )
     358             :         {
     359           0 :             double fValue = rDoc.GetValue( aPos );
     360           0 :             short nFmtType = rFormatter.GetType( rDoc.GetNumberFormat( aPos ) );
     361           0 :             if( nFmtType == NUMBERFORMAT_LOGICAL )
     362           0 :                 InsertOrigBoolItem( fValue != 0 );
     363           0 :             else if( nFmtType & NUMBERFORMAT_DATETIME )
     364           0 :                 InsertOrigDateTimeItem( GetDateTimeFromDouble( ::std::max( fValue, 0.0 ) ) );
     365             :             else
     366           0 :                 InsertOrigDoubleItem( fValue );
     367             :         }
     368             :         else
     369             :         {
     370           0 :             String aText;
     371           0 :             rDoc.GetString( aPos.Col(), aPos.Row(), aPos.Tab(), aText );
     372           0 :             InsertOrigTextItem( aText );
     373             :         }
     374             :     }
     375           0 : }
     376             : 
     377           0 : void XclExpPCField::InitStdGroupField( const XclExpPCField& rBaseField, const ScDPSaveGroupDimension& rGroupDim )
     378             : {
     379             :     OSL_ENSURE( IsGroupField(), "XclExpPCField::InitStdGroupField - only for standard grouping fields" );
     380             : 
     381           0 :     maFieldInfo.mnBaseItems = rBaseField.GetItemCount();
     382           0 :     maGroupOrder.resize( maFieldInfo.mnBaseItems, EXC_PC_NOITEM );
     383             : 
     384             :     // loop over all groups of this field
     385           0 :     for( long nGroupIdx = 0, nGroupCount = rGroupDim.GetGroupCount(); nGroupIdx < nGroupCount; ++nGroupIdx )
     386             :     {
     387           0 :         if( const ScDPSaveGroupItem* pGroupItem = rGroupDim.GetGroupByIndex( nGroupIdx ) )
     388             :         {
     389             :             // the index of the new item containing the grouping name
     390           0 :             sal_uInt16 nGroupItemIdx = EXC_PC_NOITEM;
     391             :             // loop over all elements of one group
     392           0 :             for( size_t nElemIdx = 0, nElemCount = pGroupItem->GetElementCount(); nElemIdx < nElemCount; ++nElemIdx )
     393             :             {
     394           0 :                 if (const rtl::OUString* pElemName = pGroupItem->GetElementByIndex(nElemIdx))
     395             :                 {
     396             :                     // try to find the item that is part of the group in the base field
     397           0 :                     sal_uInt16 nBaseItemIdx = rBaseField.GetItemIndex( *pElemName );
     398           0 :                     if( nBaseItemIdx < maFieldInfo.mnBaseItems )
     399             :                     {
     400             :                         // add group name item only if there are any valid base items
     401           0 :                         if( nGroupItemIdx == EXC_PC_NOITEM )
     402           0 :                             nGroupItemIdx = InsertGroupItem( new XclExpPCItem( pGroupItem->GetGroupName() ) );
     403           0 :                         maGroupOrder[ nBaseItemIdx ] = nGroupItemIdx;
     404             :                     }
     405             :                 }
     406             :             }
     407             :         }
     408             :     }
     409             : 
     410             :     // add items and base item indexes of all ungrouped elements
     411           0 :     for( sal_uInt16 nBaseItemIdx = 0; nBaseItemIdx < maFieldInfo.mnBaseItems; ++nBaseItemIdx )
     412             :         // items that are not part of a group still have the EXC_PC_NOITEM entry
     413           0 :         if( maGroupOrder[ nBaseItemIdx ] == EXC_PC_NOITEM )
     414             :             // try to find the base item
     415           0 :             if( const XclExpPCItem* pBaseItem = rBaseField.GetItem( nBaseItemIdx ) )
     416             :                 // create a clone of the base item, insert its index into item order list
     417           0 :                 maGroupOrder[ nBaseItemIdx ] = InsertGroupItem( new XclExpPCItem( *pBaseItem ) );
     418           0 : }
     419             : 
     420           0 : void XclExpPCField::InitNumGroupField( const ScDPObject& rDPObj, const ScDPNumGroupInfo& rNumInfo )
     421             : {
     422             :     OSL_ENSURE( IsStandardField(), "XclExpPCField::InitNumGroupField - only for standard fields" );
     423             :     OSL_ENSURE( rNumInfo.mbEnable, "XclExpPCField::InitNumGroupField - numeric grouping not enabled" );
     424             : 
     425             :     // new field type, date type, limit settings (min/max/step/auto)
     426           0 :     if( rNumInfo.mbDateValues )
     427             :     {
     428             :         // special case: group by days with step count
     429           0 :         meFieldType = EXC_PCFIELD_DATEGROUP;
     430           0 :         maNumGroupInfo.SetScDateType( com::sun::star::sheet::DataPilotFieldGroupBy::DAYS );
     431           0 :         SetDateGroupLimit( rNumInfo, true );
     432             :     }
     433             :     else
     434             :     {
     435           0 :         meFieldType = EXC_PCFIELD_NUMGROUP;
     436           0 :         maNumGroupInfo.SetNumType();
     437           0 :         SetNumGroupLimit( rNumInfo );
     438             :     }
     439             : 
     440             :     // generate visible items
     441           0 :     InsertNumDateGroupItems( rDPObj, rNumInfo );
     442           0 : }
     443             : 
     444           0 : void XclExpPCField::InitDateGroupField( const ScDPObject& rDPObj, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nDatePart )
     445             : {
     446             :     OSL_ENSURE( IsStandardField() || IsStdGroupField(), "XclExpPCField::InitDateGroupField - only for standard fields" );
     447             :     OSL_ENSURE( rDateInfo.mbEnable, "XclExpPCField::InitDateGroupField - date grouping not enabled" );
     448             : 
     449             :     // new field type
     450           0 :     meFieldType = IsStandardField() ? EXC_PCFIELD_DATEGROUP : EXC_PCFIELD_DATECHILD;
     451             : 
     452             :     // date type, limit settings (min/max/step/auto)
     453           0 :     maNumGroupInfo.SetScDateType( nDatePart );
     454           0 :     SetDateGroupLimit( rDateInfo, false );
     455             : 
     456             :     // generate visible items
     457           0 :     InsertNumDateGroupItems( rDPObj, rDateInfo, nDatePart );
     458           0 : }
     459             : 
     460           0 : void XclExpPCField::InsertItemArrayIndex( size_t nListPos )
     461             : {
     462             :     OSL_ENSURE( IsStandardField(), "XclExpPCField::InsertItemArrayIndex - only for standard fields" );
     463           0 :     maIndexVec.push_back( static_cast< sal_uInt16 >( nListPos ) );
     464           0 : }
     465             : 
     466           0 : void XclExpPCField::InsertOrigItem( XclExpPCItem* pNewItem )
     467             : {
     468           0 :     size_t nItemIdx = maOrigItemList.GetSize();
     469           0 :     maOrigItemList.AppendNewRecord( pNewItem );
     470           0 :     InsertItemArrayIndex( nItemIdx );
     471           0 :     mnTypeFlags |= pNewItem->GetTypeFlag();
     472           0 : }
     473             : 
     474           0 : void XclExpPCField::InsertOrigTextItem( const String& rText )
     475             : {
     476           0 :     size_t nPos = 0;
     477           0 :     bool bFound = false;
     478             :     // #i76047# maximum item text length in pivot cache is 255
     479           0 :     String aShortText( rText, 0, ::std::min( rText.Len(), EXC_PC_MAXSTRLEN ) );
     480           0 :     for( size_t nSize = maOrigItemList.GetSize(); !bFound && (nPos < nSize); ++nPos )
     481           0 :         if( (bFound = maOrigItemList.GetRecord( nPos )->EqualsText( aShortText )) == true )
     482           0 :             InsertItemArrayIndex( nPos );
     483           0 :     if( !bFound )
     484           0 :         InsertOrigItem( new XclExpPCItem( aShortText ) );
     485           0 : }
     486             : 
     487           0 : void XclExpPCField::InsertOrigDoubleItem( double fValue )
     488             : {
     489           0 :     size_t nPos = 0;
     490           0 :     bool bFound = false;
     491           0 :     for( size_t nSize = maOrigItemList.GetSize(); !bFound && (nPos < nSize); ++nPos )
     492           0 :         if( (bFound = maOrigItemList.GetRecord( nPos )->EqualsDouble( fValue )) == true )
     493           0 :             InsertItemArrayIndex( nPos );
     494           0 :     if( !bFound )
     495           0 :         InsertOrigItem( new XclExpPCItem( fValue ) );
     496           0 : }
     497             : 
     498           0 : void XclExpPCField::InsertOrigDateTimeItem( const DateTime& rDateTime )
     499             : {
     500           0 :     size_t nPos = 0;
     501           0 :     bool bFound = false;
     502           0 :     for( size_t nSize = maOrigItemList.GetSize(); !bFound && (nPos < nSize); ++nPos )
     503           0 :         if( (bFound = maOrigItemList.GetRecord( nPos )->EqualsDateTime( rDateTime )) == true )
     504           0 :             InsertItemArrayIndex( nPos );
     505           0 :     if( !bFound )
     506           0 :         InsertOrigItem( new XclExpPCItem( rDateTime ) );
     507           0 : }
     508             : 
     509           0 : void XclExpPCField::InsertOrigBoolItem( bool bValue )
     510             : {
     511           0 :     size_t nPos = 0;
     512           0 :     bool bFound = false;
     513           0 :     for( size_t nSize = maOrigItemList.GetSize(); !bFound && (nPos < nSize); ++nPos )
     514           0 :         if( (bFound = maOrigItemList.GetRecord( nPos )->EqualsBool( bValue )) == true )
     515           0 :             InsertItemArrayIndex( nPos );
     516           0 :     if( !bFound )
     517           0 :         InsertOrigItem( new XclExpPCItem( bValue ) );
     518           0 : }
     519             : 
     520           0 : sal_uInt16 XclExpPCField::InsertGroupItem( XclExpPCItem* pNewItem )
     521             : {
     522           0 :     maGroupItemList.AppendNewRecord( pNewItem );
     523           0 :     return static_cast< sal_uInt16 >( maGroupItemList.GetSize() - 1 );
     524             : }
     525             : 
     526           0 : void XclExpPCField::InsertNumDateGroupItems( const ScDPObject& rDPObj, const ScDPNumGroupInfo& rNumInfo, sal_Int32 nDatePart )
     527             : {
     528             :     OSL_ENSURE( rDPObj.GetSheetDesc(), "XclExpPCField::InsertNumDateGroupItems - cannot generate element list" );
     529           0 :     if( const ScSheetSourceDesc* pSrcDesc = rDPObj.GetSheetDesc() )
     530             :     {
     531             :         // get the string collection with original source elements
     532           0 :         const ScDPSaveData* pSaveData = rDPObj.GetSaveData();
     533           0 :         const ScDPDimensionSaveData* pDimData = NULL;
     534           0 :         if (pSaveData)
     535           0 :             pDimData = pSaveData->GetExistingDimensionData();
     536             : 
     537           0 :         const ScDPCache* pCache = pSrcDesc->CreateCache(pDimData);
     538           0 :         if (!pCache)
     539           0 :             return;
     540             : 
     541           0 :         ScSheetDPData aDPData(GetDocPtr(), *pSrcDesc, *pCache);
     542           0 :         long nDim = GetFieldIndex();
     543             :         // get the string collection with generated grouping elements
     544           0 :         ScDPNumGroupDimension aTmpDim( rNumInfo );
     545           0 :         if( nDatePart != 0 )
     546           0 :             aTmpDim.SetDateDimension();
     547             :         const std::vector<SCROW>& aMemberIds = aTmpDim.GetNumEntries(
     548           0 :             static_cast<SCCOL>(nDim), pCache);
     549           0 :         for ( size_t  nIdx = 0 ; nIdx < aMemberIds.size(); nIdx++ )
     550             :         {
     551           0 :             const ScDPItemData* pData = aDPData.GetMemberById(nDim , aMemberIds[nIdx]);
     552           0 :             if ( pData )
     553             :             {
     554           0 :                 rtl::OUString aStr = pCache->GetFormattedString(nDim, *pData);
     555           0 :                 InsertGroupItem(new XclExpPCItem(aStr));
     556             :             }
     557           0 :         }
     558             :     }
     559             : }
     560             : 
     561           0 : void XclExpPCField::SetNumGroupLimit( const ScDPNumGroupInfo& rNumInfo )
     562             : {
     563           0 :     ::set_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMIN, rNumInfo.mbAutoStart );
     564           0 :     ::set_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMAX, rNumInfo.mbAutoEnd );
     565           0 :     maNumGroupLimits.AppendNewRecord( new XclExpPCItem( rNumInfo.mfStart ) );
     566           0 :     maNumGroupLimits.AppendNewRecord( new XclExpPCItem( rNumInfo.mfEnd ) );
     567           0 :     maNumGroupLimits.AppendNewRecord( new XclExpPCItem( rNumInfo.mfStep ) );
     568           0 : }
     569             : 
     570           0 : void XclExpPCField::SetDateGroupLimit( const ScDPNumGroupInfo& rDateInfo, bool bUseStep )
     571             : {
     572           0 :     ::set_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMIN, rDateInfo.mbAutoStart );
     573           0 :     ::set_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMAX, rDateInfo.mbAutoEnd );
     574           0 :     maNumGroupLimits.AppendNewRecord( new XclExpPCItem( GetDateTimeFromDouble( rDateInfo.mfStart ) ) );
     575           0 :     maNumGroupLimits.AppendNewRecord( new XclExpPCItem( GetDateTimeFromDouble( rDateInfo.mfEnd ) ) );
     576           0 :     sal_Int16 nStep = bUseStep ? limit_cast< sal_Int16 >( rDateInfo.mfStep, 1, SAL_MAX_INT16 ) : 1;
     577           0 :     maNumGroupLimits.AppendNewRecord( new XclExpPCItem( nStep ) );
     578           0 : }
     579             : 
     580           0 : void XclExpPCField::Finalize()
     581             : {
     582             :     // flags
     583           0 :     ::set_flag( maFieldInfo.mnFlags, EXC_SXFIELD_HASITEMS, !GetVisItemList().IsEmpty() );
     584             :     // Excel writes long indexes even for 0x0100 items (indexes from 0x00 to 0xFF)
     585           0 :     ::set_flag( maFieldInfo.mnFlags, EXC_SXFIELD_16BIT, maOrigItemList.GetSize() >= 0x0100 );
     586           0 :     ::set_flag( maFieldInfo.mnFlags, EXC_SXFIELD_NUMGROUP, IsNumGroupField() || IsDateGroupField() );
     587             :     /*  mnTypeFlags is updated in all Insert***Item() functions. Now the flags
     588             :         for the current combination of item types is added to the flags. */
     589           0 :     ::set_flag( maFieldInfo.mnFlags, spnPCItemFlags[ mnTypeFlags ] );
     590             : 
     591             :     // item count fields
     592           0 :     maFieldInfo.mnVisItems = static_cast< sal_uInt16 >( GetVisItemList().GetSize() );
     593           0 :     maFieldInfo.mnGroupItems = static_cast< sal_uInt16 >( maGroupItemList.GetSize() );
     594             :     // maFieldInfo.mnBaseItems set in InitStdGroupField()
     595           0 :     maFieldInfo.mnOrigItems = static_cast< sal_uInt16 >( maOrigItemList.GetSize() );
     596           0 : }
     597             : 
     598           0 : void XclExpPCField::WriteSxnumgroup( XclExpStream& rStrm )
     599             : {
     600           0 :     if( IsNumGroupField() || IsDateGroupField() )
     601             :     {
     602             :         // SXNUMGROUP record
     603           0 :         rStrm.StartRecord( EXC_ID_SXNUMGROUP, 2 );
     604           0 :         rStrm << maNumGroupInfo;
     605           0 :         rStrm.EndRecord();
     606             : 
     607             :         // limits (min/max/step) for numeric grouping
     608             :         OSL_ENSURE( maNumGroupLimits.GetSize() == 3,
     609             :             "XclExpPCField::WriteSxnumgroup - missing numeric grouping limits" );
     610           0 :         maNumGroupLimits.Save( rStrm );
     611             :     }
     612           0 : }
     613             : 
     614           0 : void XclExpPCField::WriteSxgroupinfo( XclExpStream& rStrm )
     615             : {
     616             :     OSL_ENSURE( IsStdGroupField() != maGroupOrder.empty(),
     617             :         "XclExpPCField::WriteSxgroupinfo - missing grouping info" );
     618           0 :     if( IsStdGroupField() && !maGroupOrder.empty() )
     619             :     {
     620           0 :         rStrm.StartRecord( EXC_ID_SXGROUPINFO, 2 * maGroupOrder.size() );
     621           0 :         for( ScfUInt16Vec::const_iterator aIt = maGroupOrder.begin(), aEnd = maGroupOrder.end(); aIt != aEnd; ++aIt )
     622           0 :             rStrm << *aIt;
     623           0 :         rStrm.EndRecord();
     624             :     }
     625           0 : }
     626             : 
     627           0 : void XclExpPCField::WriteBody( XclExpStream& rStrm )
     628             : {
     629           0 :     rStrm << maFieldInfo;
     630           0 : }
     631             : 
     632             : // ============================================================================
     633             : 
     634           0 : XclExpPivotCache::XclExpPivotCache( const XclExpRoot& rRoot, const ScDPObject& rDPObj, sal_uInt16 nListIdx ) :
     635             :     XclExpRoot( rRoot ),
     636             :     mnListIdx( nListIdx ),
     637           0 :     mbValid( false )
     638             : {
     639             :     // source from sheet only
     640           0 :     if( const ScSheetSourceDesc* pSrcDesc = rDPObj.GetSheetDesc() )
     641             :     {
     642             :         /*  maOrigSrcRange: Range received from the DataPilot object.
     643             :             maExpSrcRange: Range written to the DCONREF record.
     644             :             maDocSrcRange: Range used to get source data from Calc document.
     645             :                 This range may be shorter than maExpSrcRange to improve export
     646             :                 performance (#i22541#). */
     647           0 :         maOrigSrcRange = maExpSrcRange = maDocSrcRange = pSrcDesc->GetSourceRange();
     648           0 :         maSrcRangeName = pSrcDesc->GetRangeName();
     649             : 
     650             :         // internal sheet data only
     651           0 :         SCTAB nScTab = maExpSrcRange.aStart.Tab();
     652           0 :         if( (nScTab == maExpSrcRange.aEnd.Tab()) && GetTabInfo().IsExportTab( nScTab ) )
     653             :         {
     654             :             // ValidateRange() restricts source range to valid Excel limits
     655           0 :             if( GetAddressConverter().ValidateRange( maExpSrcRange, true ) )
     656             :             {
     657             :                 // #i22541# skip empty cell areas (performance)
     658             :                 SCCOL nDocCol1, nDocCol2;
     659             :                 SCROW nDocRow1, nDocRow2;
     660           0 :                 GetDoc().GetDataStart( nScTab, nDocCol1, nDocRow1 );
     661           0 :                 GetDoc().GetPrintArea( nScTab, nDocCol2, nDocRow2, false );
     662           0 :                 SCCOL nSrcCol1 = maExpSrcRange.aStart.Col();
     663           0 :                 SCROW nSrcRow1 = maExpSrcRange.aStart.Row();
     664           0 :                 SCCOL nSrcCol2 = maExpSrcRange.aEnd.Col();
     665           0 :                 SCROW nSrcRow2 = maExpSrcRange.aEnd.Row();
     666             : 
     667             :                 // #i22541# do not store index list for too big ranges
     668           0 :                 if( 2 * (nDocRow2 - nDocRow1) < (nSrcRow2 - nSrcRow1) )
     669           0 :                     ::set_flag( maPCInfo.mnFlags, EXC_SXDB_SAVEDATA, false );
     670             : 
     671             :                 // adjust row indexes, keep one row of empty area to surely have the empty cache item
     672           0 :                 if( nSrcRow1 < nDocRow1 )
     673           0 :                     nSrcRow1 = nDocRow1 - 1;
     674           0 :                 if( nSrcRow2 > nDocRow2 )
     675           0 :                     nSrcRow2 = nDocRow2 + 1;
     676             : 
     677           0 :                 maDocSrcRange.aStart.SetCol( ::std::max( nDocCol1, nSrcCol1 ) );
     678           0 :                 maDocSrcRange.aStart.SetRow( nSrcRow1 );
     679           0 :                 maDocSrcRange.aEnd.SetCol( ::std::min( nDocCol2, nSrcCol2 ) );
     680           0 :                 maDocSrcRange.aEnd.SetRow( nSrcRow2 );
     681             : 
     682           0 :                 GetDoc().GetName( nScTab, maTabName );
     683           0 :                 maPCInfo.mnSrcRecs = static_cast< sal_uInt32 >( maExpSrcRange.aEnd.Row() - maExpSrcRange.aStart.Row() );
     684           0 :                 maPCInfo.mnStrmId = nListIdx + 1;
     685           0 :                 maPCInfo.mnSrcType = EXC_SXDB_SRC_SHEET;
     686             : 
     687           0 :                 AddFields( rDPObj );
     688             : 
     689           0 :                 mbValid = true;
     690             :             }
     691             :         }
     692             :     }
     693           0 : }
     694             : 
     695           0 : bool XclExpPivotCache::HasItemIndexList() const
     696             : {
     697           0 :     return ::get_flag( maPCInfo.mnFlags, EXC_SXDB_SAVEDATA );
     698             : }
     699             : 
     700           0 : sal_uInt16 XclExpPivotCache::GetFieldCount() const
     701             : {
     702           0 :     return static_cast< sal_uInt16 >( maFieldList.GetSize() );
     703             : }
     704             : 
     705           0 : const XclExpPCField* XclExpPivotCache::GetField( sal_uInt16 nFieldIdx ) const
     706             : {
     707           0 :     return maFieldList.GetRecord( nFieldIdx ).get();
     708             : }
     709             : 
     710           0 : bool XclExpPivotCache::HasAddFields() const
     711             : {
     712             :     // pivot cache can be shared, if there are no additional cache fields
     713           0 :     return maPCInfo.mnStdFields < maPCInfo.mnTotalFields;
     714             : }
     715             : 
     716           0 : bool XclExpPivotCache::HasEqualDataSource( const ScDPObject& rDPObj ) const
     717             : {
     718             :     /*  For now, only sheet sources are supported, therefore it is enough to
     719             :         compare the ScSheetSourceDesc. Later, there should be done more complicated
     720             :         comparisons regarding the source type of rDPObj and this cache. */
     721           0 :     if( const ScSheetSourceDesc* pSrcDesc = rDPObj.GetSheetDesc() )
     722           0 :         return pSrcDesc->GetSourceRange() == maOrigSrcRange;
     723           0 :     return false;
     724             : }
     725             : 
     726           0 : void XclExpPivotCache::Save( XclExpStream& rStrm )
     727             : {
     728             :     OSL_ENSURE( mbValid, "XclExpPivotCache::Save - invalid pivot cache" );
     729             :     // SXIDSTM
     730           0 :     XclExpUInt16Record( EXC_ID_SXIDSTM, maPCInfo.mnStrmId ).Save( rStrm );
     731             :     // SXVS
     732           0 :     XclExpUInt16Record( EXC_ID_SXVS, EXC_SXVS_SHEET ).Save( rStrm );
     733             : 
     734           0 :     if (!maSrcRangeName.isEmpty())
     735             :         // DCONNAME
     736           0 :         WriteDConName(rStrm);
     737             :     else
     738             :         // DCONREF
     739           0 :         WriteDconref(rStrm);
     740             : 
     741             :     // create the pivot cache storage stream
     742           0 :     WriteCacheStream();
     743           0 : }
     744             : 
     745           0 : void XclExpPivotCache::SaveXml( XclExpXmlStream&
     746             : #ifdef XLSX_PIVOT_CACHE
     747             :                                                  rStrm
     748             : #endif
     749             : )
     750             : {
     751             :     OSL_ENSURE( mbValid, "XclExpPivotCache::Save - invalid pivot cache" );
     752             : #ifdef XLSX_PIVOT_CACHE /* <pivotCache> without xl/pivotCaches/ cacheStream
     753             :                            results in a broken .xlsx */
     754             :     sax_fastparser::FSHelperPtr& rWorkbook = rStrm.GetCurrentStream();
     755             :     OUString sId = OUStringBuffer()
     756             :         .appendAscii("rId")
     757             :         .append( rStrm.GetUniqueIdOUString() )
     758             :         .makeStringAndClear();
     759             :     rWorkbook->startElement( XML_pivotCache,
     760             :             XML_cacheId, OString::valueOf( (sal_Int32)maPCInfo.mnStrmId ).getStr(),
     761             :             FSNS( XML_r, XML_id ), XclXmlUtils::ToOString( sId ).getStr(),
     762             :             FSEND );
     763             :     // SXIDSTM
     764             :     XclExpUInt16Record( EXC_ID_SXIDSTM, maPCInfo.mnStrmId ).SaveXml( rStrm );
     765             :     // SXVS
     766             :     XclExpUInt16Record( EXC_ID_SXVS, EXC_SXVS_SHEET ).SaveXml( rStrm );
     767             :     // DCONREF
     768             :     // OOXTODO: WriteDconref( rStrm );
     769             :     // create the pivot cache storage stream
     770             :     // OOXTODO: WriteCacheStream();
     771             :     rWorkbook->endElement( XML_pivotCache );
     772             : #endif /* XLSX_PIVOT_CACHE */
     773           0 : }
     774             : 
     775             : // private --------------------------------------------------------------------
     776             : 
     777           0 : XclExpPCField* XclExpPivotCache::GetFieldAcc( sal_uInt16 nFieldIdx )
     778             : {
     779           0 :     return maFieldList.GetRecord( nFieldIdx ).get();
     780             : }
     781             : 
     782           0 : XclExpPCField* XclExpPivotCache::GetFieldAcc( const rtl::OUString& rFieldName )
     783             : {
     784           0 :     XclExpPCField* pField = 0;
     785           0 :     for( size_t nPos = 0, nSize = maFieldList.GetSize(); !pField && (nPos < nSize); ++nPos )
     786           0 :         if( maFieldList.GetRecord( nPos )->GetFieldName() == rFieldName )
     787           0 :             pField = maFieldList.GetRecord( nPos ).get();
     788           0 :     return pField;
     789             : }
     790             : 
     791           0 : void XclExpPivotCache::AddFields( const ScDPObject& rDPObj )
     792             : {
     793           0 :     AddStdFields( rDPObj );
     794           0 :     maPCInfo.mnStdFields = GetFieldCount();
     795           0 :     AddGroupFields( rDPObj );
     796           0 :     AddCalcFields( rDPObj );
     797           0 :     maPCInfo.mnTotalFields = GetFieldCount();
     798           0 : };
     799             : 
     800           0 : void XclExpPivotCache::AddStdFields( const ScDPObject& rDPObj )
     801             : {
     802             :     // if item index list is not written, used shortened source range (maDocSrcRange) for performance
     803           0 :     const ScRange& rRange = HasItemIndexList() ? maExpSrcRange : maDocSrcRange;
     804             :     // create a standard pivot cache field for each source column
     805           0 :     for( SCCOL nScCol = rRange.aStart.Col(), nEndScCol = rRange.aEnd.Col(); nScCol <= nEndScCol; ++nScCol )
     806             :     {
     807           0 :         ScRange aColRange( rRange );
     808           0 :         aColRange.aStart.SetCol( nScCol );
     809           0 :         aColRange.aEnd.SetCol( nScCol );
     810             :         maFieldList.AppendNewRecord( new XclExpPCField(
     811           0 :             GetRoot(), *this, GetFieldCount(), rDPObj, aColRange ) );
     812             :     }
     813           0 : }
     814             : 
     815           0 : void XclExpPivotCache::AddGroupFields( const ScDPObject& rDPObj )
     816             : {
     817           0 :     if( const ScDPSaveData* pSaveData = rDPObj.GetSaveData() )
     818             :     {
     819           0 :         if( const ScDPDimensionSaveData* pSaveDimData = pSaveData->GetExistingDimensionData() )
     820             :         {
     821             :             // loop over all existing standard fields to find their group fields
     822           0 :             for( sal_uInt16 nFieldIdx = 0; nFieldIdx < maPCInfo.mnStdFields; ++nFieldIdx )
     823             :             {
     824           0 :                 if( XclExpPCField* pCurrStdField = GetFieldAcc( nFieldIdx ) )
     825             :                 {
     826           0 :                     const ScDPSaveGroupDimension* pGroupDim = pSaveDimData->GetGroupDimForBase( pCurrStdField->GetFieldName() );
     827           0 :                     XclExpPCField* pLastGroupField = pCurrStdField;
     828           0 :                     while( pGroupDim )
     829             :                     {
     830             :                         // insert the new grouping field
     831             :                         XclExpPCFieldRef xNewGroupField( new XclExpPCField(
     832           0 :                             GetRoot(), *this, GetFieldCount(), rDPObj, *pGroupDim, *pCurrStdField ) );
     833           0 :                         maFieldList.AppendRecord( xNewGroupField );
     834             : 
     835             :                         // register new grouping field at current grouping field, building a chain
     836           0 :                         pLastGroupField->SetGroupChildField( *xNewGroupField );
     837             : 
     838             :                         // next grouping dimension
     839           0 :                         pGroupDim = pSaveDimData->GetGroupDimForBase( pGroupDim->GetGroupDimName() );
     840           0 :                         pLastGroupField = xNewGroupField.get();
     841           0 :                     }
     842             :                 }
     843             :             }
     844             :         }
     845             :     }
     846           0 : }
     847             : 
     848           0 : void XclExpPivotCache::AddCalcFields( const ScDPObject& /*rDPObj*/ )
     849             : {
     850             :     // not supported
     851           0 : }
     852             : 
     853           0 : void XclExpPivotCache::WriteDconref( XclExpStream& rStrm ) const
     854             : {
     855           0 :     XclExpString aRef( XclExpUrlHelper::EncodeUrl( GetRoot(), EMPTY_STRING, &maTabName ) );
     856           0 :     rStrm.StartRecord( EXC_ID_DCONREF, 7 + aRef.GetSize() );
     857           0 :     rStrm   << static_cast< sal_uInt16 >( maExpSrcRange.aStart.Row() )
     858           0 :             << static_cast< sal_uInt16 >( maExpSrcRange.aEnd.Row() )
     859           0 :             << static_cast< sal_uInt8 >( maExpSrcRange.aStart.Col() )
     860           0 :             << static_cast< sal_uInt8 >( maExpSrcRange.aEnd.Col() )
     861           0 :             << aRef
     862           0 :             << sal_uInt8( 0 );
     863           0 :     rStrm.EndRecord();
     864           0 : }
     865             : 
     866           0 : void XclExpPivotCache::WriteDConName( XclExpStream& rStrm ) const
     867             : {
     868           0 :     XclExpString aName(maSrcRangeName);
     869           0 :     rStrm.StartRecord(EXC_ID_DCONNAME, aName.GetSize() + 2);
     870           0 :     rStrm << aName << sal_uInt16(0);
     871           0 :     rStrm.EndRecord();
     872           0 : }
     873             : 
     874           0 : void XclExpPivotCache::WriteCacheStream()
     875             : {
     876           0 :     SotStorageRef xSvStrg = OpenStorage( EXC_STORAGE_PTCACHE );
     877           0 :     SotStorageStreamRef xSvStrm = OpenStream( xSvStrg, ScfTools::GetHexStr( maPCInfo.mnStrmId ) );
     878           0 :     if( xSvStrm.Is() )
     879             :     {
     880           0 :         XclExpStream aStrm( *xSvStrm, GetRoot() );
     881             :         // SXDB
     882           0 :         WriteSxdb( aStrm );
     883             :         // SXDBEX
     884           0 :         WriteSxdbex( aStrm );
     885             :         // field list (SXFIELD and items)
     886           0 :         maFieldList.Save( aStrm );
     887             :         // index table (list of SXINDEXLIST)
     888           0 :         WriteSxindexlistList( aStrm );
     889             :         // EOF
     890           0 :         XclExpEmptyRecord( EXC_ID_EOF ).Save( aStrm );
     891           0 :     }
     892           0 : }
     893             : 
     894           0 : void XclExpPivotCache::WriteSxdb( XclExpStream& rStrm ) const
     895             : {
     896           0 :     rStrm.StartRecord( EXC_ID_SXDB, 21 );
     897           0 :     rStrm << maPCInfo;
     898           0 :     rStrm.EndRecord();
     899           0 : }
     900             : 
     901           0 : void XclExpPivotCache::WriteSxdbex( XclExpStream& rStrm ) const
     902             : {
     903           0 :     rStrm.StartRecord( EXC_ID_SXDBEX, 12 );
     904           0 :     rStrm   << EXC_SXDBEX_CREATION_DATE
     905           0 :             << sal_uInt32( 0 );             // number of SXFORMULA records
     906           0 :     rStrm.EndRecord();
     907           0 : }
     908             : 
     909           0 : void XclExpPivotCache::WriteSxindexlistList( XclExpStream& rStrm ) const
     910             : {
     911           0 :     if( HasItemIndexList() )
     912             :     {
     913           0 :         sal_Size nRecSize = 0;
     914           0 :         size_t nPos, nSize = maFieldList.GetSize();
     915           0 :         for( nPos = 0; nPos < nSize; ++nPos )
     916           0 :             nRecSize += maFieldList.GetRecord( nPos )->GetIndexSize();
     917             : 
     918           0 :         for( sal_uInt32 nSrcRow = 0; nSrcRow < maPCInfo.mnSrcRecs; ++nSrcRow )
     919             :         {
     920           0 :             rStrm.StartRecord( EXC_ID_SXINDEXLIST, nRecSize );
     921           0 :             for( nPos = 0; nPos < nSize; ++nPos )
     922           0 :                 maFieldList.GetRecord( nPos )->WriteIndex( rStrm, nSrcRow );
     923           0 :             rStrm.EndRecord();
     924             :         }
     925             :     }
     926           0 : }
     927             : 
     928             : // ============================================================================
     929             : // Pivot table
     930             : // ============================================================================
     931             : 
     932             : namespace {
     933             : 
     934             : // ----------------------------------------------------------------------------
     935             : 
     936             : /** Returns a display string for a data field containing the field name and aggregation function. */
     937           0 : String lclGetDataFieldCaption( const String& rFieldName, GeneralFunction eFunc )
     938             : {
     939           0 :     String aCaption;
     940             : 
     941           0 :     sal_uInt16 nResIdx = 0;
     942             :     using namespace ::com::sun::star::sheet;
     943           0 :     switch( eFunc )
     944             :     {
     945           0 :         case GeneralFunction_SUM:       nResIdx = STR_FUN_TEXT_SUM;     break;
     946           0 :         case GeneralFunction_COUNT:     nResIdx = STR_FUN_TEXT_COUNT;   break;
     947           0 :         case GeneralFunction_AVERAGE:   nResIdx = STR_FUN_TEXT_AVG;     break;
     948           0 :         case GeneralFunction_MAX:       nResIdx = STR_FUN_TEXT_MAX;     break;
     949           0 :         case GeneralFunction_MIN:       nResIdx = STR_FUN_TEXT_MIN;     break;
     950           0 :         case GeneralFunction_PRODUCT:   nResIdx = STR_FUN_TEXT_PRODUCT; break;
     951           0 :         case GeneralFunction_COUNTNUMS: nResIdx = STR_FUN_TEXT_COUNT;   break;
     952           0 :         case GeneralFunction_STDEV:     nResIdx = STR_FUN_TEXT_STDDEV;  break;
     953           0 :         case GeneralFunction_STDEVP:    nResIdx = STR_FUN_TEXT_STDDEV;  break;
     954           0 :         case GeneralFunction_VAR:       nResIdx = STR_FUN_TEXT_VAR;     break;
     955           0 :         case GeneralFunction_VARP:      nResIdx = STR_FUN_TEXT_VAR;     break;
     956             :         default:;
     957             :     }
     958           0 :     if( nResIdx )
     959           0 :         aCaption.Assign( ScGlobal::GetRscString( nResIdx ) ).AppendAscii( RTL_CONSTASCII_STRINGPARAM( " - " ) );
     960           0 :     aCaption.Append( rFieldName );
     961           0 :     return aCaption;
     962             : }
     963             : 
     964             : // ----------------------------------------------------------------------------
     965             : 
     966             : } // namespace
     967             : 
     968             : // ============================================================================
     969             : 
     970           0 : XclExpPTItem::XclExpPTItem( const XclExpPCField& rCacheField, sal_uInt16 nCacheIdx ) :
     971             :     XclExpRecord( EXC_ID_SXVI, 8 ),
     972           0 :     mpCacheItem( rCacheField.GetItem( nCacheIdx ) )
     973             : {
     974           0 :     maItemInfo.mnType = EXC_SXVI_TYPE_DATA;
     975           0 :     maItemInfo.mnCacheIdx = nCacheIdx;
     976           0 :     maItemInfo.maVisName.mbUseCache = mpCacheItem != 0;
     977           0 : }
     978             : 
     979           0 : XclExpPTItem::XclExpPTItem( sal_uInt16 nItemType, sal_uInt16 nCacheIdx, bool bUseCache ) :
     980             :     XclExpRecord( EXC_ID_SXVI, 8 ),
     981           0 :     mpCacheItem( 0 )
     982             : {
     983           0 :     maItemInfo.mnType = nItemType;
     984           0 :     maItemInfo.mnCacheIdx = nCacheIdx;
     985           0 :     maItemInfo.maVisName.mbUseCache = bUseCache;
     986           0 : }
     987             : 
     988           0 : rtl::OUString XclExpPTItem::GetItemName() const
     989             : {
     990           0 :     return mpCacheItem ? mpCacheItem->ConvertToText() : rtl::OUString();
     991             : }
     992             : 
     993           0 : void XclExpPTItem::SetPropertiesFromMember( const ScDPSaveMember& rSaveMem )
     994             : {
     995             :     // #i115659# GetIsVisible() is not valid if HasIsVisible() returns false, default is 'visible' then
     996           0 :     ::set_flag( maItemInfo.mnFlags, EXC_SXVI_HIDDEN, rSaveMem.HasIsVisible() && !rSaveMem.GetIsVisible() );
     997             :     // #i115659# GetShowDetails() is not valid if HasShowDetails() returns false, default is 'show detail' then
     998           0 :     ::set_flag( maItemInfo.mnFlags, EXC_SXVI_HIDEDETAIL, rSaveMem.HasShowDetails() && !rSaveMem.GetShowDetails() );
     999             : 
    1000             :     // visible name
    1001           0 :     const OUString* pVisName = rSaveMem.GetLayoutName();
    1002           0 :     if (pVisName && !pVisName->equals(GetItemName()))
    1003           0 :         maItemInfo.SetVisName(*pVisName);
    1004           0 : }
    1005             : 
    1006           0 : void XclExpPTItem::WriteBody( XclExpStream& rStrm )
    1007             : {
    1008           0 :     rStrm << maItemInfo;
    1009           0 : }
    1010             : 
    1011             : // ============================================================================
    1012             : 
    1013           0 : XclExpPTField::XclExpPTField( const XclExpPivotTable& rPTable, sal_uInt16 nCacheIdx ) :
    1014             :     mrPTable( rPTable ),
    1015           0 :     mpCacheField( rPTable.GetCacheField( nCacheIdx ) )
    1016             : {
    1017           0 :     maFieldInfo.mnCacheIdx = nCacheIdx;
    1018             : 
    1019             :     // create field items
    1020           0 :     if( mpCacheField )
    1021           0 :         for( sal_uInt16 nItemIdx = 0, nItemCount = mpCacheField->GetItemCount(); nItemIdx < nItemCount; ++nItemIdx )
    1022           0 :             maItemList.AppendNewRecord( new XclExpPTItem( *mpCacheField, nItemIdx ) );
    1023           0 :     maFieldInfo.mnItemCount = static_cast< sal_uInt16 >( maItemList.GetSize() );
    1024           0 : }
    1025             : 
    1026             : // data access ----------------------------------------------------------------
    1027             : 
    1028           0 : rtl::OUString XclExpPTField::GetFieldName() const
    1029             : {
    1030           0 :     return mpCacheField ? mpCacheField->GetFieldName() : rtl::OUString();
    1031             : }
    1032             : 
    1033           0 : sal_uInt16 XclExpPTField::GetFieldIndex() const
    1034             : {
    1035             :     // field index always equal to cache index
    1036           0 :     return maFieldInfo.mnCacheIdx;
    1037             : }
    1038             : 
    1039           0 : sal_uInt16 XclExpPTField::GetLastDataInfoIndex() const
    1040             : {
    1041             :     OSL_ENSURE( !maDataInfoVec.empty(), "XclExpPTField::GetLastDataInfoIndex - no data info found" );
    1042             :     // will return 0xFFFF for empty vector -> ok
    1043           0 :     return static_cast< sal_uInt16 >( maDataInfoVec.size() - 1 );
    1044             : }
    1045             : 
    1046           0 : sal_uInt16 XclExpPTField::GetItemIndex( const rtl::OUString& rName, sal_uInt16 nDefaultIdx ) const
    1047             : {
    1048           0 :     for( size_t nPos = 0, nSize = maItemList.GetSize(); nPos < nSize; ++nPos )
    1049           0 :         if( maItemList.GetRecord( nPos )->GetItemName() == rName )
    1050           0 :             return static_cast< sal_uInt16 >( nPos );
    1051           0 :     return nDefaultIdx;
    1052             : }
    1053             : 
    1054             : // fill data --------------------------------------------------------------
    1055             : 
    1056             : /**
    1057             :  * Calc's subtotal names are escaped with backslashes ('\'), while Excel's
    1058             :  * are not escaped at all.
    1059             :  */
    1060           0 : static OUString lcl_convertCalcSubtotalName(const OUString& rName)
    1061             : {
    1062           0 :     OUStringBuffer aBuf;
    1063           0 :     const sal_Unicode* p = rName.getStr();
    1064           0 :     sal_Int32 n = rName.getLength();
    1065           0 :     bool bEscaped = false;
    1066           0 :     for (sal_Int32 i = 0; i < n; ++i)
    1067             :     {
    1068           0 :         const sal_Unicode c = p[i];
    1069           0 :         if (!bEscaped && c == sal_Unicode('\\'))
    1070             :         {
    1071           0 :             bEscaped = true;
    1072           0 :             continue;
    1073             :         }
    1074             : 
    1075           0 :         aBuf.append(c);
    1076           0 :         bEscaped = false;
    1077             :     }
    1078           0 :     return aBuf.makeStringAndClear();
    1079             : }
    1080             : 
    1081           0 : void XclExpPTField::SetPropertiesFromDim( const ScDPSaveDimension& rSaveDim )
    1082             : {
    1083             :     // orientation
    1084           0 :     DataPilotFieldOrientation eOrient = static_cast< DataPilotFieldOrientation >( rSaveDim.GetOrientation() );
    1085             :     OSL_ENSURE( eOrient != DataPilotFieldOrientation_DATA, "XclExpPTField::SetPropertiesFromDim - called for data field" );
    1086           0 :     maFieldInfo.AddApiOrient( eOrient );
    1087             : 
    1088             :     // show empty items (#i115659# GetShowEmpty() is not valid if HasShowEmpty() returns false, default is false then)
    1089           0 :     ::set_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_SHOWALL, rSaveDim.HasShowEmpty() && rSaveDim.GetShowEmpty() );
    1090             : 
    1091             :     // visible name
    1092           0 :     const OUString* pLayoutName = rSaveDim.GetLayoutName();
    1093           0 :     if (pLayoutName && !pLayoutName->equals(GetFieldName()))
    1094           0 :         maFieldInfo.SetVisName(*pLayoutName);
    1095             : 
    1096           0 :     const rtl::OUString* pSubtotalName = rSaveDim.GetSubtotalName();
    1097           0 :     if (pSubtotalName)
    1098             :     {
    1099           0 :         OUString aSubName = lcl_convertCalcSubtotalName(*pSubtotalName);
    1100           0 :         maFieldExtInfo.mpFieldTotalName.reset(new rtl::OUString(aSubName));
    1101             :     }
    1102             : 
    1103             :     // subtotals
    1104           0 :     XclPTSubtotalVec aSubtotals;
    1105           0 :     aSubtotals.reserve( static_cast< size_t >( rSaveDim.GetSubTotalsCount() ) );
    1106           0 :     for( long nSubtIdx = 0, nSubtCount = rSaveDim.GetSubTotalsCount(); nSubtIdx < nSubtCount; ++nSubtIdx )
    1107           0 :         aSubtotals.push_back( rSaveDim.GetSubTotalFunc( nSubtIdx ) );
    1108           0 :     maFieldInfo.SetSubtotals( aSubtotals );
    1109             : 
    1110             :     // sorting
    1111           0 :     if( const DataPilotFieldSortInfo* pSortInfo = rSaveDim.GetSortInfo() )
    1112             :     {
    1113           0 :         maFieldExtInfo.SetApiSortMode( pSortInfo->Mode );
    1114           0 :         if( pSortInfo->Mode == ::com::sun::star::sheet::DataPilotFieldSortMode::DATA )
    1115           0 :             maFieldExtInfo.mnSortField = mrPTable.GetDataFieldIndex( pSortInfo->Field, EXC_SXVDEX_SORT_OWN );
    1116           0 :         ::set_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_SORT_ASC, pSortInfo->IsAscending );
    1117             :     }
    1118             : 
    1119             :     // auto show
    1120           0 :     if( const DataPilotFieldAutoShowInfo* pShowInfo = rSaveDim.GetAutoShowInfo() )
    1121             :     {
    1122           0 :         ::set_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_AUTOSHOW, pShowInfo->IsEnabled );
    1123           0 :         maFieldExtInfo.SetApiAutoShowMode( pShowInfo->ShowItemsMode );
    1124           0 :         maFieldExtInfo.SetApiAutoShowCount( pShowInfo->ItemCount );
    1125           0 :         maFieldExtInfo.mnShowField = mrPTable.GetDataFieldIndex( pShowInfo->DataField, EXC_SXVDEX_SHOW_NONE );
    1126             :     }
    1127             : 
    1128             :     // layout
    1129           0 :     if( const DataPilotFieldLayoutInfo* pLayoutInfo = rSaveDim.GetLayoutInfo() )
    1130             :     {
    1131           0 :         maFieldExtInfo.SetApiLayoutMode( pLayoutInfo->LayoutMode );
    1132           0 :         ::set_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_LAYOUT_BLANK, pLayoutInfo->AddEmptyLines );
    1133             :     }
    1134             : 
    1135             :     // special page field properties
    1136           0 :     if( eOrient == DataPilotFieldOrientation_PAGE )
    1137             :     {
    1138           0 :         maPageInfo.mnField = GetFieldIndex();
    1139           0 :         maPageInfo.mnSelItem = EXC_SXPI_ALLITEMS;
    1140             :     }
    1141             : 
    1142             :     // item properties
    1143           0 :     const ScDPSaveDimension::MemberList &rMembers = rSaveDim.GetMembers();
    1144           0 :     for (ScDPSaveDimension::MemberList::const_iterator i=rMembers.begin(); i != rMembers.end() ; ++i)
    1145           0 :         if( XclExpPTItem* pItem = GetItemAcc( (*i)->GetName() ) )
    1146           0 :             pItem->SetPropertiesFromMember( **i );
    1147           0 : }
    1148             : 
    1149           0 : void XclExpPTField::SetDataPropertiesFromDim( const ScDPSaveDimension& rSaveDim )
    1150             : {
    1151           0 :     maDataInfoVec.push_back( XclPTDataFieldInfo() );
    1152           0 :     XclPTDataFieldInfo& rDataInfo = maDataInfoVec.back();
    1153           0 :     rDataInfo.mnField = GetFieldIndex();
    1154             : 
    1155             :     // orientation
    1156           0 :     maFieldInfo.AddApiOrient( DataPilotFieldOrientation_DATA );
    1157             : 
    1158             :     // aggregation function
    1159           0 :     GeneralFunction eFunc = static_cast< GeneralFunction >( rSaveDim.GetFunction() );
    1160           0 :     rDataInfo.SetApiAggFunc( eFunc );
    1161             : 
    1162             :     // visible name
    1163           0 :     const rtl::OUString* pVisName = rSaveDim.GetLayoutName();
    1164           0 :     if (pVisName)
    1165           0 :         rDataInfo.SetVisName(*pVisName);
    1166             :     else
    1167           0 :         rDataInfo.SetVisName( lclGetDataFieldCaption( GetFieldName(), eFunc ) );
    1168             : 
    1169             :     // result field reference
    1170           0 :     if( const DataPilotFieldReference* pFieldRef = rSaveDim.GetReferenceValue() )
    1171             :     {
    1172           0 :         rDataInfo.SetApiRefType( pFieldRef->ReferenceType );
    1173           0 :         rDataInfo.SetApiRefItemType( pFieldRef->ReferenceItemType );
    1174           0 :         if( const XclExpPTField* pRefField = mrPTable.GetField( pFieldRef->ReferenceField ) )
    1175             :         {
    1176           0 :             rDataInfo.mnRefField = pRefField->GetFieldIndex();
    1177           0 :             if( pFieldRef->ReferenceItemType == ::com::sun::star::sheet::DataPilotFieldReferenceItemType::NAMED )
    1178           0 :                 rDataInfo.mnRefItem = pRefField->GetItemIndex( pFieldRef->ReferenceItemName, 0 );
    1179             :         }
    1180             :     }
    1181           0 : }
    1182             : 
    1183           0 : void XclExpPTField::AppendSubtotalItems()
    1184             : {
    1185           0 :     if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_DEFAULT )   AppendSubtotalItem( EXC_SXVI_TYPE_DEFAULT );
    1186           0 :     if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_SUM )       AppendSubtotalItem( EXC_SXVI_TYPE_SUM );
    1187           0 :     if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_COUNT )     AppendSubtotalItem( EXC_SXVI_TYPE_COUNT );
    1188           0 :     if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_AVERAGE )   AppendSubtotalItem( EXC_SXVI_TYPE_AVERAGE );
    1189           0 :     if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_MAX )       AppendSubtotalItem( EXC_SXVI_TYPE_MAX );
    1190           0 :     if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_MIN )       AppendSubtotalItem( EXC_SXVI_TYPE_MIN );
    1191           0 :     if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_PROD )      AppendSubtotalItem( EXC_SXVI_TYPE_PROD );
    1192           0 :     if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_COUNTNUM )  AppendSubtotalItem( EXC_SXVI_TYPE_COUNTNUM );
    1193           0 :     if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_STDDEV )    AppendSubtotalItem( EXC_SXVI_TYPE_STDDEV );
    1194           0 :     if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_STDDEVP )   AppendSubtotalItem( EXC_SXVI_TYPE_STDDEVP );
    1195           0 :     if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_VAR )       AppendSubtotalItem( EXC_SXVI_TYPE_VAR );
    1196           0 :     if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_VARP )      AppendSubtotalItem( EXC_SXVI_TYPE_VARP );
    1197           0 : }
    1198             : 
    1199             : // records --------------------------------------------------------------------
    1200             : 
    1201           0 : void XclExpPTField::WriteSxpiEntry( XclExpStream& rStrm ) const
    1202             : {
    1203           0 :     rStrm << maPageInfo;
    1204           0 : }
    1205             : 
    1206           0 : void XclExpPTField::WriteSxdi( XclExpStream& rStrm, sal_uInt16 nDataInfoIdx ) const
    1207             : {
    1208             :     OSL_ENSURE( nDataInfoIdx < maDataInfoVec.size(), "XclExpPTField::WriteSxdi - data field not found" );
    1209           0 :     if( nDataInfoIdx < maDataInfoVec.size() )
    1210             :     {
    1211           0 :         rStrm.StartRecord( EXC_ID_SXDI, 12 );
    1212           0 :         rStrm << maDataInfoVec[ nDataInfoIdx ];
    1213           0 :         rStrm.EndRecord();
    1214             :     }
    1215           0 : }
    1216             : 
    1217           0 : void XclExpPTField::Save( XclExpStream& rStrm )
    1218             : {
    1219             :     // SXVD
    1220           0 :     WriteSxvd( rStrm );
    1221             :     // list of SXVI records
    1222           0 :     maItemList.Save( rStrm );
    1223             :     // SXVDEX
    1224           0 :     WriteSxvdex( rStrm );
    1225           0 : }
    1226             : 
    1227             : // private --------------------------------------------------------------------
    1228             : 
    1229           0 : XclExpPTItem* XclExpPTField::GetItemAcc( const rtl::OUString& rName )
    1230             : {
    1231           0 :     XclExpPTItem* pItem = 0;
    1232           0 :     for( size_t nPos = 0, nSize = maItemList.GetSize(); !pItem && (nPos < nSize); ++nPos )
    1233           0 :         if( maItemList.GetRecord( nPos )->GetItemName() == rName )
    1234           0 :             pItem = maItemList.GetRecord( nPos ).get();
    1235           0 :     return pItem;
    1236             : }
    1237             : 
    1238           0 : void XclExpPTField::AppendSubtotalItem( sal_uInt16 nItemType )
    1239             : {
    1240           0 :     maItemList.AppendNewRecord( new XclExpPTItem( nItemType, EXC_SXVI_DEFAULT_CACHE, true ) );
    1241           0 :     ++maFieldInfo.mnItemCount;
    1242           0 : }
    1243             : 
    1244           0 : void XclExpPTField::WriteSxvd( XclExpStream& rStrm ) const
    1245             : {
    1246           0 :     rStrm.StartRecord( EXC_ID_SXVD, 10 );
    1247           0 :     rStrm << maFieldInfo;
    1248           0 :     rStrm.EndRecord();
    1249           0 : }
    1250             : 
    1251           0 : void XclExpPTField::WriteSxvdex( XclExpStream& rStrm ) const
    1252             : {
    1253           0 :     rStrm.StartRecord( EXC_ID_SXVDEX, 20 );
    1254           0 :     rStrm << maFieldExtInfo;
    1255           0 :     rStrm.EndRecord();
    1256           0 : }
    1257             : 
    1258             : // ============================================================================
    1259             : 
    1260           0 : XclExpPivotTable::XclExpPivotTable( const XclExpRoot& rRoot, const ScDPObject& rDPObj, const XclExpPivotCache& rPCache ) :
    1261             :     XclExpRoot( rRoot ),
    1262             :     mrPCache( rPCache ),
    1263             :     maDataOrientField( *this, EXC_SXIVD_DATA ),
    1264             :     mnOutScTab( 0 ),
    1265             :     mbValid( false ),
    1266           0 :     mbFilterBtn( false )
    1267             : {
    1268           0 :     const ScRange& rOutScRange = rDPObj.GetOutRange();
    1269           0 :     if( GetAddressConverter().ConvertRange( maPTInfo.maOutXclRange, rOutScRange, true ) )
    1270             :     {
    1271             :         // DataPilot properties -----------------------------------------------
    1272             : 
    1273             :         // pivot table properties from DP object
    1274           0 :         mnOutScTab = rOutScRange.aStart.Tab();
    1275           0 :         maPTInfo.maTableName = rDPObj.GetName();
    1276           0 :         maPTInfo.mnCacheIdx = mrPCache.GetCacheIndex();
    1277             : 
    1278           0 :         maPTViewEx9Info.Init( rDPObj );
    1279             : 
    1280           0 :         if( const ScDPSaveData* pSaveData = rDPObj.GetSaveData() )
    1281             :         {
    1282             :             // additional properties from ScDPSaveData
    1283           0 :             SetPropertiesFromDP( *pSaveData );
    1284             : 
    1285             :             // loop over all dimensions ---------------------------------------
    1286             : 
    1287             :             /*  1)  Default-construct all pivot table fields for all pivot cache fields. */
    1288           0 :             for( sal_uInt16 nFieldIdx = 0, nFieldCount = mrPCache.GetFieldCount(); nFieldIdx < nFieldCount; ++nFieldIdx )
    1289           0 :                 maFieldList.AppendNewRecord( new XclExpPTField( *this, nFieldIdx ) );
    1290             : 
    1291           0 :             boost::ptr_vector<ScDPSaveDimension>::const_iterator iter;
    1292           0 :             const ScDPSaveData::DimsType& rDimList = pSaveData->GetDimensions();
    1293             : 
    1294             :             /*  2)  First process all data dimensions, they are needed for extended
    1295             :                     settings of row/column/page fields (sorting/auto show). */
    1296           0 :             for (iter = rDimList.begin(); iter != rDimList.end(); ++iter)
    1297           0 :                 if (iter->GetOrientation() == DataPilotFieldOrientation_DATA)
    1298           0 :                     SetDataFieldPropertiesFromDim(*iter);
    1299             : 
    1300             :             /*  3)  Row/column/page/hidden fields. */
    1301           0 :             for (iter = rDimList.begin(); iter != rDimList.end(); ++iter)
    1302           0 :                 if (iter->GetOrientation() != DataPilotFieldOrientation_DATA)
    1303           0 :                     SetFieldPropertiesFromDim(*iter);
    1304             : 
    1305             :             // Finalize -------------------------------------------------------
    1306             : 
    1307           0 :             Finalize();
    1308           0 :             mbValid = true;
    1309             :         }
    1310             :     }
    1311           0 : }
    1312             : 
    1313           0 : const XclExpPCField* XclExpPivotTable::GetCacheField( sal_uInt16 nCacheIdx ) const
    1314             : {
    1315           0 :     return mrPCache.GetField( nCacheIdx );
    1316             : }
    1317             : 
    1318           0 : const XclExpPTField* XclExpPivotTable::GetField( sal_uInt16 nFieldIdx ) const
    1319             : {
    1320           0 :     return (nFieldIdx == EXC_SXIVD_DATA) ? &maDataOrientField : maFieldList.GetRecord( nFieldIdx ).get();
    1321             : }
    1322             : 
    1323           0 : const XclExpPTField* XclExpPivotTable::GetField( const rtl::OUString& rName ) const
    1324             : {
    1325           0 :     return const_cast< XclExpPivotTable* >( this )->GetFieldAcc( rName );
    1326             : }
    1327             : 
    1328           0 : sal_uInt16 XclExpPivotTable::GetDataFieldIndex( const rtl::OUString& rName, sal_uInt16 nDefaultIdx ) const
    1329             : {
    1330           0 :     for( XclPTDataFieldPosVec::const_iterator aIt = maDataFields.begin(), aEnd = maDataFields.end(); aIt != aEnd; ++aIt )
    1331           0 :         if( const XclExpPTField* pField = GetField( aIt->first ) )
    1332           0 :             if( pField->GetFieldName() == rName )
    1333           0 :                 return static_cast< sal_uInt16 >( aIt - maDataFields.begin() );
    1334           0 :     return nDefaultIdx;
    1335             : }
    1336             : 
    1337           0 : void XclExpPivotTable::Save( XclExpStream& rStrm )
    1338             : {
    1339           0 :     if( mbValid )
    1340             :     {
    1341             :         // SXVIEW
    1342           0 :         WriteSxview( rStrm );
    1343             :         // pivot table fields (SXVD, SXVDEX, and item records)
    1344           0 :         maFieldList.Save( rStrm );
    1345             :         // SXIVD records for row and column fields
    1346           0 :         WriteSxivd( rStrm, maRowFields );
    1347           0 :         WriteSxivd( rStrm, maColFields );
    1348             :         // SXPI
    1349           0 :         WriteSxpi( rStrm );
    1350             :         // list of SXDI records containing data field info
    1351           0 :         WriteSxdiList( rStrm );
    1352             :         // SXLI records
    1353           0 :         WriteSxli( rStrm, maPTInfo.mnDataRows, maPTInfo.mnRowFields );
    1354           0 :         WriteSxli( rStrm, maPTInfo.mnDataCols, maPTInfo.mnColFields );
    1355             :         // SXEX
    1356           0 :         WriteSxex( rStrm );
    1357             :         // QSISXTAG
    1358           0 :         WriteQsiSxTag( rStrm );
    1359             :         // SXVIEWEX9
    1360           0 :         WriteSxViewEx9( rStrm );
    1361             :     }
    1362           0 : }
    1363             : 
    1364           0 : void XclExpPivotTable::SaveXml( XclExpXmlStream& rStrm )
    1365             : {
    1366           0 :     if( !mbValid )
    1367           0 :         return;
    1368             :     sax_fastparser::FSHelperPtr aPivotTableDefinition = rStrm.CreateOutputStream(
    1369             :             XclXmlUtils::GetStreamName( "xl/", "pivotTables/pivotTable", mnOutScTab+1),
    1370             :             XclXmlUtils::GetStreamName( "../", "pivotTables/pivotTable", mnOutScTab+1),
    1371           0 :             rStrm.GetCurrentStream()->getOutputStream(),
    1372             :             "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml",
    1373           0 :             "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable");
    1374           0 :     rStrm.PushStream( aPivotTableDefinition );
    1375             : 
    1376             :     aPivotTableDefinition->startElement( XML_pivotTableDefinition,
    1377             :             XML_xmlns,                      "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
    1378             :             XML_name,                       XclXmlUtils::ToOString( maPTInfo.maTableName ).getStr(),
    1379             :             XML_cacheId,                    OString::valueOf( (sal_Int32) maPTInfo.mnCacheIdx ).getStr(),
    1380             :             XML_dataOnRows,                 XclXmlUtils::ToPsz( maPTInfo.mnDataAxis == EXC_SXVD_AXIS_COL ),
    1381             :             XML_dataPosition,               OString::valueOf( (sal_Int32) maPTInfo.mnDataPos ).getStr(),
    1382             :             XML_autoFormatId,               OString::valueOf( (sal_Int32) maPTInfo.mnAutoFmtIdx ).getStr(),
    1383             :             // OOXTODO: XML_applyNumberFormats,         [ SXVIEW fAtrNum (maPTInfo.mnFlags) ]
    1384             :             // OOXTODO: XML_applyBorderFormats,         [ SXVIEW fAtrBdr (maPTInfo.mnFlags) ]
    1385             :             // OOXTODO: XML_applyFontFormats,           [ SXVIEW fAtrFnt (maPTInfo.mnFlags) ]
    1386             :             // OOXTODO: XML_applyPatternFormats,        [ SXVIEW fAtrPat (maPTInfo.mnFlags) ]
    1387             :             // OOXTODO: XML_applyAlignmentFormats,      [ SXVIEW fAtrAlc (maPTInfo.mnFlags) ]
    1388             :             // OOXTODO: XML_applyWidthHeightFormats,    [ SXVIEW fAtrProc (maPTInfo.mnFlags) ]
    1389             :             XML_dataCaption,                XclXmlUtils::ToOString( maPTInfo.maDataName ).getStr(),
    1390             :             // OOXTODO: XML_grandTotalCaption,          [ SxViewEx9 chGrand ]
    1391             :             // OOXTODO: XML_errorCaption,               [ SXEx stError ]
    1392             :             // OOXTODO: XML_showError,                  [ SXEx fDisplayErrorString ]
    1393             :             // OOXTODO: XML_missingCaption,             [ SXEx stDisplayNull ]
    1394             :             // OOXTODO: XML_showMissing,                [ SXEx fDisplayNullString ]
    1395             :             // OOXTODO: XML_pageStyle,                  [ SXEx stPageFieldStyle ]
    1396             :             // OOXTODO: XML_pivotTableStyle,            [ SXEx stTableStyle ]
    1397             :             // OOXTODO: XML_vacatedStyle,               [ SXEx stVacateStyle ]
    1398             :             // OOXTODO: XML_tag,                        [ SXEx stTag ]
    1399             :             // OOXTODO: XML_updatedVersion,             [ app-dependent ]
    1400             :             // OOXTODO: XML_minRefreshableVersion,      [ app-dependent ]
    1401             :             // OOXTODO: XML_asteriskTotals,             [ QsiSXTag/SXView9Save fHideTotAnnotation ]
    1402             :             // OOXTODO: XML_showItems,                  [ ??? ]
    1403             :             // OOXTODO: XML_editData,                   [ ??? ]
    1404             :             // OOXTODO: XML_disableFieldList,           [ SXEx fEnableFieldDialog? ]
    1405             :             // OOXTODO: XML_showCalcMbrs,               [ ??? ]
    1406             :             // OOXTODO: XML_visualTotals,               [ ??? ]
    1407             :             // OOXTODO: XML_showMultipleLabel,          [ SXEx fMergeLabels? ]
    1408             :             // OOXTODO: XML_showDataDropDown,           [ SXEx fEnableDrillDown? ]
    1409             :             // OOXTODO: XML_showDrill,                  [ ??? ]
    1410             :             // OOXTODO: XML_printDrill,                 [ ??? ]
    1411             :             // OOXTODO: XML_showMemberPropertyTips,
    1412             :             // OOXTODO: XML_showDataTips,
    1413             :             // OOXTODO: XML_enableWizard,
    1414             :             XML_enableDrill,                XclXmlUtils::ToPsz( maPTExtInfo.mnFlags & EXC_SXEX_DRILLDOWN ), // ???
    1415             :             // OOXTODO: XML_enableFieldProperties,      [ SXEx fEnableFieldDialog (maPTExtInfo.mnFlags) ]
    1416             :             // OOXTODO: XML_preserveFormatting,         [ SXEx fPreserveFormatting (maPTExtInfo.mnFlags) ]
    1417             :             // OOXTODO: XML_pageWrap,                   [ SXEx cWrapPage (maPTExtInfo.mnFlags) ]
    1418             :             // OOXTODO: XML_pageOverThenDown,           [ SXEx fAcrossPageLay (maPTExtInfo.mnFlags) ]
    1419             :             // OOXTODO: XML_subtotalHiddenItems,        [ SXEx fSubtotalHiddenPageItems (maPTExtInfo.mnFlags) ]
    1420             :             XML_rowGrandTotals,             XclXmlUtils::ToPsz( maPTInfo.mnFlags & EXC_SXVIEW_ROWGRAND ),
    1421             :             XML_colGrandTotals,             XclXmlUtils::ToPsz( maPTInfo.mnFlags & EXC_SXVIEW_COLGRAND ),
    1422             :             // OOXTODO: XML_fieldPrintTitles,
    1423             :             // OOXTODO: XML_itemPrintTitles,
    1424             :             // OOXTODO: XML_mergeItem,
    1425             :             // OOXTODO: XML_showDropZones,
    1426             :             // OOXTODO: XML_createdVersion,
    1427             :             // OOXTODO: XML_indent,
    1428             :             // OOXTODO: XML_showEmptyRow,
    1429             :             // OOXTODO: XML_showEmptyCol,
    1430             :             // OOXTODO: XML_showHeaders,
    1431             :             // OOXTODO: XML_compact,
    1432             :             // OOXTODO: XML_outline,
    1433             :             // OOXTODO: XML_outlineData,
    1434             :             // OOXTODO: XML_compactData,
    1435             :             // OOXTODO: XML_published,
    1436             :             // OOXTODO: XML_gridDropZones,
    1437             :             // OOXTODO: XML_immersive,
    1438             :             // OOXTODO: XML_multipleFieldFilters,
    1439             :             // OOXTODO: XML_chartFormat,
    1440             :             // OOXTODO: XML_rowHeaderCaption,
    1441             :             // OOXTODO: XML_colHeaderCaption,
    1442             :             // OOXTODO: XML_fieldListSortAscending,
    1443             :             // OOXTODO: XML_mdxSubqueries,
    1444             :             // OOXTODO: XML_customListSort,
    1445           0 :             FSEND );
    1446             : 
    1447             :     aPivotTableDefinition->singleElement( XML_location,
    1448             :             XML_ref,            XclXmlUtils::ToOString( maPTInfo.maOutXclRange ).getStr(),
    1449             :             XML_firstHeaderRow, OString::valueOf( (sal_Int32) maPTInfo.mnFirstHeadRow ).getStr(),
    1450             :             XML_firstDataRow,   OString::valueOf( (sal_Int32) maPTInfo.maDataXclPos.mnRow ).getStr(),
    1451             :             XML_firstDataCol,   OString::valueOf( (sal_Int32) maPTInfo.maDataXclPos.mnCol ).getStr(),
    1452             :             XML_rowPageCount,   OString::valueOf( (sal_Int32) maPTInfo.mnDataRows ).getStr(),   // OOXTODO?
    1453             :             XML_colPageCount,   OString::valueOf( (sal_Int32) maPTInfo.mnDataCols ).getStr(),   // OOXTODO?
    1454           0 :             FSEND );
    1455             : 
    1456             :     // OOXTODO: XML_pivotFields
    1457             : 
    1458             :     // maPTInfo.mnFields?
    1459           0 :     if( maPTInfo.mnRowFields )
    1460             :     {
    1461             :         aPivotTableDefinition->startElement( XML_rowFields,
    1462             :                 XML_count,  OString::valueOf( (sal_Int32) maPTInfo.mnRowFields ).getStr(),
    1463           0 :                 FSEND );
    1464           0 :         aPivotTableDefinition->endElement( XML_rowFields );
    1465             :     }
    1466             : 
    1467             :     // OOXTODO: XML_rowItems
    1468             : 
    1469           0 :     if( maPTInfo.mnColFields )
    1470             :     {
    1471             :         aPivotTableDefinition->startElement( XML_colFields,
    1472             :                 XML_count,  OString::valueOf( (sal_Int32) maPTInfo.mnColFields ).getStr(),
    1473           0 :                 FSEND );
    1474           0 :         aPivotTableDefinition->endElement( XML_colFields );
    1475             :     }
    1476             : 
    1477             :     // OOXTODO: XML_colItems
    1478             : 
    1479           0 :     if( maPTInfo.mnPageFields )
    1480             :     {
    1481             :         aPivotTableDefinition->startElement( XML_pageFields,
    1482             :                 XML_count,  OString::valueOf( (sal_Int32) maPTInfo.mnPageFields ).getStr(),
    1483           0 :                 FSEND );
    1484           0 :         aPivotTableDefinition->endElement( XML_pageFields );
    1485             :     }
    1486             : 
    1487           0 :     if( maPTInfo.mnDataFields )
    1488             :     {
    1489             :         aPivotTableDefinition->startElement( XML_dataFields,
    1490             :                 XML_count,  OString::valueOf( (sal_Int32) maPTInfo.mnDataFields ).getStr(),
    1491           0 :                 FSEND );
    1492           0 :         aPivotTableDefinition->endElement( XML_dataFields );
    1493             :     }
    1494             : 
    1495             :     // OOXTODO: XML_formats, XML_conditionalFormats, XML_chartFormats,
    1496             :     //          XML_pivotHierarchies, XML_pivotTableStyleInfo, XML_filters,
    1497             :     //          XML_rowHierarchiesUsage, XML_colHierarchiesUsage, XML_ext
    1498             : 
    1499           0 :     aPivotTableDefinition->endElement( XML_pivotTableDefinition );
    1500             : 
    1501           0 :     rStrm.PopStream();
    1502             : }
    1503             : 
    1504             : // private --------------------------------------------------------------------
    1505             : 
    1506           0 : XclExpPTField* XclExpPivotTable::GetFieldAcc( const rtl::OUString& rName )
    1507             : {
    1508           0 :     XclExpPTField* pField = 0;
    1509           0 :     for( size_t nPos = 0, nSize = maFieldList.GetSize(); !pField && (nPos < nSize); ++nPos )
    1510           0 :         if( maFieldList.GetRecord( nPos )->GetFieldName() == rName )
    1511           0 :             pField = maFieldList.GetRecord( nPos ).get();
    1512           0 :     return pField;
    1513             : }
    1514             : 
    1515           0 : XclExpPTField* XclExpPivotTable::GetFieldAcc( const ScDPSaveDimension& rSaveDim )
    1516             : {
    1517             :     // data field orientation field?
    1518           0 :     if( rSaveDim.IsDataLayout() )
    1519           0 :         return &maDataOrientField;
    1520             : 
    1521             :     // a real dimension
    1522           0 :     rtl::OUString aFieldName = ScDPUtil::getSourceDimensionName(rSaveDim.GetName());
    1523           0 :     return aFieldName.isEmpty() ? NULL : GetFieldAcc(aFieldName);
    1524             : }
    1525             : 
    1526             : // fill data --------------------------------------------------------------
    1527             : 
    1528           0 : void XclExpPivotTable::SetPropertiesFromDP( const ScDPSaveData& rSaveData )
    1529             : {
    1530           0 :     ::set_flag( maPTInfo.mnFlags, EXC_SXVIEW_ROWGRAND, rSaveData.GetRowGrand() );
    1531           0 :     ::set_flag( maPTInfo.mnFlags, EXC_SXVIEW_COLGRAND, rSaveData.GetColumnGrand() );
    1532           0 :     ::set_flag( maPTExtInfo.mnFlags, EXC_SXEX_DRILLDOWN, rSaveData.GetDrillDown() );
    1533           0 :     mbFilterBtn = rSaveData.GetFilterButton();
    1534           0 :     const ScDPSaveDimension* pDim = rSaveData.GetExistingDataLayoutDimension();
    1535           0 :     if (!pDim)
    1536           0 :         return;
    1537             : 
    1538           0 :     const rtl::OUString* pLayoutName = pDim->GetLayoutName();
    1539           0 :     if (pLayoutName)
    1540           0 :         maPTInfo.maDataName = *pLayoutName;
    1541             :     else
    1542           0 :         maPTInfo.maDataName = ScGlobal::GetRscString(STR_PIVOT_DATA);
    1543             : }
    1544             : 
    1545           0 : void XclExpPivotTable::SetFieldPropertiesFromDim( const ScDPSaveDimension& rSaveDim )
    1546             : {
    1547           0 :     if( XclExpPTField* pField = GetFieldAcc( rSaveDim ) )
    1548             :     {
    1549             :         // field properties
    1550           0 :         pField->SetPropertiesFromDim( rSaveDim );
    1551             : 
    1552             :         // update the corresponding field position list
    1553           0 :         DataPilotFieldOrientation eOrient = static_cast< DataPilotFieldOrientation >( rSaveDim.GetOrientation() );
    1554           0 :         sal_uInt16 nFieldIdx = pField->GetFieldIndex();
    1555           0 :         bool bDataLayout = nFieldIdx == EXC_SXIVD_DATA;
    1556           0 :         bool bMultiData = maDataFields.size() > 1;
    1557             : 
    1558           0 :         if( !bDataLayout || bMultiData ) switch( eOrient )
    1559             :         {
    1560             :             case DataPilotFieldOrientation_ROW:
    1561           0 :                 maRowFields.push_back( nFieldIdx );
    1562           0 :                 if( bDataLayout )
    1563           0 :                     maPTInfo.mnDataAxis = EXC_SXVD_AXIS_ROW;
    1564           0 :             break;
    1565             :             case DataPilotFieldOrientation_COLUMN:
    1566           0 :                 maColFields.push_back( nFieldIdx );
    1567           0 :                 if( bDataLayout )
    1568           0 :                     maPTInfo.mnDataAxis = EXC_SXVD_AXIS_COL;
    1569           0 :             break;
    1570             :             case DataPilotFieldOrientation_PAGE:
    1571           0 :                 maPageFields.push_back( nFieldIdx );
    1572             :                 OSL_ENSURE( !bDataLayout, "XclExpPivotTable::SetFieldPropertiesFromDim - wrong orientation for data fields" );
    1573           0 :             break;
    1574             :             case DataPilotFieldOrientation_DATA:
    1575             :                 OSL_FAIL( "XclExpPivotTable::SetFieldPropertiesFromDim - called for data field" );
    1576           0 :             break;
    1577             :             default:;
    1578             :         }
    1579             :     }
    1580           0 : }
    1581             : 
    1582           0 : void XclExpPivotTable::SetDataFieldPropertiesFromDim( const ScDPSaveDimension& rSaveDim )
    1583             : {
    1584           0 :     if( XclExpPTField* pField = GetFieldAcc( rSaveDim ) )
    1585             :     {
    1586             :         // field properties
    1587           0 :         pField->SetDataPropertiesFromDim( rSaveDim );
    1588             :         // update the data field position list
    1589           0 :         maDataFields.push_back( XclPTDataFieldPos( pField->GetFieldIndex(), pField->GetLastDataInfoIndex() ) );
    1590             :     }
    1591           0 : }
    1592             : 
    1593           0 : void XclExpPivotTable::Finalize()
    1594             : {
    1595             :     // field numbers
    1596           0 :     maPTInfo.mnFields = static_cast< sal_uInt16 >( maFieldList.GetSize() );
    1597           0 :     maPTInfo.mnRowFields = static_cast< sal_uInt16 >( maRowFields.size() );
    1598           0 :     maPTInfo.mnColFields = static_cast< sal_uInt16 >( maColFields.size() );
    1599           0 :     maPTInfo.mnPageFields = static_cast< sal_uInt16 >( maPageFields.size() );
    1600           0 :     maPTInfo.mnDataFields = static_cast< sal_uInt16 >( maDataFields.size() );
    1601             : 
    1602           0 :     maPTExtInfo.mnPagePerRow = maPTInfo.mnPageFields;
    1603           0 :     maPTExtInfo.mnPagePerCol = (maPTInfo.mnPageFields > 0) ? 1 : 0;
    1604             : 
    1605             :     // subtotal items
    1606           0 :     for( size_t nPos = 0, nSize = maFieldList.GetSize(); nPos < nSize; ++nPos )
    1607           0 :         maFieldList.GetRecord( nPos )->AppendSubtotalItems();
    1608             : 
    1609             :     // find data field orientation field
    1610           0 :     maPTInfo.mnDataPos = EXC_SXVIEW_DATALAST;
    1611           0 :     const ScfUInt16Vec* pFieldVec = 0;
    1612           0 :     switch( maPTInfo.mnDataAxis )
    1613             :     {
    1614           0 :         case EXC_SXVD_AXIS_ROW: pFieldVec = &maRowFields;   break;
    1615           0 :         case EXC_SXVD_AXIS_COL: pFieldVec = &maColFields;   break;
    1616             :     }
    1617             : 
    1618           0 :     if( pFieldVec && !pFieldVec->empty() && (pFieldVec->back() != EXC_SXIVD_DATA) )
    1619             :     {
    1620           0 :         ScfUInt16Vec::const_iterator aIt = ::std::find( pFieldVec->begin(), pFieldVec->end(), EXC_SXIVD_DATA );
    1621           0 :         if( aIt != pFieldVec->end() )
    1622           0 :             maPTInfo.mnDataPos = static_cast< sal_uInt16 >( aIt - pFieldVec->begin() );
    1623             :     }
    1624             : 
    1625             :     // single data field is always row oriented
    1626           0 :     if( maPTInfo.mnDataAxis == EXC_SXVD_AXIS_NONE )
    1627           0 :         maPTInfo.mnDataAxis = EXC_SXVD_AXIS_ROW;
    1628             : 
    1629             :     // update output range (initialized in ctor)
    1630           0 :     sal_uInt16& rnXclCol1 = maPTInfo.maOutXclRange.maFirst.mnCol;
    1631           0 :     sal_uInt32& rnXclRow1 = maPTInfo.maOutXclRange.maFirst.mnRow;
    1632           0 :     sal_uInt16& rnXclCol2 = maPTInfo.maOutXclRange.maLast.mnCol;
    1633           0 :     sal_uInt32& rnXclRow2 = maPTInfo.maOutXclRange.maLast.mnRow;
    1634             :     // exclude page fields from output range
    1635           0 :     rnXclRow1 = rnXclRow1 + maPTInfo.mnPageFields;
    1636             :     // exclude filter button from output range
    1637           0 :     if( mbFilterBtn )
    1638           0 :         ++rnXclRow1;
    1639             :     // exclude empty row between (filter button and/or page fields) and table
    1640           0 :     if( mbFilterBtn || maPTInfo.mnPageFields )
    1641           0 :         ++rnXclRow1;
    1642             : 
    1643             :     // data area
    1644           0 :     sal_uInt16& rnDataXclCol = maPTInfo.maDataXclPos.mnCol;
    1645           0 :     sal_uInt32& rnDataXclRow = maPTInfo.maDataXclPos.mnRow;
    1646           0 :     rnDataXclCol = rnXclCol1 + maPTInfo.mnRowFields;
    1647           0 :     rnDataXclRow = rnXclRow1 + maPTInfo.mnColFields + 1;
    1648           0 :     if( maDataFields.empty() )
    1649           0 :         ++rnDataXclRow;
    1650             : 
    1651           0 :     bool bExtraHeaderRow = (0 == maPTViewEx9Info.mnGridLayout && maPTInfo.mnColFields == 0);
    1652           0 :     if (bExtraHeaderRow)
    1653             :         // Insert an extra row only when there is no column field.
    1654           0 :         ++rnDataXclRow;
    1655             : 
    1656           0 :     rnXclCol2 = ::std::max( rnXclCol2, rnDataXclCol );
    1657           0 :     rnXclRow2 = ::std::max( rnXclRow2, rnDataXclRow );
    1658           0 :     maPTInfo.mnDataCols = rnXclCol2 - rnDataXclCol + 1;
    1659           0 :     maPTInfo.mnDataRows = rnXclRow2 - rnDataXclRow + 1;
    1660             : 
    1661             :     // first heading
    1662           0 :     maPTInfo.mnFirstHeadRow = rnXclRow1;
    1663           0 :     if (bExtraHeaderRow)
    1664           0 :         maPTInfo.mnFirstHeadRow += 2;
    1665           0 : }
    1666             : 
    1667             : // records ----------------------------------------------------------------
    1668             : 
    1669           0 : void XclExpPivotTable::WriteSxview( XclExpStream& rStrm ) const
    1670             : {
    1671           0 :     rStrm.StartRecord( EXC_ID_SXVIEW, 46 + maPTInfo.maTableName.getLength() + maPTInfo.maDataName.getLength() );
    1672           0 :     rStrm << maPTInfo;
    1673           0 :     rStrm.EndRecord();
    1674           0 : }
    1675             : 
    1676           0 : void XclExpPivotTable::WriteSxivd( XclExpStream& rStrm, const ScfUInt16Vec& rFields ) const
    1677             : {
    1678           0 :     if( !rFields.empty() )
    1679             :     {
    1680           0 :         rStrm.StartRecord( EXC_ID_SXIVD, rFields.size() * 2 );
    1681           0 :         for( ScfUInt16Vec::const_iterator aIt = rFields.begin(), aEnd = rFields.end(); aIt != aEnd; ++aIt )
    1682           0 :             rStrm << *aIt;
    1683           0 :         rStrm.EndRecord();
    1684             :     }
    1685           0 : }
    1686             : 
    1687           0 : void XclExpPivotTable::WriteSxpi( XclExpStream& rStrm ) const
    1688             : {
    1689           0 :     if( !maPageFields.empty() )
    1690             :     {
    1691           0 :         rStrm.StartRecord( EXC_ID_SXPI, maPageFields.size() * 6 );
    1692           0 :         rStrm.SetSliceSize( 6 );
    1693           0 :         for( ScfUInt16Vec::const_iterator aIt = maPageFields.begin(), aEnd = maPageFields.end(); aIt != aEnd; ++aIt )
    1694             :         {
    1695           0 :             XclExpPTFieldRef xField = maFieldList.GetRecord( *aIt );
    1696           0 :             if( xField )
    1697           0 :                 xField->WriteSxpiEntry( rStrm );
    1698           0 :         }
    1699           0 :         rStrm.EndRecord();
    1700             :     }
    1701           0 : }
    1702             : 
    1703           0 : void XclExpPivotTable::WriteSxdiList( XclExpStream& rStrm ) const
    1704             : {
    1705           0 :     for( XclPTDataFieldPosVec::const_iterator aIt = maDataFields.begin(), aEnd = maDataFields.end(); aIt != aEnd; ++aIt )
    1706             :     {
    1707           0 :         XclExpPTFieldRef xField = maFieldList.GetRecord( aIt->first );
    1708           0 :         if( xField )
    1709           0 :             xField->WriteSxdi( rStrm, aIt->second );
    1710           0 :     }
    1711           0 : }
    1712             : 
    1713           0 : void XclExpPivotTable::WriteSxli( XclExpStream& rStrm, sal_uInt16 nLineCount, sal_uInt16 nIndexCount ) const
    1714             : {
    1715           0 :     if( nLineCount > 0 )
    1716             :     {
    1717           0 :         sal_uInt16 nLineSize = 8 + 2 * nIndexCount;
    1718           0 :         rStrm.StartRecord( EXC_ID_SXLI, nLineSize * nLineCount );
    1719             : 
    1720             :         /*  Excel expects the records to be filled completely, do not
    1721             :             set a segment size... */
    1722             : //        rStrm.SetSliceSize( nLineSize );
    1723             : 
    1724           0 :         for( sal_uInt16 nLine = 0; nLine < nLineCount; ++nLine )
    1725             :         {
    1726             :             // Excel XP needs a partly initialized SXLI record
    1727           0 :             rStrm   << sal_uInt16( 0 )      // number of equal index entries
    1728           0 :                     << EXC_SXVI_TYPE_DATA
    1729           0 :                     << nIndexCount
    1730           0 :                     << EXC_SXLI_DEFAULTFLAGS;
    1731           0 :             rStrm.WriteZeroBytes( 2 * nIndexCount );
    1732             :         }
    1733           0 :         rStrm.EndRecord();
    1734             :     }
    1735           0 : }
    1736             : 
    1737           0 : void XclExpPivotTable::WriteSxex( XclExpStream& rStrm ) const
    1738             : {
    1739           0 :     rStrm.StartRecord( EXC_ID_SXEX, 24 );
    1740           0 :     rStrm << maPTExtInfo;
    1741           0 :     rStrm.EndRecord();
    1742           0 : }
    1743             : 
    1744           0 : void XclExpPivotTable::WriteQsiSxTag( XclExpStream& rStrm ) const
    1745             : {
    1746           0 :     rStrm.StartRecord( 0x0802, 32 );
    1747             : 
    1748           0 :     sal_uInt16 nRecordType = 0x0802;
    1749           0 :     sal_uInt16 nDummyFlags = 0x0000;
    1750           0 :     sal_uInt16 nTableType  = 1; // 0 = query table : 1 = pivot table
    1751             : 
    1752           0 :     rStrm << nRecordType << nDummyFlags << nTableType;
    1753             : 
    1754             :     // General flags
    1755           0 :     bool bEnableRefresh = true;
    1756           0 :     bool bPCacheInvalid = false;
    1757           0 :     bool bOlapPTReport  = false;
    1758             : 
    1759           0 :     sal_uInt16 nFlags = 0x0000;
    1760           0 :     if (bEnableRefresh) nFlags |= 0x0001;
    1761           0 :     if (bPCacheInvalid) nFlags |= 0x0002;
    1762           0 :     if (bOlapPTReport)  nFlags |= 0x0004;
    1763           0 :     rStrm << nFlags;
    1764             : 
    1765             :     // Feature-specific options.  The value differs depending on the table
    1766             :     // type, but we assume the table type is always pivot table.
    1767           0 :     sal_uInt32 nOptions = 0x00000000;
    1768           0 :     bool bNoStencil = false;
    1769           0 :     bool bHideTotal = false;
    1770           0 :     bool bEmptyRows = false;
    1771           0 :     bool bEmptyCols = false;
    1772           0 :     if (bNoStencil) nOptions |= 0x00000001;
    1773           0 :     if (bHideTotal) nOptions |= 0x00000002;
    1774           0 :     if (bEmptyRows) nOptions |= 0x00000008;
    1775           0 :     if (bEmptyCols) nOptions |= 0x00000010;
    1776           0 :     rStrm << nOptions;
    1777             : 
    1778             :     enum ExcelVersion
    1779             :     {
    1780             :         Excel2000 = 0,
    1781             :         ExcelXP   = 1,
    1782             :         Excel2003 = 2,
    1783             :         Excel2007 = 3
    1784             :     };
    1785           0 :     ExcelVersion eXclVer = Excel2000;
    1786           0 :     sal_uInt8 nOffsetBytes = 16;
    1787           0 :     rStrm << static_cast<sal_uInt8>(eXclVer)  // version table last refreshed
    1788           0 :           << static_cast<sal_uInt8>(eXclVer)  // minimum version to refresh
    1789           0 :           << nOffsetBytes
    1790           0 :           << static_cast<sal_uInt8>(eXclVer); // first version created
    1791             : 
    1792           0 :     rStrm << XclExpString(maPTInfo.maTableName);
    1793           0 :     rStrm << static_cast<sal_uInt16>(0x0001); // no idea what this is for.
    1794             : 
    1795           0 :     rStrm.EndRecord();
    1796           0 : }
    1797             : 
    1798           0 : void XclExpPivotTable::WriteSxViewEx9( XclExpStream& rStrm ) const
    1799             : {
    1800             :     // Until we sync the autoformat ids only export if using grid header layout
    1801             :     // That could only have been set via xls import so far.
    1802           0 :     if ( 0 == maPTViewEx9Info.mnGridLayout )
    1803             :     {
    1804           0 :         rStrm.StartRecord( EXC_ID_SXVIEWEX9, 17 );
    1805           0 :         rStrm << maPTViewEx9Info;
    1806           0 :         rStrm.EndRecord();
    1807             :     }
    1808           0 : }
    1809             : 
    1810             : // ============================================================================
    1811             : 
    1812             : namespace {
    1813             : 
    1814             : const SCTAB EXC_PTMGR_PIVOTCACHES = SCTAB_MAX;
    1815             : 
    1816             : /** Record wrapper class to write the pivot caches or pivot tables. */
    1817           4 : class XclExpPivotRecWrapper : public XclExpRecordBase
    1818             : {
    1819             : public:
    1820             :     explicit            XclExpPivotRecWrapper( XclExpPivotTableManager& rPTMgr, SCTAB nScTab );
    1821             :     virtual void        Save( XclExpStream& rStrm );
    1822             :     virtual void        SaveXml( XclExpXmlStream& rStrm );
    1823             : private:
    1824             :     XclExpPivotTableManager& mrPTMgr;
    1825             :     SCTAB               mnScTab;
    1826             : };
    1827             : 
    1828           2 : XclExpPivotRecWrapper::XclExpPivotRecWrapper( XclExpPivotTableManager& rPTMgr, SCTAB nScTab ) :
    1829             :     mrPTMgr( rPTMgr ),
    1830           2 :     mnScTab( nScTab )
    1831             : {
    1832           2 : }
    1833             : 
    1834           0 : void XclExpPivotRecWrapper::Save( XclExpStream& rStrm )
    1835             : {
    1836           0 :     if( mnScTab == EXC_PTMGR_PIVOTCACHES )
    1837           0 :         mrPTMgr.WritePivotCaches( rStrm );
    1838             :     else
    1839           0 :         mrPTMgr.WritePivotTables( rStrm, mnScTab );
    1840           0 : }
    1841             : 
    1842           2 : void XclExpPivotRecWrapper::SaveXml( XclExpXmlStream& rStrm )
    1843             : {
    1844           2 :     if( mnScTab == EXC_PTMGR_PIVOTCACHES )
    1845           1 :         mrPTMgr.WritePivotCachesXml( rStrm );
    1846             :     else
    1847           1 :         mrPTMgr.WritePivotTablesXml( rStrm, mnScTab );
    1848           2 : }
    1849             : 
    1850             : } // namespace
    1851             : 
    1852             : // ----------------------------------------------------------------------------
    1853             : 
    1854           1 : XclExpPivotTableManager::XclExpPivotTableManager( const XclExpRoot& rRoot ) :
    1855             :     XclExpRoot( rRoot ),
    1856           1 :     mbShareCaches( true )
    1857             : {
    1858           1 : }
    1859             : 
    1860           1 : void XclExpPivotTableManager::CreatePivotTables()
    1861             : {
    1862           1 :     if( ScDPCollection* pDPColl = GetDoc().GetDPCollection() )
    1863           1 :         for( size_t nDPObj = 0, nCount = pDPColl->GetCount(); nDPObj < nCount; ++nDPObj )
    1864           0 :             if( ScDPObject* pDPObj = (*pDPColl)[ nDPObj ] )
    1865           0 :                 if( const XclExpPivotCache* pPCache = CreatePivotCache( *pDPObj ) )
    1866           0 :                     maPTableList.AppendNewRecord( new XclExpPivotTable( GetRoot(), *pDPObj, *pPCache ) );
    1867           1 : }
    1868             : 
    1869           1 : XclExpRecordRef XclExpPivotTableManager::CreatePivotCachesRecord()
    1870             : {
    1871           1 :     return XclExpRecordRef( new XclExpPivotRecWrapper( *this, EXC_PTMGR_PIVOTCACHES ) );
    1872             : }
    1873             : 
    1874           1 : XclExpRecordRef XclExpPivotTableManager::CreatePivotTablesRecord( SCTAB nScTab )
    1875             : {
    1876           1 :     return XclExpRecordRef( new XclExpPivotRecWrapper( *this, nScTab ) );
    1877             : }
    1878             : 
    1879           0 : void XclExpPivotTableManager::WritePivotCaches( XclExpStream& rStrm )
    1880             : {
    1881           0 :     maPCacheList.Save( rStrm );
    1882           0 : }
    1883             : 
    1884           1 : void XclExpPivotTableManager::WritePivotCachesXml( XclExpXmlStream&
    1885             : #ifdef XLSX_PIVOT_CACHE
    1886             :                                                                     rStrm
    1887             : #endif
    1888             : )
    1889             : {
    1890             : #ifdef XLSX_PIVOT_CACHE /* <pivotCache> without xl/pivotCaches/ cacheStream
    1891             :                            results in a broken .xlsx */
    1892             :     if( maPCacheList.IsEmpty() )
    1893             :         return;
    1894             :     sax_fastparser::FSHelperPtr& rWorkbook = rStrm.GetCurrentStream();
    1895             :     rWorkbook->startElement( XML_pivotCaches, FSEND );
    1896             :     maPCacheList.SaveXml( rStrm );
    1897             :     rWorkbook->endElement( XML_pivotCaches );
    1898             : #endif /* XLSX_PIVOT_CACHE */
    1899           1 : }
    1900             : 
    1901           0 : void XclExpPivotTableManager::WritePivotTables( XclExpStream& rStrm, SCTAB nScTab )
    1902             : {
    1903           0 :     for( size_t nPos = 0, nSize = maPTableList.GetSize(); nPos < nSize; ++nPos )
    1904             :     {
    1905           0 :         XclExpPivotTableRef xPTable = maPTableList.GetRecord( nPos );
    1906           0 :         if( xPTable->GetScTab() == nScTab )
    1907           0 :             xPTable->Save( rStrm );
    1908           0 :     }
    1909           0 : }
    1910             : 
    1911           1 : void XclExpPivotTableManager::WritePivotTablesXml( XclExpXmlStream& rStrm, SCTAB nScTab )
    1912             : {
    1913           1 :     for( size_t nPos = 0, nSize = maPTableList.GetSize(); nPos < nSize; ++nPos )
    1914             :     {
    1915           0 :         XclExpPivotTableRef xPTable = maPTableList.GetRecord( nPos );
    1916           0 :         if( xPTable->GetScTab() == nScTab )
    1917           0 :             xPTable->SaveXml( rStrm );
    1918           0 :     }
    1919           1 : }
    1920             : 
    1921             : // private --------------------------------------------------------------------
    1922             : 
    1923           0 : const XclExpPivotCache* XclExpPivotTableManager::CreatePivotCache( const ScDPObject& rDPObj )
    1924             : {
    1925             :     // try to find a pivot cache with the same data source
    1926             :     /*  #i25110# In Excel, the pivot cache contains additional fields
    1927             :         (i.e. grouping info, calculated fields). If the passed DataPilot object
    1928             :         or the found cache contains this data, do not share the cache with
    1929             :         multiple pivot tables. */
    1930           0 :     if( mbShareCaches )
    1931             :     {
    1932           0 :         if( const ScDPSaveData* pSaveData = rDPObj.GetSaveData() )
    1933             :         {
    1934           0 :             const ScDPDimensionSaveData* pDimSaveData = pSaveData->GetExistingDimensionData();
    1935             :             // no dimension save data at all or save data does not contain grouping info
    1936           0 :             if( !pDimSaveData || !pDimSaveData->HasGroupDimensions() )
    1937             :             {
    1938             :                 // check all existing pivot caches
    1939           0 :                 for( size_t nPos = 0, nSize = maPCacheList.GetSize(); nPos < nSize; ++nPos )
    1940             :                 {
    1941           0 :                     XclExpPivotCacheRef xPCache = maPCacheList.GetRecord( nPos );
    1942             :                     // pivot cache does not have grouping info and source data is equal
    1943           0 :                     if( !xPCache->HasAddFields() && xPCache->HasEqualDataSource( rDPObj ) )
    1944           0 :                         return xPCache.get();
    1945           0 :                 }
    1946             :             }
    1947             :         }
    1948             :     }
    1949             : 
    1950             :     // create a new pivot cache
    1951           0 :     sal_uInt16 nNewCacheIdx = static_cast< sal_uInt16 >( maPCacheList.GetSize() );
    1952           0 :     XclExpPivotCacheRef xNewPCache( new XclExpPivotCache( GetRoot(), rDPObj, nNewCacheIdx ) );
    1953           0 :     if( xNewPCache->IsValid() )
    1954             :     {
    1955           0 :         maPCacheList.AppendRecord( xNewPCache );
    1956           0 :         return xNewPCache.get();
    1957             :     }
    1958             : 
    1959           0 :     return 0;
    1960           9 : }
    1961             : 
    1962             : // ============================================================================
    1963             : 
    1964             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10