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

Generated by: LCOV version 1.10