/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include "scitems.hxx" #include #include #include #include #include #include #include "dpoutput.hxx" #include "dptabsrc.hxx" #include "dpfilteredcache.hxx" #include "document.hxx" #include "patattr.hxx" #include "docpool.hxx" #include "markdata.hxx" #include "attrib.hxx" #include "formula/errorcodes.hxx" // errNoValue #include "miscuno.hxx" #include "globstr.hrc" #include "stlpool.hxx" #include "stlsheet.hxx" #include "scresid.hxx" #include "unonames.hxx" #include "sc.hrc" #include "stringutil.hxx" #include "dputil.hxx" #include #include #include #include #include #include #include #include #include #include using namespace com::sun::star; using ::std::vector; using ::com::sun::star::beans::XPropertySet; using ::com::sun::star::uno::Sequence; using ::com::sun::star::uno::UNO_QUERY; using ::com::sun::star::uno::Reference; using ::com::sun::star::sheet::DataPilotTablePositionData; using ::com::sun::star::sheet::DataPilotTableResultData; using ::com::sun::star::uno::makeAny; using ::com::sun::star::uno::Any; #define SC_DP_FRAME_INNER_BOLD 20 #define SC_DP_FRAME_OUTER_BOLD 40 #define SC_DP_FRAME_COLOR Color(0,0,0) //( 0x20, 0x40, 0x68 ) #define SC_DPOUT_MAXLEVELS 256 struct ScDPOutLevelData { long nDim; long nHier; long nLevel; long nDimPos; sal_uInt32 mnSrcNumFmt; /// Prevailing number format used in the source data. uno::Sequence aResult; OUString maName; /// Name is the internal field name. OUString maCaption; /// Caption is the name visible in the output table. bool mbHasHiddenMember:1; bool mbDataLayout:1; bool mbPageDim:1; ScDPOutLevelData() : nDim(-1), nHier(-1), nLevel(-1), nDimPos(-1), mnSrcNumFmt(0), mbHasHiddenMember(false), mbDataLayout(false), mbPageDim(false) {} bool operator<(const ScDPOutLevelData& r) const { return nDimPos mbNeedLineCols; ::std::vector< SCCOL > mnCols; ::std::vector< bool > mbNeedLineRows; ::std::vector< SCROW > mnRows; SCCOL mnTabStartCol; SCROW mnTabStartRow; SCCOL mnDataStartCol; SCROW mnDataStartRow; SCCOL mnTabEndCol; SCROW mnTabEndRow; public: ScDPOutputImpl( ScDocument* pDoc, sal_uInt16 nTab, SCCOL nTabStartCol, SCROW nTabStartRow, SCCOL nDataStartCol, SCROW nDataStartRow, SCCOL nTabEndCol, SCROW nTabEndRow ); bool AddRow( SCROW nRow ); bool AddCol( SCCOL nCol ); void OutputDataArea(); void OutputBlockFrame ( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, bool bHori = false ); }; void ScDPOutputImpl::OutputDataArea() { AddRow( mnDataStartRow ); AddCol( mnDataStartCol ); mnCols.push_back( mnTabEndCol+1); //set last row bottom mnRows.push_back( mnTabEndRow+1); //set last col bottom bool bAllRows = ( ( mnTabEndRow - mnDataStartRow + 2 ) == (SCROW) mnRows.size() ); std::sort( mnCols.begin(), mnCols.end(), lcl_compareColfuc ); std::sort( mnRows.begin(), mnRows.end(), lcl_compareRowfuc ); for( SCCOL nCol = 0; nCol < (SCCOL)mnCols.size()-1; nCol ++ ) { if ( !bAllRows ) { if ( nCol < (SCCOL)mnCols.size()-2) { for ( SCROW i = nCol%2; i < (SCROW)mnRows.size()-2; i +=2 ) OutputBlockFrame( mnCols[nCol], mnRows[i], mnCols[nCol+1]-1, mnRows[i+1]-1 ); if ( mnRows.size()>=2 ) OutputBlockFrame( mnCols[nCol], mnRows[mnRows.size()-2], mnCols[nCol+1]-1, mnRows[mnRows.size()-1]-1 ); } else { for ( SCROW i = 0 ; i < (SCROW)mnRows.size()-1; i++ ) OutputBlockFrame( mnCols[nCol], mnRows[i], mnCols[nCol+1]-1, mnRows[i+1]-1 ); } } else OutputBlockFrame( mnCols[nCol], mnRows.front(), mnCols[nCol+1]-1, mnRows.back()-1, bAllRows ); } //out put rows area outer framer if ( mnTabStartCol != mnDataStartCol ) { if ( mnTabStartRow != mnDataStartRow ) OutputBlockFrame( mnTabStartCol, mnTabStartRow, mnDataStartCol-1, mnDataStartRow-1 ); OutputBlockFrame( mnTabStartCol, mnDataStartRow, mnDataStartCol-1, mnTabEndRow ); } //out put cols area outer framer OutputBlockFrame( mnDataStartCol, mnTabStartRow, mnTabEndCol, mnDataStartRow-1 ); } ScDPOutputImpl::ScDPOutputImpl( ScDocument* pDoc, sal_uInt16 nTab, SCCOL nTabStartCol, SCROW nTabStartRow, SCCOL nDataStartCol, SCROW nDataStartRow, SCCOL nTabEndCol, SCROW nTabEndRow ): mpDoc( pDoc ), mnTab( nTab ), mnTabStartCol( nTabStartCol ), mnTabStartRow( nTabStartRow ), mnDataStartCol ( nDataStartCol ), mnDataStartRow ( nDataStartRow ), mnTabEndCol( nTabEndCol ), mnTabEndRow( nTabEndRow ) { mbNeedLineCols.resize( nTabEndCol-nDataStartCol+1, false ); mbNeedLineRows.resize( nTabEndRow-nDataStartRow+1, false ); } bool ScDPOutputImpl::AddRow( SCROW nRow ) { if ( !mbNeedLineRows[ nRow - mnDataStartRow ] ) { mbNeedLineRows[ nRow - mnDataStartRow ] = true; mnRows.push_back( nRow ); return true; } else return false; } bool ScDPOutputImpl::AddCol( SCCOL nCol ) { if ( !mbNeedLineCols[ nCol - mnDataStartCol ] ) { mbNeedLineCols[ nCol - mnDataStartCol ] = true; mnCols.push_back( nCol ); return true; } else return false; } void ScDPOutputImpl::OutputBlockFrame ( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, bool bHori ) { Color color = SC_DP_FRAME_COLOR; ::editeng::SvxBorderLine aLine( &color, SC_DP_FRAME_INNER_BOLD ); ::editeng::SvxBorderLine aOutLine( &color, SC_DP_FRAME_OUTER_BOLD ); SvxBoxItem aBox( ATTR_BORDER ); if ( nStartCol == mnTabStartCol ) aBox.SetLine(&aOutLine, BOX_LINE_LEFT); else aBox.SetLine(&aLine, BOX_LINE_LEFT); if ( nStartRow == mnTabStartRow ) aBox.SetLine(&aOutLine, BOX_LINE_TOP); else aBox.SetLine(&aLine, BOX_LINE_TOP); if ( nEndCol == mnTabEndCol ) //bottom row aBox.SetLine(&aOutLine, BOX_LINE_RIGHT); else aBox.SetLine(&aLine, BOX_LINE_RIGHT); if ( nEndRow == mnTabEndRow ) //bottom aBox.SetLine(&aOutLine, BOX_LINE_BOTTOM); else aBox.SetLine(&aLine, BOX_LINE_BOTTOM); SvxBoxInfoItem aBoxInfo( ATTR_BORDER_INNER ); aBoxInfo.SetValid(VALID_VERT,false ); if ( bHori ) { aBoxInfo.SetValid(VALID_HORI,true); aBoxInfo.SetLine( &aLine, BOXINFO_LINE_HORI ); } else aBoxInfo.SetValid(VALID_HORI,false ); aBoxInfo.SetValid(VALID_DISTANCE,false); mpDoc->ApplyFrameAreaTab( ScRange( nStartCol, nStartRow, mnTab, nEndCol, nEndRow , mnTab ), &aBox, &aBoxInfo ); } void lcl_SetStyleById( ScDocument* pDoc, SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, sal_uInt16 nStrId ) { if ( nCol1 > nCol2 || nRow1 > nRow2 ) { OSL_FAIL("SetStyleById: invalid range"); return; } OUString aStyleName = ScGlobal::GetRscString( nStrId ); ScStyleSheetPool* pStlPool = pDoc->GetStyleSheetPool(); ScStyleSheet* pStyle = (ScStyleSheet*) pStlPool->Find( aStyleName, SFX_STYLE_FAMILY_PARA ); if (!pStyle) { // create new style (was in ScPivot::SetStyle) pStyle = (ScStyleSheet*) &pStlPool->Make( aStyleName, SFX_STYLE_FAMILY_PARA, SFXSTYLEBIT_USERDEF ); pStyle->SetParent( ScGlobal::GetRscString(STR_STYLENAME_STANDARD) ); SfxItemSet& rSet = pStyle->GetItemSet(); if ( nStrId==STR_PIVOT_STYLE_RESULT || nStrId==STR_PIVOT_STYLE_TITLE ) rSet.Put( SvxWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT ) ); if ( nStrId==STR_PIVOT_STYLE_CATEGORY || nStrId==STR_PIVOT_STYLE_TITLE ) rSet.Put( SvxHorJustifyItem( SVX_HOR_JUSTIFY_LEFT, ATTR_HOR_JUSTIFY ) ); } pDoc->ApplyStyleAreaTab( nCol1, nRow1, nCol2, nRow2, nTab, *pStyle ); } void lcl_SetFrame( ScDocument* pDoc, SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, sal_uInt16 nWidth ) { ::editeng::SvxBorderLine aLine(0, nWidth, table::BorderLineStyle::SOLID); SvxBoxItem aBox( ATTR_BORDER ); aBox.SetLine(&aLine, BOX_LINE_LEFT); aBox.SetLine(&aLine, BOX_LINE_TOP); aBox.SetLine(&aLine, BOX_LINE_RIGHT); aBox.SetLine(&aLine, BOX_LINE_BOTTOM); SvxBoxInfoItem aBoxInfo( ATTR_BORDER_INNER ); aBoxInfo.SetValid(VALID_HORI,false); aBoxInfo.SetValid(VALID_VERT,false); aBoxInfo.SetValid(VALID_DISTANCE,false); pDoc->ApplyFrameAreaTab( ScRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab ), &aBox, &aBoxInfo ); } // ----------------------------------------------------------------------- void lcl_FillNumberFormats( sal_uInt32*& rFormats, long& rCount, const uno::Reference& xLevRes, const uno::Reference& xDims ) { if ( rFormats ) return; // already set // xLevRes is from the data layout dimension //! use result sequence from ScDPOutLevelData! uno::Sequence aResult = xLevRes->getResults(); long nSize = aResult.getLength(); if (!nSize) return; // get names/formats for all data dimensions //! merge this with the loop to collect ScDPOutLevelData? OUString aDataNames[SC_DPOUT_MAXLEVELS]; sal_uInt32 nDataFormats[SC_DPOUT_MAXLEVELS]; long nDataCount = 0; long nDimCount = xDims->getCount(); for (long nDim=0; nDim xDim = ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) ); uno::Reference xDimProp( xDim, uno::UNO_QUERY ); uno::Reference xDimName( xDim, uno::UNO_QUERY ); if ( xDimProp.is() && xDimName.is() ) { sheet::DataPilotFieldOrientation eDimOrient = (sheet::DataPilotFieldOrientation) ScUnoHelpFunctions::GetEnumProperty( xDimProp, OUString(SC_UNO_DP_ORIENTATION), sheet::DataPilotFieldOrientation_HIDDEN ); if ( eDimOrient == sheet::DataPilotFieldOrientation_DATA ) { aDataNames[nDataCount] = xDimName->getName(); long nFormat = ScUnoHelpFunctions::GetLongProperty( xDimProp, OUString(SC_UNONAME_NUMFMT) ); nDataFormats[nDataCount] = nFormat; ++nDataCount; } } } if (!nDataCount) return; const sheet::MemberResult* pArray = aResult.getConstArray(); OUString aName; sal_uInt32* pNumFmt = new sal_uInt32[nSize]; if (nDataCount == 1) { // only one data dimension -> use its numberformat everywhere long nFormat = nDataFormats[0]; for (long nPos=0; nPos& xDims ) { long nDimCount = xDims->getCount(); for (long nDim=0; nDim xDim = ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) ); uno::Reference xDimProp( xDim, uno::UNO_QUERY ); if ( xDimProp.is() ) { sheet::DataPilotFieldOrientation eDimOrient = (sheet::DataPilotFieldOrientation) ScUnoHelpFunctions::GetEnumProperty( xDimProp, OUString(SC_UNO_DP_ORIENTATION), sheet::DataPilotFieldOrientation_HIDDEN ); if ( eDimOrient == sheet::DataPilotFieldOrientation_DATA ) { long nFormat = ScUnoHelpFunctions::GetLongProperty( xDimProp, OUString(SC_UNONAME_NUMFMT) ); return nFormat; // use format from first found data dimension } } } return 0; // none found } void lcl_SortFields( ScDPOutLevelData* pFields, long nFieldCount ) { for (long i=0; i+1& rSeq ) { // used to skip levels that have no members long nLen = rSeq.getLength(); const sheet::MemberResult* pArray = rSeq.getConstArray(); for (long i=0; i empty } /** * Get visible page dimension members as results, except that, if all * members are visible, then this function returns empty result. */ uno::Sequence getVisiblePageMembersAsResults( const uno::Reference& xLevel ) { if (!xLevel.is()) return uno::Sequence(); uno::Reference xMSupplier(xLevel, UNO_QUERY); if (!xMSupplier.is()) return uno::Sequence(); uno::Reference xNA = xMSupplier->getMembers(); if (!xNA.is()) return uno::Sequence(); std::vector aRes; uno::Sequence aNames = xNA->getElementNames(); for (sal_Int32 i = 0; i < aNames.getLength(); ++i) { const OUString& rName = aNames[i]; xNA->getByName(rName); uno::Reference xMemPS(xNA->getByName(rName), UNO_QUERY); if (!xMemPS.is()) continue; OUString aCaption = ScUnoHelpFunctions::GetStringProperty(xMemPS, SC_UNO_DP_LAYOUTNAME, OUString()); if (aCaption.isEmpty()) aCaption = rName; bool bVisible = ScUnoHelpFunctions::GetBoolProperty(xMemPS, SC_UNO_DP_ISVISIBLE, false); if (bVisible) aRes.push_back(sheet::MemberResult(rName, aCaption, 0)); } if (aNames.getLength() == static_cast(aRes.size())) // All members are visible. Return empty result. return uno::Sequence(); return ScUnoHelpFunctions::VectorToSequence(aRes); } } ScDPOutput::ScDPOutput( ScDocument* pD, const uno::Reference& xSrc, const ScAddress& rPos, bool bFilter ) : pDoc( pD ), xSource( xSrc ), aStartPos( rPos ), pColNumFmt( NULL ), pRowNumFmt( NULL ), nColFmtCount( 0 ), nRowFmtCount( 0 ), nSingleNumFmt( 0 ), bDoFilter(bFilter), bResultsError(false), mbHasDataLayout(false), bSizesValid(false), bSizeOverflow(false), mbHeaderLayout(false) { nTabStartCol = nMemberStartCol = nDataStartCol = nTabEndCol = 0; nTabStartRow = nMemberStartRow = nDataStartRow = nTabEndRow = 0; pColFields = new ScDPOutLevelData[SC_DPOUT_MAXLEVELS]; pRowFields = new ScDPOutLevelData[SC_DPOUT_MAXLEVELS]; pPageFields = new ScDPOutLevelData[SC_DPOUT_MAXLEVELS]; nColFieldCount = 0; nRowFieldCount = 0; nPageFieldCount = 0; uno::Reference xResult( xSource, uno::UNO_QUERY ); if ( xSource.is() && xResult.is() ) { // get dimension results: uno::Reference xDims = new ScNameToIndexAccess( xSource->getDimensions() ); long nDimCount = xDims->getCount(); for (long nDim=0; nDim xDim = ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) ); uno::Reference xDimProp( xDim, uno::UNO_QUERY ); uno::Reference xDimSupp( xDim, uno::UNO_QUERY ); if ( xDimProp.is() && xDimSupp.is() ) { sheet::DataPilotFieldOrientation eDimOrient = (sheet::DataPilotFieldOrientation) ScUnoHelpFunctions::GetEnumProperty( xDimProp, OUString(SC_UNO_DP_ORIENTATION), sheet::DataPilotFieldOrientation_HIDDEN ); long nDimPos = ScUnoHelpFunctions::GetLongProperty( xDimProp, OUString(SC_UNO_DP_POSITION) ); bool bIsDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp, OUString(SC_UNO_DP_ISDATALAYOUT)); bool bHasHiddenMember = ScUnoHelpFunctions::GetBoolProperty( xDimProp, OUString(SC_UNO_DP_HAS_HIDDEN_MEMBER)); sal_Int32 nNumFmt = ScUnoHelpFunctions::GetLongProperty( xDimProp, SC_UNO_DP_NUMBERFO, 0); if ( eDimOrient != sheet::DataPilotFieldOrientation_HIDDEN ) { uno::Reference xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() ); long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp, OUString(SC_UNO_DP_USEDHIERARCHY) ); if ( nHierarchy >= xHiers->getCount() ) nHierarchy = 0; uno::Reference xHier = ScUnoHelpFunctions::AnyToInterface( xHiers->getByIndex(nHierarchy) ); uno::Reference xHierSupp( xHier, uno::UNO_QUERY ); if ( xHierSupp.is() ) { uno::Reference xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() ); long nLevCount = xLevels->getCount(); for (long nLev=0; nLev xLevel = ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex(nLev) ); uno::Reference xLevNam( xLevel, uno::UNO_QUERY ); uno::Reference xLevRes( xLevel, uno::UNO_QUERY ); if ( xLevNam.is() && xLevRes.is() ) { OUString aName = xLevNam->getName(); Reference xPropSet(xLevel, UNO_QUERY); // Caption equals the field name by default. // #i108948# use ScUnoHelpFunctions::GetStringProperty, because // LayoutName is new and may not be present in external implementation OUString aCaption = ScUnoHelpFunctions::GetStringProperty( xPropSet, OUString(SC_UNO_DP_LAYOUTNAME), aName ); bool bRowFieldHasMember = false; switch ( eDimOrient ) { case sheet::DataPilotFieldOrientation_COLUMN: pColFields[nColFieldCount].nDim = nDim; pColFields[nColFieldCount].nHier = nHierarchy; pColFields[nColFieldCount].nLevel = nLev; pColFields[nColFieldCount].nDimPos = nDimPos; pColFields[nColFieldCount].aResult = xLevRes->getResults(); pColFields[nColFieldCount].mnSrcNumFmt = nNumFmt; pColFields[nColFieldCount].maName = aName; pColFields[nColFieldCount].maCaption= aCaption; pColFields[nColFieldCount].mbHasHiddenMember = bHasHiddenMember; pColFields[nColFieldCount].mbDataLayout = bIsDataLayout; if (!lcl_MemberEmpty(pColFields[nColFieldCount].aResult)) ++nColFieldCount; break; case sheet::DataPilotFieldOrientation_ROW: pRowFields[nRowFieldCount].nDim = nDim; pRowFields[nRowFieldCount].nHier = nHierarchy; pRowFields[nRowFieldCount].nLevel = nLev; pRowFields[nRowFieldCount].nDimPos = nDimPos; pRowFields[nRowFieldCount].aResult = xLevRes->getResults(); pRowFields[nRowFieldCount].mnSrcNumFmt = nNumFmt; pRowFields[nRowFieldCount].maName = aName; pRowFields[nRowFieldCount].maCaption= aCaption; pRowFields[nRowFieldCount].mbHasHiddenMember = bHasHiddenMember; pRowFields[nRowFieldCount].mbDataLayout = bIsDataLayout; if (!lcl_MemberEmpty(pRowFields[nRowFieldCount].aResult)) { ++nRowFieldCount; bRowFieldHasMember = true; } break; case sheet::DataPilotFieldOrientation_PAGE: pPageFields[nPageFieldCount].nDim = nDim; pPageFields[nPageFieldCount].nHier = nHierarchy; pPageFields[nPageFieldCount].nLevel = nLev; pPageFields[nPageFieldCount].nDimPos = nDimPos; pPageFields[nPageFieldCount].aResult = getVisiblePageMembersAsResults(xLevel); pPageFields[nPageFieldCount].mnSrcNumFmt = nNumFmt; pPageFields[nPageFieldCount].maName = aName; pPageFields[nPageFieldCount].maCaption= aCaption; pPageFields[nPageFieldCount].mbHasHiddenMember = bHasHiddenMember; pPageFields[nPageFieldCount].mbPageDim = true; // no check on results for page fields ++nPageFieldCount; break; default: { // added to avoid warnings } } // get number formats from data dimensions if ( bIsDataLayout ) { if (bRowFieldHasMember) mbHasDataLayout = true; OSL_ENSURE( nLevCount == 1, "data layout: multiple levels?" ); if ( eDimOrient == sheet::DataPilotFieldOrientation_COLUMN ) lcl_FillNumberFormats( pColNumFmt, nColFmtCount, xLevRes, xDims ); else if ( eDimOrient == sheet::DataPilotFieldOrientation_ROW ) lcl_FillNumberFormats( pRowNumFmt, nRowFmtCount, xLevRes, xDims ); } } } } } else if ( bIsDataLayout ) { // data layout dimension is hidden (allowed if there is only one data dimension) // -> use the number format from the first data dimension for all results nSingleNumFmt = lcl_GetFirstNumberFormat( xDims ); } } } lcl_SortFields( pColFields, nColFieldCount ); lcl_SortFields( pRowFields, nRowFieldCount ); lcl_SortFields( pPageFields, nPageFieldCount ); // get data results: try { aData = xResult->getResults(); } catch (const uno::RuntimeException&) { bResultsError = true; } } // get "DataDescription" property (may be missing in external sources) uno::Reference xSrcProp( xSource, uno::UNO_QUERY ); if ( xSrcProp.is() ) { try { uno::Any aAny = xSrcProp->getPropertyValue( OUString(SC_UNO_DP_DATADESC) ); OUString aUStr; aAny >>= aUStr; aDataDescription = aUStr; } catch(const uno::Exception&) { } } } ScDPOutput::~ScDPOutput() { delete[] pColFields; delete[] pRowFields; delete[] pPageFields; delete[] pColNumFmt; delete[] pRowNumFmt; } void ScDPOutput::SetPosition( const ScAddress& rPos ) { aStartPos = rPos; bSizesValid = bSizeOverflow = false; } void ScDPOutput::DataCell( SCCOL nCol, SCROW nRow, SCTAB nTab, const sheet::DataResult& rData ) { long nFlags = rData.Flags; if ( nFlags & sheet::DataResultFlags::ERROR ) { pDoc->SetError( nCol, nRow, nTab, errNoValue ); } else if ( nFlags & sheet::DataResultFlags::HASDATA ) { pDoc->SetValue( nCol, nRow, nTab, rData.Value ); // use number formats from source OSL_ENSURE( bSizesValid, "DataCell: !bSizesValid" ); sal_uInt32 nFormat = 0; bool bApplyFormat = false; if ( pColNumFmt ) { if ( nCol >= nDataStartCol ) { long nIndex = nCol - nDataStartCol; if ( nIndex < nColFmtCount ) { nFormat = pColNumFmt[nIndex]; bApplyFormat = true; } } } else if ( pRowNumFmt ) { if ( nRow >= nDataStartRow ) { long nIndex = nRow - nDataStartRow; if ( nIndex < nRowFmtCount ) { nFormat = pRowNumFmt[nIndex]; bApplyFormat = true; } } } else if ( nSingleNumFmt != 0 ) { nFormat = nSingleNumFmt; // single format is used everywhere bApplyFormat = true; } if (bApplyFormat) pDoc->ApplyAttr(nCol, nRow, nTab, SfxUInt32Item(ATTR_VALUE_FORMAT, nFormat)); } // SubTotal formatting is controlled by headers } void ScDPOutput::HeaderCell( SCCOL nCol, SCROW nRow, SCTAB nTab, const sheet::MemberResult& rData, bool bColHeader, long nLevel ) { long nFlags = rData.Flags; if ( nFlags & sheet::MemberResultFlags::HASMEMBER ) { bool bNumeric = (nFlags & sheet::MemberResultFlags::NUMERIC) != 0; ScSetStringParam aParam; if (bNumeric) aParam.setNumericInput(); else aParam.setTextInput(); pDoc->SetString(nCol, nRow, nTab, rData.Caption, &aParam); } if ( nFlags & sheet::MemberResultFlags::SUBTOTAL ) { ScDPOutputImpl outputimp( pDoc, nTab, nTabStartCol, nTabStartRow, nDataStartCol, nDataStartRow, nTabEndCol, nTabEndRow ); //! limit frames to horizontal or vertical? if (bColHeader) { outputimp.OutputBlockFrame( nCol,nMemberStartRow+(SCROW)nLevel, nCol,nDataStartRow-1 ); lcl_SetStyleById( pDoc,nTab, nCol,nMemberStartRow+(SCROW)nLevel, nCol,nDataStartRow-1, STR_PIVOT_STYLE_TITLE ); lcl_SetStyleById( pDoc,nTab, nCol,nDataStartRow, nCol,nTabEndRow, STR_PIVOT_STYLE_RESULT ); } else { outputimp.OutputBlockFrame( nMemberStartCol+(SCCOL)nLevel,nRow, nDataStartCol-1,nRow ); lcl_SetStyleById( pDoc,nTab, nMemberStartCol+(SCCOL)nLevel,nRow, nDataStartCol-1,nRow, STR_PIVOT_STYLE_TITLE ); lcl_SetStyleById( pDoc,nTab, nDataStartCol,nRow, nTabEndCol,nRow, STR_PIVOT_STYLE_RESULT ); } } } void ScDPOutput::FieldCell( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScDPOutLevelData& rData, bool bInTable) { // Avoid unwanted automatic format detection. ScSetStringParam aParam; aParam.mbDetectNumberFormat = false; aParam.meSetTextNumFormat = ScSetStringParam::Always; aParam.mbHandleApostrophe = false; pDoc->SetString(nCol, nRow, nTab, rData.maCaption, &aParam); if (bInTable) lcl_SetFrame( pDoc,nTab, nCol,nRow, nCol,nRow, 20 ); // For field button drawing sal_uInt16 nMergeFlag = 0; if (rData.mbHasHiddenMember) nMergeFlag |= SC_MF_HIDDEN_MEMBER; if (rData.mbPageDim) { nMergeFlag |= SC_MF_BUTTON_POPUP; pDoc->ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, SC_MF_BUTTON); pDoc->ApplyFlagsTab(nCol+1, nRow, nCol+1, nRow, nTab, nMergeFlag); } else { nMergeFlag |= SC_MF_BUTTON; if (!rData.mbDataLayout) nMergeFlag |= SC_MF_BUTTON_POPUP; pDoc->ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, nMergeFlag); } lcl_SetStyleById( pDoc,nTab, nCol,nRow, nCol,nRow, STR_PIVOT_STYLE_FIELDNAME ); } static void lcl_DoFilterButton( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab ) { pDoc->SetString( nCol, nRow, nTab, ScGlobal::GetRscString(STR_CELL_FILTER) ); pDoc->ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, SC_MF_BUTTON); } void ScDPOutput::CalcSizes() { if (!bSizesValid) { // get column size of data from first row //! allow different sizes (and clear following areas) ??? nRowCount = aData.getLength(); const uno::Sequence* pRowAry = aData.getConstArray(); nColCount = nRowCount ? ( pRowAry[0].getLength() ) : 0; nHeaderSize = 1; if (GetHeaderLayout() && nColFieldCount == 0) // Insert an extra header row only when there is no column field. nHeaderSize = 2; // calculate output positions and sizes long nPageSize = 0; //! use page fields! if ( bDoFilter || nPageFieldCount ) { nPageSize += nPageFieldCount + 1; // plus one empty row if ( bDoFilter ) ++nPageSize; // filter button above the page fields } if ( aStartPos.Col() + nRowFieldCount + nColCount - 1 > MAXCOL || aStartPos.Row() + nPageSize + nHeaderSize + nColFieldCount + nRowCount > MAXROW ) { bSizeOverflow = true; } nTabStartCol = aStartPos.Col(); nTabStartRow = aStartPos.Row() + (SCROW)nPageSize; // below page fields nMemberStartCol = nTabStartCol; nMemberStartRow = nTabStartRow + (SCROW) nHeaderSize; nDataStartCol = nMemberStartCol + (SCCOL)nRowFieldCount; nDataStartRow = nMemberStartRow + (SCROW)nColFieldCount; if ( nColCount > 0 ) nTabEndCol = nDataStartCol + (SCCOL)nColCount - 1; else nTabEndCol = nDataStartCol; // single column will remain empty // if page fields are involved, include the page selection cells if ( nPageFieldCount > 0 && nTabEndCol < nTabStartCol + 1 ) nTabEndCol = nTabStartCol + 1; if ( nRowCount > 0 ) nTabEndRow = nDataStartRow + (SCROW)nRowCount - 1; else nTabEndRow = nDataStartRow; // single row will remain empty bSizesValid = true; } } sal_Int32 ScDPOutput::GetPositionType(const ScAddress& rPos) { using namespace ::com::sun::star::sheet; SCCOL nCol = rPos.Col(); SCROW nRow = rPos.Row(); SCTAB nTab = rPos.Tab(); if ( nTab != aStartPos.Tab() ) return DataPilotTablePositionType::NOT_IN_TABLE; CalcSizes(); // Make sure the cursor is within the table. if (nCol < nTabStartCol || nRow < nTabStartRow || nCol > nTabEndCol || nRow > nTabEndRow) return DataPilotTablePositionType::NOT_IN_TABLE; // test for result data area. if (nCol >= nDataStartCol && nCol <= nTabEndCol && nRow >= nDataStartRow && nRow <= nTabEndRow) return DataPilotTablePositionType::RESULT; bool bInColHeader = (nRow >= nTabStartRow && nRow < nDataStartRow); bool bInRowHeader = (nCol >= nTabStartCol && nCol < nDataStartCol); if (bInColHeader && bInRowHeader) // probably in that ugly little box at the upper-left corner of the table. return DataPilotTablePositionType::OTHER; if (bInColHeader) { if (nRow == nTabStartRow) // first row in the column header area is always used for column // field buttons. return DataPilotTablePositionType::OTHER; return DataPilotTablePositionType::COLUMN_HEADER; } if (bInRowHeader) return DataPilotTablePositionType::ROW_HEADER; return DataPilotTablePositionType::OTHER; } void ScDPOutput::Output() { long nField; SCTAB nTab = aStartPos.Tab(); const uno::Sequence* pRowAry = aData.getConstArray(); // calculate output positions and sizes CalcSizes(); if ( bSizeOverflow || bResultsError ) // does output area exceed sheet limits? return; // nothing // clear whole (new) output area //! when modifying table, clear old area //! include IDF_OBJECTS ??? pDoc->DeleteAreaTab( aStartPos.Col(), aStartPos.Row(), nTabEndCol, nTabEndRow, nTab, IDF_ALL ); if ( bDoFilter ) lcl_DoFilterButton( pDoc, aStartPos.Col(), aStartPos.Row(), nTab ); // output page fields: for (nField=0; nField& rRes = pPageFields[nField].aResult; sal_Int32 n = rRes.getLength(); if (n == 1) aPageValue = rRes[0].Caption; else if (n > 1) aPageValue = ScResId(SCSTR_MULTIPLE).toString(); pDoc->SetString( nFldCol, nHdrRow, nTab, aPageValue ); lcl_SetFrame( pDoc,nTab, nFldCol,nHdrRow, nFldCol,nHdrRow, 20 ); } // data description // (may get overwritten by first row field) if (aDataDescription.isEmpty()) { //! use default string ("result") ? } pDoc->SetString(nTabStartCol, nTabStartRow, nTab, aDataDescription); // set STR_PIVOT_STYLE_INNER for whole data area (subtotals are overwritten) if ( nDataStartRow > nTabStartRow ) lcl_SetStyleById( pDoc, nTab, nTabStartCol, nTabStartRow, nTabEndCol, nDataStartRow-1, STR_PIVOT_STYLE_TOP ); lcl_SetStyleById( pDoc, nTab, nDataStartCol, nDataStartRow, nTabEndCol, nTabEndRow, STR_PIVOT_STYLE_INNER ); // output column headers: ScDPOutputImpl outputimp( pDoc, nTab, nTabStartCol, nTabStartRow, nDataStartCol, nDataStartRow, nTabEndCol, nTabEndRow ); for (nField=0; nField rSequence = pColFields[nField].aResult; const sheet::MemberResult* pArray = rSequence.getConstArray(); long nThisColCount = rSequence.getLength(); OSL_ENSURE( nThisColCount == nColCount, "count mismatch" ); //! ??? for (long nCol=0; nColApplyAttr(nColPos, nRowPos, nTab, SfxUInt32Item(ATTR_VALUE_FORMAT, pColFields[nField].mnSrcNumFmt)); } if ( nField== 0 && nColFieldCount == 1 ) outputimp.OutputBlockFrame( nDataStartCol,nTabStartRow, nTabEndCol,nRowPos-1 ); } // output row headers: std::vector vbSetBorder; vbSetBorder.resize( nTabEndRow - nDataStartRow + 1, false ); for (nField=0; nField rSequence = pRowFields[nField].aResult; const sheet::MemberResult* pArray = rSequence.getConstArray(); long nThisRowCount = rSequence.getLength(); OSL_ENSURE( nThisRowCount == nRowCount, "count mismatch" ); //! ??? for (long nRow=0; nRowApplyAttr(nColPos, nRowPos, nTab, SfxUInt32Item(ATTR_VALUE_FORMAT, pRowFields[nField].mnSrcNumFmt)); } } // output data results: for (long nRow=0; nRow aMemberResults; bool bFound = false; long nField; // look in column fields for (nField=0; nField& rDataNames, std::vector& rGivenNames, sheet::DataPilotFieldOrientation& rDataOrient, const uno::Reference& xSource ) { rDataLayoutIndex = -1; // invalid rGrandTotalCols = 0; rGrandTotalRows = 0; rDataOrient = sheet::DataPilotFieldOrientation_HIDDEN; uno::Reference xSrcProp( xSource, uno::UNO_QUERY ); bool bColGrand = ScUnoHelpFunctions::GetBoolProperty( xSrcProp, OUString(SC_UNO_DP_COLGRAND)); if ( bColGrand ) rGrandTotalCols = 1; // default if data layout not in columns bool bRowGrand = ScUnoHelpFunctions::GetBoolProperty( xSrcProp, OUString(SC_UNO_DP_ROWGRAND)); if ( bRowGrand ) rGrandTotalRows = 1; // default if data layout not in rows if ( xSource.is() ) { // find index and orientation of "data layout" dimension, count data dimensions sal_Int32 nDataCount = 0; uno::Reference xDims = new ScNameToIndexAccess( xSource->getDimensions() ); long nDimCount = xDims->getCount(); for (long nDim=0; nDim xDim = ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) ); uno::Reference xDimProp( xDim, uno::UNO_QUERY ); if ( xDimProp.is() ) { sheet::DataPilotFieldOrientation eDimOrient = (sheet::DataPilotFieldOrientation) ScUnoHelpFunctions::GetEnumProperty( xDimProp, OUString(SC_UNO_DP_ORIENTATION), sheet::DataPilotFieldOrientation_HIDDEN ); if ( ScUnoHelpFunctions::GetBoolProperty( xDimProp, OUString(SC_UNO_DP_ISDATALAYOUT) ) ) { rDataLayoutIndex = nDim; rDataOrient = eDimOrient; } if ( eDimOrient == sheet::DataPilotFieldOrientation_DATA ) { OUString aSourceName; OUString aGivenName; ScDPOutput::GetDataDimensionNames( aSourceName, aGivenName, xDim ); try { uno::Any aValue = xDimProp->getPropertyValue( SC_UNO_DP_LAYOUTNAME ); if( aValue.hasValue() ) { OUString strLayoutName; if( ( aValue >>= strLayoutName ) && !strLayoutName.isEmpty() ) aGivenName = strLayoutName; } } catch(const uno::Exception&) { } rDataNames.push_back( aSourceName ); rGivenNames.push_back( aGivenName ); ++nDataCount; } } } if ( ( rDataOrient == sheet::DataPilotFieldOrientation_COLUMN ) && bColGrand ) rGrandTotalCols = nDataCount; else if ( ( rDataOrient == sheet::DataPilotFieldOrientation_ROW ) && bRowGrand ) rGrandTotalRows = nDataCount; } } } void ScDPOutput::GetPositionData(const ScAddress& rPos, DataPilotTablePositionData& rPosData) { using namespace ::com::sun::star::sheet; SCCOL nCol = rPos.Col(); SCROW nRow = rPos.Row(); SCTAB nTab = rPos.Tab(); if ( nTab != aStartPos.Tab() ) return; // wrong sheet // calculate output positions and sizes CalcSizes(); rPosData.PositionType = GetPositionType(rPos); switch (rPosData.PositionType) { case DataPilotTablePositionType::RESULT: { vector aFilters; GetDataResultPositionData(aFilters, rPos); sal_Int32 nSize = aFilters.size(); DataPilotTableResultData aResData; aResData.FieldFilters.realloc(nSize); for (sal_Int32 i = 0; i < nSize; ++i) aResData.FieldFilters[i] = aFilters[i]; aResData.DataFieldIndex = 0; Reference xPropSet(xSource, UNO_QUERY); if (xPropSet.is()) { sal_Int32 nDataFieldCount = ScUnoHelpFunctions::GetLongProperty( xPropSet, OUString(SC_UNO_DP_DATAFIELDCOUNT) ); if (nDataFieldCount > 0) aResData.DataFieldIndex = (nRow - nDataStartRow) % nDataFieldCount; } // Copy appropriate DataResult object from the cached sheet::DataResult table. if (aData.getLength() > nRow - nDataStartRow && aData[nRow-nDataStartRow].getLength() > nCol-nDataStartCol) aResData.Result = aData[nRow-nDataStartRow][nCol-nDataStartCol]; rPosData.PositionData = makeAny(aResData); return; } case DataPilotTablePositionType::COLUMN_HEADER: { long nField = nRow - nTabStartRow - 1; // 1st line is used for the buttons if (nField < 0) break; const uno::Sequence rSequence = pColFields[nField].aResult; if (rSequence.getLength() == 0) break; const sheet::MemberResult* pArray = rSequence.getConstArray(); long nItem = nCol - nDataStartCol; // get origin of "continue" fields while (nItem > 0 && ( pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) ) --nItem; if (nItem < 0) break; DataPilotTableHeaderData aHeaderData; aHeaderData.MemberName = OUString(pArray[nItem].Name); aHeaderData.Flags = pArray[nItem].Flags; aHeaderData.Dimension = static_cast(pColFields[nField].nDim); aHeaderData.Hierarchy = static_cast(pColFields[nField].nHier); aHeaderData.Level = static_cast(pColFields[nField].nLevel); rPosData.PositionData = makeAny(aHeaderData); return; } case DataPilotTablePositionType::ROW_HEADER: { long nField = nCol - nTabStartCol; if (nField < 0) break; const uno::Sequence rSequence = pRowFields[nField].aResult; if (rSequence.getLength() == 0) break; const sheet::MemberResult* pArray = rSequence.getConstArray(); long nItem = nRow - nDataStartRow; // get origin of "continue" fields while ( nItem > 0 && (pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) ) --nItem; if (nItem < 0) break; DataPilotTableHeaderData aHeaderData; aHeaderData.MemberName = OUString(pArray[nItem].Name); aHeaderData.Flags = pArray[nItem].Flags; aHeaderData.Dimension = static_cast(pRowFields[nField].nDim); aHeaderData.Hierarchy = static_cast(pRowFields[nField].nHier); aHeaderData.Level = static_cast(pRowFields[nField].nLevel); rPosData.PositionData = makeAny(aHeaderData); return; } } } bool ScDPOutput::GetDataResultPositionData(vector& rFilters, const ScAddress& rPos) { // Check to make sure there is at least one data field. Reference xPropSet(xSource, UNO_QUERY); if (!xPropSet.is()) return false; sal_Int32 nDataFieldCount = ScUnoHelpFunctions::GetLongProperty( xPropSet, OUString(SC_UNO_DP_DATAFIELDCOUNT) ); if (nDataFieldCount == 0) // No data field is present in this datapilot table. return false; // #i111421# use lcl_GetTableVars for correct size of totals and data layout position sal_Int32 nGrandTotalCols; sal_Int32 nGrandTotalRows; sal_Int32 nDataLayoutIndex; std::vector aDataNames; std::vector aGivenNames; sheet::DataPilotFieldOrientation eDataOrient; lcl_GetTableVars( nGrandTotalCols, nGrandTotalRows, nDataLayoutIndex, aDataNames, aGivenNames, eDataOrient, xSource ); SCCOL nCol = rPos.Col(); SCROW nRow = rPos.Row(); SCTAB nTab = rPos.Tab(); if ( nTab != aStartPos.Tab() ) return false; // wrong sheet CalcSizes(); // test for data area. if (nCol < nDataStartCol || nCol > nTabEndCol || nRow < nDataStartRow || nRow > nTabEndRow) { // Cell is outside the data field area. return false; } bool bFilterByCol = (nCol <= static_cast(nTabEndCol - nGrandTotalCols)); bool bFilterByRow = (nRow <= static_cast(nTabEndRow - nGrandTotalRows)); // column fields for (SCCOL nColField = 0; nColField < nColFieldCount && bFilterByCol; ++nColField) { if (pColFields[nColField].nDim == nDataLayoutIndex) // There is no sense including the data layout field for filtering. continue; sheet::DataPilotFieldFilter filter; filter.FieldName = pColFields[nColField].maName; const uno::Sequence rSequence = pColFields[nColField].aResult; const sheet::MemberResult* pArray = rSequence.getConstArray(); OSL_ENSURE(nDataStartCol + rSequence.getLength() - 1 == nTabEndCol, "ScDPOutput::GetDataFieldCellData: error in geometric assumption"); long nItem = nCol - nDataStartCol; // get origin of "continue" fields while ( nItem > 0 && (pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) ) --nItem; filter.MatchValue = pArray[nItem].Name; rFilters.push_back(filter); } // row fields for (SCROW nRowField = 0; nRowField < nRowFieldCount && bFilterByRow; ++nRowField) { if (pRowFields[nRowField].nDim == nDataLayoutIndex) // There is no sense including the data layout field for filtering. continue; sheet::DataPilotFieldFilter filter; filter.FieldName = pRowFields[nRowField].maName; const uno::Sequence rSequence = pRowFields[nRowField].aResult; const sheet::MemberResult* pArray = rSequence.getConstArray(); OSL_ENSURE(nDataStartRow + rSequence.getLength() - 1 == nTabEndRow, "ScDPOutput::GetDataFieldCellData: error in geometric assumption"); long nItem = nRow - nDataStartRow; // get origin of "continue" fields while ( nItem > 0 && (pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) ) --nItem; filter.MatchValue = pArray[nItem].Name; rFilters.push_back(filter); } return true; } namespace { OUString lcl_GetDataFieldName( const OUString& rSourceName, sheet::GeneralFunction eFunc ) { sal_uInt16 nStrId = 0; switch ( eFunc ) { case sheet::GeneralFunction_SUM: nStrId = STR_FUN_TEXT_SUM; break; case sheet::GeneralFunction_COUNT: case sheet::GeneralFunction_COUNTNUMS: nStrId = STR_FUN_TEXT_COUNT; break; case sheet::GeneralFunction_AVERAGE: nStrId = STR_FUN_TEXT_AVG; break; case sheet::GeneralFunction_MAX: nStrId = STR_FUN_TEXT_MAX; break; case sheet::GeneralFunction_MIN: nStrId = STR_FUN_TEXT_MIN; break; case sheet::GeneralFunction_PRODUCT: nStrId = STR_FUN_TEXT_PRODUCT; break; case sheet::GeneralFunction_STDEV: case sheet::GeneralFunction_STDEVP: nStrId = STR_FUN_TEXT_STDDEV; break; case sheet::GeneralFunction_VAR: case sheet::GeneralFunction_VARP: nStrId = STR_FUN_TEXT_VAR; break; case sheet::GeneralFunction_NONE: case sheet::GeneralFunction_AUTO: default: { OSL_FAIL("wrong function"); } } if ( !nStrId ) return OUString(); OUStringBuffer aRet( ScGlobal::GetRscString( nStrId ) ); aRet.appendAscii(RTL_CONSTASCII_STRINGPARAM(" - ")); aRet.append(rSourceName); return aRet.makeStringAndClear(); } } void ScDPOutput::GetDataDimensionNames( OUString& rSourceName, OUString& rGivenName, const uno::Reference& xDim ) { uno::Reference xDimProp( xDim, uno::UNO_QUERY ); uno::Reference xDimName( xDim, uno::UNO_QUERY ); if ( xDimProp.is() && xDimName.is() ) { // Asterisks are added in ScDPSaveData::WriteToSource to create unique names. //! preserve original name there? rSourceName = ScDPUtil::getSourceDimensionName(xDimName->getName()); // Generate "given name" the same way as in dptabres. //! Should use a stored name when available sheet::GeneralFunction eFunc = (sheet::GeneralFunction)ScUnoHelpFunctions::GetEnumProperty( xDimProp, OUString(SC_UNO_DP_FUNCTION), sheet::GeneralFunction_NONE ); rGivenName = lcl_GetDataFieldName( rSourceName, eFunc ); } } bool ScDPOutput::IsFilterButton( const ScAddress& rPos ) { SCCOL nCol = rPos.Col(); SCROW nRow = rPos.Row(); SCTAB nTab = rPos.Tab(); if ( nTab != aStartPos.Tab() || !bDoFilter ) return false; // wrong sheet or no button at all // filter button is at top left return ( nCol == aStartPos.Col() && nRow == aStartPos.Row() ); } long ScDPOutput::GetHeaderDim( const ScAddress& rPos, sal_uInt16& rOrient ) { SCCOL nCol = rPos.Col(); SCROW nRow = rPos.Row(); SCTAB nTab = rPos.Tab(); if ( nTab != aStartPos.Tab() ) return -1; // wrong sheet // calculate output positions and sizes CalcSizes(); // test for column header if ( nRow == nTabStartRow && nCol >= nDataStartCol && nCol < nDataStartCol + nColFieldCount ) { rOrient = sheet::DataPilotFieldOrientation_COLUMN; long nField = nCol - nDataStartCol; return pColFields[nField].nDim; } // test for row header if ( nRow+1 == nDataStartRow && nCol >= nTabStartCol && nCol < nTabStartCol + nRowFieldCount ) { rOrient = sheet::DataPilotFieldOrientation_ROW; long nField = nCol - nTabStartCol; return pRowFields[nField].nDim; } // test for page field SCROW nPageStartRow = aStartPos.Row() + ( bDoFilter ? 1 : 0 ); if ( nCol == aStartPos.Col() && nRow >= nPageStartRow && nRow < nPageStartRow + nPageFieldCount ) { rOrient = sheet::DataPilotFieldOrientation_PAGE; long nField = nRow - nPageStartRow; return pPageFields[nField].nDim; } //! single data field (?) rOrient = sheet::DataPilotFieldOrientation_HIDDEN; return -1; // invalid } bool ScDPOutput::GetHeaderDrag( const ScAddress& rPos, bool bMouseLeft, bool bMouseTop, long nDragDim, Rectangle& rPosRect, sal_uInt16& rOrient, long& rDimPos ) { // Rectangle instead of ScRange for rPosRect to allow for negative values SCCOL nCol = rPos.Col(); SCROW nRow = rPos.Row(); SCTAB nTab = rPos.Tab(); if ( nTab != aStartPos.Tab() ) return false; // wrong sheet // calculate output positions and sizes CalcSizes(); // test for column header if ( nCol >= nDataStartCol && nCol <= nTabEndCol && nRow + 1 >= nMemberStartRow && nRow < nMemberStartRow + nColFieldCount ) { long nField = nRow - nMemberStartRow; if (nField < 0) { nField = 0; bMouseTop = true; } //! find start of dimension rPosRect = Rectangle( nDataStartCol, nMemberStartRow + nField, nTabEndCol, nMemberStartRow + nField -1 ); bool bFound = false; // is this within the same orientation? bool bBeforeDrag = false; bool bAfterDrag = false; for (long nPos=0; nPos nPos ) bAfterDrag = true; } } if ( bFound ) { if (!bBeforeDrag) { ++rPosRect.Bottom(); if (bAfterDrag) ++rPosRect.Top(); } } else { if ( !bMouseTop ) { ++rPosRect.Top(); ++rPosRect.Bottom(); ++nField; } } rOrient = sheet::DataPilotFieldOrientation_COLUMN; rDimPos = nField; //!... return true; } // test for row header // special case if no row fields bool bSpecial = ( nRow+1 >= nDataStartRow && nRow <= nTabEndRow && nRowFieldCount == 0 && nCol == nTabStartCol && bMouseLeft ); if ( bSpecial || ( nRow+1 >= nDataStartRow && nRow <= nTabEndRow && nCol + 1 >= nTabStartCol && nCol < nTabStartCol + nRowFieldCount ) ) { long nField = nCol - nTabStartCol; //! find start of dimension rPosRect = Rectangle( nTabStartCol + nField, nDataStartRow - 1, nTabStartCol + nField - 1, nTabEndRow ); bool bFound = false; // is this within the same orientation? bool bBeforeDrag = false; bool bAfterDrag = false; for (long nPos=0; nPos nPos ) bAfterDrag = true; } } if ( bFound ) { if (!bBeforeDrag) { ++rPosRect.Right(); if (bAfterDrag) ++rPosRect.Left(); } } else { if ( !bMouseLeft ) { ++rPosRect.Left(); ++rPosRect.Right(); ++nField; } } rOrient = sheet::DataPilotFieldOrientation_ROW; rDimPos = nField; //!... return true; } // test for page fields SCROW nPageStartRow = aStartPos.Row() + ( bDoFilter ? 1 : 0 ); if ( nCol >= aStartPos.Col() && nCol <= nTabEndCol && nRow + 1 >= nPageStartRow && nRow < nPageStartRow + nPageFieldCount ) { long nField = nRow - nPageStartRow; if (nField < 0) { nField = 0; bMouseTop = true; } //! find start of dimension rPosRect = Rectangle( aStartPos.Col(), nPageStartRow + nField, nTabEndCol, nPageStartRow + nField - 1 ); bool bFound = false; // is this within the same orientation? bool bBeforeDrag = false; bool bAfterDrag = false; for (long nPos=0; nPos nPos ) bAfterDrag = true; } } if ( bFound ) { if (!bBeforeDrag) { ++rPosRect.Bottom(); if (bAfterDrag) ++rPosRect.Top(); } } else { if ( !bMouseTop ) { ++rPosRect.Top(); ++rPosRect.Bottom(); ++nField; } } rOrient = sheet::DataPilotFieldOrientation_PAGE; rDimPos = nField; //!... return true; } return false; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */