LCOV - code coverage report
Current view: top level - libreoffice/sc/source/core/data - dpoutput.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 478 1064 44.9 %
Date: 2012-12-27 Functions: 35 54 64.8 %
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 "scitems.hxx"
      21             : #include <svx/algitem.hxx>
      22             : #include <editeng/boxitem.hxx>
      23             : #include <editeng/brshitem.hxx>
      24             : #include <editeng/wghtitem.hxx>
      25             : #include <editeng/justifyitem.hxx>
      26             : #include <unotools/transliterationwrapper.hxx>
      27             : 
      28             : #include "dpoutput.hxx"
      29             : #include "dptabsrc.hxx"
      30             : #include "dpfilteredcache.hxx"
      31             : #include "document.hxx"
      32             : #include "patattr.hxx"
      33             : #include "docpool.hxx"
      34             : #include "markdata.hxx"
      35             : #include "attrib.hxx"
      36             : #include "formula/errorcodes.hxx"       // errNoValue
      37             : #include "miscuno.hxx"
      38             : #include "globstr.hrc"
      39             : #include "stlpool.hxx"
      40             : #include "stlsheet.hxx"
      41             : #include "scresid.hxx"
      42             : #include "unonames.hxx"
      43             : #include "sc.hrc"
      44             : #include "stringutil.hxx"
      45             : #include "dputil.hxx"
      46             : 
      47             : #include <com/sun/star/beans/XPropertySet.hpp>
      48             : #include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
      49             : #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
      50             : #include <com/sun/star/sheet/DataPilotTablePositionData.hpp>
      51             : #include <com/sun/star/sheet/DataPilotTableResultData.hpp>
      52             : #include <com/sun/star/sheet/MemberResultFlags.hpp>
      53             : #include <com/sun/star/sheet/TableFilterField.hpp>
      54             : #include <com/sun/star/sheet/DataResultFlags.hpp>
      55             : #include <com/sun/star/sheet/DataPilotTablePositionType.hpp>
      56             : 
      57             : #include <vector>
      58             : 
      59             : using namespace com::sun::star;
      60             : using ::std::vector;
      61             : using ::com::sun::star::beans::XPropertySet;
      62             : using ::com::sun::star::uno::Sequence;
      63             : using ::com::sun::star::uno::UNO_QUERY;
      64             : using ::com::sun::star::uno::Reference;
      65             : using ::com::sun::star::sheet::DataPilotTablePositionData;
      66             : using ::com::sun::star::sheet::DataPilotTableResultData;
      67             : using ::com::sun::star::uno::makeAny;
      68             : using ::com::sun::star::uno::Any;
      69             : using ::rtl::OUString;
      70             : 
      71             : #define SC_DP_FRAME_INNER_BOLD      20
      72             : #define SC_DP_FRAME_OUTER_BOLD      40
      73             : 
      74             : #define SC_DP_FRAME_COLOR           Color(0,0,0) //( 0x20, 0x40, 0x68 )
      75             : 
      76             : #define SC_DPOUT_MAXLEVELS  256
      77             : 
      78       19232 : struct ScDPOutLevelData
      79             : {
      80             :     long                                nDim;
      81             :     long                                nHier;
      82             :     long                                nLevel;
      83             :     long                                nDimPos;
      84             :     uno::Sequence<sheet::MemberResult>  aResult;
      85             :     rtl::OUString                       maName;   /// Name is the internal field name.
      86             :     rtl::OUString                       maCaption; /// Caption is the name visible in the output table.
      87             :     bool                                mbHasHiddenMember:1;
      88             :     bool                                mbDataLayout:1;
      89             :     bool                                mbPageDim:1;
      90             : 
      91       19208 :     ScDPOutLevelData() :
      92       19208 :         nDim(-1), nHier(-1), nLevel(-1), nDimPos(-1), mbHasHiddenMember(false), mbDataLayout(false), mbPageDim(false)
      93       19208 :     {}
      94             : 
      95           9 :     bool operator<(const ScDPOutLevelData& r) const
      96             :         { return nDimPos<r.nDimPos || ( nDimPos==r.nDimPos && nHier<r.nHier ) ||
      97           9 :             ( nDimPos==r.nDimPos && nHier==r.nHier && nLevel<r.nLevel ); }
      98             : 
      99           8 :     void Swap(ScDPOutLevelData& r)
     100           8 :         { ScDPOutLevelData aTemp; aTemp = r; r = *this; *this = aTemp; }
     101             : 
     102             :     //! bug (73840) in uno::Sequence - copy and then assign doesn't work!
     103             : };
     104             : 
     105             : namespace {
     106             : 
     107          56 : bool lcl_compareColfuc ( SCCOL i,  SCCOL j) { return (i<j); }
     108         104 : bool lcl_compareRowfuc ( SCROW i,  SCROW j) { return (i<j); }
     109             : 
     110          53 : class ScDPOutputImpl
     111             : {
     112             :     ScDocument*         mpDoc;
     113             :     sal_uInt16          mnTab;
     114             :     ::std::vector< bool > mbNeedLineCols;
     115             :     ::std::vector< SCCOL > mnCols;
     116             : 
     117             :     ::std::vector< bool > mbNeedLineRows;
     118             :     ::std::vector< SCROW > mnRows;
     119             : 
     120             :     SCCOL   mnTabStartCol;
     121             :     SCROW   mnTabStartRow;
     122             : 
     123             :     SCCOL   mnDataStartCol;
     124             :     SCROW   mnDataStartRow;
     125             :     SCCOL   mnTabEndCol;
     126             :     SCROW   mnTabEndRow;
     127             : 
     128             : public:
     129             :     ScDPOutputImpl( ScDocument* pDoc, sal_uInt16 nTab,
     130             :         SCCOL   nTabStartCol,
     131             :         SCROW   nTabStartRow,
     132             :         SCCOL nDataStartCol,
     133             :         SCROW nDataStartRow,
     134             :         SCCOL nTabEndCol,
     135             :         SCROW nTabEndRow );
     136             :     bool AddRow( SCROW nRow );
     137             :     bool AddCol( SCCOL nCol );
     138             : 
     139             :     void OutputDataArea();
     140             :     void OutputBlockFrame ( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, bool bHori = false );
     141             : 
     142             : };
     143             : 
     144          25 : void ScDPOutputImpl::OutputDataArea()
     145             : {
     146          25 :     AddRow( mnDataStartRow );
     147          25 :     AddCol( mnDataStartCol );
     148             : 
     149          25 :     mnCols.push_back( mnTabEndCol+1); //set last row bottom
     150          25 :     mnRows.push_back( mnTabEndRow+1); //set last col bottom
     151             : 
     152          25 :     bool bAllRows = ( ( mnTabEndRow - mnDataStartRow + 2 ) == (SCROW) mnRows.size() );
     153             : 
     154          25 :     std::sort( mnCols.begin(), mnCols.end(), lcl_compareColfuc );
     155          25 :     std::sort( mnRows.begin(), mnRows.end(), lcl_compareRowfuc );
     156             : 
     157          56 :     for( SCCOL nCol = 0; nCol < (SCCOL)mnCols.size()-1; nCol ++ )
     158             :     {
     159          31 :         if ( !bAllRows )
     160             :         {
     161          28 :             if ( nCol < (SCCOL)mnCols.size()-2)
     162             :             {
     163          10 :                 for ( SCROW i = nCol%2; i < (SCROW)mnRows.size()-2; i +=2 )
     164           5 :                     OutputBlockFrame( mnCols[nCol], mnRows[i], mnCols[nCol+1]-1, mnRows[i+1]-1 );
     165           5 :                 if ( mnRows.size()>=2 )
     166           5 :                     OutputBlockFrame(  mnCols[nCol], mnRows[mnRows.size()-2], mnCols[nCol+1]-1, mnRows[mnRows.size()-1]-1 );
     167             :             }
     168             :             else
     169             :             {
     170          77 :                 for ( SCROW i = 0 ; i < (SCROW)mnRows.size()-1; i++ )
     171          54 :                     OutputBlockFrame(  mnCols[nCol], mnRows[i], mnCols[nCol+1]-1,  mnRows[i+1]-1 );
     172             :             }
     173             :         }
     174             :         else
     175           3 :             OutputBlockFrame( mnCols[nCol], mnRows.front(), mnCols[nCol+1]-1, mnRows.back()-1, bAllRows );
     176             :     }
     177             :     //out put rows area outer framer
     178          25 :     if ( mnTabStartCol != mnDataStartCol )
     179             :     {
     180          25 :         if ( mnTabStartRow != mnDataStartRow )
     181          25 :             OutputBlockFrame( mnTabStartCol, mnTabStartRow, mnDataStartCol-1, mnDataStartRow-1 );
     182          25 :         OutputBlockFrame( mnTabStartCol, mnDataStartRow, mnDataStartCol-1, mnTabEndRow );
     183             :     }
     184             :     //out put cols area outer framer
     185          25 :     OutputBlockFrame( mnDataStartCol, mnTabStartRow, mnTabEndCol, mnDataStartRow-1 );
     186          25 : }
     187             : 
     188          53 : ScDPOutputImpl::ScDPOutputImpl( ScDocument* pDoc, sal_uInt16 nTab,
     189             :         SCCOL   nTabStartCol,
     190             :         SCROW   nTabStartRow,
     191             :         SCCOL nDataStartCol,
     192             :         SCROW nDataStartRow,
     193             :         SCCOL nTabEndCol,
     194             :         SCROW nTabEndRow ):
     195             :     mpDoc( pDoc ),
     196             :     mnTab( nTab ),
     197             :     mnTabStartCol( nTabStartCol ),
     198             :     mnTabStartRow( nTabStartRow ),
     199             :     mnDataStartCol ( nDataStartCol ),
     200             :     mnDataStartRow ( nDataStartRow ),
     201             :     mnTabEndCol(  nTabEndCol ),
     202          53 :     mnTabEndRow(  nTabEndRow )
     203             : {
     204          53 :     mbNeedLineCols.resize( nTabEndCol-nDataStartCol+1, false );
     205          53 :     mbNeedLineRows.resize( nTabEndRow-nDataStartRow+1, false );
     206             : 
     207          53 : }
     208             : 
     209          66 : bool ScDPOutputImpl::AddRow( SCROW nRow )
     210             : {
     211          66 :     if ( !mbNeedLineRows[ nRow - mnDataStartRow ] )
     212             :     {
     213          58 :         mbNeedLineRows[ nRow - mnDataStartRow ] = true;
     214          58 :         mnRows.push_back( nRow );
     215          58 :         return true;
     216             :     }
     217             :     else
     218           8 :         return false;
     219             : }
     220             : 
     221          31 : bool ScDPOutputImpl::AddCol( SCCOL nCol )
     222             : {
     223             : 
     224          31 :     if ( !mbNeedLineCols[ nCol - mnDataStartCol ] )
     225             :     {
     226          31 :         mbNeedLineCols[ nCol - mnDataStartCol ] = true;
     227          31 :         mnCols.push_back( nCol );
     228          31 :         return true;
     229             :     }
     230             :     else
     231           0 :         return false;
     232             : }
     233             : 
     234         228 : void ScDPOutputImpl::OutputBlockFrame ( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, bool bHori )
     235             : {
     236         228 :     Color color = SC_DP_FRAME_COLOR;
     237         228 :     ::editeng::SvxBorderLine aLine( &color, SC_DP_FRAME_INNER_BOLD );
     238         228 :     ::editeng::SvxBorderLine aOutLine( &color, SC_DP_FRAME_OUTER_BOLD );
     239             : 
     240         228 :     SvxBoxItem aBox( ATTR_BORDER );
     241             : 
     242         228 :     if ( nStartCol == mnTabStartCol )
     243          98 :         aBox.SetLine(&aOutLine, BOX_LINE_LEFT);
     244             :     else
     245         130 :         aBox.SetLine(&aLine, BOX_LINE_LEFT);
     246             : 
     247         228 :     if ( nStartRow == mnTabStartRow )
     248          57 :         aBox.SetLine(&aOutLine, BOX_LINE_TOP);
     249             :     else
     250         171 :         aBox.SetLine(&aLine, BOX_LINE_TOP);
     251             : 
     252         228 :     if ( nEndCol == mnTabEndCol ) //bottom row
     253         110 :         aBox.SetLine(&aOutLine, BOX_LINE_RIGHT);
     254             :     else
     255         118 :         aBox.SetLine(&aLine,  BOX_LINE_RIGHT);
     256             : 
     257         228 :      if ( nEndRow == mnTabEndRow ) //bottom
     258          77 :         aBox.SetLine(&aOutLine,  BOX_LINE_BOTTOM);
     259             :     else
     260         151 :         aBox.SetLine(&aLine,  BOX_LINE_BOTTOM);
     261             : 
     262             : 
     263         228 :     SvxBoxInfoItem aBoxInfo( ATTR_BORDER_INNER );
     264         228 :     aBoxInfo.SetValid(VALID_VERT,false );
     265         228 :     if ( bHori )
     266             :     {
     267           3 :         aBoxInfo.SetValid(VALID_HORI,true);
     268           3 :         aBoxInfo.SetLine( &aLine, BOXINFO_LINE_HORI );
     269             :     }
     270             :     else
     271         225 :         aBoxInfo.SetValid(VALID_HORI,false );
     272             : 
     273         228 :     aBoxInfo.SetValid(VALID_DISTANCE,false);
     274             : 
     275         228 :     mpDoc->ApplyFrameAreaTab( ScRange(  nStartCol, nStartRow, mnTab, nEndCol, nEndRow , mnTab ), &aBox, &aBoxInfo );
     276             : 
     277         228 : }
     278             : 
     279         294 : void lcl_SetStyleById( ScDocument* pDoc, SCTAB nTab,
     280             :                     SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
     281             :                     sal_uInt16 nStrId )
     282             : {
     283         294 :     if ( nCol1 > nCol2 || nRow1 > nRow2 )
     284             :     {
     285             :         OSL_FAIL("SetStyleById: invalid range");
     286         294 :         return;
     287             :     }
     288             : 
     289         294 :     rtl::OUString aStyleName = ScGlobal::GetRscString( nStrId );
     290         294 :     ScStyleSheetPool* pStlPool = pDoc->GetStyleSheetPool();
     291         294 :     ScStyleSheet* pStyle = (ScStyleSheet*) pStlPool->Find( aStyleName, SFX_STYLE_FAMILY_PARA );
     292         294 :     if (!pStyle)
     293             :     {
     294             :         //  create new style (was in ScPivot::SetStyle)
     295             : 
     296             :         pStyle = (ScStyleSheet*) &pStlPool->Make( aStyleName, SFX_STYLE_FAMILY_PARA,
     297          76 :                                                     SFXSTYLEBIT_USERDEF );
     298          76 :         pStyle->SetParent( ScGlobal::GetRscString(STR_STYLENAME_STANDARD) );
     299          76 :         SfxItemSet& rSet = pStyle->GetItemSet();
     300          76 :         if ( nStrId==STR_PIVOT_STYLE_RESULT || nStrId==STR_PIVOT_STYLE_TITLE )
     301          24 :             rSet.Put( SvxWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT ) );
     302          76 :         if ( nStrId==STR_PIVOT_STYLE_CATEGORY || nStrId==STR_PIVOT_STYLE_TITLE )
     303          25 :             rSet.Put( SvxHorJustifyItem( SVX_HOR_JUSTIFY_LEFT, ATTR_HOR_JUSTIFY ) );
     304             :     }
     305             : 
     306         294 :     pDoc->ApplyStyleAreaTab( nCol1, nRow1, nCol2, nRow2, nTab, *pStyle );
     307             : }
     308             : 
     309          43 : void lcl_SetFrame( ScDocument* pDoc, SCTAB nTab,
     310             :                     SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
     311             :                     sal_uInt16 nWidth )
     312             : {
     313          43 :     ::editeng::SvxBorderLine aLine(0, nWidth, table::BorderLineStyle::SOLID);
     314          43 :     SvxBoxItem aBox( ATTR_BORDER );
     315          43 :     aBox.SetLine(&aLine, BOX_LINE_LEFT);
     316          43 :     aBox.SetLine(&aLine, BOX_LINE_TOP);
     317          43 :     aBox.SetLine(&aLine, BOX_LINE_RIGHT);
     318          43 :     aBox.SetLine(&aLine, BOX_LINE_BOTTOM);
     319          43 :     SvxBoxInfoItem aBoxInfo( ATTR_BORDER_INNER );
     320          43 :     aBoxInfo.SetValid(VALID_HORI,false);
     321          43 :     aBoxInfo.SetValid(VALID_VERT,false);
     322          43 :     aBoxInfo.SetValid(VALID_DISTANCE,false);
     323             : 
     324          43 :     pDoc->ApplyFrameAreaTab( ScRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab ), &aBox, &aBoxInfo );
     325          43 : }
     326             : 
     327             : // -----------------------------------------------------------------------
     328             : 
     329          25 : void lcl_FillNumberFormats( sal_uInt32*& rFormats, long& rCount,
     330             :                             const uno::Reference<sheet::XDataPilotMemberResults>& xLevRes,
     331             :                             const uno::Reference<container::XIndexAccess>& xDims )
     332             : {
     333          25 :     if ( rFormats )
     334          25 :         return;                         // already set
     335             : 
     336             :     //  xLevRes is from the data layout dimension
     337             :     //! use result sequence from ScDPOutLevelData!
     338             : 
     339          25 :     uno::Sequence<sheet::MemberResult> aResult = xLevRes->getResults();
     340             : 
     341          25 :     long nSize = aResult.getLength();
     342          25 :     if (nSize)
     343             :     {
     344             :         //  get names/formats for all data dimensions
     345             :         //! merge this with the loop to collect ScDPOutLevelData?
     346             : 
     347        6425 :         rtl::OUString aDataNames[SC_DPOUT_MAXLEVELS];
     348             :         sal_uInt32 nDataFormats[SC_DPOUT_MAXLEVELS];
     349          25 :         long nDataCount = 0;
     350          25 :         bool bAnySet = false;
     351             : 
     352          25 :         long nDimCount = xDims->getCount();
     353         128 :         for (long nDim=0; nDim<nDimCount; nDim++)
     354             :         {
     355             :             uno::Reference<uno::XInterface> xDim =
     356         103 :                     ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
     357         103 :             uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
     358         103 :             uno::Reference<container::XNamed> xDimName( xDim, uno::UNO_QUERY );
     359         103 :             if ( xDimProp.is() && xDimName.is() )
     360             :             {
     361             :                 sheet::DataPilotFieldOrientation eDimOrient =
     362             :                     (sheet::DataPilotFieldOrientation) ScUnoHelpFunctions::GetEnumProperty(
     363             :                         xDimProp, rtl::OUString(SC_UNO_DP_ORIENTATION),
     364         103 :                         sheet::DataPilotFieldOrientation_HIDDEN );
     365         103 :                 if ( eDimOrient == sheet::DataPilotFieldOrientation_DATA )
     366             :                 {
     367          31 :                     aDataNames[nDataCount] = xDimName->getName();
     368             :                     long nFormat = ScUnoHelpFunctions::GetLongProperty(
     369             :                                             xDimProp,
     370          31 :                                             rtl::OUString(SC_UNONAME_NUMFMT) );
     371          31 :                     nDataFormats[nDataCount] = nFormat;
     372          31 :                     if ( nFormat != 0 )
     373           0 :                         bAnySet = true;
     374          31 :                     ++nDataCount;
     375             :                 }
     376             :             }
     377         103 :         }
     378             : 
     379          25 :         if ( bAnySet )      // forget everything if all formats are 0 (or no data dimensions)
     380             :         {
     381           0 :             const sheet::MemberResult* pArray = aResult.getConstArray();
     382             : 
     383           0 :             rtl::OUString aName;
     384           0 :             sal_uInt32* pNumFmt = new sal_uInt32[nSize];
     385           0 :             if (nDataCount == 1)
     386             :             {
     387             :                 //  only one data dimension -> use its numberformat everywhere
     388           0 :                 long nFormat = nDataFormats[0];
     389           0 :                 for (long nPos=0; nPos<nSize; nPos++)
     390           0 :                     pNumFmt[nPos] = nFormat;
     391             :             }
     392             :             else
     393             :             {
     394           0 :                 for (long nPos=0; nPos<nSize; nPos++)
     395             :                 {
     396             :                     //  if CONTINUE bit is set, keep previous name
     397             :                     //! keep number format instead!
     398           0 :                     if ( !(pArray[nPos].Flags & sheet::MemberResultFlags::CONTINUE) )
     399           0 :                         aName = pArray[nPos].Name;
     400             : 
     401           0 :                     sal_uInt32 nFormat = 0;
     402           0 :                     for (long i=0; i<nDataCount; i++)
     403           0 :                         if (aName == aDataNames[i])         //! search more efficiently?
     404             :                         {
     405           0 :                             nFormat = nDataFormats[i];
     406           0 :                             break;
     407             :                         }
     408           0 :                     pNumFmt[nPos] = nFormat;
     409             :                 }
     410             :             }
     411             : 
     412           0 :             rFormats = pNumFmt;
     413           0 :             rCount = nSize;
     414        6425 :         }
     415          25 :     }
     416             : }
     417             : 
     418           0 : sal_uInt32 lcl_GetFirstNumberFormat( const uno::Reference<container::XIndexAccess>& xDims )
     419             : {
     420           0 :     long nDimCount = xDims->getCount();
     421           0 :     for (long nDim=0; nDim<nDimCount; nDim++)
     422             :     {
     423             :         uno::Reference<uno::XInterface> xDim =
     424           0 :                 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
     425           0 :         uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
     426           0 :         if ( xDimProp.is() )
     427             :         {
     428             :             sheet::DataPilotFieldOrientation eDimOrient =
     429             :                 (sheet::DataPilotFieldOrientation) ScUnoHelpFunctions::GetEnumProperty(
     430             :                     xDimProp, rtl::OUString(SC_UNO_DP_ORIENTATION),
     431           0 :                     sheet::DataPilotFieldOrientation_HIDDEN );
     432           0 :             if ( eDimOrient == sheet::DataPilotFieldOrientation_DATA )
     433             :             {
     434             :                 long nFormat = ScUnoHelpFunctions::GetLongProperty(
     435             :                                         xDimProp,
     436           0 :                                         rtl::OUString(SC_UNONAME_NUMFMT) );
     437             : 
     438           0 :                 return nFormat;     // use format from first found data dimension
     439             :             }
     440             :         }
     441           0 :     }
     442             : 
     443           0 :     return 0;       // none found
     444             : }
     445             : 
     446          75 : void lcl_SortFields( ScDPOutLevelData* pFields, long nFieldCount )
     447             : {
     448          82 :     for (long i=0; i+1<nFieldCount; i++)
     449             :     {
     450          16 :         for (long j=0; j+i+1<nFieldCount; j++)
     451           9 :             if ( pFields[j+1] < pFields[j] )
     452           8 :                 pFields[j].Swap( pFields[j+1] );
     453             :     }
     454          75 : }
     455             : 
     456          58 : bool lcl_MemberEmpty( const uno::Sequence<sheet::MemberResult>& rSeq )
     457             : {
     458             :     //  used to skip levels that have no members
     459             : 
     460          58 :     long nLen = rSeq.getLength();
     461          58 :     const sheet::MemberResult* pArray = rSeq.getConstArray();
     462         169 :     for (long i=0; i<nLen; i++)
     463         150 :         if (pArray[i].Flags & sheet::MemberResultFlags::HASMEMBER)
     464          39 :             return false;
     465             : 
     466          19 :     return true;    // no member data -> empty
     467             : }
     468             : 
     469             : /**
     470             :  * Get visible page dimension members as results, except that, if all
     471             :  * members are visible, then this function returns empty result.
     472             :  */
     473           4 : uno::Sequence<sheet::MemberResult> getVisiblePageMembersAsResults( const uno::Reference<uno::XInterface>& xLevel )
     474             : {
     475           4 :     if (!xLevel.is())
     476           0 :         return uno::Sequence<sheet::MemberResult>();
     477             : 
     478           4 :     uno::Reference<sheet::XMembersSupplier> xMSupplier(xLevel, UNO_QUERY);
     479           4 :     if (!xMSupplier.is())
     480           0 :         return uno::Sequence<sheet::MemberResult>();
     481             : 
     482           4 :     uno::Reference<container::XNameAccess> xNA = xMSupplier->getMembers();
     483           4 :     if (!xNA.is())
     484           0 :         return uno::Sequence<sheet::MemberResult>();
     485             : 
     486           4 :     std::vector<sheet::MemberResult> aRes;
     487           4 :     uno::Sequence<OUString> aNames = xNA->getElementNames();
     488          12 :     for (sal_Int32 i = 0; i < aNames.getLength(); ++i)
     489             :     {
     490           8 :         const OUString& rName = aNames[i];
     491           8 :         xNA->getByName(rName);
     492             : 
     493           8 :         uno::Reference<beans::XPropertySet> xMemPS(xNA->getByName(rName), UNO_QUERY);
     494           8 :         if (!xMemPS.is())
     495           0 :             continue;
     496             : 
     497           8 :         OUString aCaption = ScUnoHelpFunctions::GetStringProperty(xMemPS, SC_UNO_DP_LAYOUTNAME, OUString());
     498           8 :         if (aCaption.isEmpty())
     499           8 :             aCaption = rName;
     500             : 
     501           8 :         bool bVisible = ScUnoHelpFunctions::GetBoolProperty(xMemPS, SC_UNO_DP_ISVISIBLE, false);
     502             : 
     503           8 :         if (bVisible)
     504           6 :             aRes.push_back(sheet::MemberResult(rName, aCaption, 0));
     505           8 :     }
     506             : 
     507           4 :     if (aNames.getLength() == static_cast<sal_Int32>(aRes.size()))
     508             :         // All members are visible.  Return empty result.
     509           2 :         return uno::Sequence<sheet::MemberResult>();
     510             : 
     511           2 :     return ScUnoHelpFunctions::VectorToSequence(aRes);
     512             : }
     513             : 
     514             : }
     515             : 
     516          25 : ScDPOutput::ScDPOutput( ScDocument* pD, const uno::Reference<sheet::XDimensionsSupplier>& xSrc,
     517             :                         const ScAddress& rPos, bool bFilter ) :
     518             :     pDoc( pD ),
     519             :     xSource( xSrc ),
     520             :     aStartPos( rPos ),
     521             :     pColNumFmt( NULL ),
     522             :     pRowNumFmt( NULL ),
     523             :     nColFmtCount( 0 ),
     524             :     nRowFmtCount( 0 ),
     525             :     nSingleNumFmt( 0 ),
     526             :     bDoFilter(bFilter),
     527             :     bResultsError(false),
     528             :     mbHasDataLayout(false),
     529             :     bSizesValid(false),
     530             :     bSizeOverflow(false),
     531          25 :     mbHeaderLayout(false)
     532             : {
     533          25 :     nTabStartCol = nMemberStartCol = nDataStartCol = nTabEndCol = 0;
     534          25 :     nTabStartRow = nMemberStartRow = nDataStartRow = nTabEndRow = 0;
     535             : 
     536          25 :     pColFields  = new ScDPOutLevelData[SC_DPOUT_MAXLEVELS];
     537          25 :     pRowFields  = new ScDPOutLevelData[SC_DPOUT_MAXLEVELS];
     538          25 :     pPageFields = new ScDPOutLevelData[SC_DPOUT_MAXLEVELS];
     539          25 :     nColFieldCount = 0;
     540          25 :     nRowFieldCount = 0;
     541          25 :     nPageFieldCount = 0;
     542             : 
     543          25 :     uno::Reference<sheet::XDataPilotResults> xResult( xSource, uno::UNO_QUERY );
     544          25 :     if ( xSource.is() && xResult.is() )
     545             :     {
     546             :         //  get dimension results:
     547             : 
     548             :         uno::Reference<container::XIndexAccess> xDims =
     549          25 :                 new ScNameToIndexAccess( xSource->getDimensions() );
     550          25 :         long nDimCount = xDims->getCount();
     551         128 :         for (long nDim=0; nDim<nDimCount; nDim++)
     552             :         {
     553             :             uno::Reference<uno::XInterface> xDim =
     554         103 :                     ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
     555         103 :             uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
     556         103 :             uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDim, uno::UNO_QUERY );
     557         103 :             if ( xDimProp.is() && xDimSupp.is() )
     558             :             {
     559             :                 sheet::DataPilotFieldOrientation eDimOrient =
     560             :                     (sheet::DataPilotFieldOrientation) ScUnoHelpFunctions::GetEnumProperty(
     561             :                         xDimProp, rtl::OUString(SC_UNO_DP_ORIENTATION),
     562         103 :                         sheet::DataPilotFieldOrientation_HIDDEN );
     563             :                 long nDimPos = ScUnoHelpFunctions::GetLongProperty( xDimProp,
     564         103 :                         rtl::OUString(SC_UNO_DP_POSITION) );
     565             :                 bool bIsDataLayout = ScUnoHelpFunctions::GetBoolProperty(
     566         103 :                     xDimProp, rtl::OUString(SC_UNO_DP_ISDATALAYOUT));
     567             :                 bool bHasHiddenMember = ScUnoHelpFunctions::GetBoolProperty(
     568         103 :                     xDimProp, OUString(SC_UNO_DP_HAS_HIDDEN_MEMBER));
     569             : 
     570         103 :                 if ( eDimOrient != sheet::DataPilotFieldOrientation_HIDDEN )
     571             :                 {
     572             :                     uno::Reference<container::XIndexAccess> xHiers =
     573          93 :                             new ScNameToIndexAccess( xDimSupp->getHierarchies() );
     574             :                     long nHierarchy = ScUnoHelpFunctions::GetLongProperty(
     575             :                                             xDimProp,
     576          93 :                                             rtl::OUString(SC_UNO_DP_USEDHIERARCHY) );
     577          93 :                     if ( nHierarchy >= xHiers->getCount() )
     578           0 :                         nHierarchy = 0;
     579             : 
     580             :                     uno::Reference<uno::XInterface> xHier =
     581             :                             ScUnoHelpFunctions::AnyToInterface(
     582          93 :                                                 xHiers->getByIndex(nHierarchy) );
     583          93 :                     uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
     584          93 :                     if ( xHierSupp.is() )
     585             :                     {
     586             :                         uno::Reference<container::XIndexAccess> xLevels =
     587          93 :                                 new ScNameToIndexAccess( xHierSupp->getLevels() );
     588          93 :                         long nLevCount = xLevels->getCount();
     589         186 :                         for (long nLev=0; nLev<nLevCount; nLev++)
     590             :                         {
     591             :                             uno::Reference<uno::XInterface> xLevel =
     592             :                                         ScUnoHelpFunctions::AnyToInterface(
     593          93 :                                                             xLevels->getByIndex(nLev) );
     594          93 :                             uno::Reference<container::XNamed> xLevNam( xLevel, uno::UNO_QUERY );
     595             :                             uno::Reference<sheet::XDataPilotMemberResults> xLevRes(
     596          93 :                                     xLevel, uno::UNO_QUERY );
     597          93 :                             if ( xLevNam.is() && xLevRes.is() )
     598             :                             {
     599          93 :                                 rtl::OUString aName = xLevNam->getName();
     600          93 :                                 Reference<XPropertySet> xPropSet(xLevel, UNO_QUERY);
     601             :                                 // Caption equals the field name by default.
     602             :                                 // #i108948# use ScUnoHelpFunctions::GetStringProperty, because
     603             :                                 // LayoutName is new and may not be present in external implementation
     604             :                                 OUString aCaption = ScUnoHelpFunctions::GetStringProperty( xPropSet,
     605          93 :                                     OUString(SC_UNO_DP_LAYOUTNAME), aName );
     606             : 
     607          93 :                                 bool bRowFieldHasMember = false;
     608          93 :                                 switch ( eDimOrient )
     609             :                                 {
     610             :                                     case sheet::DataPilotFieldOrientation_COLUMN:
     611           7 :                                         pColFields[nColFieldCount].nDim    = nDim;
     612           7 :                                         pColFields[nColFieldCount].nHier   = nHierarchy;
     613           7 :                                         pColFields[nColFieldCount].nLevel  = nLev;
     614           7 :                                         pColFields[nColFieldCount].nDimPos = nDimPos;
     615           7 :                                         pColFields[nColFieldCount].aResult = xLevRes->getResults();
     616           7 :                                         pColFields[nColFieldCount].maName  = aName;
     617           7 :                                         pColFields[nColFieldCount].maCaption= aCaption;
     618           7 :                                         pColFields[nColFieldCount].mbHasHiddenMember = bHasHiddenMember;
     619           7 :                                         pColFields[nColFieldCount].mbDataLayout = bIsDataLayout;
     620           7 :                                         if (!lcl_MemberEmpty(pColFields[nColFieldCount].aResult))
     621           7 :                                             ++nColFieldCount;
     622           7 :                                         break;
     623             :                                     case sheet::DataPilotFieldOrientation_ROW:
     624          51 :                                         pRowFields[nRowFieldCount].nDim    = nDim;
     625          51 :                                         pRowFields[nRowFieldCount].nHier   = nHierarchy;
     626          51 :                                         pRowFields[nRowFieldCount].nLevel  = nLev;
     627          51 :                                         pRowFields[nRowFieldCount].nDimPos = nDimPos;
     628          51 :                                         pRowFields[nRowFieldCount].aResult = xLevRes->getResults();
     629          51 :                                         pRowFields[nRowFieldCount].maName  = aName;
     630          51 :                                         pRowFields[nRowFieldCount].maCaption= aCaption;
     631          51 :                                         pRowFields[nRowFieldCount].mbHasHiddenMember = bHasHiddenMember;
     632          51 :                                         pRowFields[nRowFieldCount].mbDataLayout = bIsDataLayout;
     633          51 :                                         if (!lcl_MemberEmpty(pRowFields[nRowFieldCount].aResult))
     634             :                                         {
     635          32 :                                             ++nRowFieldCount;
     636          32 :                                             bRowFieldHasMember = true;
     637             :                                         }
     638          51 :                                         break;
     639             :                                     case sheet::DataPilotFieldOrientation_PAGE:
     640           4 :                                         pPageFields[nPageFieldCount].nDim    = nDim;
     641           4 :                                         pPageFields[nPageFieldCount].nHier   = nHierarchy;
     642           4 :                                         pPageFields[nPageFieldCount].nLevel  = nLev;
     643           4 :                                         pPageFields[nPageFieldCount].nDimPos = nDimPos;
     644           4 :                                         pPageFields[nPageFieldCount].aResult = getVisiblePageMembersAsResults(xLevel);
     645           4 :                                         pPageFields[nPageFieldCount].maName  = aName;
     646           4 :                                         pPageFields[nPageFieldCount].maCaption= aCaption;
     647           4 :                                         pPageFields[nPageFieldCount].mbHasHiddenMember = bHasHiddenMember;
     648           4 :                                         pPageFields[nPageFieldCount].mbPageDim = true;
     649             :                                         // no check on results for page fields
     650           4 :                                         ++nPageFieldCount;
     651           4 :                                         break;
     652             :                                     default:
     653             :                                     {
     654             :                                         // added to avoid warnings
     655             :                                     }
     656             :                                 }
     657             : 
     658             :                                 // get number formats from data dimensions
     659          93 :                                 if ( bIsDataLayout )
     660             :                                 {
     661          25 :                                     if (bRowFieldHasMember)
     662           5 :                                         mbHasDataLayout = true;
     663             : 
     664             :                                     OSL_ENSURE( nLevCount == 1, "data layout: multiple levels?" );
     665          25 :                                     if ( eDimOrient == sheet::DataPilotFieldOrientation_COLUMN )
     666           1 :                                         lcl_FillNumberFormats( pColNumFmt, nColFmtCount, xLevRes, xDims );
     667          24 :                                     else if ( eDimOrient == sheet::DataPilotFieldOrientation_ROW )
     668          24 :                                         lcl_FillNumberFormats( pRowNumFmt, nRowFmtCount, xLevRes, xDims );
     669          93 :                                 }
     670             :                             }
     671         186 :                         }
     672          93 :                     }
     673             :                 }
     674          10 :                 else if ( bIsDataLayout )
     675             :                 {
     676             :                     // data layout dimension is hidden (allowed if there is only one data dimension)
     677             :                     // -> use the number format from the first data dimension for all results
     678             : 
     679           0 :                     nSingleNumFmt = lcl_GetFirstNumberFormat( xDims );
     680             :                 }
     681             :             }
     682         103 :         }
     683          25 :         lcl_SortFields( pColFields, nColFieldCount );
     684          25 :         lcl_SortFields( pRowFields, nRowFieldCount );
     685          25 :         lcl_SortFields( pPageFields, nPageFieldCount );
     686             : 
     687             :         //  get data results:
     688             : 
     689             :         try
     690             :         {
     691          25 :             aData = xResult->getResults();
     692             :         }
     693           0 :         catch (uno::RuntimeException&)
     694             :         {
     695           0 :             bResultsError = true;
     696          25 :         }
     697             :     }
     698             : 
     699             :     // get "DataDescription" property (may be missing in external sources)
     700             : 
     701          25 :     uno::Reference<beans::XPropertySet> xSrcProp( xSource, uno::UNO_QUERY );
     702          25 :     if ( xSrcProp.is() )
     703             :     {
     704             :         try
     705             :         {
     706          25 :             uno::Any aAny = xSrcProp->getPropertyValue(
     707          25 :                     rtl::OUString(SC_UNO_DP_DATADESC) );
     708          25 :             rtl::OUString aUStr;
     709          25 :             aAny >>= aUStr;
     710          25 :             aDataDescription = aUStr;
     711             :         }
     712           0 :         catch(uno::Exception&)
     713             :         {
     714             :         }
     715          25 :     }
     716          25 : }
     717             : 
     718          50 : ScDPOutput::~ScDPOutput()
     719             : {
     720          25 :     delete[] pColFields;
     721          25 :     delete[] pRowFields;
     722          25 :     delete[] pPageFields;
     723             : 
     724          25 :     delete[] pColNumFmt;
     725          25 :     delete[] pRowNumFmt;
     726          25 : }
     727             : 
     728          27 : void ScDPOutput::SetPosition( const ScAddress& rPos )
     729             : {
     730          27 :     aStartPos = rPos;
     731          27 :     bSizesValid = bSizeOverflow = false;
     732          27 : }
     733             : 
     734         233 : void ScDPOutput::DataCell( SCCOL nCol, SCROW nRow, SCTAB nTab, const sheet::DataResult& rData )
     735             : {
     736         233 :     long nFlags = rData.Flags;
     737         233 :     if ( nFlags & sheet::DataResultFlags::ERROR )
     738             :     {
     739           0 :         pDoc->SetError( nCol, nRow, nTab, errNoValue );
     740             :     }
     741         233 :     else if ( nFlags & sheet::DataResultFlags::HASDATA )
     742             :     {
     743         178 :         pDoc->SetValue( nCol, nRow, nTab, rData.Value );
     744             : 
     745             :         //  use number formats from source
     746             : 
     747             :         OSL_ENSURE( bSizesValid, "DataCell: !bSizesValid" );
     748         178 :         sal_uInt32 nFormat = 0;
     749         178 :         if ( pColNumFmt )
     750             :         {
     751           0 :             if ( nCol >= nDataStartCol )
     752             :             {
     753           0 :                 long nIndex = nCol - nDataStartCol;
     754           0 :                 if ( nIndex < nColFmtCount )
     755           0 :                     nFormat = pColNumFmt[nIndex];
     756             :             }
     757             :         }
     758         178 :         else if ( pRowNumFmt )
     759             :         {
     760           0 :             if ( nRow >= nDataStartRow )
     761             :             {
     762           0 :                 long nIndex = nRow - nDataStartRow;
     763           0 :                 if ( nIndex < nRowFmtCount )
     764           0 :                     nFormat = pRowNumFmt[nIndex];
     765             :             }
     766             :         }
     767         178 :         else if ( nSingleNumFmt != 0 )
     768           0 :             nFormat = nSingleNumFmt;        // single format is used everywhere
     769         178 :         if ( nFormat != 0 )
     770           0 :             pDoc->ApplyAttr( nCol, nRow, nTab, SfxUInt32Item( ATTR_VALUE_FORMAT, nFormat ) );
     771             :     }
     772             :     //  SubTotal formatting is controlled by headers
     773         233 : }
     774             : 
     775         200 : void ScDPOutput::HeaderCell( SCCOL nCol, SCROW nRow, SCTAB nTab,
     776             :                              const sheet::MemberResult& rData, bool bColHeader, long nLevel )
     777             : {
     778         200 :     long nFlags = rData.Flags;
     779             : 
     780         200 :     if ( nFlags & sheet::MemberResultFlags::HASMEMBER )
     781             :     {
     782         173 :         bool bNumeric = (nFlags & sheet::MemberResultFlags::NUMERIC) != 0;
     783         173 :         ScSetStringParam aParam;
     784         173 :         if (bNumeric)
     785             :         {
     786          11 :             aParam.mbDetectNumberFormat = true;
     787          11 :             aParam.meSetTextNumFormat = ScSetStringParam::Never;
     788          11 :             aParam.mbHandleApostrophe = true;
     789             :         }
     790             :         else
     791             :         {
     792         162 :             aParam.mbDetectNumberFormat = false;
     793         162 :             aParam.meSetTextNumFormat = ScSetStringParam::Always;
     794         162 :             aParam.mbHandleApostrophe = false;
     795             :         }
     796         173 :         pDoc->SetString(nCol, nRow, nTab, rData.Caption, &aParam);
     797             :     }
     798             : 
     799         200 :     if ( nFlags & sheet::MemberResultFlags::SUBTOTAL )
     800             :     {
     801             :         ScDPOutputImpl outputimp( pDoc, nTab,
     802             :             nTabStartCol, nTabStartRow,
     803          28 :             nDataStartCol, nDataStartRow, nTabEndCol, nTabEndRow );
     804             :         //! limit frames to horizontal or vertical?
     805          28 :         if (bColHeader)
     806             :         {
     807           6 :             outputimp.OutputBlockFrame( nCol,nMemberStartRow+(SCROW)nLevel, nCol,nDataStartRow-1 );
     808             : 
     809             :             lcl_SetStyleById( pDoc,nTab, nCol,nMemberStartRow+(SCROW)nLevel, nCol,nDataStartRow-1,
     810           6 :                                     STR_PIVOT_STYLE_TITLE );
     811             :             lcl_SetStyleById( pDoc,nTab, nCol,nDataStartRow, nCol,nTabEndRow,
     812           6 :                                     STR_PIVOT_STYLE_RESULT );
     813             :         }
     814             :         else
     815             :         {
     816          22 :             outputimp.OutputBlockFrame( nMemberStartCol+(SCCOL)nLevel,nRow, nDataStartCol-1,nRow );
     817             :             lcl_SetStyleById( pDoc,nTab, nMemberStartCol+(SCCOL)nLevel,nRow, nDataStartCol-1,nRow,
     818          22 :                                     STR_PIVOT_STYLE_TITLE );
     819             :             lcl_SetStyleById( pDoc,nTab, nDataStartCol,nRow, nTabEndCol,nRow,
     820          22 :                                     STR_PIVOT_STYLE_RESULT );
     821          28 :         }
     822             :     }
     823         200 : }
     824             : 
     825          43 : void ScDPOutput::FieldCell(
     826             :     SCCOL nCol, SCROW nRow, SCTAB nTab, const ScDPOutLevelData& rData, bool bInTable)
     827             : {
     828             :     // Avoid unwanted automatic format detection.
     829          43 :     ScSetStringParam aParam;
     830          43 :     aParam.mbDetectNumberFormat = false;
     831          43 :     aParam.meSetTextNumFormat = ScSetStringParam::Always;
     832          43 :     aParam.mbHandleApostrophe = false;
     833          43 :     pDoc->SetString(nCol, nRow, nTab, rData.maCaption, &aParam);
     834             : 
     835          43 :     if (bInTable)
     836          39 :         lcl_SetFrame( pDoc,nTab, nCol,nRow, nCol,nRow, 20 );
     837             : 
     838             :     // For field button drawing
     839          43 :     sal_uInt16 nMergeFlag = 0;
     840          43 :     if (rData.mbHasHiddenMember)
     841           3 :         nMergeFlag |= SC_MF_HIDDEN_MEMBER;
     842             : 
     843          43 :     if (rData.mbPageDim)
     844             :     {
     845           4 :         nMergeFlag |= SC_MF_BUTTON_POPUP;
     846           4 :         pDoc->ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, SC_MF_BUTTON);
     847           4 :         pDoc->ApplyFlagsTab(nCol+1, nRow, nCol+1, nRow, nTab, nMergeFlag);
     848             :     }
     849             :     else
     850             :     {
     851          39 :         nMergeFlag |= SC_MF_BUTTON;
     852          39 :         if (!rData.mbDataLayout)
     853          33 :             nMergeFlag |= SC_MF_BUTTON_POPUP;
     854          39 :         pDoc->ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, nMergeFlag);
     855             :     }
     856             : 
     857             : 
     858          43 :     lcl_SetStyleById( pDoc,nTab, nCol,nRow, nCol,nRow, STR_PIVOT_STYLE_FIELDNAME );
     859          43 : }
     860             : 
     861           4 : static void lcl_DoFilterButton( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
     862             : {
     863           4 :     pDoc->SetString( nCol, nRow, nTab, ScGlobal::GetRscString(STR_CELL_FILTER) );
     864           4 :     pDoc->ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, SC_MF_BUTTON);
     865           4 : }
     866             : 
     867          96 : void ScDPOutput::CalcSizes()
     868             : {
     869          96 :     if (!bSizesValid)
     870             :     {
     871             :         //  get column size of data from first row
     872             :         //! allow different sizes (and clear following areas) ???
     873             : 
     874          48 :         nRowCount = aData.getLength();
     875          48 :         const uno::Sequence<sheet::DataResult>* pRowAry = aData.getConstArray();
     876          48 :         nColCount = nRowCount ? ( pRowAry[0].getLength() ) : 0;
     877             : 
     878          48 :         nHeaderSize = 1;
     879          48 :         if (GetHeaderLayout() && nColFieldCount == 0)
     880             :             // Insert an extra header row only when there is no column field.
     881           0 :             nHeaderSize = 2;
     882             : 
     883             :         //  calculate output positions and sizes
     884             : 
     885          48 :         long nPageSize = 0;     //! use page fields!
     886          48 :         if ( bDoFilter || nPageFieldCount )
     887             :         {
     888           8 :             nPageSize += nPageFieldCount + 1;   // plus one empty row
     889           8 :             if ( bDoFilter )
     890           8 :                 ++nPageSize;        //  filter button above the page fields
     891             :         }
     892             : 
     893          96 :         if ( aStartPos.Col() + nRowFieldCount + nColCount - 1 > MAXCOL ||
     894          48 :              aStartPos.Row() + nPageSize + nHeaderSize + nColFieldCount + nRowCount > MAXROW )
     895             :         {
     896           0 :             bSizeOverflow = true;
     897             :         }
     898             : 
     899          48 :         nTabStartCol = aStartPos.Col();
     900          48 :         nTabStartRow = aStartPos.Row() + (SCROW)nPageSize;          // below page fields
     901          48 :         nMemberStartCol = nTabStartCol;
     902          48 :         nMemberStartRow = nTabStartRow + (SCROW) nHeaderSize;
     903          48 :         nDataStartCol = nMemberStartCol + (SCCOL)nRowFieldCount;
     904          48 :         nDataStartRow = nMemberStartRow + (SCROW)nColFieldCount;
     905          48 :         if ( nColCount > 0 )
     906          48 :             nTabEndCol = nDataStartCol + (SCCOL)nColCount - 1;
     907             :         else
     908           0 :             nTabEndCol = nDataStartCol;     // single column will remain empty
     909             :         // if page fields are involved, include the page selection cells
     910          48 :         if ( nPageFieldCount > 0 && nTabEndCol < nTabStartCol + 1 )
     911           0 :             nTabEndCol = nTabStartCol + 1;
     912          48 :         if ( nRowCount > 0 )
     913          48 :             nTabEndRow = nDataStartRow + (SCROW)nRowCount - 1;
     914             :         else
     915           0 :             nTabEndRow = nDataStartRow;     // single row will remain empty
     916          48 :         bSizesValid = true;
     917             :     }
     918          96 : }
     919             : 
     920           0 : sal_Int32 ScDPOutput::GetPositionType(const ScAddress& rPos)
     921             : {
     922             :     using namespace ::com::sun::star::sheet;
     923             : 
     924           0 :     SCCOL nCol = rPos.Col();
     925           0 :     SCROW nRow = rPos.Row();
     926           0 :     SCTAB nTab = rPos.Tab();
     927           0 :     if ( nTab != aStartPos.Tab() )
     928           0 :         return DataPilotTablePositionType::NOT_IN_TABLE;
     929             : 
     930           0 :     CalcSizes();
     931             : 
     932             :     // Make sure the cursor is within the table.
     933           0 :     if (nCol < nTabStartCol || nRow < nTabStartRow || nCol > nTabEndCol || nRow > nTabEndRow)
     934           0 :         return DataPilotTablePositionType::NOT_IN_TABLE;
     935             : 
     936             :     // test for result data area.
     937           0 :     if (nCol >= nDataStartCol && nCol <= nTabEndCol && nRow >= nDataStartRow && nRow <= nTabEndRow)
     938           0 :         return DataPilotTablePositionType::RESULT;
     939             : 
     940           0 :     bool bInColHeader = (nRow >= nTabStartRow && nRow < nDataStartRow);
     941           0 :     bool bInRowHeader = (nCol >= nTabStartCol && nCol < nDataStartCol);
     942             : 
     943           0 :     if (bInColHeader && bInRowHeader)
     944             :         // probably in that ugly little box at the upper-left corner of the table.
     945           0 :         return DataPilotTablePositionType::OTHER;
     946             : 
     947           0 :     if (bInColHeader)
     948             :     {
     949           0 :         if (nRow == nTabStartRow)
     950             :             // first row in the column header area is always used for column
     951             :             // field buttons.
     952           0 :             return DataPilotTablePositionType::OTHER;
     953             : 
     954           0 :         return DataPilotTablePositionType::COLUMN_HEADER;
     955             :     }
     956             : 
     957           0 :     if (bInRowHeader)
     958           0 :         return DataPilotTablePositionType::ROW_HEADER;
     959             : 
     960           0 :     return DataPilotTablePositionType::OTHER;
     961             : }
     962             : 
     963          25 : void ScDPOutput::Output()
     964             : {
     965             :     long nField;
     966          25 :     SCTAB nTab = aStartPos.Tab();
     967          25 :     const uno::Sequence<sheet::DataResult>* pRowAry = aData.getConstArray();
     968             : 
     969             :     //  calculate output positions and sizes
     970             : 
     971          25 :     CalcSizes();
     972          25 :     if ( bSizeOverflow || bResultsError )   // does output area exceed sheet limits?
     973          25 :         return;                             // nothing
     974             : 
     975             :     //  clear whole (new) output area
     976             :     //! when modifying table, clear old area
     977             :     //! include IDF_OBJECTS ???
     978          25 :     pDoc->DeleteAreaTab( aStartPos.Col(), aStartPos.Row(), nTabEndCol, nTabEndRow, nTab, IDF_ALL );
     979             : 
     980          25 :     if ( bDoFilter )
     981           4 :         lcl_DoFilterButton( pDoc, aStartPos.Col(), aStartPos.Row(), nTab );
     982             : 
     983             :     //  output data results:
     984             : 
     985         153 :     for (long nRow=0; nRow<nRowCount; nRow++)
     986             :     {
     987         128 :         SCROW nRowPos = nDataStartRow + (SCROW)nRow;                    //! check for overflow
     988         128 :         const sheet::DataResult* pColAry = pRowAry[nRow].getConstArray();
     989         128 :         long nThisColCount = pRowAry[nRow].getLength();
     990             :         OSL_ENSURE( nThisColCount == nColCount, "count mismatch" );     //! ???
     991         361 :         for (long nCol=0; nCol<nThisColCount; nCol++)
     992             :         {
     993         233 :             SCCOL nColPos = nDataStartCol + (SCCOL)nCol;                //! check for overflow
     994         233 :             DataCell( nColPos, nRowPos, nTab, pColAry[nCol] );
     995             :         }
     996             :     }
     997             :     //  output page fields:
     998             : 
     999          29 :     for (nField=0; nField<nPageFieldCount; nField++)
    1000             :     {
    1001           4 :         SCCOL nHdrCol = aStartPos.Col();
    1002           4 :         SCROW nHdrRow = aStartPos.Row() + nField + ( bDoFilter ? 1 : 0 );
    1003             :         // draw without frame for consistency with filter button:
    1004           4 :         FieldCell(nHdrCol, nHdrRow, nTab, pPageFields[nField], false);
    1005           4 :         SCCOL nFldCol = nHdrCol + 1;
    1006             : 
    1007           4 :         OUString aPageValue = ScResId(SCSTR_ALL).toString();
    1008           4 :         const uno::Sequence<sheet::MemberResult>& rRes = pPageFields[nField].aResult;
    1009           4 :         sal_Int32 n = rRes.getLength();
    1010           4 :         if (n == 1)
    1011           2 :             aPageValue = rRes[0].Caption;
    1012           2 :         else if (n > 1)
    1013           0 :             aPageValue = ScResId(SCSTR_MULTIPLE).toString();
    1014             : 
    1015           4 :         pDoc->SetString( nFldCol, nHdrRow, nTab, aPageValue );
    1016             : 
    1017           4 :         lcl_SetFrame( pDoc,nTab, nFldCol,nHdrRow, nFldCol,nHdrRow, 20 );
    1018           4 :     }
    1019             : 
    1020             :     //  data description
    1021             :     //  (may get overwritten by first row field)
    1022             : 
    1023          25 :     if (aDataDescription.isEmpty())
    1024             :     {
    1025             :         //! use default string ("result") ?
    1026             :     }
    1027          25 :     pDoc->SetString(nTabStartCol, nTabStartRow, nTab, aDataDescription);
    1028             : 
    1029             :     //  set STR_PIVOT_STYLE_INNER for whole data area (subtotals are overwritten)
    1030             : 
    1031          25 :     if ( nDataStartRow > nTabStartRow )
    1032             :         lcl_SetStyleById( pDoc, nTab, nTabStartCol, nTabStartRow, nTabEndCol, nDataStartRow-1,
    1033          25 :                             STR_PIVOT_STYLE_TOP );
    1034             :     lcl_SetStyleById( pDoc, nTab, nDataStartCol, nDataStartRow, nTabEndCol, nTabEndRow,
    1035          25 :                         STR_PIVOT_STYLE_INNER );
    1036             : 
    1037             :     //  output column headers:
    1038             :     ScDPOutputImpl outputimp( pDoc, nTab,
    1039             :         nTabStartCol, nTabStartRow,
    1040          25 :         nDataStartCol, nDataStartRow, nTabEndCol, nTabEndRow );
    1041          32 :     for (nField=0; nField<nColFieldCount; nField++)
    1042             :     {
    1043           7 :         SCCOL nHdrCol = nDataStartCol + (SCCOL)nField;              //! check for overflow
    1044           7 :         FieldCell(nHdrCol, nTabStartRow, nTab, pColFields[nField], true);
    1045             : 
    1046           7 :         SCROW nRowPos = nMemberStartRow + (SCROW)nField;                //! check for overflow
    1047           7 :         const uno::Sequence<sheet::MemberResult> rSequence = pColFields[nField].aResult;
    1048           7 :         const sheet::MemberResult* pArray = rSequence.getConstArray();
    1049           7 :         long nThisColCount = rSequence.getLength();
    1050             :         OSL_ENSURE( nThisColCount == nColCount, "count mismatch" );     //! ???
    1051          33 :         for (long nCol=0; nCol<nThisColCount; nCol++)
    1052             :         {
    1053          26 :             SCCOL nColPos = nDataStartCol + (SCCOL)nCol;                //! check for overflow
    1054          26 :             HeaderCell( nColPos, nRowPos, nTab, pArray[nCol], true, nField );
    1055          52 :             if ( ( pArray[nCol].Flags & sheet::MemberResultFlags::HASMEMBER ) &&
    1056          26 :                 !( pArray[nCol].Flags & sheet::MemberResultFlags::SUBTOTAL ) )
    1057             :             {
    1058          20 :                 long nEnd = nCol;
    1059          40 :                 while ( nEnd+1 < nThisColCount && ( pArray[nEnd+1].Flags & sheet::MemberResultFlags::CONTINUE ) )
    1060           0 :                     ++nEnd;
    1061          20 :                 SCCOL nEndColPos = nDataStartCol + (SCCOL)nEnd;     //! check for overflow
    1062          20 :                 if ( nField+1 < nColFieldCount )
    1063             :                 {
    1064           0 :                     if ( nField == nColFieldCount - 2 )
    1065             :                     {
    1066           0 :                         outputimp.AddCol( nColPos );
    1067           0 :                         if ( nColPos + 1 == nEndColPos  )
    1068           0 :                             outputimp.OutputBlockFrame( nColPos,nRowPos, nEndColPos,nRowPos+1, true );
    1069             :                     }
    1070             :                     else
    1071           0 :                         outputimp.OutputBlockFrame( nColPos,nRowPos, nEndColPos,nRowPos );
    1072             : 
    1073           0 :                     lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nEndColPos,nDataStartRow-1, STR_PIVOT_STYLE_CATEGORY );
    1074             :                 }
    1075             :                 else
    1076          20 :                     lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nColPos,nDataStartRow-1, STR_PIVOT_STYLE_CATEGORY );
    1077             :             }
    1078           6 :             else if (  pArray[nCol].Flags & sheet::MemberResultFlags::SUBTOTAL )
    1079           6 :                 outputimp.AddCol( nColPos );
    1080             :         }
    1081           7 :         if ( nField== 0 && nColFieldCount == 1 )
    1082           7 :             outputimp.OutputBlockFrame( nDataStartCol,nTabStartRow, nTabEndCol,nRowPos-1 );
    1083           7 :     }
    1084             : 
    1085             :     //  output row headers:
    1086          25 :     std::vector<bool> vbSetBorder;
    1087          25 :     vbSetBorder.resize( nTabEndRow - nDataStartRow + 1, false );
    1088          57 :     for (nField=0; nField<nRowFieldCount; nField++)
    1089             :     {
    1090          32 :         SCCOL nHdrCol = nTabStartCol + (SCCOL)nField;                   //! check for overflow
    1091          32 :         SCROW nHdrRow = nDataStartRow - 1;
    1092          32 :         FieldCell(nHdrCol, nHdrRow, nTab, pRowFields[nField], true);
    1093             : 
    1094          32 :         SCCOL nColPos = nMemberStartCol + (SCCOL)nField;                //! check for overflow
    1095          32 :         const uno::Sequence<sheet::MemberResult> rSequence = pRowFields[nField].aResult;
    1096          32 :         const sheet::MemberResult* pArray = rSequence.getConstArray();
    1097          32 :         long nThisRowCount = rSequence.getLength();
    1098             :         OSL_ENSURE( nThisRowCount == nRowCount, "count mismatch" );     //! ???
    1099         206 :         for (long nRow=0; nRow<nThisRowCount; nRow++)
    1100             :         {
    1101         174 :             SCROW nRowPos = nDataStartRow + (SCROW)nRow;                //! check for overflow
    1102         174 :             HeaderCell( nColPos, nRowPos, nTab, pArray[nRow], false, nField );
    1103         321 :             if ( ( pArray[nRow].Flags & sheet::MemberResultFlags::HASMEMBER ) &&
    1104         147 :                 !( pArray[nRow].Flags & sheet::MemberResultFlags::SUBTOTAL ) )
    1105             :             {
    1106         125 :                 if ( nField+1 < nRowFieldCount )
    1107             :                 {
    1108          19 :                     long nEnd = nRow;
    1109          57 :                     while ( nEnd+1 < nThisRowCount && ( pArray[nEnd+1].Flags & sheet::MemberResultFlags::CONTINUE ) )
    1110          19 :                         ++nEnd;
    1111          19 :                     SCROW nEndRowPos = nDataStartRow + (SCROW)nEnd;     //! check for overflow
    1112          19 :                     outputimp.AddRow( nRowPos );
    1113          19 :                     if ( vbSetBorder[ nRow ] == false )
    1114             :                     {
    1115          16 :                         outputimp.OutputBlockFrame( nColPos, nRowPos, nTabEndCol, nEndRowPos );
    1116          16 :                         vbSetBorder[ nRow ]  = true;
    1117             :                     }
    1118          19 :                     outputimp.OutputBlockFrame( nColPos, nRowPos, nColPos, nEndRowPos );
    1119             : 
    1120          19 :                     if ( nField == nRowFieldCount - 2 )
    1121          16 :                         outputimp.OutputBlockFrame( nColPos+1, nRowPos, nColPos+1, nEndRowPos );
    1122             : 
    1123          19 :                     lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nDataStartCol-1,nEndRowPos, STR_PIVOT_STYLE_CATEGORY );
    1124             :                 }
    1125             :                 else
    1126         106 :                     lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nDataStartCol-1,nRowPos, STR_PIVOT_STYLE_CATEGORY );
    1127             :             }
    1128          49 :             else if (  pArray[nRow].Flags & sheet::MemberResultFlags::SUBTOTAL )
    1129          22 :                 outputimp.AddRow( nRowPos );
    1130             :         }
    1131          32 :     }
    1132             : 
    1133          25 :     outputimp.OutputDataArea();
    1134             : }
    1135             : 
    1136          48 : ScRange ScDPOutput::GetOutputRange( sal_Int32 nRegionType )
    1137             : {
    1138             :     using namespace ::com::sun::star::sheet;
    1139             : 
    1140          48 :     CalcSizes();
    1141             : 
    1142          48 :     SCTAB nTab = aStartPos.Tab();
    1143          48 :     switch (nRegionType)
    1144             :     {
    1145             :         case DataPilotOutputRangeType::RESULT:
    1146           0 :             return ScRange(nDataStartCol, nDataStartRow, nTab, nTabEndCol, nTabEndRow, nTab);
    1147             :         case DataPilotOutputRangeType::TABLE:
    1148           0 :             return ScRange(aStartPos.Col(), nTabStartRow, nTab, nTabEndCol, nTabEndRow, nTab);
    1149             :         default:
    1150             :             OSL_ENSURE(nRegionType == DataPilotOutputRangeType::WHOLE, "ScDPOutput::GetOutputRange: unknown region type");
    1151          48 :         break;
    1152             :     }
    1153          48 :     return ScRange(aStartPos.Col(), aStartPos.Row(), nTab, nTabEndCol, nTabEndRow, nTab);
    1154             : }
    1155             : 
    1156          23 : bool ScDPOutput::HasError()
    1157             : {
    1158          23 :     CalcSizes();
    1159             : 
    1160          23 :     return bSizeOverflow || bResultsError;
    1161             : }
    1162             : 
    1163          25 : long ScDPOutput::GetHeaderRows()
    1164             : {
    1165          25 :     return nPageFieldCount + ( bDoFilter ? 1 : 0 );
    1166             : }
    1167             : 
    1168           0 : void ScDPOutput::GetMemberResultNames(ScDPUniqueStringSet& rNames, long nDimension)
    1169             : {
    1170             :     //  Return the list of all member names in a dimension's MemberResults.
    1171             :     //  Only the dimension has to be compared because this is only used with table data,
    1172             :     //  where each dimension occurs only once.
    1173             : 
    1174           0 :     uno::Sequence<sheet::MemberResult> aMemberResults;
    1175           0 :     bool bFound = false;
    1176             :     long nField;
    1177             : 
    1178             :     // look in column fields
    1179             : 
    1180           0 :     for (nField=0; nField<nColFieldCount && !bFound; nField++)
    1181           0 :         if ( pColFields[nField].nDim == nDimension )
    1182             :         {
    1183           0 :             aMemberResults = pColFields[nField].aResult;
    1184           0 :             bFound = true;
    1185             :         }
    1186             : 
    1187             :     // look in row fields
    1188             : 
    1189           0 :     for (nField=0; nField<nRowFieldCount && !bFound; nField++)
    1190           0 :         if ( pRowFields[nField].nDim == nDimension )
    1191             :         {
    1192           0 :             aMemberResults = pRowFields[nField].aResult;
    1193           0 :             bFound = true;
    1194             :         }
    1195             : 
    1196             :     // collect the member names
    1197             : 
    1198           0 :     if ( bFound )
    1199             :     {
    1200           0 :         const sheet::MemberResult* pArray = aMemberResults.getConstArray();
    1201           0 :         long nResultCount = aMemberResults.getLength();
    1202             : 
    1203           0 :         for (long nItem=0; nItem<nResultCount; nItem++)
    1204             :         {
    1205           0 :             if ( pArray[nItem].Flags & sheet::MemberResultFlags::HASMEMBER )
    1206           0 :                 rNames.insert(pArray[nItem].Name);
    1207             :         }
    1208           0 :     }
    1209           0 : }
    1210             : 
    1211          25 : void ScDPOutput::SetHeaderLayout(bool bUseGrid)
    1212             : {
    1213          25 :     mbHeaderLayout = bUseGrid;
    1214          25 :     bSizesValid = false;
    1215          25 : }
    1216             : 
    1217          48 : bool ScDPOutput::GetHeaderLayout() const
    1218             : {
    1219          48 :     return mbHeaderLayout;
    1220             : }
    1221             : 
    1222             : namespace {
    1223             : 
    1224           0 : void lcl_GetTableVars( sal_Int32& rGrandTotalCols, sal_Int32& rGrandTotalRows, sal_Int32& rDataLayoutIndex,
    1225             :                        std::vector<rtl::OUString>& rDataNames, std::vector<rtl::OUString>& rGivenNames,
    1226             :                        sheet::DataPilotFieldOrientation& rDataOrient,
    1227             :                        const uno::Reference<sheet::XDimensionsSupplier>& xSource )
    1228             : {
    1229           0 :     rDataLayoutIndex = -1;  // invalid
    1230           0 :     rGrandTotalCols = 0;
    1231           0 :     rGrandTotalRows = 0;
    1232           0 :     rDataOrient = sheet::DataPilotFieldOrientation_HIDDEN;
    1233             : 
    1234           0 :     uno::Reference<beans::XPropertySet> xSrcProp( xSource, uno::UNO_QUERY );
    1235             :     bool bColGrand = ScUnoHelpFunctions::GetBoolProperty(
    1236           0 :         xSrcProp, rtl::OUString(SC_UNO_DP_COLGRAND));
    1237           0 :     if ( bColGrand )
    1238           0 :         rGrandTotalCols = 1;    // default if data layout not in columns
    1239             : 
    1240             :     bool bRowGrand = ScUnoHelpFunctions::GetBoolProperty(
    1241           0 :         xSrcProp, rtl::OUString(SC_UNO_DP_ROWGRAND));
    1242           0 :     if ( bRowGrand )
    1243           0 :         rGrandTotalRows = 1;    // default if data layout not in rows
    1244             : 
    1245           0 :     if ( xSource.is() )
    1246             :     {
    1247             :         // find index and orientation of "data layout" dimension, count data dimensions
    1248             : 
    1249           0 :         sal_Int32 nDataCount = 0;
    1250             : 
    1251           0 :         uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xSource->getDimensions() );
    1252           0 :         long nDimCount = xDims->getCount();
    1253           0 :         for (long nDim=0; nDim<nDimCount; nDim++)
    1254             :         {
    1255             :             uno::Reference<uno::XInterface> xDim =
    1256           0 :                     ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
    1257           0 :             uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
    1258           0 :             if ( xDimProp.is() )
    1259             :             {
    1260             :                 sheet::DataPilotFieldOrientation eDimOrient =
    1261             :                     (sheet::DataPilotFieldOrientation) ScUnoHelpFunctions::GetEnumProperty(
    1262             :                         xDimProp, rtl::OUString(SC_UNO_DP_ORIENTATION),
    1263           0 :                         sheet::DataPilotFieldOrientation_HIDDEN );
    1264           0 :                 if ( ScUnoHelpFunctions::GetBoolProperty( xDimProp,
    1265           0 :                                          rtl::OUString(SC_UNO_DP_ISDATALAYOUT) ) )
    1266             :                 {
    1267           0 :                     rDataLayoutIndex = nDim;
    1268           0 :                     rDataOrient = eDimOrient;
    1269             :                 }
    1270           0 :                 if ( eDimOrient == sheet::DataPilotFieldOrientation_DATA )
    1271             :                 {
    1272           0 :                     rtl::OUString aSourceName;
    1273           0 :                     rtl::OUString aGivenName;
    1274           0 :                     ScDPOutput::GetDataDimensionNames( aSourceName, aGivenName, xDim );
    1275           0 :                     rDataNames.push_back( aSourceName );
    1276           0 :                     rGivenNames.push_back( aGivenName );
    1277             : 
    1278           0 :                     ++nDataCount;
    1279             :                 }
    1280             :             }
    1281           0 :         }
    1282             : 
    1283           0 :         if ( ( rDataOrient == sheet::DataPilotFieldOrientation_COLUMN ) && bColGrand )
    1284           0 :             rGrandTotalCols = nDataCount;
    1285           0 :         else if ( ( rDataOrient == sheet::DataPilotFieldOrientation_ROW ) && bRowGrand )
    1286           0 :             rGrandTotalRows = nDataCount;
    1287           0 :     }
    1288           0 : }
    1289             : 
    1290             : }
    1291             : 
    1292           0 : void ScDPOutput::GetPositionData(const ScAddress& rPos, DataPilotTablePositionData& rPosData)
    1293             : {
    1294             :     using namespace ::com::sun::star::sheet;
    1295             : 
    1296           0 :     SCCOL nCol = rPos.Col();
    1297           0 :     SCROW nRow = rPos.Row();
    1298           0 :     SCTAB nTab = rPos.Tab();
    1299           0 :     if ( nTab != aStartPos.Tab() )
    1300           0 :         return;                                     // wrong sheet
    1301             : 
    1302             :     //  calculate output positions and sizes
    1303             : 
    1304           0 :     CalcSizes();
    1305             : 
    1306           0 :     rPosData.PositionType = GetPositionType(rPos);
    1307           0 :     switch (rPosData.PositionType)
    1308             :     {
    1309             :         case DataPilotTablePositionType::RESULT:
    1310             :         {
    1311           0 :             vector<DataPilotFieldFilter> aFilters;
    1312           0 :             GetDataResultPositionData(aFilters, rPos);
    1313           0 :             sal_Int32 nSize = aFilters.size();
    1314             : 
    1315           0 :             DataPilotTableResultData aResData;
    1316           0 :             aResData.FieldFilters.realloc(nSize);
    1317           0 :             for (sal_Int32 i = 0; i < nSize; ++i)
    1318           0 :                 aResData.FieldFilters[i] = aFilters[i];
    1319             : 
    1320           0 :             aResData.DataFieldIndex = 0;
    1321           0 :             Reference<beans::XPropertySet> xPropSet(xSource, UNO_QUERY);
    1322           0 :             if (xPropSet.is())
    1323             :             {
    1324             :                 sal_Int32 nDataFieldCount = ScUnoHelpFunctions::GetLongProperty( xPropSet,
    1325           0 :                                             rtl::OUString(SC_UNO_DP_DATAFIELDCOUNT) );
    1326           0 :                 if (nDataFieldCount > 0)
    1327           0 :                     aResData.DataFieldIndex = (nRow - nDataStartRow) % nDataFieldCount;
    1328             :             }
    1329             : 
    1330             :             // Copy appropriate DataResult object from the cached sheet::DataResult table.
    1331           0 :             if (aData.getLength() > nRow - nDataStartRow &&
    1332           0 :                 aData[nRow-nDataStartRow].getLength() > nCol-nDataStartCol)
    1333           0 :                 aResData.Result = aData[nRow-nDataStartRow][nCol-nDataStartCol];
    1334             : 
    1335           0 :             rPosData.PositionData = makeAny(aResData);
    1336           0 :             return;
    1337             :         }
    1338             :         case DataPilotTablePositionType::COLUMN_HEADER:
    1339             :         {
    1340           0 :             long nField = nRow - nTabStartRow - 1; // 1st line is used for the buttons
    1341           0 :             if (nField < 0)
    1342             :                 break;
    1343             : 
    1344           0 :             const uno::Sequence<sheet::MemberResult> rSequence = pColFields[nField].aResult;
    1345           0 :             if (rSequence.getLength() == 0)
    1346             :                 break;
    1347           0 :             const sheet::MemberResult* pArray = rSequence.getConstArray();
    1348             : 
    1349           0 :             long nItem = nCol - nDataStartCol;
    1350             :             //  get origin of "continue" fields
    1351           0 :             while (nItem > 0 && ( pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
    1352           0 :                 --nItem;
    1353             : 
    1354           0 :             if (nItem < 0)
    1355             :                 break;
    1356             : 
    1357           0 :             DataPilotTableHeaderData aHeaderData;
    1358           0 :             aHeaderData.MemberName = OUString(pArray[nItem].Name);
    1359           0 :             aHeaderData.Flags = pArray[nItem].Flags;
    1360           0 :             aHeaderData.Dimension = static_cast<sal_Int32>(pColFields[nField].nDim);
    1361           0 :             aHeaderData.Hierarchy = static_cast<sal_Int32>(pColFields[nField].nHier);
    1362           0 :             aHeaderData.Level     = static_cast<sal_Int32>(pColFields[nField].nLevel);
    1363             : 
    1364           0 :             rPosData.PositionData = makeAny(aHeaderData);
    1365           0 :             return;
    1366             :         }
    1367             :         case DataPilotTablePositionType::ROW_HEADER:
    1368             :         {
    1369           0 :             long nField = nCol - nTabStartCol;
    1370           0 :             if (nField < 0)
    1371             :                 break;
    1372             : 
    1373           0 :             const uno::Sequence<sheet::MemberResult> rSequence = pRowFields[nField].aResult;
    1374           0 :             if (rSequence.getLength() == 0)
    1375             :                 break;
    1376           0 :             const sheet::MemberResult* pArray = rSequence.getConstArray();
    1377             : 
    1378           0 :             long nItem = nRow - nDataStartRow;
    1379             :             //  get origin of "continue" fields
    1380           0 :             while ( nItem > 0 && (pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
    1381           0 :                 --nItem;
    1382             : 
    1383           0 :             if (nItem < 0)
    1384             :                 break;
    1385             : 
    1386           0 :             DataPilotTableHeaderData aHeaderData;
    1387           0 :             aHeaderData.MemberName = OUString(pArray[nItem].Name);
    1388           0 :             aHeaderData.Flags = pArray[nItem].Flags;
    1389           0 :             aHeaderData.Dimension = static_cast<sal_Int32>(pRowFields[nField].nDim);
    1390           0 :             aHeaderData.Hierarchy = static_cast<sal_Int32>(pRowFields[nField].nHier);
    1391           0 :             aHeaderData.Level     = static_cast<sal_Int32>(pRowFields[nField].nLevel);
    1392             : 
    1393           0 :             rPosData.PositionData = makeAny(aHeaderData);
    1394           0 :             return;
    1395             :         }
    1396             :     }
    1397             : }
    1398             : 
    1399           0 : bool ScDPOutput::GetDataResultPositionData(vector<sheet::DataPilotFieldFilter>& rFilters, const ScAddress& rPos)
    1400             : {
    1401             :     // Check to make sure there is at least one data field.
    1402           0 :     Reference<beans::XPropertySet> xPropSet(xSource, UNO_QUERY);
    1403           0 :     if (!xPropSet.is())
    1404           0 :         return false;
    1405             : 
    1406             :     sal_Int32 nDataFieldCount = ScUnoHelpFunctions::GetLongProperty( xPropSet,
    1407           0 :                                 rtl::OUString(SC_UNO_DP_DATAFIELDCOUNT) );
    1408           0 :     if (nDataFieldCount == 0)
    1409             :         // No data field is present in this datapilot table.
    1410           0 :         return false;
    1411             : 
    1412             :     // #i111421# use lcl_GetTableVars for correct size of totals and data layout position
    1413             :     sal_Int32 nGrandTotalCols;
    1414             :     sal_Int32 nGrandTotalRows;
    1415             :     sal_Int32 nDataLayoutIndex;
    1416           0 :     std::vector<rtl::OUString> aDataNames;
    1417           0 :     std::vector<rtl::OUString> aGivenNames;
    1418             :     sheet::DataPilotFieldOrientation eDataOrient;
    1419           0 :     lcl_GetTableVars( nGrandTotalCols, nGrandTotalRows, nDataLayoutIndex, aDataNames, aGivenNames, eDataOrient, xSource );
    1420             : 
    1421           0 :     SCCOL nCol = rPos.Col();
    1422           0 :     SCROW nRow = rPos.Row();
    1423           0 :     SCTAB nTab = rPos.Tab();
    1424           0 :     if ( nTab != aStartPos.Tab() )
    1425           0 :         return false;                                     // wrong sheet
    1426             : 
    1427           0 :     CalcSizes();
    1428             : 
    1429             :     // test for data area.
    1430           0 :     if (nCol < nDataStartCol || nCol > nTabEndCol || nRow < nDataStartRow || nRow > nTabEndRow)
    1431             :     {
    1432             :         // Cell is outside the data field area.
    1433           0 :         return false;
    1434             :     }
    1435             : 
    1436           0 :     bool bFilterByCol = (nCol <= static_cast<SCCOL>(nTabEndCol - nGrandTotalCols));
    1437           0 :     bool bFilterByRow = (nRow <= static_cast<SCROW>(nTabEndRow - nGrandTotalRows));
    1438             : 
    1439             :     // column fields
    1440           0 :     for (SCCOL nColField = 0; nColField < nColFieldCount && bFilterByCol; ++nColField)
    1441             :     {
    1442           0 :         if (pColFields[nColField].nDim == nDataLayoutIndex)
    1443             :             // There is no sense including the data layout field for filtering.
    1444           0 :             continue;
    1445             : 
    1446           0 :         sheet::DataPilotFieldFilter filter;
    1447           0 :         filter.FieldName = pColFields[nColField].maName;
    1448             : 
    1449           0 :         const uno::Sequence<sheet::MemberResult> rSequence = pColFields[nColField].aResult;
    1450           0 :         const sheet::MemberResult* pArray = rSequence.getConstArray();
    1451             : 
    1452             :         OSL_ENSURE(nDataStartCol + rSequence.getLength() - 1 == nTabEndCol, "ScDPOutput::GetDataFieldCellData: error in geometric assumption");
    1453             : 
    1454           0 :         long nItem = nCol - nDataStartCol;
    1455             :                 //  get origin of "continue" fields
    1456           0 :         while ( nItem > 0 && (pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
    1457           0 :             --nItem;
    1458             : 
    1459           0 :         filter.MatchValue = pArray[nItem].Name;
    1460           0 :         rFilters.push_back(filter);
    1461           0 :     }
    1462             : 
    1463             :     // row fields
    1464           0 :     for (SCROW nRowField = 0; nRowField < nRowFieldCount && bFilterByRow; ++nRowField)
    1465             :     {
    1466           0 :         if (pRowFields[nRowField].nDim == nDataLayoutIndex)
    1467             :             // There is no sense including the data layout field for filtering.
    1468           0 :             continue;
    1469             : 
    1470           0 :         sheet::DataPilotFieldFilter filter;
    1471           0 :         filter.FieldName = pRowFields[nRowField].maName;
    1472             : 
    1473           0 :         const uno::Sequence<sheet::MemberResult> rSequence = pRowFields[nRowField].aResult;
    1474           0 :         const sheet::MemberResult* pArray = rSequence.getConstArray();
    1475             : 
    1476             :         OSL_ENSURE(nDataStartRow + rSequence.getLength() - 1 == nTabEndRow, "ScDPOutput::GetDataFieldCellData: error in geometric assumption");
    1477             : 
    1478           0 :         long nItem = nRow - nDataStartRow;
    1479             :             //  get origin of "continue" fields
    1480           0 :         while ( nItem > 0 && (pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
    1481           0 :             --nItem;
    1482             : 
    1483           0 :         filter.MatchValue = pArray[nItem].Name;
    1484           0 :         rFilters.push_back(filter);
    1485           0 :     }
    1486             : 
    1487           0 :     return true;
    1488             : }
    1489             : 
    1490             : namespace {
    1491             : 
    1492             : //
    1493             : //  helper functions for ScDPOutput::GetPivotData
    1494             : //
    1495             : 
    1496           0 : bool lcl_IsNamedDataField( const ScDPGetPivotDataField& rTarget, const rtl::OUString& rSourceName, const rtl::OUString& rGivenName )
    1497             : {
    1498             :     // match one of the names, ignoring case
    1499           0 :     return ScGlobal::GetpTransliteration()->isEqual( rTarget.maFieldName, rSourceName ) ||
    1500           0 :            ScGlobal::GetpTransliteration()->isEqual( rTarget.maFieldName, rGivenName );
    1501             : }
    1502             : 
    1503           0 : bool lcl_IsNamedCategoryField( const ScDPGetPivotDataField& rFilter, const ScDPOutLevelData& rField )
    1504             : {
    1505           0 :     return ScGlobal::GetpTransliteration()->isEqual( rFilter.maFieldName, rField.maName );
    1506             : }
    1507             : 
    1508           0 : bool lcl_IsCondition( const sheet::MemberResult& rResultEntry, const ScDPGetPivotDataField& rFilter )
    1509             : {
    1510             :     //! handle numeric conditions?
    1511           0 :     return ScGlobal::GetpTransliteration()->isEqual( rResultEntry.Name, rFilter.maValStr );
    1512             : }
    1513             : 
    1514           0 : bool lcl_CheckPageField( const ScDPOutLevelData& rField,
    1515             :                          const std::vector< ScDPGetPivotDataField >& rFilters,
    1516             :                          std::vector<bool>& rFilterUsed )
    1517             : {
    1518           0 :     for (SCSIZE nFilterPos = 0; nFilterPos < rFilters.size(); ++nFilterPos)
    1519             :     {
    1520           0 :         if ( lcl_IsNamedCategoryField( rFilters[nFilterPos], rField ) )
    1521             :         {
    1522           0 :             rFilterUsed[nFilterPos] = true;
    1523             : 
    1524             :             // page field result is empty or the selection as single entry (see lcl_GetSelectedPageAsResult)
    1525           0 :             if ( rField.aResult.getLength() == 1 &&
    1526           0 :                  lcl_IsCondition( rField.aResult[0], rFilters[nFilterPos] ) )
    1527             :             {
    1528           0 :                 return true;        // condition matches page selection
    1529             :             }
    1530             :             else
    1531             :             {
    1532           0 :                 return false;       // no page selection or different entry
    1533             :             }
    1534             :         }
    1535             :     }
    1536             : 
    1537           0 :     return true;    // valid if the page field doesn't have a filter
    1538             : }
    1539             : 
    1540           0 : uno::Sequence<sheet::GeneralFunction> lcl_GetSubTotals(
    1541             :         const uno::Reference<sheet::XDimensionsSupplier>& xSource, const ScDPOutLevelData& rField )
    1542             : {
    1543           0 :     uno::Sequence<sheet::GeneralFunction> aSubTotals;
    1544             : 
    1545           0 :     uno::Reference<sheet::XHierarchiesSupplier> xHierSupp;
    1546           0 :     uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
    1547           0 :     uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
    1548           0 :     sal_Int32 nIntCount = xIntDims->getCount();
    1549           0 :     if ( rField.nDim < nIntCount )
    1550             :     {
    1551             :         uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface(
    1552           0 :                                     xIntDims->getByIndex( rField.nDim ) );
    1553           0 :         xHierSupp = uno::Reference<sheet::XHierarchiesSupplier>( xIntDim, uno::UNO_QUERY );
    1554             :     }
    1555             :     OSL_ENSURE( xHierSupp.is(), "dimension not found" );
    1556             : 
    1557           0 :     sal_Int32 nHierCount = 0;
    1558           0 :     uno::Reference<container::XIndexAccess> xHiers;
    1559           0 :     if ( xHierSupp.is() )
    1560             :     {
    1561           0 :         uno::Reference<container::XNameAccess> xHiersName = xHierSupp->getHierarchies();
    1562           0 :         xHiers = new ScNameToIndexAccess( xHiersName );
    1563           0 :         nHierCount = xHiers->getCount();
    1564             :     }
    1565           0 :     uno::Reference<uno::XInterface> xHier;
    1566           0 :     if ( rField.nHier < nHierCount )
    1567           0 :         xHier = ScUnoHelpFunctions::AnyToInterface( xHiers->getByIndex( rField.nHier ) );
    1568             :     OSL_ENSURE( xHier.is(), "hierarchy not found" );
    1569             : 
    1570           0 :     sal_Int32 nLevCount = 0;
    1571           0 :     uno::Reference<container::XIndexAccess> xLevels;
    1572           0 :     uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHier, uno::UNO_QUERY );
    1573           0 :     if ( xLevSupp.is() )
    1574             :     {
    1575           0 :         uno::Reference<container::XNameAccess> xLevsName = xLevSupp->getLevels();
    1576           0 :         xLevels = new ScNameToIndexAccess( xLevsName );
    1577           0 :         nLevCount = xLevels->getCount();
    1578             :     }
    1579           0 :     uno::Reference<uno::XInterface> xLevel;
    1580           0 :     if ( rField.nLevel < nLevCount )
    1581           0 :         xLevel = ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex( rField.nLevel ) );
    1582             :     OSL_ENSURE( xLevel.is(), "level not found" );
    1583             : 
    1584           0 :     uno::Reference<beans::XPropertySet> xLevelProp( xLevel, uno::UNO_QUERY );
    1585           0 :     if ( xLevelProp.is() )
    1586             :     {
    1587             :         try
    1588             :         {
    1589           0 :             uno::Any aValue = xLevelProp->getPropertyValue( rtl::OUString(SC_UNO_DP_SUBTOTAL) );
    1590           0 :             aValue >>= aSubTotals;
    1591             :         }
    1592           0 :         catch(uno::Exception&)
    1593             :         {
    1594             :         }
    1595             :     }
    1596             : 
    1597           0 :     return aSubTotals;
    1598             : }
    1599             : 
    1600           0 : void lcl_FilterInclude( std::vector<bool>& rResult, std::vector< sal_Int32 >& rSubtotal,
    1601             :                         const ScDPOutLevelData& rField,
    1602             :                         const std::vector< ScDPGetPivotDataField >& rFilters,
    1603             :                         std::vector<bool>& rFilterUsed,
    1604             :                         bool& rBeforeDataLayout,
    1605             :                         sal_Int32 nGrandTotals, sal_Int32 nDataLayoutIndex,
    1606             :                         const std::vector<rtl::OUString>& rDataNames, const std::vector<rtl::OUString>& rGivenNames,
    1607             :                         const ScDPGetPivotDataField& rTarget, const uno::Reference<sheet::XDimensionsSupplier>& xSource )
    1608             : {
    1609             :     // returns true if a filter was given for the field
    1610             : 
    1611             :     OSL_ENSURE( rFilters.size() == rFilterUsed.size(), "wrong size" );
    1612             : 
    1613           0 :     const bool bIsDataLayout = ( rField.nDim == nDataLayoutIndex );
    1614           0 :     if (bIsDataLayout)
    1615           0 :         rBeforeDataLayout = false;
    1616             : 
    1617           0 :     bool bHasFilter = false;
    1618           0 :     ScDPGetPivotDataField aFilter;
    1619           0 :     if ( !bIsDataLayout )          // selection of data field is handled separately
    1620             :     {
    1621           0 :         for (SCSIZE nFilterPos = 0; nFilterPos < rFilters.size() && !bHasFilter; ++nFilterPos)
    1622             :         {
    1623           0 :             if ( lcl_IsNamedCategoryField( rFilters[nFilterPos], rField ) )
    1624             :             {
    1625           0 :                 aFilter = rFilters[nFilterPos];
    1626           0 :                 rFilterUsed[nFilterPos] = true;
    1627           0 :                 bHasFilter = true;
    1628             :             }
    1629             :         }
    1630             :     }
    1631             : 
    1632           0 :     bool bHasFunc = bHasFilter && aFilter.meFunction != sheet::GeneralFunction_NONE;
    1633             : 
    1634           0 :     uno::Sequence<sheet::GeneralFunction> aSubTotals;
    1635           0 :     if ( !bIsDataLayout )
    1636           0 :         aSubTotals = lcl_GetSubTotals( xSource, rField );
    1637           0 :     bool bManualSub = ( aSubTotals.getLength() > 0 && aSubTotals[0] != sheet::GeneralFunction_AUTO );
    1638             : 
    1639           0 :     const uno::Sequence<sheet::MemberResult>& rSequence = rField.aResult;
    1640           0 :     const sheet::MemberResult* pArray = rSequence.getConstArray();
    1641           0 :     sal_Int32 nSize = rSequence.getLength();
    1642             : 
    1643             :     OSL_ENSURE( (sal_Int32)rResult.size() == nSize, "Number of fields do not match result count" );
    1644             : 
    1645           0 :     sal_Int32 nContCount = 0;
    1646           0 :     sal_Int32 nSubTotalCount = 0;
    1647           0 :     sheet::MemberResult aPrevious;
    1648           0 :     for( sal_Int32 j=0; j < nSize; j++ )
    1649             :     {
    1650           0 :         sheet::MemberResult aResultEntry = pArray[j];
    1651           0 :         if ( aResultEntry.Flags & sheet::MemberResultFlags::CONTINUE )
    1652             :         {
    1653           0 :             aResultEntry = aPrevious;
    1654           0 :             ++nContCount;
    1655             :         }
    1656           0 :         else if ( ( aResultEntry.Flags & sheet::MemberResultFlags::SUBTOTAL ) == 0 )
    1657             :         {
    1658             :             // count the CONTINUE entries before a SUBTOTAL
    1659           0 :             nContCount = 0;
    1660             :         }
    1661             : 
    1662           0 :         if ( j >= nSize - nGrandTotals )
    1663             :         {
    1664             :             // mark as subtotal for the preceding data
    1665           0 :             if ( ( aResultEntry.Flags & sheet::MemberResultFlags::SUBTOTAL ) != 0 )
    1666             :             {
    1667           0 :                 rSubtotal[j] = nSize - nGrandTotals;
    1668             : 
    1669           0 :                 if ( rResult[j] && nGrandTotals > 1 )
    1670             :                 {
    1671             :                     // grand total is always automatic
    1672           0 :                     sal_Int32 nDataPos = j - ( nSize - nGrandTotals );
    1673             :                     OSL_ENSURE( nDataPos < (sal_Int32)rDataNames.size(), "wrong data count" );
    1674           0 :                     rtl::OUString aSourceName( rDataNames[nDataPos] );     // vector contains source names
    1675           0 :                     rtl::OUString aGivenName( rGivenNames[nDataPos] );
    1676             : 
    1677           0 :                     rResult[j] = lcl_IsNamedDataField( rTarget, aSourceName, aGivenName );
    1678             :                 }
    1679             :             }
    1680             : 
    1681             :             // treat "grand total" columns/rows as empty description, as if they were marked
    1682             :             // in a previous field
    1683             : 
    1684             :             OSL_ENSURE( ( aResultEntry.Flags &
    1685             :                             ( sheet::MemberResultFlags::HASMEMBER | sheet::MemberResultFlags::SUBTOTAL ) ) == 0 ||
    1686             :                         ( aResultEntry.Flags &
    1687             :                             ( sheet::MemberResultFlags::HASMEMBER | sheet::MemberResultFlags::SUBTOTAL ) ) ==
    1688             :                                 ( sheet::MemberResultFlags::HASMEMBER | sheet::MemberResultFlags::SUBTOTAL ),
    1689             :                         "non-subtotal member found in grand total result" );
    1690           0 :             aResultEntry.Flags = 0;
    1691             :         }
    1692             : 
    1693             :         // mark subtotals (not grand total) for preceding data (assume CONTINUE is set)
    1694           0 :         if ( ( aResultEntry.Flags & sheet::MemberResultFlags::SUBTOTAL ) != 0 )
    1695             :         {
    1696           0 :             rSubtotal[j] = nContCount + 1 + nSubTotalCount;
    1697             : 
    1698           0 :             if ( rResult[j] )
    1699             :             {
    1700           0 :                 if ( bManualSub )
    1701             :                 {
    1702           0 :                     if ( rBeforeDataLayout )
    1703             :                     {
    1704             :                         // manual subtotals and several data fields
    1705             : 
    1706           0 :                         sal_Int32 nDataCount = rDataNames.size();
    1707           0 :                         sal_Int32 nFuncPos = nSubTotalCount / nDataCount;       // outer order: subtotal functions
    1708           0 :                         sal_Int32 nDataPos = nSubTotalCount % nDataCount;       // inner order: data fields
    1709             : 
    1710           0 :                         rtl::OUString aSourceName( rDataNames[nDataPos] );             // vector contains source names
    1711           0 :                         rtl::OUString aGivenName( rGivenNames[nDataPos] );
    1712             : 
    1713             :                         OSL_ENSURE( nFuncPos < aSubTotals.getLength(), "wrong subtotal count" );
    1714           0 :                         rResult[j] = lcl_IsNamedDataField( rTarget, aSourceName, aGivenName ) &&
    1715           0 :                                      aSubTotals[nFuncPos] == aFilter.meFunction;
    1716             :                     }
    1717             :                     else
    1718             :                     {
    1719             :                         // manual subtotals for a single data field
    1720             : 
    1721             :                         OSL_ENSURE( nSubTotalCount < aSubTotals.getLength(), "wrong subtotal count" );
    1722           0 :                         rResult[j] = ( aSubTotals[nSubTotalCount] == aFilter.meFunction );
    1723             :                     }
    1724             :                 }
    1725             :                 else    // automatic subtotals
    1726             :                 {
    1727           0 :                     if ( rBeforeDataLayout )
    1728             :                     {
    1729             :                         OSL_ENSURE( nSubTotalCount < (sal_Int32)rDataNames.size(), "wrong data count" );
    1730           0 :                         rtl::OUString aSourceName( rDataNames[nSubTotalCount] );       // vector contains source names
    1731           0 :                         rtl::OUString aGivenName( rGivenNames[nSubTotalCount] );
    1732             : 
    1733           0 :                         rResult[j] = lcl_IsNamedDataField( rTarget, aSourceName, aGivenName );
    1734             :                     }
    1735             : 
    1736             :                     // if a function was specified, automatic subtotals never match
    1737           0 :                     if ( bHasFunc )
    1738           0 :                         rResult[j] = false;
    1739             :                 }
    1740             :             }
    1741             : 
    1742           0 :             ++nSubTotalCount;
    1743             :         }
    1744             :         else
    1745           0 :             nSubTotalCount = 0;
    1746             : 
    1747           0 :         if( rResult[j] )
    1748             :         {
    1749           0 :             if ( bIsDataLayout )
    1750             :             {
    1751           0 :                 if ( ( aResultEntry.Flags & sheet::MemberResultFlags::HASMEMBER ) != 0 )
    1752             :                 {
    1753             :                     // Asterisks are added in ScDPSaveData::WriteToSource to create unique names.
    1754             :                     //! preserve original name there?
    1755           0 :                     rtl::OUString aSourceName = ScDPUtil::getSourceDimensionName(aResultEntry.Name);
    1756             : 
    1757           0 :                     rResult[j] = lcl_IsNamedDataField(
    1758           0 :                         rTarget, aSourceName, aResultEntry.Caption);
    1759             :                 }
    1760             :             }
    1761           0 :             else if ( bHasFilter )
    1762             :             {
    1763             :                 // name must match (simple value or subtotal)
    1764           0 :                 rResult[j] = ( ( aResultEntry.Flags & sheet::MemberResultFlags::HASMEMBER ) != 0 ) &&
    1765           0 :                              lcl_IsCondition( aResultEntry, aFilter );
    1766             : 
    1767             :                 // if a function was specified, simple (non-subtotal) values never match
    1768           0 :                 if ( bHasFunc && nSubTotalCount == 0 )
    1769           0 :                     rResult[j] = false;
    1770             :             }
    1771             :             // if no condition is given, keep the columns/rows included
    1772             :         }
    1773           0 :         aPrevious = aResultEntry;
    1774           0 :     }
    1775           0 : }
    1776             : 
    1777           0 : void lcl_StripSubTotals( std::vector<bool>& rResult, const std::vector<sal_Int32>& rSubtotal )
    1778             : {
    1779           0 :     sal_Int32 nSize = rResult.size();
    1780             :     OSL_ENSURE( (sal_Int32)rSubtotal.size() == nSize, "sizes don't match" );
    1781             : 
    1782           0 :     for (sal_Int32 nPos=0; nPos<nSize; nPos++)
    1783           0 :         if ( rResult[nPos] && rSubtotal[nPos] )
    1784             :         {
    1785             :             // if a subtotal is included, clear the result flag for the columns/rows that the subtotal includes
    1786           0 :             sal_Int32 nStart = nPos - rSubtotal[nPos];
    1787             :             OSL_ENSURE( nStart >= 0, "invalid subtotal count" );
    1788             : 
    1789           0 :             for (sal_Int32 nPrev = nStart; nPrev < nPos; nPrev++)
    1790           0 :                 rResult[nPrev] = false;
    1791             :         }
    1792           0 : }
    1793             : 
    1794           0 : rtl::OUString lcl_GetDataFieldName( const rtl::OUString& rSourceName, sheet::GeneralFunction eFunc )
    1795             : {
    1796           0 :     sal_uInt16 nStrId = 0;
    1797           0 :     switch ( eFunc )
    1798             :     {
    1799           0 :         case sheet::GeneralFunction_SUM:        nStrId = STR_FUN_TEXT_SUM;      break;
    1800             :         case sheet::GeneralFunction_COUNT:
    1801           0 :         case sheet::GeneralFunction_COUNTNUMS:  nStrId = STR_FUN_TEXT_COUNT;    break;
    1802           0 :         case sheet::GeneralFunction_AVERAGE:    nStrId = STR_FUN_TEXT_AVG;      break;
    1803           0 :         case sheet::GeneralFunction_MAX:        nStrId = STR_FUN_TEXT_MAX;      break;
    1804           0 :         case sheet::GeneralFunction_MIN:        nStrId = STR_FUN_TEXT_MIN;      break;
    1805           0 :         case sheet::GeneralFunction_PRODUCT:    nStrId = STR_FUN_TEXT_PRODUCT;  break;
    1806             :         case sheet::GeneralFunction_STDEV:
    1807           0 :         case sheet::GeneralFunction_STDEVP:     nStrId = STR_FUN_TEXT_STDDEV;   break;
    1808             :         case sheet::GeneralFunction_VAR:
    1809           0 :         case sheet::GeneralFunction_VARP:       nStrId = STR_FUN_TEXT_VAR;      break;
    1810             :         case sheet::GeneralFunction_NONE:
    1811             :         case sheet::GeneralFunction_AUTO:
    1812             :         default:
    1813             :         {
    1814             :             OSL_FAIL("wrong function");
    1815             :         }
    1816             :     }
    1817           0 :     if ( !nStrId )
    1818           0 :         return rtl::OUString();
    1819             : 
    1820           0 :     rtl::OUStringBuffer aRet( ScGlobal::GetRscString( nStrId ) );
    1821           0 :     aRet.appendAscii(RTL_CONSTASCII_STRINGPARAM(" - "));
    1822           0 :     aRet.append(rSourceName);
    1823           0 :     return aRet.makeStringAndClear();
    1824             : }
    1825             : 
    1826             : }
    1827             : 
    1828           0 : void ScDPOutput::GetDataDimensionNames(
    1829             :     rtl::OUString& rSourceName, rtl::OUString& rGivenName, const uno::Reference<uno::XInterface>& xDim )
    1830             : {
    1831           0 :     uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
    1832           0 :     uno::Reference<container::XNamed> xDimName( xDim, uno::UNO_QUERY );
    1833           0 :     if ( xDimProp.is() && xDimName.is() )
    1834             :     {
    1835             :         // Asterisks are added in ScDPSaveData::WriteToSource to create unique names.
    1836             :         //! preserve original name there?
    1837           0 :         rSourceName = ScDPUtil::getSourceDimensionName(xDimName->getName());
    1838             : 
    1839             :         // Generate "given name" the same way as in dptabres.
    1840             :         //! Should use a stored name when available
    1841             : 
    1842             :         sheet::GeneralFunction eFunc = (sheet::GeneralFunction)ScUnoHelpFunctions::GetEnumProperty(
    1843             :                                 xDimProp, rtl::OUString(SC_UNO_DP_FUNCTION),
    1844           0 :                                 sheet::GeneralFunction_NONE );
    1845           0 :         rGivenName = lcl_GetDataFieldName( rSourceName, eFunc );
    1846           0 :     }
    1847           0 : }
    1848             : 
    1849           0 : bool ScDPOutput::GetPivotData( ScDPGetPivotDataField& rTarget,
    1850             :                                const std::vector< ScDPGetPivotDataField >& rFilters )
    1851             : {
    1852           0 :     CalcSizes();
    1853             : 
    1854             :     // need to know about grand total columns/rows:
    1855             :     sal_Int32 nGrandTotalCols;
    1856             :     sal_Int32 nGrandTotalRows;
    1857             :     sal_Int32 nDataLayoutIndex;
    1858           0 :     std::vector<rtl::OUString> aDataNames;
    1859           0 :     std::vector<rtl::OUString> aGivenNames;
    1860             :     sheet::DataPilotFieldOrientation eDataOrient;
    1861           0 :     lcl_GetTableVars( nGrandTotalCols, nGrandTotalRows, nDataLayoutIndex, aDataNames, aGivenNames, eDataOrient, xSource );
    1862             : 
    1863           0 :     if ( aDataNames.empty() )
    1864           0 :         return false;               // incomplete table without data fields -> no result
    1865             : 
    1866           0 :     if ( eDataOrient == sheet::DataPilotFieldOrientation_HIDDEN )
    1867             :     {
    1868             :         // no data layout field -> single data field -> must match the selected field in rTarget
    1869             : 
    1870             :         OSL_ENSURE( aDataNames.size() == 1, "several data fields but no data layout field" );
    1871           0 :         if ( !lcl_IsNamedDataField( rTarget, aDataNames[0], aGivenNames[0] ) )
    1872           0 :             return false;
    1873             :     }
    1874             : 
    1875           0 :     std::vector<bool> aIncludeCol(nColCount, true);
    1876           0 :     std::vector< sal_Int32 > aSubtotalCol( nColCount, 0 );
    1877           0 :     std::vector<bool> aIncludeRow(nRowCount, true);
    1878           0 :     std::vector< sal_Int32 > aSubtotalRow( nRowCount, 0 );
    1879             : 
    1880           0 :     std::vector<bool> aFilterUsed(rFilters.size(), false);
    1881             : 
    1882             :     long nField;
    1883             :     long nCol;
    1884             :     long nRow;
    1885             :     bool bBeforeDataLayout;
    1886             : 
    1887             :     // look in column fields
    1888             : 
    1889           0 :     bBeforeDataLayout = ( eDataOrient == sheet::DataPilotFieldOrientation_COLUMN );
    1890           0 :     for (nField=0; nField<nColFieldCount; nField++)
    1891             :         lcl_FilterInclude( aIncludeCol, aSubtotalCol, pColFields[nField], rFilters, aFilterUsed, bBeforeDataLayout,
    1892           0 :                            nGrandTotalCols, nDataLayoutIndex, aDataNames, aGivenNames, rTarget, xSource );
    1893             : 
    1894             :     // look in row fields
    1895             : 
    1896           0 :     bBeforeDataLayout = ( eDataOrient == sheet::DataPilotFieldOrientation_ROW );
    1897           0 :     for (nField=0; nField<nRowFieldCount; nField++)
    1898             :         lcl_FilterInclude( aIncludeRow, aSubtotalRow, pRowFields[nField], rFilters, aFilterUsed, bBeforeDataLayout,
    1899           0 :                            nGrandTotalRows, nDataLayoutIndex, aDataNames, aGivenNames, rTarget, xSource );
    1900             : 
    1901             :     // page fields
    1902             : 
    1903           0 :     for (nField=0; nField<nPageFieldCount; nField++)
    1904           0 :         if ( !lcl_CheckPageField( pPageFields[nField], rFilters, aFilterUsed ) )
    1905           0 :             return false;
    1906             : 
    1907             :     // all filter fields must be used
    1908           0 :     for (SCSIZE nFilter=0; nFilter<aFilterUsed.size(); nFilter++)
    1909           0 :         if (!aFilterUsed[nFilter])
    1910           0 :             return false;
    1911             : 
    1912           0 :     lcl_StripSubTotals( aIncludeCol, aSubtotalCol );
    1913           0 :     lcl_StripSubTotals( aIncludeRow, aSubtotalRow );
    1914             : 
    1915           0 :     long nColPos = 0;
    1916           0 :     long nColIncluded = 0;
    1917           0 :     for (nCol=0; nCol<nColCount; nCol++)
    1918           0 :         if (aIncludeCol[nCol])
    1919             :         {
    1920           0 :             nColPos = nCol;
    1921           0 :             ++nColIncluded;
    1922             :         }
    1923             : 
    1924           0 :     long nRowPos = 0;
    1925           0 :     long nRowIncluded = 0;
    1926           0 :     for (nRow=0; nRow<nRowCount; nRow++)
    1927           0 :         if (aIncludeRow[nRow])
    1928             :         {
    1929           0 :             nRowPos = nRow;
    1930           0 :             ++nRowIncluded;
    1931             :         }
    1932             : 
    1933           0 :     if ( nColIncluded != 1 || nRowIncluded != 1 )
    1934           0 :         return false;
    1935             : 
    1936           0 :     const uno::Sequence<sheet::DataResult>& rDataRow = aData[nRowPos];
    1937           0 :     if ( nColPos >= rDataRow.getLength() )
    1938           0 :         return false;
    1939             : 
    1940           0 :     const sheet::DataResult& rResult = rDataRow[nColPos];
    1941           0 :     if ( rResult.Flags & sheet::DataResultFlags::ERROR )
    1942           0 :         return false;                                       //! different error?
    1943             : 
    1944           0 :     rTarget.mbValIsStr = false;
    1945           0 :     rTarget.mnValNum = rResult.Value;
    1946             : 
    1947           0 :     return true;
    1948             : }
    1949             : 
    1950           0 : bool ScDPOutput::IsFilterButton( const ScAddress& rPos )
    1951             : {
    1952           0 :     SCCOL nCol = rPos.Col();
    1953           0 :     SCROW nRow = rPos.Row();
    1954           0 :     SCTAB nTab = rPos.Tab();
    1955           0 :     if ( nTab != aStartPos.Tab() || !bDoFilter )
    1956           0 :         return false;                               // wrong sheet or no button at all
    1957             : 
    1958             :     //  filter button is at top left
    1959           0 :     return ( nCol == aStartPos.Col() && nRow == aStartPos.Row() );
    1960             : }
    1961             : 
    1962           0 : long ScDPOutput::GetHeaderDim( const ScAddress& rPos, sal_uInt16& rOrient )
    1963             : {
    1964           0 :     SCCOL nCol = rPos.Col();
    1965           0 :     SCROW nRow = rPos.Row();
    1966           0 :     SCTAB nTab = rPos.Tab();
    1967           0 :     if ( nTab != aStartPos.Tab() )
    1968           0 :         return -1;                                      // wrong sheet
    1969             : 
    1970             :     //  calculate output positions and sizes
    1971             : 
    1972           0 :     CalcSizes();
    1973             : 
    1974             :     //  test for column header
    1975             : 
    1976           0 :     if ( nRow == nTabStartRow && nCol >= nDataStartCol && nCol < nDataStartCol + nColFieldCount )
    1977             :     {
    1978           0 :         rOrient = sheet::DataPilotFieldOrientation_COLUMN;
    1979           0 :         long nField = nCol - nDataStartCol;
    1980           0 :         return pColFields[nField].nDim;
    1981             :     }
    1982             : 
    1983             :     //  test for row header
    1984             : 
    1985           0 :     if ( nRow+1 == nDataStartRow && nCol >= nTabStartCol && nCol < nTabStartCol + nRowFieldCount )
    1986             :     {
    1987           0 :         rOrient = sheet::DataPilotFieldOrientation_ROW;
    1988           0 :         long nField = nCol - nTabStartCol;
    1989           0 :         return pRowFields[nField].nDim;
    1990             :     }
    1991             : 
    1992             :     //  test for page field
    1993             : 
    1994           0 :     SCROW nPageStartRow = aStartPos.Row() + ( bDoFilter ? 1 : 0 );
    1995           0 :     if ( nCol == aStartPos.Col() && nRow >= nPageStartRow && nRow < nPageStartRow + nPageFieldCount )
    1996             :     {
    1997           0 :         rOrient = sheet::DataPilotFieldOrientation_PAGE;
    1998           0 :         long nField = nRow - nPageStartRow;
    1999           0 :         return pPageFields[nField].nDim;
    2000             :     }
    2001             : 
    2002             :     //! single data field (?)
    2003             : 
    2004           0 :     rOrient = sheet::DataPilotFieldOrientation_HIDDEN;
    2005           0 :     return -1;      // invalid
    2006             : }
    2007             : 
    2008           0 : bool ScDPOutput::GetHeaderDrag( const ScAddress& rPos, bool bMouseLeft, bool bMouseTop,
    2009             :                                 long nDragDim,
    2010             :                                 Rectangle& rPosRect, sal_uInt16& rOrient, long& rDimPos )
    2011             : {
    2012             :     //  Rectangle instead of ScRange for rPosRect to allow for negative values
    2013             : 
    2014           0 :     SCCOL nCol = rPos.Col();
    2015           0 :     SCROW nRow = rPos.Row();
    2016           0 :     SCTAB nTab = rPos.Tab();
    2017           0 :     if ( nTab != aStartPos.Tab() )
    2018           0 :         return false;                                       // wrong sheet
    2019             : 
    2020             :     //  calculate output positions and sizes
    2021             : 
    2022           0 :     CalcSizes();
    2023             : 
    2024             :     //  test for column header
    2025             : 
    2026           0 :     if ( nCol >= nDataStartCol && nCol <= nTabEndCol &&
    2027             :             nRow + 1 >= nMemberStartRow && nRow < nMemberStartRow + nColFieldCount )
    2028             :     {
    2029           0 :         long nField = nRow - nMemberStartRow;
    2030           0 :         if (nField < 0)
    2031             :         {
    2032           0 :             nField = 0;
    2033           0 :             bMouseTop = true;
    2034             :         }
    2035             :         //! find start of dimension
    2036             : 
    2037             :         rPosRect = Rectangle( nDataStartCol, nMemberStartRow + nField,
    2038           0 :                               nTabEndCol, nMemberStartRow + nField -1 );
    2039             : 
    2040           0 :         bool bFound = false;            // is this within the same orientation?
    2041           0 :         bool bBeforeDrag = false;
    2042           0 :         bool bAfterDrag = false;
    2043           0 :         for (long nPos=0; nPos<nColFieldCount && !bFound; nPos++)
    2044             :         {
    2045           0 :             if (pColFields[nPos].nDim == nDragDim)
    2046             :             {
    2047           0 :                 bFound = true;
    2048           0 :                 if ( nField < nPos )
    2049           0 :                     bBeforeDrag = true;
    2050           0 :                 else if ( nField > nPos )
    2051           0 :                     bAfterDrag = true;
    2052             :             }
    2053             :         }
    2054             : 
    2055           0 :         if ( bFound )
    2056             :         {
    2057           0 :             if (!bBeforeDrag)
    2058             :             {
    2059           0 :                 ++rPosRect.Bottom();
    2060           0 :                 if (bAfterDrag)
    2061           0 :                     ++rPosRect.Top();
    2062             :             }
    2063             :         }
    2064             :         else
    2065             :         {
    2066           0 :             if ( !bMouseTop )
    2067             :             {
    2068           0 :                 ++rPosRect.Top();
    2069           0 :                 ++rPosRect.Bottom();
    2070           0 :                 ++nField;
    2071             :             }
    2072             :         }
    2073             : 
    2074           0 :         rOrient = sheet::DataPilotFieldOrientation_COLUMN;
    2075           0 :         rDimPos = nField;                       //!...
    2076           0 :         return true;
    2077             :     }
    2078             : 
    2079             :     //  test for row header
    2080             : 
    2081             :     //  special case if no row fields
    2082             :     bool bSpecial = ( nRow+1 >= nDataStartRow && nRow <= nTabEndRow &&
    2083           0 :                         nRowFieldCount == 0 && nCol == nTabStartCol && bMouseLeft );
    2084             : 
    2085           0 :     if ( bSpecial || ( nRow+1 >= nDataStartRow && nRow <= nTabEndRow &&
    2086             :                         nCol + 1 >= nTabStartCol && nCol < nTabStartCol + nRowFieldCount ) )
    2087             :     {
    2088           0 :         long nField = nCol - nTabStartCol;
    2089             :         //! find start of dimension
    2090             : 
    2091             :         rPosRect = Rectangle( nTabStartCol + nField, nDataStartRow - 1,
    2092           0 :                               nTabStartCol + nField - 1, nTabEndRow );
    2093             : 
    2094           0 :         bool bFound = false;            // is this within the same orientation?
    2095           0 :         bool bBeforeDrag = false;
    2096           0 :         bool bAfterDrag = false;
    2097           0 :         for (long nPos=0; nPos<nRowFieldCount && !bFound; nPos++)
    2098             :         {
    2099           0 :             if (pRowFields[nPos].nDim == nDragDim)
    2100             :             {
    2101           0 :                 bFound = true;
    2102           0 :                 if ( nField < nPos )
    2103           0 :                     bBeforeDrag = true;
    2104           0 :                 else if ( nField > nPos )
    2105           0 :                     bAfterDrag = true;
    2106             :             }
    2107             :         }
    2108             : 
    2109           0 :         if ( bFound )
    2110             :         {
    2111           0 :             if (!bBeforeDrag)
    2112             :             {
    2113           0 :                 ++rPosRect.Right();
    2114           0 :                 if (bAfterDrag)
    2115           0 :                     ++rPosRect.Left();
    2116             :             }
    2117             :         }
    2118             :         else
    2119             :         {
    2120           0 :             if ( !bMouseLeft )
    2121             :             {
    2122           0 :                 ++rPosRect.Left();
    2123           0 :                 ++rPosRect.Right();
    2124           0 :                 ++nField;
    2125             :             }
    2126             :         }
    2127             : 
    2128           0 :         rOrient = sheet::DataPilotFieldOrientation_ROW;
    2129           0 :         rDimPos = nField;                       //!...
    2130           0 :         return true;
    2131             :     }
    2132             : 
    2133             :     //  test for page fields
    2134             : 
    2135           0 :     SCROW nPageStartRow = aStartPos.Row() + ( bDoFilter ? 1 : 0 );
    2136           0 :     if ( nCol >= aStartPos.Col() && nCol <= nTabEndCol &&
    2137             :             nRow + 1 >= nPageStartRow && nRow < nPageStartRow + nPageFieldCount )
    2138             :     {
    2139           0 :         long nField = nRow - nPageStartRow;
    2140           0 :         if (nField < 0)
    2141             :         {
    2142           0 :             nField = 0;
    2143           0 :             bMouseTop = true;
    2144             :         }
    2145             :         //! find start of dimension
    2146             : 
    2147           0 :         rPosRect = Rectangle( aStartPos.Col(), nPageStartRow + nField,
    2148           0 :                               nTabEndCol, nPageStartRow + nField - 1 );
    2149             : 
    2150           0 :         bool bFound = false;            // is this within the same orientation?
    2151           0 :         bool bBeforeDrag = false;
    2152           0 :         bool bAfterDrag = false;
    2153           0 :         for (long nPos=0; nPos<nPageFieldCount && !bFound; nPos++)
    2154             :         {
    2155           0 :             if (pPageFields[nPos].nDim == nDragDim)
    2156             :             {
    2157           0 :                 bFound = true;
    2158           0 :                 if ( nField < nPos )
    2159           0 :                     bBeforeDrag = true;
    2160           0 :                 else if ( nField > nPos )
    2161           0 :                     bAfterDrag = true;
    2162             :             }
    2163             :         }
    2164             : 
    2165           0 :         if ( bFound )
    2166             :         {
    2167           0 :             if (!bBeforeDrag)
    2168             :             {
    2169           0 :                 ++rPosRect.Bottom();
    2170           0 :                 if (bAfterDrag)
    2171           0 :                     ++rPosRect.Top();
    2172             :             }
    2173             :         }
    2174             :         else
    2175             :         {
    2176           0 :             if ( !bMouseTop )
    2177             :             {
    2178           0 :                 ++rPosRect.Top();
    2179           0 :                 ++rPosRect.Bottom();
    2180           0 :                 ++nField;
    2181             :             }
    2182             :         }
    2183             : 
    2184           0 :         rOrient = sheet::DataPilotFieldOrientation_PAGE;
    2185           0 :         rDimPos = nField;                       //!...
    2186           0 :         return true;
    2187             :     }
    2188             : 
    2189           0 :     return false;
    2190          15 : }
    2191             : 
    2192             : 
    2193             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10