summaryrefslogtreecommitdiff
path: root/sc/source/core/data/dpobject.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/core/data/dpobject.cxx')
-rw-r--r--sc/source/core/data/dpobject.cxx2559
1 files changed, 2559 insertions, 0 deletions
diff --git a/sc/source/core/data/dpobject.cxx b/sc/source/core/data/dpobject.cxx
new file mode 100644
index 000000000000..295ed78159b3
--- /dev/null
+++ b/sc/source/core/data/dpobject.cxx
@@ -0,0 +1,2559 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: dpobject.cxx,v $
+ * $Revision: 1.23.30.5 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#include "dpobject.hxx"
+#include "dptabsrc.hxx"
+#include "dpsave.hxx"
+#include "dpdimsave.hxx"
+#include "dpoutput.hxx"
+#include "dpshttab.hxx"
+#include "dpsdbtab.hxx"
+#include "dpgroup.hxx"
+#include "document.hxx"
+#include "rechead.hxx"
+#include "pivot.hxx" // PIVOT_DATA_FIELD
+#include "dapiuno.hxx" // ScDataPilotConversion
+#include "miscuno.hxx"
+#include "scerrors.hxx"
+#include "refupdat.hxx"
+#include "scresid.hxx"
+#include "sc.hrc"
+#include "attrib.hxx"
+#include "scitems.hxx"
+#include "unonames.hxx"
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sheet/GeneralFunction.hpp>
+#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
+#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
+#include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
+#include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
+#include <com/sun/star/sheet/DataPilotTablePositionData.hpp>
+#include <com/sun/star/sheet/DataPilotTablePositionType.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/container/XContentEnumerationAccess.hpp>
+#include <com/sun/star/sheet/XDrillDownDataSupplier.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <tools/debug.hxx>
+#include <svl/zforlist.hxx> // IsNumberFormat
+
+#include <vector>
+#include <stdio.h>
+
+using namespace com::sun::star;
+using ::std::vector;
+using ::boost::shared_ptr;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::sheet::DataPilotTableHeaderData;
+using ::com::sun::star::sheet::DataPilotTablePositionData;
+using ::com::sun::star::beans::XPropertySet;
+using ::rtl::OUString;
+
+// -----------------------------------------------------------------------
+
+#define MAX_LABELS 256 //!!! from fieldwnd.hxx, must be moved to global.hxx
+
+// -----------------------------------------------------------------------
+
+#define SCDPSOURCE_SERVICE "com.sun.star.sheet.DataPilotSource"
+
+// -----------------------------------------------------------------------
+
+// incompatible versions of data pilot files
+#define SC_DP_VERSION_CURRENT 6
+
+// type of source data
+#define SC_DP_SOURCE_SHEET 0
+#define SC_DP_SOURCE_DATABASE 1
+#define SC_DP_SOURCE_SERVICE 2
+
+// -----------------------------------------------------------------------
+
+//! move to a header file
+#define DP_PROP_COLUMNGRAND "ColumnGrand"
+#define DP_PROP_FUNCTION "Function"
+#define DP_PROP_IGNOREEMPTY "IgnoreEmptyRows"
+#define DP_PROP_ISDATALAYOUT "IsDataLayoutDimension"
+//#define DP_PROP_ISVISIBLE "IsVisible"
+#define DP_PROP_ORIENTATION "Orientation"
+#define DP_PROP_ORIGINAL "Original"
+#define DP_PROP_POSITION "Position"
+#define DP_PROP_REPEATIFEMPTY "RepeatIfEmpty"
+#define DP_PROP_ROWGRAND "RowGrand"
+#define DP_PROP_SHOWDETAILS "ShowDetails"
+#define DP_PROP_SHOWEMPTY "ShowEmpty"
+#define DP_PROP_SUBTOTALS "SubTotals"
+#define DP_PROP_USEDHIERARCHY "UsedHierarchy"
+
+// -----------------------------------------------------------------------
+
+USHORT lcl_GetDataGetOrientation( const uno::Reference<sheet::XDimensionsSupplier>& xSource )
+{
+ long nRet = sheet::DataPilotFieldOrientation_HIDDEN;
+ if ( xSource.is() )
+ {
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
+ long nIntCount = xIntDims->getCount();
+ BOOL bFound = FALSE;
+ for (long nIntDim=0; nIntDim<nIntCount && !bFound; nIntDim++)
+ {
+ uno::Reference<uno::XInterface> xIntDim =
+ ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nIntDim) );
+ uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
+ if ( xDimProp.is() )
+ {
+ bFound = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
+ //! error checking -- is "IsDataLayoutDimension" property required??
+ if (bFound)
+ nRet = ScUnoHelpFunctions::GetEnumProperty(
+ xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION),
+ sheet::DataPilotFieldOrientation_HIDDEN );
+ }
+ }
+ }
+ return static_cast< USHORT >( nRet );
+}
+
+// -----------------------------------------------------------------------
+
+ScDPObject::ScDPObject( ScDocument* pD ) :
+ pDoc( pD ),
+ pSaveData( NULL ),
+ pSheetDesc( NULL ),
+ pImpDesc( NULL ),
+ pServDesc( NULL ),
+ mpTableData(static_cast<ScDPTableData*>(NULL)),
+ pOutput( NULL ),
+ bSettingsChanged( FALSE ),
+ bAlive( FALSE ),
+ mnAutoFormatIndex( 65535 ),
+ bAllowMove( FALSE ),
+ nHeaderRows( 0 ),
+ mbHeaderLayout(false)
+{
+}
+
+ScDPObject::ScDPObject(const ScDPObject& r) :
+ ScDataObject(),
+ pDoc( r.pDoc ),
+ pSaveData( NULL ),
+ aTableName( r.aTableName ),
+ aTableTag( r.aTableTag ),
+ aOutRange( r.aOutRange ),
+ pSheetDesc( NULL ),
+ pImpDesc( NULL ),
+ pServDesc( NULL ),
+ mpTableData(static_cast<ScDPTableData*>(NULL)),
+ pOutput( NULL ),
+ bSettingsChanged( FALSE ),
+ bAlive( FALSE ),
+ mnAutoFormatIndex( r.mnAutoFormatIndex ),
+ bAllowMove( FALSE ),
+ nHeaderRows( r.nHeaderRows ),
+ mbHeaderLayout( r.mbHeaderLayout )
+{
+ if (r.pSaveData)
+ pSaveData = new ScDPSaveData(*r.pSaveData);
+ if (r.pSheetDesc)
+ pSheetDesc = new ScSheetSourceDesc(*r.pSheetDesc);
+ if (r.pImpDesc)
+ pImpDesc = new ScImportSourceDesc(*r.pImpDesc);
+ if (r.pServDesc)
+ pServDesc = new ScDPServiceDesc(*r.pServDesc);
+ // xSource (and pOutput) is not copied
+}
+
+ScDPObject::~ScDPObject()
+{
+ delete pOutput;
+ delete pSaveData;
+ delete pSheetDesc;
+ delete pImpDesc;
+ delete pServDesc;
+}
+
+ScDataObject* ScDPObject::Clone() const
+{
+ return new ScDPObject(*this);
+}
+
+void ScDPObject::SetAlive(BOOL bSet)
+{
+ bAlive = bSet;
+}
+
+void ScDPObject::SetAllowMove(BOOL bSet)
+{
+ bAllowMove = bSet;
+}
+
+void ScDPObject::SetSaveData(const ScDPSaveData& rData)
+{
+ if ( pSaveData != &rData ) // API implementation modifies the original SaveData object
+ {
+ delete pSaveData;
+ pSaveData = new ScDPSaveData( rData );
+ }
+
+ InvalidateData(); // re-init source from SaveData
+}
+
+void ScDPObject::SetAutoFormatIndex(const sal_uInt16 nIndex)
+{
+ mnAutoFormatIndex = nIndex;
+}
+
+sal_uInt16 ScDPObject::GetAutoFormatIndex() const
+{
+ return mnAutoFormatIndex;
+}
+
+void ScDPObject::SetHeaderLayout (bool bUseGrid)
+{
+ mbHeaderLayout = bUseGrid;
+}
+
+bool ScDPObject::GetHeaderLayout() const
+{
+ return mbHeaderLayout;
+}
+
+void ScDPObject::SetOutRange(const ScRange& rRange)
+{
+ aOutRange = rRange;
+
+ if ( pOutput )
+ pOutput->SetPosition( rRange.aStart );
+}
+
+void ScDPObject::SetSheetDesc(const ScSheetSourceDesc& rDesc)
+{
+ if ( pSheetDesc && rDesc == *pSheetDesc )
+ return; // nothing to do
+
+ DELETEZ( pImpDesc );
+ DELETEZ( pServDesc );
+
+ delete pImpDesc;
+ pSheetDesc = new ScSheetSourceDesc(rDesc);
+
+ // make valid QueryParam
+
+ pSheetDesc->aQueryParam.nCol1 = pSheetDesc->aSourceRange.aStart.Col();
+ pSheetDesc->aQueryParam.nRow1 = pSheetDesc->aSourceRange.aStart.Row();
+ pSheetDesc->aQueryParam.nCol2 = pSheetDesc->aSourceRange.aEnd.Col();
+ pSheetDesc->aQueryParam.nRow2 = pSheetDesc->aSourceRange.aEnd.Row();;
+ pSheetDesc->aQueryParam.bHasHeader = TRUE;
+
+ InvalidateSource(); // new source must be created
+}
+
+void ScDPObject::SetImportDesc(const ScImportSourceDesc& rDesc)
+{
+ if ( pImpDesc && rDesc == *pImpDesc )
+ return; // nothing to do
+
+ DELETEZ( pSheetDesc );
+ DELETEZ( pServDesc );
+
+ delete pImpDesc;
+ pImpDesc = new ScImportSourceDesc(rDesc);
+
+ InvalidateSource(); // new source must be created
+}
+
+void ScDPObject::SetServiceData(const ScDPServiceDesc& rDesc)
+{
+ if ( pServDesc && rDesc == *pServDesc )
+ return; // nothing to do
+
+ DELETEZ( pSheetDesc );
+ DELETEZ( pImpDesc );
+
+ delete pServDesc;
+ pServDesc = new ScDPServiceDesc(rDesc);
+
+ InvalidateSource(); // new source must be created
+}
+
+void ScDPObject::WriteSourceDataTo( ScDPObject& rDest ) const
+{
+ if ( pSheetDesc )
+ rDest.SetSheetDesc( *pSheetDesc );
+ else if ( pImpDesc )
+ rDest.SetImportDesc( *pImpDesc );
+ else if ( pServDesc )
+ rDest.SetServiceData( *pServDesc );
+
+ // name/tag are not source data, but needed along with source data
+
+ rDest.aTableName = aTableName;
+ rDest.aTableTag = aTableTag;
+}
+
+void ScDPObject::WriteTempDataTo( ScDPObject& rDest ) const
+{
+ rDest.nHeaderRows = nHeaderRows;
+}
+
+BOOL ScDPObject::IsSheetData() const
+{
+ return ( pSheetDesc != NULL );
+}
+
+void ScDPObject::SetName(const String& rNew)
+{
+ aTableName = rNew;
+}
+
+void ScDPObject::SetTag(const String& rNew)
+{
+ aTableTag = rNew;
+}
+
+bool ScDPObject::IsDataDescriptionCell(const ScAddress& rPos)
+{
+ if (!pSaveData)
+ return false;
+
+ long nDataDimCount = pSaveData->GetDataDimensionCount();
+ if (nDataDimCount != 1)
+ // There has to be exactly one data dimension for the description to
+ // appear at top-left corner.
+ return false;
+
+ CreateOutput();
+ ScRange aTabRange = pOutput->GetOutputRange(sheet::DataPilotOutputRangeType::TABLE);
+ return (rPos == aTabRange.aStart);
+}
+
+uno::Reference<sheet::XDimensionsSupplier> ScDPObject::GetSource()
+{
+ CreateObjects();
+ return xSource;
+}
+
+void ScDPObject::CreateOutput()
+{
+ CreateObjects();
+ if (!pOutput)
+ {
+ BOOL bFilterButton = IsSheetData() && pSaveData && pSaveData->GetFilterButton();
+ pOutput = new ScDPOutput( pDoc, xSource, aOutRange.aStart, bFilterButton );
+ pOutput->SetHeaderLayout ( mbHeaderLayout );
+
+ long nOldRows = nHeaderRows;
+ nHeaderRows = pOutput->GetHeaderRows();
+
+ if ( bAllowMove && nHeaderRows != nOldRows )
+ {
+ long nDiff = nOldRows - nHeaderRows;
+ if ( nOldRows == 0 )
+ --nDiff;
+ if ( nHeaderRows == 0 )
+ ++nDiff;
+
+ long nNewRow = aOutRange.aStart.Row() + nDiff;
+ if ( nNewRow < 0 )
+ nNewRow = 0;
+
+ ScAddress aStart( aOutRange.aStart );
+ aStart.SetRow( (USHORT) nNewRow );
+ pOutput->SetPosition( aStart );
+
+ //! modify aOutRange?
+
+ bAllowMove = FALSE; // use only once
+ }
+ }
+}
+
+ScDPTableData* ScDPObject::GetTableData()
+{
+ if (!mpTableData)
+ {
+ if ( pImpDesc )
+ {
+ // database data
+ mpTableData.reset(new ScDatabaseDPData(pDoc, *pImpDesc));
+ }
+ else
+ {
+ // cell data
+ if (!pSheetDesc)
+ {
+ DBG_ERROR("no source descriptor");
+ pSheetDesc = new ScSheetSourceDesc; // dummy defaults
+ }
+ mpTableData.reset(new ScSheetDPData(pDoc, *pSheetDesc));
+ }
+
+ // grouping (for cell or database data)
+ if ( pSaveData && pSaveData->GetExistingDimensionData() )
+ {
+ shared_ptr<ScDPGroupTableData> pGroupData(new ScDPGroupTableData(mpTableData, pDoc));
+ pSaveData->GetExistingDimensionData()->WriteToData(*pGroupData);
+ mpTableData = pGroupData;
+ }
+ }
+
+ return mpTableData.get();
+}
+
+void ScDPObject::CreateObjects()
+{
+ // if groups are involved, create a new source with the ScDPGroupTableData
+ if ( bSettingsChanged && pSaveData && pSaveData->GetExistingDimensionData() )
+ InvalidateSource();
+
+ if (!xSource.is())
+ {
+ //! cache DPSource and/or Output?
+
+ DBG_ASSERT( bAlive, "CreateObjects on non-inserted DPObject" );
+
+ DELETEZ( pOutput ); // not valid when xSource is changed
+
+ if ( pServDesc )
+ {
+ xSource = CreateSource( *pServDesc );
+ }
+
+ if ( !xSource.is() ) // database or sheet data, or error in CreateSource
+ {
+ DBG_ASSERT( !pServDesc, "DPSource could not be created" );
+ ScDPTableData* pData = GetTableData();
+ ScDPSource* pSource = new ScDPSource( pData );
+ xSource = pSource;
+ }
+
+ if (pSaveData)
+ pSaveData->WriteToSource( xSource );
+ }
+ else if (bSettingsChanged)
+ {
+ DELETEZ( pOutput ); // not valid when xSource is changed
+
+ uno::Reference<util::XRefreshable> xRef( xSource, uno::UNO_QUERY );
+ if (xRef.is())
+ {
+ try
+ {
+ xRef->refresh();
+ }
+ catch(uno::Exception&)
+ {
+ DBG_ERROR("exception in refresh");
+ }
+ }
+
+ if (pSaveData)
+ pSaveData->WriteToSource( xSource );
+ }
+ bSettingsChanged = FALSE;
+}
+
+void ScDPObject::InvalidateData()
+{
+ bSettingsChanged = TRUE;
+}
+
+void ScDPObject::InvalidateSource()
+{
+ xSource = NULL;
+ mpTableData.reset();
+}
+
+ScRange ScDPObject::GetNewOutputRange( BOOL& rOverflow )
+{
+ CreateOutput(); // create xSource and pOutput if not already done
+
+ rOverflow = pOutput->HasError(); // range overflow or exception from source
+ if ( rOverflow )
+ return ScRange( aOutRange.aStart );
+ else
+ {
+ // don't store the result in aOutRange, because nothing has been output yet
+ return pOutput->GetOutputRange();
+ }
+}
+
+void ScDPObject::Output( const ScAddress& rPos )
+{
+ // clear old output area
+ pDoc->DeleteAreaTab( aOutRange.aStart.Col(), aOutRange.aStart.Row(),
+ aOutRange.aEnd.Col(), aOutRange.aEnd.Row(),
+ aOutRange.aStart.Tab(), IDF_ALL );
+ pDoc->RemoveFlagsTab( aOutRange.aStart.Col(), aOutRange.aStart.Row(),
+ aOutRange.aEnd.Col(), aOutRange.aEnd.Row(),
+ aOutRange.aStart.Tab(), SC_MF_AUTO );
+
+ CreateOutput(); // create xSource and pOutput if not already done
+
+ pOutput->SetPosition( rPos );
+
+ pOutput->Output();
+
+ // aOutRange is always the range that was last output to the document
+ aOutRange = pOutput->GetOutputRange();
+ const ScAddress& s = aOutRange.aStart;
+ const ScAddress& e = aOutRange.aEnd;
+ pDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
+}
+
+const ScRange ScDPObject::GetOutputRangeByType( sal_Int32 nType )
+{
+ CreateOutput();
+
+ if (pOutput->HasError())
+ return ScRange(aOutRange.aStart);
+
+ return pOutput->GetOutputRange(nType);
+}
+
+BOOL lcl_HasButton( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
+{
+ return ((const ScMergeFlagAttr*)pDoc->GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG ))->HasButton();
+}
+
+void ScDPObject::RefreshAfterLoad()
+{
+ // apply drop-down attribute, initialize nHeaderRows, without accessing the source
+ // (button attribute must be present)
+
+ // simple test: block of button cells at the top, followed by an empty cell
+
+ SCCOL nFirstCol = aOutRange.aStart.Col();
+ SCROW nFirstRow = aOutRange.aStart.Row();
+ SCTAB nTab = aOutRange.aStart.Tab();
+
+ SCROW nInitial = 0;
+ SCROW nOutRows = aOutRange.aEnd.Row() + 1 - aOutRange.aStart.Row();
+ while ( nInitial + 1 < nOutRows && lcl_HasButton( pDoc, nFirstCol, nFirstRow + nInitial, nTab ) )
+ ++nInitial;
+
+ if ( nInitial + 1 < nOutRows &&
+ pDoc->IsBlockEmpty( nTab, nFirstCol, nFirstRow + nInitial, nFirstCol, nFirstRow + nInitial ) &&
+ aOutRange.aEnd.Col() > nFirstCol )
+ {
+ BOOL bFilterButton = IsSheetData(); // when available, filter button setting must be checked here
+
+ SCROW nSkip = bFilterButton ? 1 : 0;
+ for (SCROW nPos=nSkip; nPos<nInitial; nPos++)
+ pDoc->ApplyAttr( nFirstCol + 1, nFirstRow + nPos, nTab, ScMergeFlagAttr(SC_MF_AUTO) );
+
+ nHeaderRows = nInitial;
+ }
+ else
+ nHeaderRows = 0; // nothing found, no drop-down lists
+}
+
+void ScDPObject::BuildAllDimensionMembers()
+{
+ if (!pSaveData)
+ return;
+
+ pSaveData->BuildAllDimensionMembers(GetTableData());
+}
+
+bool ScDPObject::GetMemberNames( sal_Int32 nDim, Sequence<OUString>& rNames )
+{
+ vector<ScDPLabelData::Member> aMembers;
+ if (!GetMembers(nDim, GetUsedHierarchy(nDim), aMembers))
+ return false;
+
+ size_t n = aMembers.size();
+ rNames.realloc(n);
+ for (size_t i = 0; i < n; ++i)
+ rNames[i] = aMembers[i].maName;
+
+ return true;
+}
+
+bool ScDPObject::GetMembers( sal_Int32 nDim, sal_Int32 nHier, vector<ScDPLabelData::Member>& rMembers )
+{
+ Reference< container::XNameAccess > xMembersNA;
+ if (!GetMembersNA( nDim, nHier, xMembersNA ))
+ return false;
+
+ Reference<container::XIndexAccess> xMembersIA( new ScNameToIndexAccess(xMembersNA) );
+ sal_Int32 nCount = xMembersIA->getCount();
+ vector<ScDPLabelData::Member> aMembers;
+ aMembers.reserve(nCount);
+
+ for (sal_Int32 i = 0; i < nCount; ++i)
+ {
+ Reference<container::XNamed> xMember(xMembersIA->getByIndex(i), UNO_QUERY);
+ ScDPLabelData::Member aMem;
+
+ if (xMember.is())
+ aMem.maName = xMember->getName();
+
+ Reference<beans::XPropertySet> xMemProp(xMember, UNO_QUERY);
+ if (xMemProp.is())
+ {
+ aMem.mbVisible = ScUnoHelpFunctions::GetBoolProperty(xMemProp, OUString::createFromAscii(SC_UNO_ISVISIBL));
+ aMem.mbShowDetails = ScUnoHelpFunctions::GetBoolProperty(xMemProp, OUString::createFromAscii(SC_UNO_SHOWDETA));
+
+ aMem.maLayoutName = ScUnoHelpFunctions::GetStringProperty(
+ xMemProp, OUString::createFromAscii(SC_UNO_LAYOUTNAME), OUString());
+ }
+
+ aMembers.push_back(aMem);
+ }
+ rMembers.swap(aMembers);
+ return true;
+}
+
+void ScDPObject::UpdateReference( UpdateRefMode eUpdateRefMode,
+ const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ // Output area
+
+ SCCOL nCol1 = aOutRange.aStart.Col();
+ SCROW nRow1 = aOutRange.aStart.Row();
+ SCTAB nTab1 = aOutRange.aStart.Tab();
+ SCCOL nCol2 = aOutRange.aEnd.Col();
+ SCROW nRow2 = aOutRange.aEnd.Row();
+ SCTAB nTab2 = aOutRange.aEnd.Tab();
+
+ ScRefUpdateRes eRes =
+ ScRefUpdate::Update( pDoc, eUpdateRefMode,
+ rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
+ rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz,
+ nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ if ( eRes != UR_NOTHING )
+ SetOutRange( ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ) );
+
+ // sheet source data
+
+ if ( pSheetDesc )
+ {
+ nCol1 = pSheetDesc->aSourceRange.aStart.Col();
+ nRow1 = pSheetDesc->aSourceRange.aStart.Row();
+ nTab1 = pSheetDesc->aSourceRange.aStart.Tab();
+ nCol2 = pSheetDesc->aSourceRange.aEnd.Col();
+ nRow2 = pSheetDesc->aSourceRange.aEnd.Row();
+ nTab2 = pSheetDesc->aSourceRange.aEnd.Tab();
+
+ eRes = ScRefUpdate::Update( pDoc, eUpdateRefMode,
+ rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
+ rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz,
+ nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ if ( eRes != UR_NOTHING )
+ {
+ ScSheetSourceDesc aNewDesc;
+ aNewDesc.aSourceRange = ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+
+ SCsCOL nDiffX = nCol1 - (SCsCOL) pSheetDesc->aSourceRange.aStart.Col();
+ SCsROW nDiffY = nRow1 - (SCsROW) pSheetDesc->aSourceRange.aStart.Row();
+
+ aNewDesc.aQueryParam = pSheetDesc->aQueryParam;
+ aNewDesc.aQueryParam.nCol1 = sal::static_int_cast<SCCOL>( aNewDesc.aQueryParam.nCol1 + nDiffX );
+ aNewDesc.aQueryParam.nCol2 = sal::static_int_cast<SCCOL>( aNewDesc.aQueryParam.nCol2 + nDiffX );
+ aNewDesc.aQueryParam.nRow1 += nDiffY; //! used?
+ aNewDesc.aQueryParam.nRow2 += nDiffY; //! used?
+ SCSIZE nEC = aNewDesc.aQueryParam.GetEntryCount();
+ for (SCSIZE i=0; i<nEC; i++)
+ if (aNewDesc.aQueryParam.GetEntry(i).bDoQuery)
+ aNewDesc.aQueryParam.GetEntry(i).nField += nDiffX;
+
+ SetSheetDesc( aNewDesc ); // allocates new pSheetDesc
+ }
+ }
+}
+
+BOOL ScDPObject::RefsEqual( const ScDPObject& r ) const
+{
+ if ( aOutRange != r.aOutRange )
+ return FALSE;
+
+ if ( pSheetDesc && r.pSheetDesc )
+ {
+ if ( pSheetDesc->aSourceRange != r.pSheetDesc->aSourceRange )
+ return FALSE;
+ }
+ else if ( pSheetDesc || r.pSheetDesc )
+ {
+ DBG_ERROR("RefsEqual: SheetDesc set at only one object");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void ScDPObject::WriteRefsTo( ScDPObject& r ) const
+{
+ r.SetOutRange( aOutRange );
+ if ( pSheetDesc )
+ r.SetSheetDesc( *pSheetDesc );
+}
+
+void ScDPObject::GetPositionData(const ScAddress& rPos, DataPilotTablePositionData& rPosData)
+{
+ CreateOutput();
+ pOutput->GetPositionData(rPos, rPosData);
+}
+
+bool ScDPObject::GetDataFieldPositionData(
+ const ScAddress& rPos, Sequence<sheet::DataPilotFieldFilter>& rFilters)
+{
+ CreateOutput();
+
+ vector<sheet::DataPilotFieldFilter> aFilters;
+ if (!pOutput->GetDataResultPositionData(aFilters, rPos))
+ return false;
+
+ sal_Int32 n = static_cast<sal_Int32>(aFilters.size());
+ rFilters.realloc(n);
+ for (sal_Int32 i = 0; i < n; ++i)
+ rFilters[i] = aFilters[i];
+
+ return true;
+}
+
+void ScDPObject::GetDrillDownData(const ScAddress& rPos, Sequence< Sequence<Any> >& rTableData)
+{
+ CreateOutput();
+
+ Reference<sheet::XDrillDownDataSupplier> xDrillDownData(xSource, UNO_QUERY);
+ if (!xDrillDownData.is())
+ return;
+
+ Sequence<sheet::DataPilotFieldFilter> filters;
+ if (!GetDataFieldPositionData(rPos, filters))
+ return;
+
+ rTableData = xDrillDownData->getDrillDownData(filters);
+}
+
+bool ScDPObject::IsDimNameInUse(const OUString& rName) const
+{
+ if (!xSource.is())
+ return false;
+
+ Reference<container::XNameAccess> xDims = xSource->getDimensions();
+ Sequence<OUString> aDimNames = xDims->getElementNames();
+ sal_Int32 n = aDimNames.getLength();
+ for (sal_Int32 i = 0; i < n; ++i)
+ {
+ const OUString& rDimName = aDimNames[i];
+ if (rDimName.equalsIgnoreAsciiCase(rName))
+ return true;
+
+ Reference<beans::XPropertySet> xPropSet(xDims->getByName(rDimName), UNO_QUERY);
+ if (!xPropSet.is())
+ continue;
+
+ Any any = xPropSet->getPropertyValue(OUString::createFromAscii(SC_UNO_LAYOUTNAME));
+ OUString aLayoutName;
+ if (any >>= aLayoutName)
+ {
+ if (aLayoutName.equalsIgnoreAsciiCase(rName))
+ return true;
+ }
+ }
+ return false;
+}
+
+String ScDPObject::GetDimName( long nDim, BOOL& rIsDataLayout )
+{
+ rIsDataLayout = FALSE;
+ String aRet;
+
+ if ( xSource.is() )
+ {
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
+ long nDimCount = xDims->getCount();
+ if ( nDim < nDimCount )
+ {
+ uno::Reference<uno::XInterface> xIntDim =
+ ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
+ uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
+ uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
+ if ( xDimName.is() && xDimProp.is() )
+ {
+ BOOL bData = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
+ //! error checking -- is "IsDataLayoutDimension" property required??
+
+ rtl::OUString aName;
+ try
+ {
+ aName = xDimName->getName();
+ }
+ catch(uno::Exception&)
+ {
+ }
+ if ( bData )
+ rIsDataLayout = TRUE;
+ else
+ aRet = String( aName );
+ }
+ }
+ }
+
+ return aRet;
+}
+
+BOOL ScDPObject::IsDuplicated( long nDim )
+{
+ BOOL bDuplicated = FALSE;
+ if ( xSource.is() )
+ {
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
+ long nDimCount = xDims->getCount();
+ if ( nDim < nDimCount )
+ {
+ uno::Reference<uno::XInterface> xIntDim =
+ ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
+ uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
+ if ( xDimProp.is() )
+ {
+ try
+ {
+ uno::Any aOrigAny = xDimProp->getPropertyValue(
+ rtl::OUString::createFromAscii(DP_PROP_ORIGINAL) );
+ uno::Reference<uno::XInterface> xIntOrig;
+ if ( (aOrigAny >>= xIntOrig) && xIntOrig.is() )
+ bDuplicated = TRUE;
+ }
+ catch(uno::Exception&)
+ {
+ }
+ }
+ }
+ }
+ return bDuplicated;
+}
+
+long ScDPObject::GetDimCount()
+{
+ long nRet = 0;
+ if ( xSource.is() )
+ {
+ try
+ {
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ if ( xDimsName.is() )
+ nRet = xDimsName->getElementNames().getLength();
+ }
+ catch(uno::Exception&)
+ {
+ }
+ }
+ return nRet;
+}
+
+void ScDPObject::FillPageList( TypedScStrCollection& rStrings, long nField )
+{
+ //! merge members access with ToggleDetails?
+
+ //! convert field index to dimension index?
+
+ DBG_ASSERT( xSource.is(), "no source" );
+ if ( !xSource.is() ) return;
+
+ uno::Reference<container::XNamed> xDim;
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
+ long nIntCount = xIntDims->getCount();
+ if ( nField < nIntCount )
+ {
+ uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface(
+ xIntDims->getByIndex(nField) );
+ xDim = uno::Reference<container::XNamed>( xIntDim, uno::UNO_QUERY );
+ }
+ DBG_ASSERT( xDim.is(), "dimension not found" );
+ if ( !xDim.is() ) return;
+
+ uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
+ long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
+ long nLevel = 0;
+
+ long nHierCount = 0;
+ uno::Reference<container::XIndexAccess> xHiers;
+ uno::Reference<sheet::XHierarchiesSupplier> xHierSupp( xDim, uno::UNO_QUERY );
+ if ( xHierSupp.is() )
+ {
+ uno::Reference<container::XNameAccess> xHiersName = xHierSupp->getHierarchies();
+ xHiers = new ScNameToIndexAccess( xHiersName );
+ nHierCount = xHiers->getCount();
+ }
+ uno::Reference<uno::XInterface> xHier;
+ if ( nHierarchy < nHierCount )
+ xHier = ScUnoHelpFunctions::AnyToInterface( xHiers->getByIndex(nHierarchy) );
+ DBG_ASSERT( xHier.is(), "hierarchy not found" );
+ if ( !xHier.is() ) return;
+
+ long nLevCount = 0;
+ uno::Reference<container::XIndexAccess> xLevels;
+ uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHier, uno::UNO_QUERY );
+ if ( xLevSupp.is() )
+ {
+ uno::Reference<container::XNameAccess> xLevsName = xLevSupp->getLevels();
+ xLevels = new ScNameToIndexAccess( xLevsName );
+ nLevCount = xLevels->getCount();
+ }
+ uno::Reference<uno::XInterface> xLevel;
+ if ( nLevel < nLevCount )
+ xLevel = ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex(nLevel) );
+ DBG_ASSERT( xLevel.is(), "level not found" );
+ if ( !xLevel.is() ) return;
+
+ uno::Reference<container::XNameAccess> xMembers;
+ uno::Reference<sheet::XMembersSupplier> xMbrSupp( xLevel, uno::UNO_QUERY );
+ if ( xMbrSupp.is() )
+ xMembers = xMbrSupp->getMembers();
+ DBG_ASSERT( xMembers.is(), "members not found" );
+ if ( !xMembers.is() ) return;
+
+ uno::Sequence<rtl::OUString> aNames = xMembers->getElementNames();
+ long nNameCount = aNames.getLength();
+ const rtl::OUString* pNameArr = aNames.getConstArray();
+ for (long nPos = 0; nPos < nNameCount; ++nPos)
+ {
+ // Make sure to insert only visible members.
+ Reference<XPropertySet> xPropSet(xMembers->getByName(pNameArr[nPos]), UNO_QUERY);
+ sal_Bool bVisible = false;
+ if (xPropSet.is())
+ {
+ Any any = xPropSet->getPropertyValue(OUString::createFromAscii(SC_UNO_ISVISIBL));
+ any >>= bVisible;
+ }
+
+ if (bVisible)
+ {
+ // use the order from getElementNames
+ TypedStrData* pData = new TypedStrData( pNameArr[nPos] );
+ if ( !rStrings.AtInsert( rStrings.GetCount(), pData ) )
+ delete pData;
+ }
+ }
+
+ // add "-all-" entry to the top (unsorted)
+ TypedStrData* pAllData = new TypedStrData( String( ScResId( SCSTR_ALL ) ) ); //! separate string? (also output)
+ if ( !rStrings.AtInsert( 0, pAllData ) )
+ delete pAllData;
+}
+
+void ScDPObject::GetHeaderPositionData(const ScAddress& rPos, DataPilotTableHeaderData& rData)
+{
+ using namespace ::com::sun::star::sheet::DataPilotTablePositionType;
+
+ CreateOutput(); // create xSource and pOutput if not already done
+
+ // Reset member values to invalid state.
+ rData.Dimension = rData.Hierarchy = rData.Level = -1;
+ rData.Flags = 0;
+
+ DataPilotTablePositionData aPosData;
+ pOutput->GetPositionData(rPos, aPosData);
+ const sal_Int32 nPosType = aPosData.PositionType;
+ if (nPosType == COLUMN_HEADER || nPosType == ROW_HEADER)
+ aPosData.PositionData >>= rData;
+}
+
+// Returns TRUE on success and stores the result in rTarget
+BOOL ScDPObject::GetPivotData( ScDPGetPivotDataField& rTarget,
+ const std::vector< ScDPGetPivotDataField >& rFilters )
+{
+ CreateOutput(); // create xSource and pOutput if not already done
+
+ return pOutput->GetPivotData( rTarget, rFilters );
+}
+
+BOOL ScDPObject::IsFilterButton( const ScAddress& rPos )
+{
+ CreateOutput(); // create xSource and pOutput if not already done
+
+ return pOutput->IsFilterButton( rPos );
+}
+
+long ScDPObject::GetHeaderDim( const ScAddress& rPos, USHORT& rOrient )
+{
+ CreateOutput(); // create xSource and pOutput if not already done
+
+ return pOutput->GetHeaderDim( rPos, rOrient );
+}
+
+BOOL ScDPObject::GetHeaderDrag( const ScAddress& rPos, BOOL bMouseLeft, BOOL bMouseTop, long nDragDim,
+ Rectangle& rPosRect, USHORT& rOrient, long& rDimPos )
+{
+ CreateOutput(); // create xSource and pOutput if not already done
+
+ return pOutput->GetHeaderDrag( rPos, bMouseLeft, bMouseTop, nDragDim, rPosRect, rOrient, rDimPos );
+}
+
+void ScDPObject::GetMemberResultNames( ScStrCollection& rNames, long nDimension )
+{
+ CreateOutput(); // create xSource and pOutput if not already done
+
+ pOutput->GetMemberResultNames( rNames, nDimension ); // used only with table data -> level not needed
+}
+
+bool lcl_Dequote( const String& rSource, xub_StrLen nStartPos, xub_StrLen& rEndPos, String& rResult )
+{
+ // nStartPos has to point to opening quote
+
+ bool bRet = false;
+ const sal_Unicode cQuote = '\'';
+
+ if ( rSource.GetChar(nStartPos) == cQuote )
+ {
+ rtl::OUStringBuffer aBuffer;
+ xub_StrLen nPos = nStartPos + 1;
+ const xub_StrLen nLen = rSource.Len();
+
+ while ( nPos < nLen )
+ {
+ const sal_Unicode cNext = rSource.GetChar(nPos);
+ if ( cNext == cQuote )
+ {
+ if ( nPos+1 < nLen && rSource.GetChar(nPos+1) == cQuote )
+ {
+ // double quote is used for an embedded quote
+ aBuffer.append( cNext ); // append one quote
+ ++nPos; // skip the next one
+ }
+ else
+ {
+ // end of quoted string
+ rResult = aBuffer.makeStringAndClear();
+ rEndPos = nPos + 1; // behind closing quote
+ return true;
+ }
+ }
+ else
+ aBuffer.append( cNext );
+
+ ++nPos;
+ }
+ // no closing quote before the end of the string -> error (bRet still false)
+ }
+
+ return bRet;
+}
+
+struct ScGetPivotDataFunctionEntry
+{
+ const sal_Char* pName;
+ sheet::GeneralFunction eFunc;
+};
+
+bool lcl_ParseFunction( const String& rList, xub_StrLen nStartPos, xub_StrLen& rEndPos, sheet::GeneralFunction& rFunc )
+{
+ static const ScGetPivotDataFunctionEntry aFunctions[] =
+ {
+ // our names
+ { "Sum", sheet::GeneralFunction_SUM },
+ { "Count", sheet::GeneralFunction_COUNT },
+ { "Average", sheet::GeneralFunction_AVERAGE },
+ { "Max", sheet::GeneralFunction_MAX },
+ { "Min", sheet::GeneralFunction_MIN },
+ { "Product", sheet::GeneralFunction_PRODUCT },
+ { "CountNums", sheet::GeneralFunction_COUNTNUMS },
+ { "StDev", sheet::GeneralFunction_STDEV },
+ { "StDevp", sheet::GeneralFunction_STDEVP },
+ { "Var", sheet::GeneralFunction_VAR },
+ { "VarP", sheet::GeneralFunction_VARP },
+ // compatibility names
+ { "Count Nums", sheet::GeneralFunction_COUNTNUMS },
+ { "StdDev", sheet::GeneralFunction_STDEV },
+ { "StdDevp", sheet::GeneralFunction_STDEVP }
+ };
+
+ const xub_StrLen nListLen = rList.Len();
+ while ( nStartPos < nListLen && rList.GetChar(nStartPos) == ' ' )
+ ++nStartPos;
+
+ bool bParsed = false;
+ bool bFound = false;
+ String aFuncStr;
+ xub_StrLen nFuncEnd = 0;
+ if ( nStartPos < nListLen && rList.GetChar(nStartPos) == '\'' )
+ bParsed = lcl_Dequote( rList, nStartPos, nFuncEnd, aFuncStr );
+ else
+ {
+ nFuncEnd = rList.Search( static_cast<sal_Unicode>(']'), nStartPos );
+ if ( nFuncEnd != STRING_NOTFOUND )
+ {
+ aFuncStr = rList.Copy( nStartPos, nFuncEnd - nStartPos );
+ bParsed = true;
+ }
+ }
+
+ if ( bParsed )
+ {
+ aFuncStr.EraseLeadingAndTrailingChars( ' ' );
+
+ const sal_Int32 nFuncCount = sizeof(aFunctions) / sizeof(aFunctions[0]);
+ for ( sal_Int32 nFunc=0; nFunc<nFuncCount && !bFound; nFunc++ )
+ {
+ if ( aFuncStr.EqualsIgnoreCaseAscii( aFunctions[nFunc].pName ) )
+ {
+ rFunc = aFunctions[nFunc].eFunc;
+ bFound = true;
+
+ while ( nFuncEnd < nListLen && rList.GetChar(nFuncEnd) == ' ' )
+ ++nFuncEnd;
+ rEndPos = nFuncEnd;
+ }
+ }
+ }
+
+ return bFound;
+}
+
+bool lcl_IsAtStart( const String& rList, const String& rSearch, sal_Int32& rMatched,
+ bool bAllowBracket, sheet::GeneralFunction* pFunc )
+{
+ sal_Int32 nMatchList = 0;
+ sal_Int32 nMatchSearch = 0;
+ sal_Unicode cFirst = rList.GetChar(0);
+ if ( cFirst == '\'' || cFirst == '[' )
+ {
+ // quoted string or string in brackets must match completely
+
+ String aDequoted;
+ xub_StrLen nQuoteEnd = 0;
+ bool bParsed = false;
+
+ if ( cFirst == '\'' )
+ bParsed = lcl_Dequote( rList, 0, nQuoteEnd, aDequoted );
+ else if ( cFirst == '[' )
+ {
+ // skip spaces after the opening bracket
+
+ xub_StrLen nStartPos = 1;
+ const xub_StrLen nListLen = rList.Len();
+ while ( nStartPos < nListLen && rList.GetChar(nStartPos) == ' ' )
+ ++nStartPos;
+
+ if ( rList.GetChar(nStartPos) == '\'' ) // quoted within the brackets?
+ {
+ if ( lcl_Dequote( rList, nStartPos, nQuoteEnd, aDequoted ) )
+ {
+ // after the quoted string, there must be the closing bracket, optionally preceded by spaces,
+ // and/or a function name
+ while ( nQuoteEnd < nListLen && rList.GetChar(nQuoteEnd) == ' ' )
+ ++nQuoteEnd;
+
+ // semicolon separates function name
+ if ( nQuoteEnd < nListLen && rList.GetChar(nQuoteEnd) == ';' && pFunc )
+ {
+ xub_StrLen nFuncEnd = 0;
+ if ( lcl_ParseFunction( rList, nQuoteEnd + 1, nFuncEnd, *pFunc ) )
+ nQuoteEnd = nFuncEnd;
+ }
+ if ( nQuoteEnd < nListLen && rList.GetChar(nQuoteEnd) == ']' )
+ {
+ ++nQuoteEnd; // include the closing bracket for the matched length
+ bParsed = true;
+ }
+ }
+ }
+ else
+ {
+ // implicit quoting to the closing bracket
+
+ xub_StrLen nClosePos = rList.Search( static_cast<sal_Unicode>(']'), nStartPos );
+ if ( nClosePos != STRING_NOTFOUND )
+ {
+ xub_StrLen nNameEnd = nClosePos;
+ xub_StrLen nSemiPos = rList.Search( static_cast<sal_Unicode>(';'), nStartPos );
+ if ( nSemiPos != STRING_NOTFOUND && nSemiPos < nClosePos && pFunc )
+ {
+ xub_StrLen nFuncEnd = 0;
+ if ( lcl_ParseFunction( rList, nSemiPos + 1, nFuncEnd, *pFunc ) )
+ nNameEnd = nSemiPos;
+ }
+
+ aDequoted = rList.Copy( nStartPos, nNameEnd - nStartPos );
+ aDequoted.EraseTrailingChars( ' ' ); // spaces before the closing bracket or semicolon
+ nQuoteEnd = nClosePos + 1;
+ bParsed = true;
+ }
+ }
+ }
+
+ if ( bParsed && ScGlobal::GetpTransliteration()->isEqual( aDequoted, rSearch ) )
+ {
+ nMatchList = nQuoteEnd; // match count in the list string, including quotes
+ nMatchSearch = rSearch.Len();
+ }
+ }
+ else
+ {
+ // otherwise look for search string at the start of rList
+ ScGlobal::GetpTransliteration()->equals( rList, 0, rList.Len(), nMatchList,
+ rSearch, 0, rSearch.Len(), nMatchSearch );
+ }
+
+ if ( nMatchSearch == rSearch.Len() )
+ {
+ // search string is at start of rList - look for following space or end of string
+
+ bool bValid = false;
+ if ( sal::static_int_cast<xub_StrLen>(nMatchList) >= rList.Len() )
+ bValid = true;
+ else
+ {
+ sal_Unicode cNext = rList.GetChar(sal::static_int_cast<xub_StrLen>(nMatchList));
+ if ( cNext == ' ' || ( bAllowBracket && cNext == '[' ) )
+ bValid = true;
+ }
+
+ if ( bValid )
+ {
+ rMatched = nMatchList;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+BOOL ScDPObject::ParseFilters( ScDPGetPivotDataField& rTarget,
+ std::vector< ScDPGetPivotDataField >& rFilters,
+ const String& rFilterList )
+{
+ // parse the string rFilterList into parameters for GetPivotData
+
+ CreateObjects(); // create xSource if not already done
+
+ std::vector<String> aDataNames; // data fields (source name)
+ std::vector<String> aGivenNames; // data fields (compound name)
+ std::vector<String> aFieldNames; // column/row/data fields
+ std::vector< uno::Sequence<rtl::OUString> > aFieldValues;
+
+ //
+ // get all the field and item names
+ //
+
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
+ sal_Int32 nDimCount = xIntDims->getCount();
+ for ( sal_Int32 nDim = 0; nDim<nDimCount; nDim++ )
+ {
+ uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nDim) );
+ uno::Reference<container::XNamed> xDim( xIntDim, uno::UNO_QUERY );
+ uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
+ uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDim, uno::UNO_QUERY );
+ BOOL bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
+ sal_Int32 nOrient = ScUnoHelpFunctions::GetEnumProperty(
+ xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION),
+ sheet::DataPilotFieldOrientation_HIDDEN );
+ if ( !bDataLayout )
+ {
+ if ( nOrient == sheet::DataPilotFieldOrientation_DATA )
+ {
+ String aSourceName;
+ String aGivenName;
+ ScDPOutput::GetDataDimensionNames( aSourceName, aGivenName, xIntDim );
+ aDataNames.push_back( aSourceName );
+ aGivenNames.push_back( aGivenName );
+ }
+ else if ( nOrient != sheet::DataPilotFieldOrientation_HIDDEN )
+ {
+ // get level names, as in ScDPOutput
+
+ uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
+ sal_Int32 nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
+ if ( nHierarchy >= xHiers->getCount() )
+ nHierarchy = 0;
+
+ uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
+ xHiers->getByIndex(nHierarchy) );
+ uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
+ if ( xHierSupp.is() )
+ {
+ uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
+ sal_Int32 nLevCount = xLevels->getCount();
+ for (sal_Int32 nLev=0; nLev<nLevCount; nLev++)
+ {
+ uno::Reference<uno::XInterface> xLevel = ScUnoHelpFunctions::AnyToInterface(
+ xLevels->getByIndex(nLev) );
+ uno::Reference<container::XNamed> xLevNam( xLevel, uno::UNO_QUERY );
+ uno::Reference<sheet::XMembersSupplier> xLevSupp( xLevel, uno::UNO_QUERY );
+ if ( xLevNam.is() && xLevSupp.is() )
+ {
+ uno::Reference<container::XNameAccess> xMembers = xLevSupp->getMembers();
+
+ String aFieldName( xLevNam->getName() );
+ uno::Sequence<rtl::OUString> aMemberNames( xMembers->getElementNames() );
+
+ aFieldNames.push_back( aFieldName );
+ aFieldValues.push_back( aMemberNames );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // compare and build filters
+ //
+
+ SCSIZE nDataFields = aDataNames.size();
+ SCSIZE nFieldCount = aFieldNames.size();
+ DBG_ASSERT( aGivenNames.size() == nDataFields && aFieldValues.size() == nFieldCount, "wrong count" );
+
+ bool bError = false;
+ bool bHasData = false;
+ String aRemaining( rFilterList );
+ aRemaining.EraseLeadingAndTrailingChars( ' ' );
+ while ( aRemaining.Len() && !bError )
+ {
+ bool bUsed = false;
+
+ // look for data field name
+
+ for ( SCSIZE nDataPos=0; nDataPos<nDataFields && !bUsed; nDataPos++ )
+ {
+ String aFound;
+ sal_Int32 nMatched = 0;
+ if ( lcl_IsAtStart( aRemaining, aDataNames[nDataPos], nMatched, false, NULL ) )
+ aFound = aDataNames[nDataPos];
+ else if ( lcl_IsAtStart( aRemaining, aGivenNames[nDataPos], nMatched, false, NULL ) )
+ aFound = aGivenNames[nDataPos];
+
+ if ( aFound.Len() )
+ {
+ rTarget.maFieldName = aFound;
+ aRemaining.Erase( 0, sal::static_int_cast<xub_StrLen>(nMatched) );
+ bHasData = true;
+ bUsed = true;
+ }
+ }
+
+ // look for field name
+
+ String aSpecField;
+ bool bHasFieldName = false;
+ if ( !bUsed )
+ {
+ sal_Int32 nMatched = 0;
+ for ( SCSIZE nField=0; nField<nFieldCount && !bHasFieldName; nField++ )
+ {
+ if ( lcl_IsAtStart( aRemaining, aFieldNames[nField], nMatched, true, NULL ) )
+ {
+ aSpecField = aFieldNames[nField];
+ aRemaining.Erase( 0, sal::static_int_cast<xub_StrLen>(nMatched) );
+ aRemaining.EraseLeadingChars( ' ' );
+
+ // field name has to be followed by item name in brackets
+ if ( aRemaining.GetChar(0) == '[' )
+ {
+ bHasFieldName = true;
+ // bUsed remains false - still need the item
+ }
+ else
+ {
+ bUsed = true;
+ bError = true;
+ }
+ }
+ }
+ }
+
+ // look for field item
+
+ if ( !bUsed )
+ {
+ bool bItemFound = false;
+ sal_Int32 nMatched = 0;
+ String aFoundName;
+ String aFoundValue;
+ sheet::GeneralFunction eFunc = sheet::GeneralFunction_NONE;
+ sheet::GeneralFunction eFoundFunc = sheet::GeneralFunction_NONE;
+
+ for ( SCSIZE nField=0; nField<nFieldCount; nField++ )
+ {
+ // If a field name is given, look in that field only, otherwise in all fields.
+ // aSpecField is initialized from aFieldNames array, so exact comparison can be used.
+ if ( !bHasFieldName || aFieldNames[nField] == aSpecField )
+ {
+ const uno::Sequence<rtl::OUString>& rItems = aFieldValues[nField];
+ sal_Int32 nItemCount = rItems.getLength();
+ const rtl::OUString* pItemArr = rItems.getConstArray();
+ for ( sal_Int32 nItem=0; nItem<nItemCount; nItem++ )
+ {
+ if ( lcl_IsAtStart( aRemaining, pItemArr[nItem], nMatched, false, &eFunc ) )
+ {
+ if ( bItemFound )
+ bError = true; // duplicate (also across fields)
+ else
+ {
+ aFoundName = aFieldNames[nField];
+ aFoundValue = pItemArr[nItem];
+ eFoundFunc = eFunc;
+ bItemFound = true;
+ bUsed = true;
+ }
+ }
+ }
+ }
+ }
+
+ if ( bItemFound && !bError )
+ {
+ ScDPGetPivotDataField aField;
+ aField.maFieldName = aFoundName;
+ aField.meFunction = eFoundFunc;
+ aField.mbValIsStr = true;
+ aField.maValStr = aFoundValue;
+ aField.mnValNum = 0.0;
+ rFilters.push_back( aField );
+
+ aRemaining.Erase( 0, sal::static_int_cast<xub_StrLen>(nMatched) );
+ }
+ }
+
+ if ( !bUsed )
+ bError = true;
+
+ aRemaining.EraseLeadingChars( ' ' ); // remove any number of spaces between entries
+ }
+
+ if ( !bError && !bHasData && aDataNames.size() == 1 )
+ {
+ // if there's only one data field, its name need not be specified
+ rTarget.maFieldName = aDataNames[0];
+ bHasData = true;
+ }
+
+ return bHasData && !bError;
+}
+
+void ScDPObject::ToggleDetails(const DataPilotTableHeaderData& rElemDesc, ScDPObject* pDestObj)
+{
+ CreateObjects(); // create xSource if not already done
+
+ // find dimension name
+
+ uno::Reference<container::XNamed> xDim;
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
+ long nIntCount = xIntDims->getCount();
+ if ( rElemDesc.Dimension < nIntCount )
+ {
+ uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface(
+ xIntDims->getByIndex(rElemDesc.Dimension) );
+ xDim = uno::Reference<container::XNamed>( xIntDim, uno::UNO_QUERY );
+ }
+ DBG_ASSERT( xDim.is(), "dimension not found" );
+ if ( !xDim.is() ) return;
+ String aDimName = xDim->getName();
+
+ uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
+ BOOL bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
+ if (bDataLayout)
+ {
+ // the elements of the data layout dimension can't be found by their names
+ // -> don't change anything
+ return;
+ }
+
+ // query old state
+
+ long nHierCount = 0;
+ uno::Reference<container::XIndexAccess> xHiers;
+ uno::Reference<sheet::XHierarchiesSupplier> xHierSupp( xDim, uno::UNO_QUERY );
+ if ( xHierSupp.is() )
+ {
+ uno::Reference<container::XNameAccess> xHiersName = xHierSupp->getHierarchies();
+ xHiers = new ScNameToIndexAccess( xHiersName );
+ nHierCount = xHiers->getCount();
+ }
+ uno::Reference<uno::XInterface> xHier;
+ if ( rElemDesc.Hierarchy < nHierCount )
+ xHier = ScUnoHelpFunctions::AnyToInterface( xHiers->getByIndex(rElemDesc.Hierarchy) );
+ DBG_ASSERT( xHier.is(), "hierarchy not found" );
+ if ( !xHier.is() ) return;
+
+ long nLevCount = 0;
+ uno::Reference<container::XIndexAccess> xLevels;
+ uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHier, uno::UNO_QUERY );
+ if ( xLevSupp.is() )
+ {
+ uno::Reference<container::XNameAccess> xLevsName = xLevSupp->getLevels();
+ xLevels = new ScNameToIndexAccess( xLevsName );
+ nLevCount = xLevels->getCount();
+ }
+ uno::Reference<uno::XInterface> xLevel;
+ if ( rElemDesc.Level < nLevCount )
+ xLevel = ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex(rElemDesc.Level) );
+ DBG_ASSERT( xLevel.is(), "level not found" );
+ if ( !xLevel.is() ) return;
+
+ uno::Reference<container::XNameAccess> xMembers;
+ uno::Reference<sheet::XMembersSupplier> xMbrSupp( xLevel, uno::UNO_QUERY );
+ if ( xMbrSupp.is() )
+ xMembers = xMbrSupp->getMembers();
+
+ BOOL bFound = FALSE;
+ BOOL bShowDetails = TRUE;
+
+ if ( xMembers.is() )
+ {
+ if ( xMembers->hasByName(rElemDesc.MemberName) )
+ {
+ uno::Reference<uno::XInterface> xMemberInt = ScUnoHelpFunctions::AnyToInterface(
+ xMembers->getByName(rElemDesc.MemberName) );
+ uno::Reference<beans::XPropertySet> xMbrProp( xMemberInt, uno::UNO_QUERY );
+ if ( xMbrProp.is() )
+ {
+ bShowDetails = ScUnoHelpFunctions::GetBoolProperty( xMbrProp,
+ rtl::OUString::createFromAscii(DP_PROP_SHOWDETAILS) );
+ //! don't set bFound if property is unknown?
+ bFound = TRUE;
+ }
+ }
+ }
+
+ DBG_ASSERT( bFound, "member not found" );
+
+ //! use Hierarchy and Level in SaveData !!!!
+
+ // modify pDestObj if set, this object otherwise
+ ScDPSaveData* pModifyData = pDestObj ? ( pDestObj->pSaveData ) : pSaveData;
+ DBG_ASSERT( pModifyData, "no data?" );
+ if ( pModifyData )
+ {
+ const String aName = rElemDesc.MemberName;
+ pModifyData->GetDimensionByName(aDimName)->
+ GetMemberByName(aName)->SetShowDetails( !bShowDetails ); // toggle
+
+ if ( pDestObj )
+ pDestObj->InvalidateData(); // re-init source from SaveData
+ else
+ InvalidateData(); // re-init source from SaveData
+ }
+}
+
+long lcl_FindName( const rtl::OUString& rString, const uno::Reference<container::XNameAccess>& xCollection )
+{
+ if ( xCollection.is() )
+ {
+ uno::Sequence<rtl::OUString> aSeq = xCollection->getElementNames();
+ long nCount = aSeq.getLength();
+ const rtl::OUString* pArr = aSeq.getConstArray();
+ for (long nPos=0; nPos<nCount; nPos++)
+ if ( pArr[nPos] == rString )
+ return nPos;
+ }
+ return -1; // not found
+}
+
+USHORT lcl_FirstSubTotal( const uno::Reference<beans::XPropertySet>& xDimProp ) // PIVOT_FUNC mask
+{
+ uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDimProp, uno::UNO_QUERY );
+ if ( xDimProp.is() && xDimSupp.is() )
+ {
+ uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
+ long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
+ if ( nHierarchy >= xHiers->getCount() )
+ nHierarchy = 0;
+
+ uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
+ xHiers->getByIndex(nHierarchy) );
+ uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
+ if ( xHierSupp.is() )
+ {
+ uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
+ uno::Reference<uno::XInterface> xLevel =
+ ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex( 0 ) );
+ uno::Reference<beans::XPropertySet> xLevProp( xLevel, uno::UNO_QUERY );
+ if ( xLevProp.is() )
+ {
+ uno::Any aSubAny;
+ try
+ {
+ aSubAny = xLevProp->getPropertyValue(
+ rtl::OUString::createFromAscii(DP_PROP_SUBTOTALS) );
+ }
+ catch(uno::Exception&)
+ {
+ }
+ uno::Sequence<sheet::GeneralFunction> aSeq;
+ if ( aSubAny >>= aSeq )
+ {
+ USHORT nMask = 0;
+ const sheet::GeneralFunction* pArray = aSeq.getConstArray();
+ long nCount = aSeq.getLength();
+ for (long i=0; i<nCount; i++)
+ nMask |= ScDataPilotConversion::FunctionBit(pArray[i]);
+ return nMask;
+ }
+ }
+ }
+ }
+
+ DBG_ERROR("FirstSubTotal: NULL");
+ return 0;
+}
+
+USHORT lcl_CountBits( USHORT nBits )
+{
+ if (!nBits) return 0;
+
+ USHORT nCount = 0;
+ USHORT nMask = 1;
+ for (USHORT i=0; i<16; i++)
+ {
+ if ( nBits & nMask )
+ ++nCount;
+ nMask <<= 1;
+ }
+ return nCount;
+}
+
+SCSIZE lcl_FillOldFields( PivotField* pFields,
+ const uno::Reference<sheet::XDimensionsSupplier>& xSource,
+ USHORT nOrient, SCCOL nColAdd, BOOL bAddData )
+{
+ SCSIZE nOutCount = 0;
+ BOOL bDataFound = FALSE;
+
+ SCSIZE nCount = (nOrient == sheet::DataPilotFieldOrientation_PAGE) ? PIVOT_MAXPAGEFIELD : PIVOT_MAXFIELD;
+
+ //! merge multiple occurences (data field with different functions)
+ //! force data field in one dimension
+
+ std::vector< long > aPos( nCount, 0 );
+
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
+ long nDimCount = xDims->getCount();
+ for (long nDim=0; nDim < nDimCount && nOutCount < nCount; nDim++)
+ {
+ uno::Reference<uno::XInterface> xIntDim =
+ ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
+ uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
+ long nDimOrient = ScUnoHelpFunctions::GetEnumProperty(
+ xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION),
+ sheet::DataPilotFieldOrientation_HIDDEN );
+ if ( xDimProp.is() && nDimOrient == nOrient )
+ {
+ USHORT nMask = 0;
+ if ( nOrient == sheet::DataPilotFieldOrientation_DATA )
+ {
+ sheet::GeneralFunction eFunc = (sheet::GeneralFunction)ScUnoHelpFunctions::GetEnumProperty(
+ xDimProp, rtl::OUString::createFromAscii(DP_PROP_FUNCTION),
+ sheet::GeneralFunction_NONE );
+ if ( eFunc == sheet::GeneralFunction_AUTO )
+ {
+ //! test for numeric data
+ eFunc = sheet::GeneralFunction_SUM;
+ }
+ nMask = ScDataPilotConversion::FunctionBit(eFunc);
+ }
+ else
+ nMask = lcl_FirstSubTotal( xDimProp ); // from first hierarchy
+
+ BOOL bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
+ uno::Any aOrigAny;
+ try
+ {
+ aOrigAny = xDimProp->getPropertyValue(
+ rtl::OUString::createFromAscii(DP_PROP_ORIGINAL) );
+ }
+ catch(uno::Exception&)
+ {
+ }
+
+ long nDupSource = -1;
+ uno::Reference<uno::XInterface> xIntOrig = ScUnoHelpFunctions::AnyToInterface( aOrigAny );
+ if ( xIntOrig.is() )
+ {
+ uno::Reference<container::XNamed> xNameOrig( xIntOrig, uno::UNO_QUERY );
+ if ( xNameOrig.is() )
+ nDupSource = lcl_FindName( xNameOrig->getName(), xDimsName );
+ }
+
+ BOOL bDupUsed = FALSE;
+ if ( nDupSource >= 0 )
+ {
+ // add function bit to previous entry
+
+ SCsCOL nCompCol;
+ if ( bDataLayout )
+ nCompCol = PIVOT_DATA_FIELD;
+ else
+ nCompCol = static_cast<SCsCOL>(nDupSource)+nColAdd; //! seek source column from name
+
+ for (SCSIZE nOld=0; nOld<nOutCount && !bDupUsed; nOld++)
+ if ( pFields[nOld].nCol == nCompCol )
+ {
+ // add to previous column only if new bits aren't already set there
+ if ( ( pFields[nOld].nFuncMask & nMask ) == 0 )
+ {
+ pFields[nOld].nFuncMask |= nMask;
+ pFields[nOld].nFuncCount = lcl_CountBits( pFields[nOld].nFuncMask );
+ bDupUsed = TRUE;
+ }
+ }
+ }
+
+ if ( !bDupUsed ) // also for duplicated dim if original has different orientation
+ {
+ if ( bDataLayout )
+ {
+ pFields[nOutCount].nCol = PIVOT_DATA_FIELD;
+ bDataFound = TRUE;
+ }
+ else if ( nDupSource >= 0 ) // if source was not found (different orientation)
+ pFields[nOutCount].nCol = static_cast<SCsCOL>(nDupSource)+nColAdd; //! seek from name
+ else
+ pFields[nOutCount].nCol = static_cast<SCsCOL>(nDim)+nColAdd; //! seek source column from name
+
+ pFields[nOutCount].nFuncMask = nMask;
+ pFields[nOutCount].nFuncCount = lcl_CountBits( nMask );
+ aPos[nOutCount] = ScUnoHelpFunctions::GetLongProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_POSITION) );
+
+ try
+ {
+ if( nOrient == sheet::DataPilotFieldOrientation_DATA )
+ xDimProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_REFVALUE ) ) )
+ >>= pFields[nOutCount].maFieldRef;
+ }
+ catch( uno::Exception& )
+ {
+ }
+
+ ++nOutCount;
+ }
+ }
+ }
+
+ // sort by getPosition() value
+
+ for (SCSIZE i=0; i+1<nOutCount; i++)
+ {
+ for (SCSIZE j=0; j+i+1<nOutCount; j++)
+ if ( aPos[j+1] < aPos[j] )
+ {
+ std::swap( aPos[j], aPos[j+1] );
+ std::swap( pFields[j], pFields[j+1] );
+ }
+ }
+
+ if ( bAddData && !bDataFound )
+ {
+ if ( nOutCount >= nCount ) // space for data field?
+ --nOutCount; //! error?
+ pFields[nOutCount].nCol = PIVOT_DATA_FIELD;
+ pFields[nOutCount].nFuncMask = 0;
+ pFields[nOutCount].nFuncCount = 0;
+ ++nOutCount;
+ }
+
+ return nOutCount;
+}
+
+BOOL ScDPObject::FillOldParam(ScPivotParam& rParam, BOOL bForFile) const
+{
+ ((ScDPObject*)this)->CreateObjects(); // xSource is needed for field numbers
+
+ rParam.nCol = aOutRange.aStart.Col();
+ rParam.nRow = aOutRange.aStart.Row();
+ rParam.nTab = aOutRange.aStart.Tab();
+ // ppLabelArr / nLabels is not changed
+
+ SCCOL nColAdd = 0;
+ if ( bForFile )
+ {
+ // in old file format, columns are within document, not within source range
+
+ DBG_ASSERT( pSheetDesc, "FillOldParam: bForFile, !pSheetDesc" );
+ nColAdd = pSheetDesc->aSourceRange.aStart.Col();
+ }
+
+ BOOL bAddData = ( lcl_GetDataGetOrientation( xSource ) == sheet::DataPilotFieldOrientation_HIDDEN );
+ rParam.nPageCount = lcl_FillOldFields( rParam.aPageArr,
+ xSource, sheet::DataPilotFieldOrientation_PAGE, nColAdd, FALSE );
+ rParam.nColCount = lcl_FillOldFields( rParam.aColArr,
+ xSource, sheet::DataPilotFieldOrientation_COLUMN, nColAdd, bAddData );
+ rParam.nRowCount = lcl_FillOldFields( rParam.aRowArr,
+ xSource, sheet::DataPilotFieldOrientation_ROW, nColAdd, FALSE );
+ rParam.nDataCount = lcl_FillOldFields( rParam.aDataArr,
+ xSource, sheet::DataPilotFieldOrientation_DATA, nColAdd, FALSE );
+
+ uno::Reference<beans::XPropertySet> xProp( xSource, uno::UNO_QUERY );
+ if (xProp.is())
+ {
+ try
+ {
+ rParam.bMakeTotalCol = ScUnoHelpFunctions::GetBoolProperty( xProp,
+ rtl::OUString::createFromAscii(DP_PROP_COLUMNGRAND), TRUE );
+ rParam.bMakeTotalRow = ScUnoHelpFunctions::GetBoolProperty( xProp,
+ rtl::OUString::createFromAscii(DP_PROP_ROWGRAND), TRUE );
+
+ // following properties may be missing for external sources
+ rParam.bIgnoreEmptyRows = ScUnoHelpFunctions::GetBoolProperty( xProp,
+ rtl::OUString::createFromAscii(DP_PROP_IGNOREEMPTY) );
+ rParam.bDetectCategories = ScUnoHelpFunctions::GetBoolProperty( xProp,
+ rtl::OUString::createFromAscii(DP_PROP_REPEATIFEMPTY) );
+ }
+ catch(uno::Exception&)
+ {
+ // no error
+ }
+ }
+ return TRUE;
+}
+
+void lcl_FillLabelData( ScDPLabelData& rData, const uno::Reference< beans::XPropertySet >& xDimProp )
+{
+ uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDimProp, uno::UNO_QUERY );
+ if ( xDimProp.is() && xDimSupp.is() )
+ {
+ uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
+ long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
+ if ( nHierarchy >= xHiers->getCount() )
+ nHierarchy = 0;
+ rData.mnUsedHier = nHierarchy;
+
+ uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
+ xHiers->getByIndex(nHierarchy) );
+
+ uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
+ if ( xHierSupp.is() )
+ {
+ uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
+ uno::Reference<uno::XInterface> xLevel =
+ ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex( 0 ) );
+ uno::Reference<beans::XPropertySet> xLevProp( xLevel, uno::UNO_QUERY );
+ if ( xLevProp.is() )
+ {
+ rData.mbShowAll = ScUnoHelpFunctions::GetBoolProperty( xLevProp,
+ rtl::OUString::createFromAscii(DP_PROP_SHOWEMPTY) );
+
+ try
+ {
+ xLevProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_SORTING ) ) )
+ >>= rData.maSortInfo;
+ xLevProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_LAYOUT ) ) )
+ >>= rData.maLayoutInfo;
+ xLevProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_AUTOSHOW ) ) )
+ >>= rData.maShowInfo;
+ }
+ catch(uno::Exception&)
+ {
+ }
+ }
+ }
+ }
+}
+
+BOOL ScDPObject::FillLabelData(ScPivotParam& rParam)
+{
+ rParam.maLabelArray.clear();
+
+ ((ScDPObject*)this)->CreateObjects();
+
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
+ long nDimCount = xDims->getCount();
+ if ( nDimCount > MAX_LABELS )
+ nDimCount = MAX_LABELS;
+ if (!nDimCount)
+ return FALSE;
+
+ for (long nDim=0; nDim < nDimCount; nDim++)
+ {
+ String aFieldName;
+ uno::Reference<uno::XInterface> xIntDim =
+ ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
+ uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
+ uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
+
+ if ( xDimName.is() && xDimProp.is() )
+ {
+ BOOL bDuplicated = FALSE;
+ BOOL bData = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
+ //! error checking -- is "IsDataLayoutDimension" property required??
+
+ try
+ {
+ aFieldName = String( xDimName->getName() );
+
+ uno::Any aOrigAny = xDimProp->getPropertyValue(
+ rtl::OUString::createFromAscii(DP_PROP_ORIGINAL) );
+ uno::Reference<uno::XInterface> xIntOrig;
+ if ( (aOrigAny >>= xIntOrig) && xIntOrig.is() )
+ bDuplicated = TRUE;
+ }
+ catch(uno::Exception&)
+ {
+ }
+
+ OUString aLayoutName = ScUnoHelpFunctions::GetStringProperty(
+ xDimProp, OUString::createFromAscii(SC_UNO_LAYOUTNAME), OUString());
+
+ if ( aFieldName.Len() && !bData && !bDuplicated )
+ {
+ SCsCOL nCol = static_cast< SCsCOL >( nDim ); //! ???
+ bool bIsValue = true; //! check
+
+ ScDPLabelDataRef pNewLabel(new ScDPLabelData(aFieldName, nCol, bIsValue));
+ pNewLabel->maLayoutName = aLayoutName;
+ GetHierarchies(nDim, pNewLabel->maHiers);
+ GetMembers(nDim, GetUsedHierarchy(nDim), pNewLabel->maMembers);
+ lcl_FillLabelData(*pNewLabel, xDimProp);
+ rParam.maLabelArray.push_back(pNewLabel);
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+BOOL ScDPObject::GetHierarchiesNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xHiers )
+{
+ BOOL bRet = FALSE;
+ uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
+ uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
+ if( xIntDims.is() )
+ {
+ uno::Reference<sheet::XHierarchiesSupplier> xHierSup(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
+ if (xHierSup.is())
+ {
+ xHiers.set( xHierSup->getHierarchies() );
+ bRet = xHiers.is();
+ }
+ }
+ return bRet;
+}
+
+BOOL ScDPObject::GetHierarchies( sal_Int32 nDim, uno::Sequence< rtl::OUString >& rHiers )
+{
+ BOOL bRet = FALSE;
+ uno::Reference< container::XNameAccess > xHiersNA;
+ if( GetHierarchiesNA( nDim, xHiersNA ) )
+ {
+ rHiers = xHiersNA->getElementNames();
+ bRet = TRUE;
+ }
+ return bRet;
+}
+
+sal_Int32 ScDPObject::GetUsedHierarchy( sal_Int32 nDim )
+{
+ sal_Int32 nHier = 0;
+ uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
+ uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
+ uno::Reference<beans::XPropertySet> xDim(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
+ if (xDim.is())
+ nHier = ScUnoHelpFunctions::GetLongProperty( xDim, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( SC_UNO_USEDHIER ) ) );
+ return nHier;
+}
+
+BOOL ScDPObject::GetMembersNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xMembers )
+{
+ return GetMembersNA( nDim, GetUsedHierarchy( nDim ), xMembers );
+}
+
+BOOL ScDPObject::GetMembersNA( sal_Int32 nDim, sal_Int32 nHier, uno::Reference< container::XNameAccess >& xMembers )
+{
+ BOOL bRet = FALSE;
+ uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
+ uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
+ uno::Reference<beans::XPropertySet> xDim(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
+ if (xDim.is())
+ {
+ uno::Reference<sheet::XHierarchiesSupplier> xHierSup(xDim, uno::UNO_QUERY);
+ if (xHierSup.is())
+ {
+ uno::Reference<container::XIndexAccess> xHiers(new ScNameToIndexAccess(xHierSup->getHierarchies()));
+ uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHiers->getByIndex(nHier), uno::UNO_QUERY );
+ if ( xLevSupp.is() )
+ {
+ uno::Reference<container::XIndexAccess> xLevels(new ScNameToIndexAccess( xLevSupp->getLevels()));
+ if (xLevels.is())
+ {
+ sal_Int32 nLevCount = xLevels->getCount();
+ if (nLevCount > 0)
+ {
+ uno::Reference<sheet::XMembersSupplier> xMembSupp( xLevels->getByIndex(0), uno::UNO_QUERY );
+ if ( xMembSupp.is() )
+ {
+ xMembers.set(xMembSupp->getMembers());
+ bRet = TRUE;
+ }
+ }
+ }
+ }
+ }
+ }
+ return bRet;
+}
+
+//------------------------------------------------------------------------
+// convert old pivot tables into new datapilot tables
+
+String lcl_GetDimName( const uno::Reference<sheet::XDimensionsSupplier>& xSource, long nDim )
+{
+ rtl::OUString aName;
+ if ( xSource.is() )
+ {
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
+ long nDimCount = xDims->getCount();
+ if ( nDim < nDimCount )
+ {
+ uno::Reference<uno::XInterface> xIntDim =
+ ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
+ uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
+ if (xDimName.is())
+ {
+ try
+ {
+ aName = xDimName->getName();
+ }
+ catch(uno::Exception&)
+ {
+ }
+ }
+ }
+ }
+ return aName;
+}
+
+// static
+void ScDPObject::ConvertOrientation( ScDPSaveData& rSaveData,
+ PivotField* pFields, SCSIZE nCount, USHORT nOrient,
+ ScDocument* pDoc, SCROW nRow, SCTAB nTab,
+ const uno::Reference<sheet::XDimensionsSupplier>& xSource,
+ BOOL bOldDefaults,
+ PivotField* pRefColFields, SCSIZE nRefColCount,
+ PivotField* pRefRowFields, SCSIZE nRefRowCount,
+ PivotField* pRefPageFields, SCSIZE nRefPageCount )
+{
+ // pDoc or xSource must be set
+ DBG_ASSERT( pDoc || xSource.is(), "missing string source" );
+
+ String aDocStr;
+ ScDPSaveDimension* pDim;
+
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ SCCOL nCol = pFields[i].nCol;
+ USHORT nFuncs = pFields[i].nFuncMask;
+ const sheet::DataPilotFieldReference& rFieldRef = pFields[i].maFieldRef;
+
+ if ( nCol == PIVOT_DATA_FIELD )
+ pDim = rSaveData.GetDataLayoutDimension();
+ else
+ {
+ if ( pDoc )
+ pDoc->GetString( nCol, nRow, nTab, aDocStr );
+ else
+ aDocStr = lcl_GetDimName( xSource, nCol ); // cols must start at 0
+
+ if ( aDocStr.Len() )
+ pDim = rSaveData.GetDimensionByName(aDocStr);
+ else
+ pDim = NULL;
+ }
+
+ if ( pDim )
+ {
+ if ( nOrient == sheet::DataPilotFieldOrientation_DATA ) // set summary function
+ {
+ // generate an individual entry for each function
+ BOOL bFirst = TRUE;
+
+ // if a dimension is used for column/row/page and data,
+ // use duplicated dimensions for all data occurrences
+ if (pRefColFields)
+ for (SCSIZE nRefCol=0; nRefCol<nRefColCount; nRefCol++)
+ if (pRefColFields[nRefCol].nCol == nCol)
+ bFirst = FALSE;
+ if (pRefRowFields)
+ for (SCSIZE nRefRow=0; nRefRow<nRefRowCount; nRefRow++)
+ if (pRefRowFields[nRefRow].nCol == nCol)
+ bFirst = FALSE;
+ if (pRefPageFields)
+ for (USHORT nRefPage=0; nRefPage<nRefPageCount; ++nRefPage)
+ if (pRefPageFields[nRefPage].nCol == nCol)
+ bFirst = FALSE;
+
+ // if set via api, a data column may occur several times
+ // (if the function hasn't been changed yet) -> also look for duplicate data column
+ for (SCSIZE nPrevData=0; nPrevData<i; nPrevData++)
+ if (pFields[nPrevData].nCol == nCol)
+ bFirst = FALSE;
+
+ USHORT nMask = 1;
+ for (USHORT nBit=0; nBit<16; nBit++)
+ {
+ if ( nFuncs & nMask )
+ {
+ sheet::GeneralFunction eFunc = ScDataPilotConversion::FirstFunc( nMask );
+ ScDPSaveDimension* pCurrDim = bFirst ? pDim : rSaveData.DuplicateDimension(pDim->GetName());
+ pCurrDim->SetOrientation( nOrient );
+ pCurrDim->SetFunction( sal::static_int_cast<USHORT>(eFunc) );
+
+ if( rFieldRef.ReferenceType == sheet::DataPilotFieldReferenceType::NONE )
+ pCurrDim->SetReferenceValue( 0 );
+ else
+ pCurrDim->SetReferenceValue( &rFieldRef );
+
+ bFirst = FALSE;
+ }
+ nMask *= 2;
+ }
+ }
+ else // set SubTotals
+ {
+ pDim->SetOrientation( nOrient );
+
+ USHORT nFuncArray[16];
+ USHORT nFuncCount = 0;
+ USHORT nMask = 1;
+ for (USHORT nBit=0; nBit<16; nBit++)
+ {
+ if ( nFuncs & nMask )
+ nFuncArray[nFuncCount++] = sal::static_int_cast<USHORT>(ScDataPilotConversion::FirstFunc( nMask ));
+ nMask *= 2;
+ }
+ pDim->SetSubTotals( nFuncCount, nFuncArray );
+
+ // ShowEmpty was implicit in old tables,
+ // must be set for data layout dimension (not accessible in dialog)
+ if ( bOldDefaults || nCol == PIVOT_DATA_FIELD )
+ pDim->SetShowEmpty( TRUE );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+// static
+BOOL ScDPObject::HasRegisteredSources()
+{
+ BOOL bFound = FALSE;
+
+ uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
+ uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
+ if ( xEnAc.is() )
+ {
+ uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
+ rtl::OUString::createFromAscii( SCDPSOURCE_SERVICE ) );
+ if ( xEnum.is() && xEnum->hasMoreElements() )
+ bFound = TRUE;
+ }
+
+ return bFound;
+}
+
+// static
+uno::Sequence<rtl::OUString> ScDPObject::GetRegisteredSources()
+{
+ long nCount = 0;
+ uno::Sequence<rtl::OUString> aSeq(0);
+
+ // use implementation names...
+
+ uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
+ uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
+ if ( xEnAc.is() )
+ {
+ uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
+ rtl::OUString::createFromAscii( SCDPSOURCE_SERVICE ) );
+ if ( xEnum.is() )
+ {
+ while ( xEnum->hasMoreElements() )
+ {
+ uno::Any aAddInAny = xEnum->nextElement();
+// if ( aAddInAny.getReflection()->getTypeClass() == TypeClass_INTERFACE )
+ {
+ uno::Reference<uno::XInterface> xIntFac;
+ aAddInAny >>= xIntFac;
+ if ( xIntFac.is() )
+ {
+ uno::Reference<lang::XServiceInfo> xInfo( xIntFac, uno::UNO_QUERY );
+ if ( xInfo.is() )
+ {
+ rtl::OUString sName = xInfo->getImplementationName();
+
+ aSeq.realloc( nCount+1 );
+ aSeq.getArray()[nCount] = sName;
+ ++nCount;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return aSeq;
+}
+
+// static
+uno::Reference<sheet::XDimensionsSupplier> ScDPObject::CreateSource( const ScDPServiceDesc& rDesc )
+{
+ rtl::OUString aImplName = rDesc.aServiceName;
+ uno::Reference<sheet::XDimensionsSupplier> xRet = NULL;
+
+ uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
+ uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
+ if ( xEnAc.is() )
+ {
+ uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
+ rtl::OUString::createFromAscii( SCDPSOURCE_SERVICE ) );
+ if ( xEnum.is() )
+ {
+ while ( xEnum->hasMoreElements() && !xRet.is() )
+ {
+ uno::Any aAddInAny = xEnum->nextElement();
+// if ( aAddInAny.getReflection()->getTypeClass() == TypeClass_INTERFACE )
+ {
+ uno::Reference<uno::XInterface> xIntFac;
+ aAddInAny >>= xIntFac;
+ if ( xIntFac.is() )
+ {
+ uno::Reference<lang::XServiceInfo> xInfo( xIntFac, uno::UNO_QUERY );
+ uno::Reference<lang::XSingleServiceFactory> xFac( xIntFac, uno::UNO_QUERY );
+ if ( xFac.is() && xInfo.is() && xInfo->getImplementationName() == aImplName )
+ {
+ try
+ {
+ uno::Reference<uno::XInterface> xInterface = xFac->createInstance();
+ uno::Reference<lang::XInitialization> xInit( xInterface, uno::UNO_QUERY );
+ if (xInit.is())
+ {
+ // initialize
+ uno::Sequence<uno::Any> aSeq(4);
+ uno::Any* pArray = aSeq.getArray();
+ pArray[0] <<= rtl::OUString( rDesc.aParSource );
+ pArray[1] <<= rtl::OUString( rDesc.aParName );
+ pArray[2] <<= rtl::OUString( rDesc.aParUser );
+ pArray[3] <<= rtl::OUString( rDesc.aParPass );
+ xInit->initialize( aSeq );
+ }
+ xRet = uno::Reference<sheet::XDimensionsSupplier>( xInterface, uno::UNO_QUERY );
+ }
+ catch(uno::Exception&)
+ {
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return xRet;
+}
+
+// ============================================================================
+
+ScDPCacheCell::ScDPCacheCell() :
+ mnStrId(ScSimpleSharedString::EMPTY),
+ mnType(SC_VALTYPE_EMPTY),
+ mfValue(0.0),
+ mbNumeric(false)
+{
+}
+
+ScDPCacheCell::ScDPCacheCell(const ScDPCacheCell& r) :
+ mnStrId(r.mnStrId),
+ mnType(r.mnType),
+ mfValue(r.mfValue),
+ mbNumeric(r.mbNumeric)
+{
+}
+
+ScDPCacheCell::~ScDPCacheCell()
+{
+}
+
+// ============================================================================
+
+size_t ScDPCollection::CacheCellHash::operator()(const ScDPCacheCell* pCell) const
+{
+ return pCell->mnStrId + static_cast<size_t>(pCell->mnType) +
+ static_cast<size_t>(pCell->mfValue) + static_cast<size_t>(pCell->mbNumeric);
+}
+
+bool ScDPCollection::CacheCellEqual::operator()(const ScDPCacheCell* p1, const ScDPCacheCell* p2) const
+{
+ if (!p1 && !p2)
+ return true;
+
+ if ((!p1 && p2) || (p1 && !p2))
+ return false;
+
+ return p1->mnStrId == p2->mnStrId && p1->mfValue == p2->mfValue &&
+ p1->mbNumeric == p2->mbNumeric && p1->mnType == p2->mnType;
+}
+
+// ----------------------------------------------------------------------------
+
+ScDPCollection::ScDPCollection(ScDocument* pDocument) :
+ pDoc( pDocument )
+{
+}
+
+ScDPCollection::ScDPCollection(const ScDPCollection& r) :
+ ScCollection(r),
+ pDoc(r.pDoc),
+ maSharedString(r.maSharedString),
+ maCacheCellPool() // #i101725# don't copy hash_set with pointers from the other collection
+{
+}
+
+ScDPCollection::~ScDPCollection()
+{
+ clearCacheCellPool();
+}
+
+ScDataObject* ScDPCollection::Clone() const
+{
+ return new ScDPCollection(*this);
+}
+
+void ScDPCollection::DeleteOnTab( SCTAB nTab )
+{
+ USHORT nPos = 0;
+ while ( nPos < nCount )
+ {
+ // look for output positions on the deleted sheet
+ if ( static_cast<const ScDPObject*>(At(nPos))->GetOutRange().aStart.Tab() == nTab )
+ AtFree(nPos);
+ else
+ ++nPos;
+ }
+}
+
+void ScDPCollection::UpdateReference( UpdateRefMode eUpdateRefMode,
+ const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ for (USHORT i=0; i<nCount; i++)
+ ((ScDPObject*)At(i))->UpdateReference( eUpdateRefMode, r, nDx, nDy, nDz );
+}
+
+BOOL ScDPCollection::RefsEqual( const ScDPCollection& r ) const
+{
+ if ( nCount != r.nCount )
+ return FALSE;
+
+ for (USHORT i=0; i<nCount; i++)
+ if ( ! ((const ScDPObject*)At(i))->RefsEqual( *((const ScDPObject*)r.At(i)) ) )
+ return FALSE;
+
+ return TRUE; // all equal
+}
+
+void ScDPCollection::WriteRefsTo( ScDPCollection& r ) const
+{
+ if ( nCount == r.nCount )
+ {
+ //! assert equal names?
+ for (USHORT i=0; i<nCount; i++)
+ ((const ScDPObject*)At(i))->WriteRefsTo( *((ScDPObject*)r.At(i)) );
+ }
+ else
+ {
+ // #i8180# If data pilot tables were deleted with their sheet,
+ // this collection contains extra entries that must be restored.
+ // Matching objects are found by their names.
+
+ DBG_ASSERT( nCount >= r.nCount, "WriteRefsTo: missing entries in document" );
+ for (USHORT nSourcePos=0; nSourcePos<nCount; nSourcePos++)
+ {
+ const ScDPObject* pSourceObj = static_cast<const ScDPObject*>(At(nSourcePos));
+ String aName = pSourceObj->GetName();
+ bool bFound = false;
+ for (USHORT nDestPos=0; nDestPos<r.nCount && !bFound; nDestPos++)
+ {
+ ScDPObject* pDestObj = static_cast<ScDPObject*>(r.At(nDestPos));
+ if ( pDestObj->GetName() == aName )
+ {
+ pSourceObj->WriteRefsTo( *pDestObj ); // found object, copy refs
+ bFound = true;
+ }
+ }
+ if ( !bFound )
+ {
+ // none found, re-insert deleted object (see ScUndoDataPilot::Undo)
+
+ ScDPObject* pDestObj = new ScDPObject( *pSourceObj );
+ pDestObj->SetAlive(TRUE);
+ if ( !r.InsertNewTable(pDestObj) )
+ {
+ DBG_ERROR("cannot insert DPObject");
+ DELETEZ( pDestObj );
+ }
+ }
+ }
+ DBG_ASSERT( nCount == r.nCount, "WriteRefsTo: couldn't restore all entries" );
+ }
+}
+
+String ScDPCollection::CreateNewName( USHORT nMin ) const
+{
+ String aBase = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("DataPilot"));
+ //! from Resource?
+
+ for (USHORT nAdd=0; nAdd<=nCount; nAdd++) // nCount+1 tries
+ {
+ String aNewName = aBase;
+ aNewName += String::CreateFromInt32( nMin + nAdd );
+ BOOL bFound = FALSE;
+ for (USHORT i=0; i<nCount && !bFound; i++)
+ if (((const ScDPObject*)pItems[i])->GetName() == aNewName)
+ bFound = TRUE;
+ if (!bFound)
+ return aNewName; // found unused Name
+ }
+ return String(); // should not happen
+}
+
+ScSimpleSharedString& ScDPCollection::GetSharedString()
+{
+ return maSharedString;
+}
+
+void ScDPCollection::FreeTable(ScDPObject* pDPObj)
+{
+ const ScRange& rOutRange = pDPObj->GetOutRange();
+ const ScAddress& s = rOutRange.aStart;
+ const ScAddress& e = rOutRange.aEnd;
+ pDoc->RemoveFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
+ Free(pDPObj);
+}
+
+bool ScDPCollection::InsertNewTable(ScDPObject* pDPObj)
+{
+ bool bSuccess = Insert(pDPObj);
+ if (bSuccess)
+ {
+ const ScRange& rOutRange = pDPObj->GetOutRange();
+ const ScAddress& s = rOutRange.aStart;
+ const ScAddress& e = rOutRange.aEnd;
+ pDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
+ }
+ return bSuccess;
+}
+
+bool ScDPCollection::HasDPTable(SCCOL nCol, SCROW nRow, SCTAB nTab) const
+{
+ const ScMergeFlagAttr* pMergeAttr = static_cast<const ScMergeFlagAttr*>(
+ pDoc->GetAttr(nCol, nRow, nTab, ATTR_MERGE_FLAG));
+
+ if (!pMergeAttr)
+ return false;
+
+ return pMergeAttr->HasDPTable();
+}
+
+ScDPCacheCell* ScDPCollection::getCacheCellFromPool(const ScDPCacheCell& rCell)
+{
+ ScDPCacheCell aCell(rCell);
+ CacheCellPoolType::iterator itr = maCacheCellPool.find(&aCell);
+ if (itr == maCacheCellPool.end())
+ {
+ // Insert a new instance.
+ ScDPCacheCell* p = new ScDPCacheCell(rCell);
+ ::std::pair<CacheCellPoolType::iterator, bool> r =
+ maCacheCellPool.insert(p);
+ if (!r.second)
+ delete p;
+
+ ScDPCacheCell* p2 = r.second ? *r.first : NULL;
+ DBG_ASSERT(p == p2, "ScDPCollection::getCacheCellFromPool: pointer addresses differ");
+ return p2;
+ }
+ return *itr;
+}
+
+namespace {
+
+class DeleteCacheCells : public ::std::unary_function<ScDPCacheCell*, void>
+{
+public:
+ void operator()(ScDPCacheCell* p) const
+ {
+ delete p;
+ }
+};
+
+}
+
+void ScDPCollection::clearCacheCellPool()
+{
+ // Transferring all stored pointers to a vector first. For some unknown
+ // reason, deleting cell content instances by directly iterating through
+ // the hash set causes the iteration to return an identical pointer
+ // value twice, causing a double-delete. I have no idea why this happens.
+
+ using ::std::copy;
+ using ::std::back_inserter;
+
+ vector<ScDPCacheCell*> ps;
+ ps.reserve(maCacheCellPool.size());
+ copy(maCacheCellPool.begin(), maCacheCellPool.end(), back_inserter(ps));
+ maCacheCellPool.clear();
+ // for correctness' sake, delete the elements after clearing the hash_set
+ for_each(ps.begin(), ps.end(), DeleteCacheCells());
+}
+