Update ooo320-m1
[ooovba.git] / sc / source / core / data / dpobject.cxx
blob5dcd70893e3aa46738d2a99b667aba879e4335bf
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: dpobject.cxx,v $
10 * $Revision: 1.23.30.5 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
36 // INCLUDE ---------------------------------------------------------------
38 #include "dpobject.hxx"
39 #include "dptabsrc.hxx"
40 #include "dpsave.hxx"
41 #include "dpdimsave.hxx"
42 #include "dpoutput.hxx"
43 #include "dpshttab.hxx"
44 #include "dpsdbtab.hxx"
45 #include "dpgroup.hxx"
46 #include "document.hxx"
47 #include "rechead.hxx"
48 #include "pivot.hxx" // PIVOT_DATA_FIELD
49 #include "dapiuno.hxx" // ScDataPilotConversion
50 #include "miscuno.hxx"
51 #include "scerrors.hxx"
52 #include "refupdat.hxx"
53 #include "scresid.hxx"
54 #include "sc.hrc"
55 #include "attrib.hxx"
56 #include "scitems.hxx"
57 #include "unonames.hxx"
59 #include <com/sun/star/beans/XPropertySet.hpp>
60 #include <com/sun/star/sheet/GeneralFunction.hpp>
61 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
62 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
63 #include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
64 #include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
65 #include <com/sun/star/sheet/DataPilotTablePositionData.hpp>
66 #include <com/sun/star/sheet/DataPilotTablePositionType.hpp>
67 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
68 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
69 #include <com/sun/star/lang/XInitialization.hpp>
70 #include <com/sun/star/container/XContentEnumerationAccess.hpp>
71 #include <com/sun/star/sheet/XDrillDownDataSupplier.hpp>
73 #include <comphelper/processfactory.hxx>
74 #include <tools/debug.hxx>
75 #include <svtools/zforlist.hxx> // IsNumberFormat
77 #include <vector>
78 #include <stdio.h>
80 using namespace com::sun::star;
81 using ::std::vector;
82 using ::boost::shared_ptr;
83 using ::com::sun::star::uno::Sequence;
84 using ::com::sun::star::uno::Reference;
85 using ::com::sun::star::uno::UNO_QUERY;
86 using ::com::sun::star::uno::Any;
87 using ::com::sun::star::sheet::DataPilotTableHeaderData;
88 using ::com::sun::star::sheet::DataPilotTablePositionData;
89 using ::com::sun::star::beans::XPropertySet;
90 using ::rtl::OUString;
92 // -----------------------------------------------------------------------
94 #define MAX_LABELS 256 //!!! from fieldwnd.hxx, must be moved to global.hxx
96 // -----------------------------------------------------------------------
98 #define SCDPSOURCE_SERVICE "com.sun.star.sheet.DataPilotSource"
100 // -----------------------------------------------------------------------
102 // incompatible versions of data pilot files
103 #define SC_DP_VERSION_CURRENT 6
105 // type of source data
106 #define SC_DP_SOURCE_SHEET 0
107 #define SC_DP_SOURCE_DATABASE 1
108 #define SC_DP_SOURCE_SERVICE 2
110 // -----------------------------------------------------------------------
112 //! move to a header file
113 #define DP_PROP_COLUMNGRAND "ColumnGrand"
114 #define DP_PROP_FUNCTION "Function"
115 #define DP_PROP_IGNOREEMPTY "IgnoreEmptyRows"
116 #define DP_PROP_ISDATALAYOUT "IsDataLayoutDimension"
117 //#define DP_PROP_ISVISIBLE "IsVisible"
118 #define DP_PROP_ORIENTATION "Orientation"
119 #define DP_PROP_ORIGINAL "Original"
120 #define DP_PROP_POSITION "Position"
121 #define DP_PROP_REPEATIFEMPTY "RepeatIfEmpty"
122 #define DP_PROP_ROWGRAND "RowGrand"
123 #define DP_PROP_SHOWDETAILS "ShowDetails"
124 #define DP_PROP_SHOWEMPTY "ShowEmpty"
125 #define DP_PROP_SUBTOTALS "SubTotals"
126 #define DP_PROP_USEDHIERARCHY "UsedHierarchy"
128 // -----------------------------------------------------------------------
130 USHORT lcl_GetDataGetOrientation( const uno::Reference<sheet::XDimensionsSupplier>& xSource )
132 long nRet = sheet::DataPilotFieldOrientation_HIDDEN;
133 if ( xSource.is() )
135 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
136 uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
137 long nIntCount = xIntDims->getCount();
138 BOOL bFound = FALSE;
139 for (long nIntDim=0; nIntDim<nIntCount && !bFound; nIntDim++)
141 uno::Reference<uno::XInterface> xIntDim =
142 ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nIntDim) );
143 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
144 if ( xDimProp.is() )
146 bFound = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
147 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
148 //! error checking -- is "IsDataLayoutDimension" property required??
149 if (bFound)
150 nRet = ScUnoHelpFunctions::GetEnumProperty(
151 xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION),
152 sheet::DataPilotFieldOrientation_HIDDEN );
156 return static_cast< USHORT >( nRet );
159 // -----------------------------------------------------------------------
161 ScDPObject::ScDPObject( ScDocument* pD ) :
162 pDoc( pD ),
163 pSaveData( NULL ),
164 pSheetDesc( NULL ),
165 pImpDesc( NULL ),
166 pServDesc( NULL ),
167 mpTableData(static_cast<ScDPTableData*>(NULL)),
168 pOutput( NULL ),
169 bSettingsChanged( FALSE ),
170 bAlive( FALSE ),
171 mnAutoFormatIndex( 65535 ),
172 bAllowMove( FALSE ),
173 nHeaderRows( 0 ),
174 mbHeaderLayout(false)
178 ScDPObject::ScDPObject(const ScDPObject& r) :
179 ScDataObject(),
180 pDoc( r.pDoc ),
181 pSaveData( NULL ),
182 aTableName( r.aTableName ),
183 aTableTag( r.aTableTag ),
184 aOutRange( r.aOutRange ),
185 pSheetDesc( NULL ),
186 pImpDesc( NULL ),
187 pServDesc( NULL ),
188 mpTableData(static_cast<ScDPTableData*>(NULL)),
189 pOutput( NULL ),
190 bSettingsChanged( FALSE ),
191 bAlive( FALSE ),
192 mnAutoFormatIndex( r.mnAutoFormatIndex ),
193 bAllowMove( FALSE ),
194 nHeaderRows( r.nHeaderRows ),
195 mbHeaderLayout( r.mbHeaderLayout )
197 if (r.pSaveData)
198 pSaveData = new ScDPSaveData(*r.pSaveData);
199 if (r.pSheetDesc)
200 pSheetDesc = new ScSheetSourceDesc(*r.pSheetDesc);
201 if (r.pImpDesc)
202 pImpDesc = new ScImportSourceDesc(*r.pImpDesc);
203 if (r.pServDesc)
204 pServDesc = new ScDPServiceDesc(*r.pServDesc);
205 // xSource (and pOutput) is not copied
208 ScDPObject::~ScDPObject()
210 delete pOutput;
211 delete pSaveData;
212 delete pSheetDesc;
213 delete pImpDesc;
214 delete pServDesc;
217 ScDataObject* ScDPObject::Clone() const
219 return new ScDPObject(*this);
222 void ScDPObject::SetAlive(BOOL bSet)
224 bAlive = bSet;
227 void ScDPObject::SetAllowMove(BOOL bSet)
229 bAllowMove = bSet;
232 void ScDPObject::SetSaveData(const ScDPSaveData& rData)
234 if ( pSaveData != &rData ) // API implementation modifies the original SaveData object
236 delete pSaveData;
237 pSaveData = new ScDPSaveData( rData );
240 InvalidateData(); // re-init source from SaveData
243 void ScDPObject::SetAutoFormatIndex(const sal_uInt16 nIndex)
245 mnAutoFormatIndex = nIndex;
248 sal_uInt16 ScDPObject::GetAutoFormatIndex() const
250 return mnAutoFormatIndex;
253 void ScDPObject::SetHeaderLayout (bool bUseGrid)
255 mbHeaderLayout = bUseGrid;
258 bool ScDPObject::GetHeaderLayout() const
260 return mbHeaderLayout;
263 void ScDPObject::SetOutRange(const ScRange& rRange)
265 aOutRange = rRange;
267 if ( pOutput )
268 pOutput->SetPosition( rRange.aStart );
271 void ScDPObject::SetSheetDesc(const ScSheetSourceDesc& rDesc)
273 if ( pSheetDesc && rDesc == *pSheetDesc )
274 return; // nothing to do
276 DELETEZ( pImpDesc );
277 DELETEZ( pServDesc );
279 delete pImpDesc;
280 pSheetDesc = new ScSheetSourceDesc(rDesc);
282 // make valid QueryParam
284 pSheetDesc->aQueryParam.nCol1 = pSheetDesc->aSourceRange.aStart.Col();
285 pSheetDesc->aQueryParam.nRow1 = pSheetDesc->aSourceRange.aStart.Row();
286 pSheetDesc->aQueryParam.nCol2 = pSheetDesc->aSourceRange.aEnd.Col();
287 pSheetDesc->aQueryParam.nRow2 = pSheetDesc->aSourceRange.aEnd.Row();;
288 pSheetDesc->aQueryParam.bHasHeader = TRUE;
290 InvalidateSource(); // new source must be created
293 void ScDPObject::SetImportDesc(const ScImportSourceDesc& rDesc)
295 if ( pImpDesc && rDesc == *pImpDesc )
296 return; // nothing to do
298 DELETEZ( pSheetDesc );
299 DELETEZ( pServDesc );
301 delete pImpDesc;
302 pImpDesc = new ScImportSourceDesc(rDesc);
304 InvalidateSource(); // new source must be created
307 void ScDPObject::SetServiceData(const ScDPServiceDesc& rDesc)
309 if ( pServDesc && rDesc == *pServDesc )
310 return; // nothing to do
312 DELETEZ( pSheetDesc );
313 DELETEZ( pImpDesc );
315 delete pServDesc;
316 pServDesc = new ScDPServiceDesc(rDesc);
318 InvalidateSource(); // new source must be created
321 void ScDPObject::WriteSourceDataTo( ScDPObject& rDest ) const
323 if ( pSheetDesc )
324 rDest.SetSheetDesc( *pSheetDesc );
325 else if ( pImpDesc )
326 rDest.SetImportDesc( *pImpDesc );
327 else if ( pServDesc )
328 rDest.SetServiceData( *pServDesc );
330 // name/tag are not source data, but needed along with source data
332 rDest.aTableName = aTableName;
333 rDest.aTableTag = aTableTag;
336 void ScDPObject::WriteTempDataTo( ScDPObject& rDest ) const
338 rDest.nHeaderRows = nHeaderRows;
341 BOOL ScDPObject::IsSheetData() const
343 return ( pSheetDesc != NULL );
346 void ScDPObject::SetName(const String& rNew)
348 aTableName = rNew;
351 void ScDPObject::SetTag(const String& rNew)
353 aTableTag = rNew;
356 bool ScDPObject::IsDataDescriptionCell(const ScAddress& rPos)
358 if (!pSaveData)
359 return false;
361 long nDataDimCount = pSaveData->GetDataDimensionCount();
362 if (nDataDimCount != 1)
363 // There has to be exactly one data dimension for the description to
364 // appear at top-left corner.
365 return false;
367 CreateOutput();
368 ScRange aTabRange = pOutput->GetOutputRange(sheet::DataPilotOutputRangeType::TABLE);
369 return (rPos == aTabRange.aStart);
372 uno::Reference<sheet::XDimensionsSupplier> ScDPObject::GetSource()
374 CreateObjects();
375 return xSource;
378 void ScDPObject::CreateOutput()
380 CreateObjects();
381 if (!pOutput)
383 BOOL bFilterButton = IsSheetData() && pSaveData && pSaveData->GetFilterButton();
384 pOutput = new ScDPOutput( pDoc, xSource, aOutRange.aStart, bFilterButton );
385 pOutput->SetHeaderLayout ( mbHeaderLayout );
387 long nOldRows = nHeaderRows;
388 nHeaderRows = pOutput->GetHeaderRows();
390 if ( bAllowMove && nHeaderRows != nOldRows )
392 long nDiff = nOldRows - nHeaderRows;
393 if ( nOldRows == 0 )
394 --nDiff;
395 if ( nHeaderRows == 0 )
396 ++nDiff;
398 long nNewRow = aOutRange.aStart.Row() + nDiff;
399 if ( nNewRow < 0 )
400 nNewRow = 0;
402 ScAddress aStart( aOutRange.aStart );
403 aStart.SetRow(nNewRow);
404 pOutput->SetPosition( aStart );
406 //! modify aOutRange?
408 bAllowMove = FALSE; // use only once
413 ScDPTableData* ScDPObject::GetTableData()
415 if (!mpTableData)
417 if ( pImpDesc )
419 // database data
420 mpTableData.reset(new ScDatabaseDPData(pDoc, *pImpDesc));
422 else
424 // cell data
425 if (!pSheetDesc)
427 DBG_ERROR("no source descriptor");
428 pSheetDesc = new ScSheetSourceDesc; // dummy defaults
430 mpTableData.reset(new ScSheetDPData(pDoc, *pSheetDesc));
433 // grouping (for cell or database data)
434 if ( pSaveData && pSaveData->GetExistingDimensionData() )
436 shared_ptr<ScDPGroupTableData> pGroupData(new ScDPGroupTableData(mpTableData, pDoc));
437 pSaveData->GetExistingDimensionData()->WriteToData(*pGroupData);
438 mpTableData = pGroupData;
442 return mpTableData.get();
445 void ScDPObject::CreateObjects()
447 // if groups are involved, create a new source with the ScDPGroupTableData
448 if ( bSettingsChanged && pSaveData && pSaveData->GetExistingDimensionData() )
449 InvalidateSource();
451 if (!xSource.is())
453 //! cache DPSource and/or Output?
455 DBG_ASSERT( bAlive, "CreateObjects on non-inserted DPObject" );
457 DELETEZ( pOutput ); // not valid when xSource is changed
459 if ( pServDesc )
461 xSource = CreateSource( *pServDesc );
464 if ( !xSource.is() ) // database or sheet data, or error in CreateSource
466 DBG_ASSERT( !pServDesc, "DPSource could not be created" );
467 ScDPTableData* pData = GetTableData();
468 ScDPSource* pSource = new ScDPSource( pData );
469 xSource = pSource;
472 if (pSaveData)
473 pSaveData->WriteToSource( xSource );
475 else if (bSettingsChanged)
477 DELETEZ( pOutput ); // not valid when xSource is changed
479 uno::Reference<util::XRefreshable> xRef( xSource, uno::UNO_QUERY );
480 if (xRef.is())
484 xRef->refresh();
486 catch(uno::Exception&)
488 DBG_ERROR("exception in refresh");
492 if (pSaveData)
493 pSaveData->WriteToSource( xSource );
495 bSettingsChanged = FALSE;
498 void ScDPObject::InvalidateData()
500 bSettingsChanged = TRUE;
503 void ScDPObject::InvalidateSource()
505 xSource = NULL;
506 mpTableData.reset();
509 ScRange ScDPObject::GetNewOutputRange( BOOL& rOverflow )
511 CreateOutput(); // create xSource and pOutput if not already done
513 rOverflow = pOutput->HasError(); // range overflow or exception from source
514 if ( rOverflow )
515 return ScRange( aOutRange.aStart );
516 else
518 // don't store the result in aOutRange, because nothing has been output yet
519 return pOutput->GetOutputRange();
523 void ScDPObject::Output( const ScAddress& rPos )
525 // clear old output area
526 pDoc->DeleteAreaTab( aOutRange.aStart.Col(), aOutRange.aStart.Row(),
527 aOutRange.aEnd.Col(), aOutRange.aEnd.Row(),
528 aOutRange.aStart.Tab(), IDF_ALL );
529 pDoc->RemoveFlagsTab( aOutRange.aStart.Col(), aOutRange.aStart.Row(),
530 aOutRange.aEnd.Col(), aOutRange.aEnd.Row(),
531 aOutRange.aStart.Tab(), SC_MF_AUTO );
533 CreateOutput(); // create xSource and pOutput if not already done
535 pOutput->SetPosition( rPos );
537 pOutput->Output();
539 // aOutRange is always the range that was last output to the document
540 aOutRange = pOutput->GetOutputRange();
541 const ScAddress& s = aOutRange.aStart;
542 const ScAddress& e = aOutRange.aEnd;
543 pDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
546 const ScRange ScDPObject::GetOutputRangeByType( sal_Int32 nType )
548 CreateOutput();
550 if (pOutput->HasError())
551 return ScRange(aOutRange.aStart);
553 return pOutput->GetOutputRange(nType);
556 BOOL lcl_HasButton( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
558 return ((const ScMergeFlagAttr*)pDoc->GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG ))->HasButton();
561 void ScDPObject::RefreshAfterLoad()
563 // apply drop-down attribute, initialize nHeaderRows, without accessing the source
564 // (button attribute must be present)
566 // simple test: block of button cells at the top, followed by an empty cell
568 SCCOL nFirstCol = aOutRange.aStart.Col();
569 SCROW nFirstRow = aOutRange.aStart.Row();
570 SCTAB nTab = aOutRange.aStart.Tab();
572 SCROW nInitial = 0;
573 SCROW nOutRows = aOutRange.aEnd.Row() + 1 - aOutRange.aStart.Row();
574 while ( nInitial + 1 < nOutRows && lcl_HasButton( pDoc, nFirstCol, nFirstRow + nInitial, nTab ) )
575 ++nInitial;
577 if ( nInitial + 1 < nOutRows &&
578 pDoc->IsBlockEmpty( nTab, nFirstCol, nFirstRow + nInitial, nFirstCol, nFirstRow + nInitial ) &&
579 aOutRange.aEnd.Col() > nFirstCol )
581 BOOL bFilterButton = IsSheetData(); // when available, filter button setting must be checked here
583 SCROW nSkip = bFilterButton ? 1 : 0;
584 for (SCROW nPos=nSkip; nPos<nInitial; nPos++)
585 pDoc->ApplyAttr( nFirstCol + 1, nFirstRow + nPos, nTab, ScMergeFlagAttr(SC_MF_AUTO) );
587 nHeaderRows = nInitial;
589 else
590 nHeaderRows = 0; // nothing found, no drop-down lists
593 void ScDPObject::BuildAllDimensionMembers()
595 if (!pSaveData)
596 return;
598 pSaveData->BuildAllDimensionMembers(GetTableData());
601 bool ScDPObject::GetMemberNames( sal_Int32 nDim, Sequence<OUString>& rNames )
603 vector<ScDPLabelData::Member> aMembers;
604 if (!GetMembers(nDim, GetUsedHierarchy(nDim), aMembers))
605 return false;
607 size_t n = aMembers.size();
608 rNames.realloc(n);
609 for (size_t i = 0; i < n; ++i)
610 rNames[i] = aMembers[i].maName;
612 return true;
615 bool ScDPObject::GetMembers( sal_Int32 nDim, sal_Int32 nHier, vector<ScDPLabelData::Member>& rMembers )
617 Reference< container::XNameAccess > xMembersNA;
618 if (!GetMembersNA( nDim, nHier, xMembersNA ))
619 return false;
621 Reference<container::XIndexAccess> xMembersIA( new ScNameToIndexAccess(xMembersNA) );
622 sal_Int32 nCount = xMembersIA->getCount();
623 vector<ScDPLabelData::Member> aMembers;
624 aMembers.reserve(nCount);
626 for (sal_Int32 i = 0; i < nCount; ++i)
628 Reference<container::XNamed> xMember(xMembersIA->getByIndex(i), UNO_QUERY);
629 ScDPLabelData::Member aMem;
631 if (xMember.is())
632 aMem.maName = xMember->getName();
634 Reference<beans::XPropertySet> xMemProp(xMember, UNO_QUERY);
635 if (xMemProp.is())
637 aMem.mbVisible = ScUnoHelpFunctions::GetBoolProperty(xMemProp, OUString::createFromAscii(SC_UNO_ISVISIBL));
638 aMem.mbShowDetails = ScUnoHelpFunctions::GetBoolProperty(xMemProp, OUString::createFromAscii(SC_UNO_SHOWDETA));
640 aMem.maLayoutName = ScUnoHelpFunctions::GetStringProperty(
641 xMemProp, OUString::createFromAscii(SC_UNO_LAYOUTNAME), OUString());
644 aMembers.push_back(aMem);
646 rMembers.swap(aMembers);
647 return true;
650 void ScDPObject::UpdateReference( UpdateRefMode eUpdateRefMode,
651 const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
653 // Output area
655 SCCOL nCol1 = aOutRange.aStart.Col();
656 SCROW nRow1 = aOutRange.aStart.Row();
657 SCTAB nTab1 = aOutRange.aStart.Tab();
658 SCCOL nCol2 = aOutRange.aEnd.Col();
659 SCROW nRow2 = aOutRange.aEnd.Row();
660 SCTAB nTab2 = aOutRange.aEnd.Tab();
662 ScRefUpdateRes eRes =
663 ScRefUpdate::Update( pDoc, eUpdateRefMode,
664 rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
665 rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz,
666 nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
667 if ( eRes != UR_NOTHING )
668 SetOutRange( ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ) );
670 // sheet source data
672 if ( pSheetDesc )
674 nCol1 = pSheetDesc->aSourceRange.aStart.Col();
675 nRow1 = pSheetDesc->aSourceRange.aStart.Row();
676 nTab1 = pSheetDesc->aSourceRange.aStart.Tab();
677 nCol2 = pSheetDesc->aSourceRange.aEnd.Col();
678 nRow2 = pSheetDesc->aSourceRange.aEnd.Row();
679 nTab2 = pSheetDesc->aSourceRange.aEnd.Tab();
681 eRes = ScRefUpdate::Update( pDoc, eUpdateRefMode,
682 rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
683 rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz,
684 nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
685 if ( eRes != UR_NOTHING )
687 ScSheetSourceDesc aNewDesc;
688 aNewDesc.aSourceRange = ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
690 SCsCOL nDiffX = nCol1 - (SCsCOL) pSheetDesc->aSourceRange.aStart.Col();
691 SCsROW nDiffY = nRow1 - (SCsROW) pSheetDesc->aSourceRange.aStart.Row();
693 aNewDesc.aQueryParam = pSheetDesc->aQueryParam;
694 aNewDesc.aQueryParam.nCol1 = sal::static_int_cast<SCCOL>( aNewDesc.aQueryParam.nCol1 + nDiffX );
695 aNewDesc.aQueryParam.nCol2 = sal::static_int_cast<SCCOL>( aNewDesc.aQueryParam.nCol2 + nDiffX );
696 aNewDesc.aQueryParam.nRow1 += nDiffY; //! used?
697 aNewDesc.aQueryParam.nRow2 += nDiffY; //! used?
698 SCSIZE nEC = aNewDesc.aQueryParam.GetEntryCount();
699 for (SCSIZE i=0; i<nEC; i++)
700 if (aNewDesc.aQueryParam.GetEntry(i).bDoQuery)
701 aNewDesc.aQueryParam.GetEntry(i).nField += nDiffX;
703 SetSheetDesc( aNewDesc ); // allocates new pSheetDesc
708 BOOL ScDPObject::RefsEqual( const ScDPObject& r ) const
710 if ( aOutRange != r.aOutRange )
711 return FALSE;
713 if ( pSheetDesc && r.pSheetDesc )
715 if ( pSheetDesc->aSourceRange != r.pSheetDesc->aSourceRange )
716 return FALSE;
718 else if ( pSheetDesc || r.pSheetDesc )
720 DBG_ERROR("RefsEqual: SheetDesc set at only one object");
721 return FALSE;
724 return TRUE;
727 void ScDPObject::WriteRefsTo( ScDPObject& r ) const
729 r.SetOutRange( aOutRange );
730 if ( pSheetDesc )
731 r.SetSheetDesc( *pSheetDesc );
734 void ScDPObject::GetPositionData(const ScAddress& rPos, DataPilotTablePositionData& rPosData)
736 CreateOutput();
737 pOutput->GetPositionData(rPos, rPosData);
740 bool ScDPObject::GetDataFieldPositionData(
741 const ScAddress& rPos, Sequence<sheet::DataPilotFieldFilter>& rFilters)
743 CreateOutput();
745 vector<sheet::DataPilotFieldFilter> aFilters;
746 if (!pOutput->GetDataResultPositionData(aFilters, rPos))
747 return false;
749 sal_Int32 n = static_cast<sal_Int32>(aFilters.size());
750 rFilters.realloc(n);
751 for (sal_Int32 i = 0; i < n; ++i)
752 rFilters[i] = aFilters[i];
754 return true;
757 void ScDPObject::GetDrillDownData(const ScAddress& rPos, Sequence< Sequence<Any> >& rTableData)
759 CreateOutput();
761 Reference<sheet::XDrillDownDataSupplier> xDrillDownData(xSource, UNO_QUERY);
762 if (!xDrillDownData.is())
763 return;
765 Sequence<sheet::DataPilotFieldFilter> filters;
766 if (!GetDataFieldPositionData(rPos, filters))
767 return;
769 rTableData = xDrillDownData->getDrillDownData(filters);
772 bool ScDPObject::IsDimNameInUse(const OUString& rName) const
774 if (!xSource.is())
775 return false;
777 Reference<container::XNameAccess> xDims = xSource->getDimensions();
778 Sequence<OUString> aDimNames = xDims->getElementNames();
779 sal_Int32 n = aDimNames.getLength();
780 for (sal_Int32 i = 0; i < n; ++i)
782 const OUString& rDimName = aDimNames[i];
783 if (rDimName.equalsIgnoreAsciiCase(rName))
784 return true;
786 Reference<beans::XPropertySet> xPropSet(xDims->getByName(rDimName), UNO_QUERY);
787 if (!xPropSet.is())
788 continue;
790 Any any = xPropSet->getPropertyValue(OUString::createFromAscii(SC_UNO_LAYOUTNAME));
791 OUString aLayoutName;
792 if (any >>= aLayoutName)
794 if (aLayoutName.equalsIgnoreAsciiCase(rName))
795 return true;
798 return false;
801 String ScDPObject::GetDimName( long nDim, BOOL& rIsDataLayout )
803 rIsDataLayout = FALSE;
804 String aRet;
806 if ( xSource.is() )
808 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
809 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
810 long nDimCount = xDims->getCount();
811 if ( nDim < nDimCount )
813 uno::Reference<uno::XInterface> xIntDim =
814 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
815 uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
816 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
817 if ( xDimName.is() && xDimProp.is() )
819 BOOL bData = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
820 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
821 //! error checking -- is "IsDataLayoutDimension" property required??
823 rtl::OUString aName;
826 aName = xDimName->getName();
828 catch(uno::Exception&)
831 if ( bData )
832 rIsDataLayout = TRUE;
833 else
834 aRet = String( aName );
839 return aRet;
842 BOOL ScDPObject::IsDuplicated( long nDim )
844 BOOL bDuplicated = FALSE;
845 if ( xSource.is() )
847 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
848 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
849 long nDimCount = xDims->getCount();
850 if ( nDim < nDimCount )
852 uno::Reference<uno::XInterface> xIntDim =
853 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
854 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
855 if ( xDimProp.is() )
859 uno::Any aOrigAny = xDimProp->getPropertyValue(
860 rtl::OUString::createFromAscii(DP_PROP_ORIGINAL) );
861 uno::Reference<uno::XInterface> xIntOrig;
862 if ( (aOrigAny >>= xIntOrig) && xIntOrig.is() )
863 bDuplicated = TRUE;
865 catch(uno::Exception&)
871 return bDuplicated;
874 long ScDPObject::GetDimCount()
876 long nRet = 0;
877 if ( xSource.is() )
881 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
882 if ( xDimsName.is() )
883 nRet = xDimsName->getElementNames().getLength();
885 catch(uno::Exception&)
889 return nRet;
892 void ScDPObject::FillPageList( TypedScStrCollection& rStrings, long nField )
894 //! merge members access with ToggleDetails?
896 //! convert field index to dimension index?
898 DBG_ASSERT( xSource.is(), "no source" );
899 if ( !xSource.is() ) return;
901 uno::Reference<container::XNamed> xDim;
902 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
903 uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
904 long nIntCount = xIntDims->getCount();
905 if ( nField < nIntCount )
907 uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface(
908 xIntDims->getByIndex(nField) );
909 xDim = uno::Reference<container::XNamed>( xIntDim, uno::UNO_QUERY );
911 DBG_ASSERT( xDim.is(), "dimension not found" );
912 if ( !xDim.is() ) return;
914 uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
915 long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
916 rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
917 long nLevel = 0;
919 long nHierCount = 0;
920 uno::Reference<container::XIndexAccess> xHiers;
921 uno::Reference<sheet::XHierarchiesSupplier> xHierSupp( xDim, uno::UNO_QUERY );
922 if ( xHierSupp.is() )
924 uno::Reference<container::XNameAccess> xHiersName = xHierSupp->getHierarchies();
925 xHiers = new ScNameToIndexAccess( xHiersName );
926 nHierCount = xHiers->getCount();
928 uno::Reference<uno::XInterface> xHier;
929 if ( nHierarchy < nHierCount )
930 xHier = ScUnoHelpFunctions::AnyToInterface( xHiers->getByIndex(nHierarchy) );
931 DBG_ASSERT( xHier.is(), "hierarchy not found" );
932 if ( !xHier.is() ) return;
934 long nLevCount = 0;
935 uno::Reference<container::XIndexAccess> xLevels;
936 uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHier, uno::UNO_QUERY );
937 if ( xLevSupp.is() )
939 uno::Reference<container::XNameAccess> xLevsName = xLevSupp->getLevels();
940 xLevels = new ScNameToIndexAccess( xLevsName );
941 nLevCount = xLevels->getCount();
943 uno::Reference<uno::XInterface> xLevel;
944 if ( nLevel < nLevCount )
945 xLevel = ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex(nLevel) );
946 DBG_ASSERT( xLevel.is(), "level not found" );
947 if ( !xLevel.is() ) return;
949 uno::Reference<container::XNameAccess> xMembers;
950 uno::Reference<sheet::XMembersSupplier> xMbrSupp( xLevel, uno::UNO_QUERY );
951 if ( xMbrSupp.is() )
952 xMembers = xMbrSupp->getMembers();
953 DBG_ASSERT( xMembers.is(), "members not found" );
954 if ( !xMembers.is() ) return;
956 uno::Sequence<rtl::OUString> aNames = xMembers->getElementNames();
957 long nNameCount = aNames.getLength();
958 const rtl::OUString* pNameArr = aNames.getConstArray();
959 for (long nPos = 0; nPos < nNameCount; ++nPos)
961 // Make sure to insert only visible members.
962 Reference<XPropertySet> xPropSet(xMembers->getByName(pNameArr[nPos]), UNO_QUERY);
963 sal_Bool bVisible = false;
964 if (xPropSet.is())
966 Any any = xPropSet->getPropertyValue(OUString::createFromAscii(SC_UNO_ISVISIBL));
967 any >>= bVisible;
970 if (bVisible)
972 // use the order from getElementNames
973 TypedStrData* pData = new TypedStrData( pNameArr[nPos] );
974 if ( !rStrings.AtInsert( rStrings.GetCount(), pData ) )
975 delete pData;
979 // add "-all-" entry to the top (unsorted)
980 TypedStrData* pAllData = new TypedStrData( String( ScResId( SCSTR_ALL ) ) ); //! separate string? (also output)
981 if ( !rStrings.AtInsert( 0, pAllData ) )
982 delete pAllData;
985 void ScDPObject::GetHeaderPositionData(const ScAddress& rPos, DataPilotTableHeaderData& rData)
987 using namespace ::com::sun::star::sheet::DataPilotTablePositionType;
989 CreateOutput(); // create xSource and pOutput if not already done
991 // Reset member values to invalid state.
992 rData.Dimension = rData.Hierarchy = rData.Level = -1;
993 rData.Flags = 0;
995 DataPilotTablePositionData aPosData;
996 pOutput->GetPositionData(rPos, aPosData);
997 const sal_Int32 nPosType = aPosData.PositionType;
998 if (nPosType == COLUMN_HEADER || nPosType == ROW_HEADER)
999 aPosData.PositionData >>= rData;
1002 // Returns TRUE on success and stores the result in rTarget
1003 BOOL ScDPObject::GetPivotData( ScDPGetPivotDataField& rTarget,
1004 const std::vector< ScDPGetPivotDataField >& rFilters )
1006 CreateOutput(); // create xSource and pOutput if not already done
1008 return pOutput->GetPivotData( rTarget, rFilters );
1011 BOOL ScDPObject::IsFilterButton( const ScAddress& rPos )
1013 CreateOutput(); // create xSource and pOutput if not already done
1015 return pOutput->IsFilterButton( rPos );
1018 long ScDPObject::GetHeaderDim( const ScAddress& rPos, USHORT& rOrient )
1020 CreateOutput(); // create xSource and pOutput if not already done
1022 return pOutput->GetHeaderDim( rPos, rOrient );
1025 BOOL ScDPObject::GetHeaderDrag( const ScAddress& rPos, BOOL bMouseLeft, BOOL bMouseTop, long nDragDim,
1026 Rectangle& rPosRect, USHORT& rOrient, long& rDimPos )
1028 CreateOutput(); // create xSource and pOutput if not already done
1030 return pOutput->GetHeaderDrag( rPos, bMouseLeft, bMouseTop, nDragDim, rPosRect, rOrient, rDimPos );
1033 void ScDPObject::GetMemberResultNames( ScStrCollection& rNames, long nDimension )
1035 CreateOutput(); // create xSource and pOutput if not already done
1037 pOutput->GetMemberResultNames( rNames, nDimension ); // used only with table data -> level not needed
1040 bool lcl_Dequote( const String& rSource, xub_StrLen nStartPos, xub_StrLen& rEndPos, String& rResult )
1042 // nStartPos has to point to opening quote
1044 bool bRet = false;
1045 const sal_Unicode cQuote = '\'';
1047 if ( rSource.GetChar(nStartPos) == cQuote )
1049 rtl::OUStringBuffer aBuffer;
1050 xub_StrLen nPos = nStartPos + 1;
1051 const xub_StrLen nLen = rSource.Len();
1053 while ( nPos < nLen )
1055 const sal_Unicode cNext = rSource.GetChar(nPos);
1056 if ( cNext == cQuote )
1058 if ( nPos+1 < nLen && rSource.GetChar(nPos+1) == cQuote )
1060 // double quote is used for an embedded quote
1061 aBuffer.append( cNext ); // append one quote
1062 ++nPos; // skip the next one
1064 else
1066 // end of quoted string
1067 rResult = aBuffer.makeStringAndClear();
1068 rEndPos = nPos + 1; // behind closing quote
1069 return true;
1072 else
1073 aBuffer.append( cNext );
1075 ++nPos;
1077 // no closing quote before the end of the string -> error (bRet still false)
1080 return bRet;
1083 struct ScGetPivotDataFunctionEntry
1085 const sal_Char* pName;
1086 sheet::GeneralFunction eFunc;
1089 bool lcl_ParseFunction( const String& rList, xub_StrLen nStartPos, xub_StrLen& rEndPos, sheet::GeneralFunction& rFunc )
1091 static const ScGetPivotDataFunctionEntry aFunctions[] =
1093 // our names
1094 { "Sum", sheet::GeneralFunction_SUM },
1095 { "Count", sheet::GeneralFunction_COUNT },
1096 { "Average", sheet::GeneralFunction_AVERAGE },
1097 { "Max", sheet::GeneralFunction_MAX },
1098 { "Min", sheet::GeneralFunction_MIN },
1099 { "Product", sheet::GeneralFunction_PRODUCT },
1100 { "CountNums", sheet::GeneralFunction_COUNTNUMS },
1101 { "StDev", sheet::GeneralFunction_STDEV },
1102 { "StDevp", sheet::GeneralFunction_STDEVP },
1103 { "Var", sheet::GeneralFunction_VAR },
1104 { "VarP", sheet::GeneralFunction_VARP },
1105 // compatibility names
1106 { "Count Nums", sheet::GeneralFunction_COUNTNUMS },
1107 { "StdDev", sheet::GeneralFunction_STDEV },
1108 { "StdDevp", sheet::GeneralFunction_STDEVP }
1111 const xub_StrLen nListLen = rList.Len();
1112 while ( nStartPos < nListLen && rList.GetChar(nStartPos) == ' ' )
1113 ++nStartPos;
1115 bool bParsed = false;
1116 bool bFound = false;
1117 String aFuncStr;
1118 xub_StrLen nFuncEnd = 0;
1119 if ( nStartPos < nListLen && rList.GetChar(nStartPos) == '\'' )
1120 bParsed = lcl_Dequote( rList, nStartPos, nFuncEnd, aFuncStr );
1121 else
1123 nFuncEnd = rList.Search( static_cast<sal_Unicode>(']'), nStartPos );
1124 if ( nFuncEnd != STRING_NOTFOUND )
1126 aFuncStr = rList.Copy( nStartPos, nFuncEnd - nStartPos );
1127 bParsed = true;
1131 if ( bParsed )
1133 aFuncStr.EraseLeadingAndTrailingChars( ' ' );
1135 const sal_Int32 nFuncCount = sizeof(aFunctions) / sizeof(aFunctions[0]);
1136 for ( sal_Int32 nFunc=0; nFunc<nFuncCount && !bFound; nFunc++ )
1138 if ( aFuncStr.EqualsIgnoreCaseAscii( aFunctions[nFunc].pName ) )
1140 rFunc = aFunctions[nFunc].eFunc;
1141 bFound = true;
1143 while ( nFuncEnd < nListLen && rList.GetChar(nFuncEnd) == ' ' )
1144 ++nFuncEnd;
1145 rEndPos = nFuncEnd;
1150 return bFound;
1153 bool lcl_IsAtStart( const String& rList, const String& rSearch, sal_Int32& rMatched,
1154 bool bAllowBracket, sheet::GeneralFunction* pFunc )
1156 sal_Int32 nMatchList = 0;
1157 sal_Int32 nMatchSearch = 0;
1158 sal_Unicode cFirst = rList.GetChar(0);
1159 if ( cFirst == '\'' || cFirst == '[' )
1161 // quoted string or string in brackets must match completely
1163 String aDequoted;
1164 xub_StrLen nQuoteEnd = 0;
1165 bool bParsed = false;
1167 if ( cFirst == '\'' )
1168 bParsed = lcl_Dequote( rList, 0, nQuoteEnd, aDequoted );
1169 else if ( cFirst == '[' )
1171 // skip spaces after the opening bracket
1173 xub_StrLen nStartPos = 1;
1174 const xub_StrLen nListLen = rList.Len();
1175 while ( nStartPos < nListLen && rList.GetChar(nStartPos) == ' ' )
1176 ++nStartPos;
1178 if ( rList.GetChar(nStartPos) == '\'' ) // quoted within the brackets?
1180 if ( lcl_Dequote( rList, nStartPos, nQuoteEnd, aDequoted ) )
1182 // after the quoted string, there must be the closing bracket, optionally preceded by spaces,
1183 // and/or a function name
1184 while ( nQuoteEnd < nListLen && rList.GetChar(nQuoteEnd) == ' ' )
1185 ++nQuoteEnd;
1187 // semicolon separates function name
1188 if ( nQuoteEnd < nListLen && rList.GetChar(nQuoteEnd) == ';' && pFunc )
1190 xub_StrLen nFuncEnd = 0;
1191 if ( lcl_ParseFunction( rList, nQuoteEnd + 1, nFuncEnd, *pFunc ) )
1192 nQuoteEnd = nFuncEnd;
1194 if ( nQuoteEnd < nListLen && rList.GetChar(nQuoteEnd) == ']' )
1196 ++nQuoteEnd; // include the closing bracket for the matched length
1197 bParsed = true;
1201 else
1203 // implicit quoting to the closing bracket
1205 xub_StrLen nClosePos = rList.Search( static_cast<sal_Unicode>(']'), nStartPos );
1206 if ( nClosePos != STRING_NOTFOUND )
1208 xub_StrLen nNameEnd = nClosePos;
1209 xub_StrLen nSemiPos = rList.Search( static_cast<sal_Unicode>(';'), nStartPos );
1210 if ( nSemiPos != STRING_NOTFOUND && nSemiPos < nClosePos && pFunc )
1212 xub_StrLen nFuncEnd = 0;
1213 if ( lcl_ParseFunction( rList, nSemiPos + 1, nFuncEnd, *pFunc ) )
1214 nNameEnd = nSemiPos;
1217 aDequoted = rList.Copy( nStartPos, nNameEnd - nStartPos );
1218 aDequoted.EraseTrailingChars( ' ' ); // spaces before the closing bracket or semicolon
1219 nQuoteEnd = nClosePos + 1;
1220 bParsed = true;
1225 if ( bParsed && ScGlobal::GetpTransliteration()->isEqual( aDequoted, rSearch ) )
1227 nMatchList = nQuoteEnd; // match count in the list string, including quotes
1228 nMatchSearch = rSearch.Len();
1231 else
1233 // otherwise look for search string at the start of rList
1234 ScGlobal::GetpTransliteration()->equals( rList, 0, rList.Len(), nMatchList,
1235 rSearch, 0, rSearch.Len(), nMatchSearch );
1238 if ( nMatchSearch == rSearch.Len() )
1240 // search string is at start of rList - look for following space or end of string
1242 bool bValid = false;
1243 if ( sal::static_int_cast<xub_StrLen>(nMatchList) >= rList.Len() )
1244 bValid = true;
1245 else
1247 sal_Unicode cNext = rList.GetChar(sal::static_int_cast<xub_StrLen>(nMatchList));
1248 if ( cNext == ' ' || ( bAllowBracket && cNext == '[' ) )
1249 bValid = true;
1252 if ( bValid )
1254 rMatched = nMatchList;
1255 return true;
1259 return false;
1262 BOOL ScDPObject::ParseFilters( ScDPGetPivotDataField& rTarget,
1263 std::vector< ScDPGetPivotDataField >& rFilters,
1264 const String& rFilterList )
1266 // parse the string rFilterList into parameters for GetPivotData
1268 CreateObjects(); // create xSource if not already done
1270 std::vector<String> aDataNames; // data fields (source name)
1271 std::vector<String> aGivenNames; // data fields (compound name)
1272 std::vector<String> aFieldNames; // column/row/data fields
1273 std::vector< uno::Sequence<rtl::OUString> > aFieldValues;
1276 // get all the field and item names
1279 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1280 uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
1281 sal_Int32 nDimCount = xIntDims->getCount();
1282 for ( sal_Int32 nDim = 0; nDim<nDimCount; nDim++ )
1284 uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nDim) );
1285 uno::Reference<container::XNamed> xDim( xIntDim, uno::UNO_QUERY );
1286 uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
1287 uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDim, uno::UNO_QUERY );
1288 BOOL bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1289 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
1290 sal_Int32 nOrient = ScUnoHelpFunctions::GetEnumProperty(
1291 xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION),
1292 sheet::DataPilotFieldOrientation_HIDDEN );
1293 if ( !bDataLayout )
1295 if ( nOrient == sheet::DataPilotFieldOrientation_DATA )
1297 String aSourceName;
1298 String aGivenName;
1299 ScDPOutput::GetDataDimensionNames( aSourceName, aGivenName, xIntDim );
1300 aDataNames.push_back( aSourceName );
1301 aGivenNames.push_back( aGivenName );
1303 else if ( nOrient != sheet::DataPilotFieldOrientation_HIDDEN )
1305 // get level names, as in ScDPOutput
1307 uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
1308 sal_Int32 nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
1309 rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
1310 if ( nHierarchy >= xHiers->getCount() )
1311 nHierarchy = 0;
1313 uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
1314 xHiers->getByIndex(nHierarchy) );
1315 uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
1316 if ( xHierSupp.is() )
1318 uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
1319 sal_Int32 nLevCount = xLevels->getCount();
1320 for (sal_Int32 nLev=0; nLev<nLevCount; nLev++)
1322 uno::Reference<uno::XInterface> xLevel = ScUnoHelpFunctions::AnyToInterface(
1323 xLevels->getByIndex(nLev) );
1324 uno::Reference<container::XNamed> xLevNam( xLevel, uno::UNO_QUERY );
1325 uno::Reference<sheet::XMembersSupplier> xLevSupp( xLevel, uno::UNO_QUERY );
1326 if ( xLevNam.is() && xLevSupp.is() )
1328 uno::Reference<container::XNameAccess> xMembers = xLevSupp->getMembers();
1330 String aFieldName( xLevNam->getName() );
1331 uno::Sequence<rtl::OUString> aMemberNames( xMembers->getElementNames() );
1333 aFieldNames.push_back( aFieldName );
1334 aFieldValues.push_back( aMemberNames );
1343 // compare and build filters
1346 SCSIZE nDataFields = aDataNames.size();
1347 SCSIZE nFieldCount = aFieldNames.size();
1348 DBG_ASSERT( aGivenNames.size() == nDataFields && aFieldValues.size() == nFieldCount, "wrong count" );
1350 bool bError = false;
1351 bool bHasData = false;
1352 String aRemaining( rFilterList );
1353 aRemaining.EraseLeadingAndTrailingChars( ' ' );
1354 while ( aRemaining.Len() && !bError )
1356 bool bUsed = false;
1358 // look for data field name
1360 for ( SCSIZE nDataPos=0; nDataPos<nDataFields && !bUsed; nDataPos++ )
1362 String aFound;
1363 sal_Int32 nMatched = 0;
1364 if ( lcl_IsAtStart( aRemaining, aDataNames[nDataPos], nMatched, false, NULL ) )
1365 aFound = aDataNames[nDataPos];
1366 else if ( lcl_IsAtStart( aRemaining, aGivenNames[nDataPos], nMatched, false, NULL ) )
1367 aFound = aGivenNames[nDataPos];
1369 if ( aFound.Len() )
1371 rTarget.maFieldName = aFound;
1372 aRemaining.Erase( 0, sal::static_int_cast<xub_StrLen>(nMatched) );
1373 bHasData = true;
1374 bUsed = true;
1378 // look for field name
1380 String aSpecField;
1381 bool bHasFieldName = false;
1382 if ( !bUsed )
1384 sal_Int32 nMatched = 0;
1385 for ( SCSIZE nField=0; nField<nFieldCount && !bHasFieldName; nField++ )
1387 if ( lcl_IsAtStart( aRemaining, aFieldNames[nField], nMatched, true, NULL ) )
1389 aSpecField = aFieldNames[nField];
1390 aRemaining.Erase( 0, sal::static_int_cast<xub_StrLen>(nMatched) );
1391 aRemaining.EraseLeadingChars( ' ' );
1393 // field name has to be followed by item name in brackets
1394 if ( aRemaining.GetChar(0) == '[' )
1396 bHasFieldName = true;
1397 // bUsed remains false - still need the item
1399 else
1401 bUsed = true;
1402 bError = true;
1408 // look for field item
1410 if ( !bUsed )
1412 bool bItemFound = false;
1413 sal_Int32 nMatched = 0;
1414 String aFoundName;
1415 String aFoundValue;
1416 sheet::GeneralFunction eFunc = sheet::GeneralFunction_NONE;
1417 sheet::GeneralFunction eFoundFunc = sheet::GeneralFunction_NONE;
1419 for ( SCSIZE nField=0; nField<nFieldCount; nField++ )
1421 // If a field name is given, look in that field only, otherwise in all fields.
1422 // aSpecField is initialized from aFieldNames array, so exact comparison can be used.
1423 if ( !bHasFieldName || aFieldNames[nField] == aSpecField )
1425 const uno::Sequence<rtl::OUString>& rItems = aFieldValues[nField];
1426 sal_Int32 nItemCount = rItems.getLength();
1427 const rtl::OUString* pItemArr = rItems.getConstArray();
1428 for ( sal_Int32 nItem=0; nItem<nItemCount; nItem++ )
1430 if ( lcl_IsAtStart( aRemaining, pItemArr[nItem], nMatched, false, &eFunc ) )
1432 if ( bItemFound )
1433 bError = true; // duplicate (also across fields)
1434 else
1436 aFoundName = aFieldNames[nField];
1437 aFoundValue = pItemArr[nItem];
1438 eFoundFunc = eFunc;
1439 bItemFound = true;
1440 bUsed = true;
1447 if ( bItemFound && !bError )
1449 ScDPGetPivotDataField aField;
1450 aField.maFieldName = aFoundName;
1451 aField.meFunction = eFoundFunc;
1452 aField.mbValIsStr = true;
1453 aField.maValStr = aFoundValue;
1454 aField.mnValNum = 0.0;
1455 rFilters.push_back( aField );
1457 aRemaining.Erase( 0, sal::static_int_cast<xub_StrLen>(nMatched) );
1461 if ( !bUsed )
1462 bError = true;
1464 aRemaining.EraseLeadingChars( ' ' ); // remove any number of spaces between entries
1467 if ( !bError && !bHasData && aDataNames.size() == 1 )
1469 // if there's only one data field, its name need not be specified
1470 rTarget.maFieldName = aDataNames[0];
1471 bHasData = true;
1474 return bHasData && !bError;
1477 void ScDPObject::ToggleDetails(const DataPilotTableHeaderData& rElemDesc, ScDPObject* pDestObj)
1479 CreateObjects(); // create xSource if not already done
1481 // find dimension name
1483 uno::Reference<container::XNamed> xDim;
1484 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1485 uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
1486 long nIntCount = xIntDims->getCount();
1487 if ( rElemDesc.Dimension < nIntCount )
1489 uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface(
1490 xIntDims->getByIndex(rElemDesc.Dimension) );
1491 xDim = uno::Reference<container::XNamed>( xIntDim, uno::UNO_QUERY );
1493 DBG_ASSERT( xDim.is(), "dimension not found" );
1494 if ( !xDim.is() ) return;
1495 String aDimName = xDim->getName();
1497 uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
1498 BOOL bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1499 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
1500 if (bDataLayout)
1502 // the elements of the data layout dimension can't be found by their names
1503 // -> don't change anything
1504 return;
1507 // query old state
1509 long nHierCount = 0;
1510 uno::Reference<container::XIndexAccess> xHiers;
1511 uno::Reference<sheet::XHierarchiesSupplier> xHierSupp( xDim, uno::UNO_QUERY );
1512 if ( xHierSupp.is() )
1514 uno::Reference<container::XNameAccess> xHiersName = xHierSupp->getHierarchies();
1515 xHiers = new ScNameToIndexAccess( xHiersName );
1516 nHierCount = xHiers->getCount();
1518 uno::Reference<uno::XInterface> xHier;
1519 if ( rElemDesc.Hierarchy < nHierCount )
1520 xHier = ScUnoHelpFunctions::AnyToInterface( xHiers->getByIndex(rElemDesc.Hierarchy) );
1521 DBG_ASSERT( xHier.is(), "hierarchy not found" );
1522 if ( !xHier.is() ) return;
1524 long nLevCount = 0;
1525 uno::Reference<container::XIndexAccess> xLevels;
1526 uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHier, uno::UNO_QUERY );
1527 if ( xLevSupp.is() )
1529 uno::Reference<container::XNameAccess> xLevsName = xLevSupp->getLevels();
1530 xLevels = new ScNameToIndexAccess( xLevsName );
1531 nLevCount = xLevels->getCount();
1533 uno::Reference<uno::XInterface> xLevel;
1534 if ( rElemDesc.Level < nLevCount )
1535 xLevel = ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex(rElemDesc.Level) );
1536 DBG_ASSERT( xLevel.is(), "level not found" );
1537 if ( !xLevel.is() ) return;
1539 uno::Reference<container::XNameAccess> xMembers;
1540 uno::Reference<sheet::XMembersSupplier> xMbrSupp( xLevel, uno::UNO_QUERY );
1541 if ( xMbrSupp.is() )
1542 xMembers = xMbrSupp->getMembers();
1544 BOOL bFound = FALSE;
1545 BOOL bShowDetails = TRUE;
1547 if ( xMembers.is() )
1549 if ( xMembers->hasByName(rElemDesc.MemberName) )
1551 uno::Reference<uno::XInterface> xMemberInt = ScUnoHelpFunctions::AnyToInterface(
1552 xMembers->getByName(rElemDesc.MemberName) );
1553 uno::Reference<beans::XPropertySet> xMbrProp( xMemberInt, uno::UNO_QUERY );
1554 if ( xMbrProp.is() )
1556 bShowDetails = ScUnoHelpFunctions::GetBoolProperty( xMbrProp,
1557 rtl::OUString::createFromAscii(DP_PROP_SHOWDETAILS) );
1558 //! don't set bFound if property is unknown?
1559 bFound = TRUE;
1564 DBG_ASSERT( bFound, "member not found" );
1566 //! use Hierarchy and Level in SaveData !!!!
1568 // modify pDestObj if set, this object otherwise
1569 ScDPSaveData* pModifyData = pDestObj ? ( pDestObj->pSaveData ) : pSaveData;
1570 DBG_ASSERT( pModifyData, "no data?" );
1571 if ( pModifyData )
1573 const String aName = rElemDesc.MemberName;
1574 pModifyData->GetDimensionByName(aDimName)->
1575 GetMemberByName(aName)->SetShowDetails( !bShowDetails ); // toggle
1577 if ( pDestObj )
1578 pDestObj->InvalidateData(); // re-init source from SaveData
1579 else
1580 InvalidateData(); // re-init source from SaveData
1584 long lcl_FindName( const rtl::OUString& rString, const uno::Reference<container::XNameAccess>& xCollection )
1586 if ( xCollection.is() )
1588 uno::Sequence<rtl::OUString> aSeq = xCollection->getElementNames();
1589 long nCount = aSeq.getLength();
1590 const rtl::OUString* pArr = aSeq.getConstArray();
1591 for (long nPos=0; nPos<nCount; nPos++)
1592 if ( pArr[nPos] == rString )
1593 return nPos;
1595 return -1; // not found
1598 USHORT lcl_FirstSubTotal( const uno::Reference<beans::XPropertySet>& xDimProp ) // PIVOT_FUNC mask
1600 uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDimProp, uno::UNO_QUERY );
1601 if ( xDimProp.is() && xDimSupp.is() )
1603 uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
1604 long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
1605 rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
1606 if ( nHierarchy >= xHiers->getCount() )
1607 nHierarchy = 0;
1609 uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
1610 xHiers->getByIndex(nHierarchy) );
1611 uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
1612 if ( xHierSupp.is() )
1614 uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
1615 uno::Reference<uno::XInterface> xLevel =
1616 ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex( 0 ) );
1617 uno::Reference<beans::XPropertySet> xLevProp( xLevel, uno::UNO_QUERY );
1618 if ( xLevProp.is() )
1620 uno::Any aSubAny;
1623 aSubAny = xLevProp->getPropertyValue(
1624 rtl::OUString::createFromAscii(DP_PROP_SUBTOTALS) );
1626 catch(uno::Exception&)
1629 uno::Sequence<sheet::GeneralFunction> aSeq;
1630 if ( aSubAny >>= aSeq )
1632 USHORT nMask = 0;
1633 const sheet::GeneralFunction* pArray = aSeq.getConstArray();
1634 long nCount = aSeq.getLength();
1635 for (long i=0; i<nCount; i++)
1636 nMask |= ScDataPilotConversion::FunctionBit(pArray[i]);
1637 return nMask;
1643 DBG_ERROR("FirstSubTotal: NULL");
1644 return 0;
1647 USHORT lcl_CountBits( USHORT nBits )
1649 if (!nBits) return 0;
1651 USHORT nCount = 0;
1652 USHORT nMask = 1;
1653 for (USHORT i=0; i<16; i++)
1655 if ( nBits & nMask )
1656 ++nCount;
1657 nMask <<= 1;
1659 return nCount;
1662 SCSIZE lcl_FillOldFields( PivotField* pFields,
1663 const uno::Reference<sheet::XDimensionsSupplier>& xSource,
1664 USHORT nOrient, SCCOL nColAdd, BOOL bAddData )
1666 SCSIZE nOutCount = 0;
1667 BOOL bDataFound = FALSE;
1669 SCSIZE nCount = (nOrient == sheet::DataPilotFieldOrientation_PAGE) ? PIVOT_MAXPAGEFIELD : PIVOT_MAXFIELD;
1671 //! merge multiple occurences (data field with different functions)
1672 //! force data field in one dimension
1674 std::vector< long > aPos( nCount, 0 );
1676 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1677 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
1678 long nDimCount = xDims->getCount();
1679 for (long nDim=0; nDim < nDimCount && nOutCount < nCount; nDim++)
1681 uno::Reference<uno::XInterface> xIntDim =
1682 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
1683 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
1684 long nDimOrient = ScUnoHelpFunctions::GetEnumProperty(
1685 xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION),
1686 sheet::DataPilotFieldOrientation_HIDDEN );
1687 if ( xDimProp.is() && nDimOrient == nOrient )
1689 USHORT nMask = 0;
1690 if ( nOrient == sheet::DataPilotFieldOrientation_DATA )
1692 sheet::GeneralFunction eFunc = (sheet::GeneralFunction)ScUnoHelpFunctions::GetEnumProperty(
1693 xDimProp, rtl::OUString::createFromAscii(DP_PROP_FUNCTION),
1694 sheet::GeneralFunction_NONE );
1695 if ( eFunc == sheet::GeneralFunction_AUTO )
1697 //! test for numeric data
1698 eFunc = sheet::GeneralFunction_SUM;
1700 nMask = ScDataPilotConversion::FunctionBit(eFunc);
1702 else
1703 nMask = lcl_FirstSubTotal( xDimProp ); // from first hierarchy
1705 BOOL bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1706 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
1707 uno::Any aOrigAny;
1710 aOrigAny = xDimProp->getPropertyValue(
1711 rtl::OUString::createFromAscii(DP_PROP_ORIGINAL) );
1713 catch(uno::Exception&)
1717 long nDupSource = -1;
1718 uno::Reference<uno::XInterface> xIntOrig = ScUnoHelpFunctions::AnyToInterface( aOrigAny );
1719 if ( xIntOrig.is() )
1721 uno::Reference<container::XNamed> xNameOrig( xIntOrig, uno::UNO_QUERY );
1722 if ( xNameOrig.is() )
1723 nDupSource = lcl_FindName( xNameOrig->getName(), xDimsName );
1726 BOOL bDupUsed = FALSE;
1727 if ( nDupSource >= 0 )
1729 // add function bit to previous entry
1731 SCsCOL nCompCol;
1732 if ( bDataLayout )
1733 nCompCol = PIVOT_DATA_FIELD;
1734 else
1735 nCompCol = static_cast<SCsCOL>(nDupSource)+nColAdd; //! seek source column from name
1737 for (SCSIZE nOld=0; nOld<nOutCount && !bDupUsed; nOld++)
1738 if ( pFields[nOld].nCol == nCompCol )
1740 // add to previous column only if new bits aren't already set there
1741 if ( ( pFields[nOld].nFuncMask & nMask ) == 0 )
1743 pFields[nOld].nFuncMask |= nMask;
1744 pFields[nOld].nFuncCount = lcl_CountBits( pFields[nOld].nFuncMask );
1745 bDupUsed = TRUE;
1750 if ( !bDupUsed ) // also for duplicated dim if original has different orientation
1752 if ( bDataLayout )
1754 pFields[nOutCount].nCol = PIVOT_DATA_FIELD;
1755 bDataFound = TRUE;
1757 else if ( nDupSource >= 0 ) // if source was not found (different orientation)
1758 pFields[nOutCount].nCol = static_cast<SCsCOL>(nDupSource)+nColAdd; //! seek from name
1759 else
1760 pFields[nOutCount].nCol = static_cast<SCsCOL>(nDim)+nColAdd; //! seek source column from name
1762 pFields[nOutCount].nFuncMask = nMask;
1763 pFields[nOutCount].nFuncCount = lcl_CountBits( nMask );
1764 aPos[nOutCount] = ScUnoHelpFunctions::GetLongProperty( xDimProp,
1765 rtl::OUString::createFromAscii(DP_PROP_POSITION) );
1769 if( nOrient == sheet::DataPilotFieldOrientation_DATA )
1770 xDimProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_REFVALUE ) ) )
1771 >>= pFields[nOutCount].maFieldRef;
1773 catch( uno::Exception& )
1777 ++nOutCount;
1782 // sort by getPosition() value
1784 for (SCSIZE i=0; i+1<nOutCount; i++)
1786 for (SCSIZE j=0; j+i+1<nOutCount; j++)
1787 if ( aPos[j+1] < aPos[j] )
1789 std::swap( aPos[j], aPos[j+1] );
1790 std::swap( pFields[j], pFields[j+1] );
1794 if ( bAddData && !bDataFound )
1796 if ( nOutCount >= nCount ) // space for data field?
1797 --nOutCount; //! error?
1798 pFields[nOutCount].nCol = PIVOT_DATA_FIELD;
1799 pFields[nOutCount].nFuncMask = 0;
1800 pFields[nOutCount].nFuncCount = 0;
1801 ++nOutCount;
1804 return nOutCount;
1807 BOOL ScDPObject::FillOldParam(ScPivotParam& rParam, BOOL bForFile) const
1809 ((ScDPObject*)this)->CreateObjects(); // xSource is needed for field numbers
1811 rParam.nCol = aOutRange.aStart.Col();
1812 rParam.nRow = aOutRange.aStart.Row();
1813 rParam.nTab = aOutRange.aStart.Tab();
1814 // ppLabelArr / nLabels is not changed
1816 SCCOL nColAdd = 0;
1817 if ( bForFile )
1819 // in old file format, columns are within document, not within source range
1821 DBG_ASSERT( pSheetDesc, "FillOldParam: bForFile, !pSheetDesc" );
1822 nColAdd = pSheetDesc->aSourceRange.aStart.Col();
1825 BOOL bAddData = ( lcl_GetDataGetOrientation( xSource ) == sheet::DataPilotFieldOrientation_HIDDEN );
1826 rParam.nPageCount = lcl_FillOldFields( rParam.aPageArr,
1827 xSource, sheet::DataPilotFieldOrientation_PAGE, nColAdd, FALSE );
1828 rParam.nColCount = lcl_FillOldFields( rParam.aColArr,
1829 xSource, sheet::DataPilotFieldOrientation_COLUMN, nColAdd, bAddData );
1830 rParam.nRowCount = lcl_FillOldFields( rParam.aRowArr,
1831 xSource, sheet::DataPilotFieldOrientation_ROW, nColAdd, FALSE );
1832 rParam.nDataCount = lcl_FillOldFields( rParam.aDataArr,
1833 xSource, sheet::DataPilotFieldOrientation_DATA, nColAdd, FALSE );
1835 uno::Reference<beans::XPropertySet> xProp( xSource, uno::UNO_QUERY );
1836 if (xProp.is())
1840 rParam.bMakeTotalCol = ScUnoHelpFunctions::GetBoolProperty( xProp,
1841 rtl::OUString::createFromAscii(DP_PROP_COLUMNGRAND), TRUE );
1842 rParam.bMakeTotalRow = ScUnoHelpFunctions::GetBoolProperty( xProp,
1843 rtl::OUString::createFromAscii(DP_PROP_ROWGRAND), TRUE );
1845 // following properties may be missing for external sources
1846 rParam.bIgnoreEmptyRows = ScUnoHelpFunctions::GetBoolProperty( xProp,
1847 rtl::OUString::createFromAscii(DP_PROP_IGNOREEMPTY) );
1848 rParam.bDetectCategories = ScUnoHelpFunctions::GetBoolProperty( xProp,
1849 rtl::OUString::createFromAscii(DP_PROP_REPEATIFEMPTY) );
1851 catch(uno::Exception&)
1853 // no error
1856 return TRUE;
1859 void lcl_FillLabelData( ScDPLabelData& rData, const uno::Reference< beans::XPropertySet >& xDimProp )
1861 uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDimProp, uno::UNO_QUERY );
1862 if ( xDimProp.is() && xDimSupp.is() )
1864 uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
1865 long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
1866 rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
1867 if ( nHierarchy >= xHiers->getCount() )
1868 nHierarchy = 0;
1869 rData.mnUsedHier = nHierarchy;
1871 uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
1872 xHiers->getByIndex(nHierarchy) );
1874 uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
1875 if ( xHierSupp.is() )
1877 uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
1878 uno::Reference<uno::XInterface> xLevel =
1879 ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex( 0 ) );
1880 uno::Reference<beans::XPropertySet> xLevProp( xLevel, uno::UNO_QUERY );
1881 if ( xLevProp.is() )
1883 rData.mbShowAll = ScUnoHelpFunctions::GetBoolProperty( xLevProp,
1884 rtl::OUString::createFromAscii(DP_PROP_SHOWEMPTY) );
1888 xLevProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_SORTING ) ) )
1889 >>= rData.maSortInfo;
1890 xLevProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_LAYOUT ) ) )
1891 >>= rData.maLayoutInfo;
1892 xLevProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_AUTOSHOW ) ) )
1893 >>= rData.maShowInfo;
1895 catch(uno::Exception&)
1903 BOOL ScDPObject::FillLabelData(ScPivotParam& rParam)
1905 rParam.maLabelArray.clear();
1907 ((ScDPObject*)this)->CreateObjects();
1909 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1910 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
1911 long nDimCount = xDims->getCount();
1912 if ( nDimCount > MAX_LABELS )
1913 nDimCount = MAX_LABELS;
1914 if (!nDimCount)
1915 return FALSE;
1917 for (long nDim=0; nDim < nDimCount; nDim++)
1919 String aFieldName;
1920 uno::Reference<uno::XInterface> xIntDim =
1921 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
1922 uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
1923 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
1925 if ( xDimName.is() && xDimProp.is() )
1927 BOOL bDuplicated = FALSE;
1928 BOOL bData = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1929 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
1930 //! error checking -- is "IsDataLayoutDimension" property required??
1934 aFieldName = String( xDimName->getName() );
1936 uno::Any aOrigAny = xDimProp->getPropertyValue(
1937 rtl::OUString::createFromAscii(DP_PROP_ORIGINAL) );
1938 uno::Reference<uno::XInterface> xIntOrig;
1939 if ( (aOrigAny >>= xIntOrig) && xIntOrig.is() )
1940 bDuplicated = TRUE;
1942 catch(uno::Exception&)
1946 OUString aLayoutName = ScUnoHelpFunctions::GetStringProperty(
1947 xDimProp, OUString::createFromAscii(SC_UNO_LAYOUTNAME), OUString());
1949 if ( aFieldName.Len() && !bData && !bDuplicated )
1951 SCsCOL nCol = static_cast< SCsCOL >( nDim ); //! ???
1952 bool bIsValue = true; //! check
1954 ScDPLabelDataRef pNewLabel(new ScDPLabelData(aFieldName, nCol, bIsValue));
1955 pNewLabel->maLayoutName = aLayoutName;
1956 GetHierarchies(nDim, pNewLabel->maHiers);
1957 GetMembers(nDim, GetUsedHierarchy(nDim), pNewLabel->maMembers);
1958 lcl_FillLabelData(*pNewLabel, xDimProp);
1959 rParam.maLabelArray.push_back(pNewLabel);
1964 return TRUE;
1967 BOOL ScDPObject::GetHierarchiesNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xHiers )
1969 BOOL bRet = FALSE;
1970 uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
1971 uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
1972 if( xIntDims.is() )
1974 uno::Reference<sheet::XHierarchiesSupplier> xHierSup(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
1975 if (xHierSup.is())
1977 xHiers.set( xHierSup->getHierarchies() );
1978 bRet = xHiers.is();
1981 return bRet;
1984 BOOL ScDPObject::GetHierarchies( sal_Int32 nDim, uno::Sequence< rtl::OUString >& rHiers )
1986 BOOL bRet = FALSE;
1987 uno::Reference< container::XNameAccess > xHiersNA;
1988 if( GetHierarchiesNA( nDim, xHiersNA ) )
1990 rHiers = xHiersNA->getElementNames();
1991 bRet = TRUE;
1993 return bRet;
1996 sal_Int32 ScDPObject::GetUsedHierarchy( sal_Int32 nDim )
1998 sal_Int32 nHier = 0;
1999 uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
2000 uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
2001 uno::Reference<beans::XPropertySet> xDim(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
2002 if (xDim.is())
2003 nHier = ScUnoHelpFunctions::GetLongProperty( xDim, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( SC_UNO_USEDHIER ) ) );
2004 return nHier;
2007 BOOL ScDPObject::GetMembersNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xMembers )
2009 return GetMembersNA( nDim, GetUsedHierarchy( nDim ), xMembers );
2012 BOOL ScDPObject::GetMembersNA( sal_Int32 nDim, sal_Int32 nHier, uno::Reference< container::XNameAccess >& xMembers )
2014 BOOL bRet = FALSE;
2015 uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
2016 uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
2017 uno::Reference<beans::XPropertySet> xDim(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
2018 if (xDim.is())
2020 uno::Reference<sheet::XHierarchiesSupplier> xHierSup(xDim, uno::UNO_QUERY);
2021 if (xHierSup.is())
2023 uno::Reference<container::XIndexAccess> xHiers(new ScNameToIndexAccess(xHierSup->getHierarchies()));
2024 uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHiers->getByIndex(nHier), uno::UNO_QUERY );
2025 if ( xLevSupp.is() )
2027 uno::Reference<container::XIndexAccess> xLevels(new ScNameToIndexAccess( xLevSupp->getLevels()));
2028 if (xLevels.is())
2030 sal_Int32 nLevCount = xLevels->getCount();
2031 if (nLevCount > 0)
2033 uno::Reference<sheet::XMembersSupplier> xMembSupp( xLevels->getByIndex(0), uno::UNO_QUERY );
2034 if ( xMembSupp.is() )
2036 xMembers.set(xMembSupp->getMembers());
2037 bRet = TRUE;
2044 return bRet;
2047 //------------------------------------------------------------------------
2048 // convert old pivot tables into new datapilot tables
2050 String lcl_GetDimName( const uno::Reference<sheet::XDimensionsSupplier>& xSource, long nDim )
2052 rtl::OUString aName;
2053 if ( xSource.is() )
2055 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
2056 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
2057 long nDimCount = xDims->getCount();
2058 if ( nDim < nDimCount )
2060 uno::Reference<uno::XInterface> xIntDim =
2061 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
2062 uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
2063 if (xDimName.is())
2067 aName = xDimName->getName();
2069 catch(uno::Exception&)
2075 return aName;
2078 // static
2079 void ScDPObject::ConvertOrientation( ScDPSaveData& rSaveData,
2080 PivotField* pFields, SCSIZE nCount, USHORT nOrient,
2081 ScDocument* pDoc, SCROW nRow, SCTAB nTab,
2082 const uno::Reference<sheet::XDimensionsSupplier>& xSource,
2083 BOOL bOldDefaults,
2084 PivotField* pRefColFields, SCSIZE nRefColCount,
2085 PivotField* pRefRowFields, SCSIZE nRefRowCount,
2086 PivotField* pRefPageFields, SCSIZE nRefPageCount )
2088 // pDoc or xSource must be set
2089 DBG_ASSERT( pDoc || xSource.is(), "missing string source" );
2091 String aDocStr;
2092 ScDPSaveDimension* pDim;
2094 for (SCSIZE i=0; i<nCount; i++)
2096 SCCOL nCol = pFields[i].nCol;
2097 USHORT nFuncs = pFields[i].nFuncMask;
2098 const sheet::DataPilotFieldReference& rFieldRef = pFields[i].maFieldRef;
2100 if ( nCol == PIVOT_DATA_FIELD )
2101 pDim = rSaveData.GetDataLayoutDimension();
2102 else
2104 if ( pDoc )
2105 pDoc->GetString( nCol, nRow, nTab, aDocStr );
2106 else
2107 aDocStr = lcl_GetDimName( xSource, nCol ); // cols must start at 0
2109 if ( aDocStr.Len() )
2110 pDim = rSaveData.GetDimensionByName(aDocStr);
2111 else
2112 pDim = NULL;
2115 if ( pDim )
2117 if ( nOrient == sheet::DataPilotFieldOrientation_DATA ) // set summary function
2119 // generate an individual entry for each function
2120 BOOL bFirst = TRUE;
2122 // if a dimension is used for column/row/page and data,
2123 // use duplicated dimensions for all data occurrences
2124 if (pRefColFields)
2125 for (SCSIZE nRefCol=0; nRefCol<nRefColCount; nRefCol++)
2126 if (pRefColFields[nRefCol].nCol == nCol)
2127 bFirst = FALSE;
2128 if (pRefRowFields)
2129 for (SCSIZE nRefRow=0; nRefRow<nRefRowCount; nRefRow++)
2130 if (pRefRowFields[nRefRow].nCol == nCol)
2131 bFirst = FALSE;
2132 if (pRefPageFields)
2133 for (USHORT nRefPage=0; nRefPage<nRefPageCount; ++nRefPage)
2134 if (pRefPageFields[nRefPage].nCol == nCol)
2135 bFirst = FALSE;
2137 // if set via api, a data column may occur several times
2138 // (if the function hasn't been changed yet) -> also look for duplicate data column
2139 for (SCSIZE nPrevData=0; nPrevData<i; nPrevData++)
2140 if (pFields[nPrevData].nCol == nCol)
2141 bFirst = FALSE;
2143 USHORT nMask = 1;
2144 for (USHORT nBit=0; nBit<16; nBit++)
2146 if ( nFuncs & nMask )
2148 sheet::GeneralFunction eFunc = ScDataPilotConversion::FirstFunc( nMask );
2149 ScDPSaveDimension* pCurrDim = bFirst ? pDim : rSaveData.DuplicateDimension(pDim->GetName());
2150 pCurrDim->SetOrientation( nOrient );
2151 pCurrDim->SetFunction( sal::static_int_cast<USHORT>(eFunc) );
2153 if( rFieldRef.ReferenceType == sheet::DataPilotFieldReferenceType::NONE )
2154 pCurrDim->SetReferenceValue( 0 );
2155 else
2156 pCurrDim->SetReferenceValue( &rFieldRef );
2158 bFirst = FALSE;
2160 nMask *= 2;
2163 else // set SubTotals
2165 pDim->SetOrientation( nOrient );
2167 USHORT nFuncArray[16];
2168 USHORT nFuncCount = 0;
2169 USHORT nMask = 1;
2170 for (USHORT nBit=0; nBit<16; nBit++)
2172 if ( nFuncs & nMask )
2173 nFuncArray[nFuncCount++] = sal::static_int_cast<USHORT>(ScDataPilotConversion::FirstFunc( nMask ));
2174 nMask *= 2;
2176 pDim->SetSubTotals( nFuncCount, nFuncArray );
2178 // ShowEmpty was implicit in old tables,
2179 // must be set for data layout dimension (not accessible in dialog)
2180 if ( bOldDefaults || nCol == PIVOT_DATA_FIELD )
2181 pDim->SetShowEmpty( TRUE );
2187 // -----------------------------------------------------------------------
2189 // static
2190 BOOL ScDPObject::HasRegisteredSources()
2192 BOOL bFound = FALSE;
2194 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
2195 uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
2196 if ( xEnAc.is() )
2198 uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
2199 rtl::OUString::createFromAscii( SCDPSOURCE_SERVICE ) );
2200 if ( xEnum.is() && xEnum->hasMoreElements() )
2201 bFound = TRUE;
2204 return bFound;
2207 // static
2208 uno::Sequence<rtl::OUString> ScDPObject::GetRegisteredSources()
2210 long nCount = 0;
2211 uno::Sequence<rtl::OUString> aSeq(0);
2213 // use implementation names...
2215 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
2216 uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
2217 if ( xEnAc.is() )
2219 uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
2220 rtl::OUString::createFromAscii( SCDPSOURCE_SERVICE ) );
2221 if ( xEnum.is() )
2223 while ( xEnum->hasMoreElements() )
2225 uno::Any aAddInAny = xEnum->nextElement();
2226 // if ( aAddInAny.getReflection()->getTypeClass() == TypeClass_INTERFACE )
2228 uno::Reference<uno::XInterface> xIntFac;
2229 aAddInAny >>= xIntFac;
2230 if ( xIntFac.is() )
2232 uno::Reference<lang::XServiceInfo> xInfo( xIntFac, uno::UNO_QUERY );
2233 if ( xInfo.is() )
2235 rtl::OUString sName = xInfo->getImplementationName();
2237 aSeq.realloc( nCount+1 );
2238 aSeq.getArray()[nCount] = sName;
2239 ++nCount;
2247 return aSeq;
2250 // static
2251 uno::Reference<sheet::XDimensionsSupplier> ScDPObject::CreateSource( const ScDPServiceDesc& rDesc )
2253 rtl::OUString aImplName = rDesc.aServiceName;
2254 uno::Reference<sheet::XDimensionsSupplier> xRet = NULL;
2256 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
2257 uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
2258 if ( xEnAc.is() )
2260 uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
2261 rtl::OUString::createFromAscii( SCDPSOURCE_SERVICE ) );
2262 if ( xEnum.is() )
2264 while ( xEnum->hasMoreElements() && !xRet.is() )
2266 uno::Any aAddInAny = xEnum->nextElement();
2267 // if ( aAddInAny.getReflection()->getTypeClass() == TypeClass_INTERFACE )
2269 uno::Reference<uno::XInterface> xIntFac;
2270 aAddInAny >>= xIntFac;
2271 if ( xIntFac.is() )
2273 uno::Reference<lang::XServiceInfo> xInfo( xIntFac, uno::UNO_QUERY );
2274 uno::Reference<lang::XSingleServiceFactory> xFac( xIntFac, uno::UNO_QUERY );
2275 if ( xFac.is() && xInfo.is() && xInfo->getImplementationName() == aImplName )
2279 uno::Reference<uno::XInterface> xInterface = xFac->createInstance();
2280 uno::Reference<lang::XInitialization> xInit( xInterface, uno::UNO_QUERY );
2281 if (xInit.is())
2283 // initialize
2284 uno::Sequence<uno::Any> aSeq(4);
2285 uno::Any* pArray = aSeq.getArray();
2286 pArray[0] <<= rtl::OUString( rDesc.aParSource );
2287 pArray[1] <<= rtl::OUString( rDesc.aParName );
2288 pArray[2] <<= rtl::OUString( rDesc.aParUser );
2289 pArray[3] <<= rtl::OUString( rDesc.aParPass );
2290 xInit->initialize( aSeq );
2292 xRet = uno::Reference<sheet::XDimensionsSupplier>( xInterface, uno::UNO_QUERY );
2294 catch(uno::Exception&)
2304 return xRet;
2307 // ============================================================================
2309 ScDPCacheCell::ScDPCacheCell() :
2310 mnStrId(ScSimpleSharedString::EMPTY),
2311 mnType(SC_VALTYPE_EMPTY),
2312 mfValue(0.0),
2313 mbNumeric(false)
2317 ScDPCacheCell::ScDPCacheCell(const ScDPCacheCell& r) :
2318 mnStrId(r.mnStrId),
2319 mnType(r.mnType),
2320 mfValue(r.mfValue),
2321 mbNumeric(r.mbNumeric)
2325 ScDPCacheCell::~ScDPCacheCell()
2329 // ============================================================================
2331 size_t ScDPCollection::CacheCellHash::operator()(const ScDPCacheCell* pCell) const
2333 return pCell->mnStrId + static_cast<size_t>(pCell->mnType) +
2334 static_cast<size_t>(pCell->mfValue) + static_cast<size_t>(pCell->mbNumeric);
2337 bool ScDPCollection::CacheCellEqual::operator()(const ScDPCacheCell* p1, const ScDPCacheCell* p2) const
2339 if (!p1 && !p2)
2340 return true;
2342 if ((!p1 && p2) || (p1 && !p2))
2343 return false;
2345 return p1->mnStrId == p2->mnStrId && p1->mfValue == p2->mfValue &&
2346 p1->mbNumeric == p2->mbNumeric && p1->mnType == p2->mnType;
2349 // ----------------------------------------------------------------------------
2351 ScDPCollection::ScDPCollection(ScDocument* pDocument) :
2352 pDoc( pDocument )
2356 ScDPCollection::ScDPCollection(const ScDPCollection& r) :
2357 ScCollection(r),
2358 pDoc(r.pDoc),
2359 maSharedString(r.maSharedString),
2360 maCacheCellPool() // #i101725# don't copy hash_set with pointers from the other collection
2364 ScDPCollection::~ScDPCollection()
2366 clearCacheCellPool();
2369 ScDataObject* ScDPCollection::Clone() const
2371 return new ScDPCollection(*this);
2374 void ScDPCollection::DeleteOnTab( SCTAB nTab )
2376 USHORT nPos = 0;
2377 while ( nPos < nCount )
2379 // look for output positions on the deleted sheet
2380 if ( static_cast<const ScDPObject*>(At(nPos))->GetOutRange().aStart.Tab() == nTab )
2381 AtFree(nPos);
2382 else
2383 ++nPos;
2387 void ScDPCollection::UpdateReference( UpdateRefMode eUpdateRefMode,
2388 const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
2390 for (USHORT i=0; i<nCount; i++)
2391 ((ScDPObject*)At(i))->UpdateReference( eUpdateRefMode, r, nDx, nDy, nDz );
2394 BOOL ScDPCollection::RefsEqual( const ScDPCollection& r ) const
2396 if ( nCount != r.nCount )
2397 return FALSE;
2399 for (USHORT i=0; i<nCount; i++)
2400 if ( ! ((const ScDPObject*)At(i))->RefsEqual( *((const ScDPObject*)r.At(i)) ) )
2401 return FALSE;
2403 return TRUE; // all equal
2406 void ScDPCollection::WriteRefsTo( ScDPCollection& r ) const
2408 if ( nCount == r.nCount )
2410 //! assert equal names?
2411 for (USHORT i=0; i<nCount; i++)
2412 ((const ScDPObject*)At(i))->WriteRefsTo( *((ScDPObject*)r.At(i)) );
2414 else
2416 // #i8180# If data pilot tables were deleted with their sheet,
2417 // this collection contains extra entries that must be restored.
2418 // Matching objects are found by their names.
2420 DBG_ASSERT( nCount >= r.nCount, "WriteRefsTo: missing entries in document" );
2421 for (USHORT nSourcePos=0; nSourcePos<nCount; nSourcePos++)
2423 const ScDPObject* pSourceObj = static_cast<const ScDPObject*>(At(nSourcePos));
2424 String aName = pSourceObj->GetName();
2425 bool bFound = false;
2426 for (USHORT nDestPos=0; nDestPos<r.nCount && !bFound; nDestPos++)
2428 ScDPObject* pDestObj = static_cast<ScDPObject*>(r.At(nDestPos));
2429 if ( pDestObj->GetName() == aName )
2431 pSourceObj->WriteRefsTo( *pDestObj ); // found object, copy refs
2432 bFound = true;
2435 if ( !bFound )
2437 // none found, re-insert deleted object (see ScUndoDataPilot::Undo)
2439 ScDPObject* pDestObj = new ScDPObject( *pSourceObj );
2440 pDestObj->SetAlive(TRUE);
2441 if ( !r.InsertNewTable(pDestObj) )
2443 DBG_ERROR("cannot insert DPObject");
2444 DELETEZ( pDestObj );
2448 DBG_ASSERT( nCount == r.nCount, "WriteRefsTo: couldn't restore all entries" );
2452 String ScDPCollection::CreateNewName( USHORT nMin ) const
2454 String aBase = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("DataPilot"));
2455 //! from Resource?
2457 for (USHORT nAdd=0; nAdd<=nCount; nAdd++) // nCount+1 tries
2459 String aNewName = aBase;
2460 aNewName += String::CreateFromInt32( nMin + nAdd );
2461 BOOL bFound = FALSE;
2462 for (USHORT i=0; i<nCount && !bFound; i++)
2463 if (((const ScDPObject*)pItems[i])->GetName() == aNewName)
2464 bFound = TRUE;
2465 if (!bFound)
2466 return aNewName; // found unused Name
2468 return String(); // should not happen
2471 ScSimpleSharedString& ScDPCollection::GetSharedString()
2473 return maSharedString;
2476 void ScDPCollection::FreeTable(ScDPObject* pDPObj)
2478 const ScRange& rOutRange = pDPObj->GetOutRange();
2479 const ScAddress& s = rOutRange.aStart;
2480 const ScAddress& e = rOutRange.aEnd;
2481 pDoc->RemoveFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
2482 Free(pDPObj);
2485 bool ScDPCollection::InsertNewTable(ScDPObject* pDPObj)
2487 bool bSuccess = Insert(pDPObj);
2488 if (bSuccess)
2490 const ScRange& rOutRange = pDPObj->GetOutRange();
2491 const ScAddress& s = rOutRange.aStart;
2492 const ScAddress& e = rOutRange.aEnd;
2493 pDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
2495 return bSuccess;
2498 bool ScDPCollection::HasDPTable(SCCOL nCol, SCROW nRow, SCTAB nTab) const
2500 const ScMergeFlagAttr* pMergeAttr = static_cast<const ScMergeFlagAttr*>(
2501 pDoc->GetAttr(nCol, nRow, nTab, ATTR_MERGE_FLAG));
2503 if (!pMergeAttr)
2504 return false;
2506 return pMergeAttr->HasDPTable();
2509 ScDPCacheCell* ScDPCollection::getCacheCellFromPool(const ScDPCacheCell& rCell)
2511 ScDPCacheCell aCell(rCell);
2512 CacheCellPoolType::iterator itr = maCacheCellPool.find(&aCell);
2513 if (itr == maCacheCellPool.end())
2515 // Insert a new instance.
2516 ScDPCacheCell* p = new ScDPCacheCell(rCell);
2517 ::std::pair<CacheCellPoolType::iterator, bool> r =
2518 maCacheCellPool.insert(p);
2519 if (!r.second)
2520 delete p;
2522 ScDPCacheCell* p2 = r.second ? *r.first : NULL;
2523 DBG_ASSERT(p == p2, "ScDPCollection::getCacheCellFromPool: pointer addresses differ");
2524 return p2;
2526 return *itr;
2529 namespace {
2531 class DeleteCacheCells : public ::std::unary_function<ScDPCacheCell*, void>
2533 public:
2534 void operator()(ScDPCacheCell* p) const
2536 delete p;
2542 void ScDPCollection::clearCacheCellPool()
2544 // Transferring all stored pointers to a vector first. For some unknown
2545 // reason, deleting cell content instances by directly iterating through
2546 // the hash set causes the iteration to return an identical pointer
2547 // value twice, causing a double-delete. I have no idea why this happens.
2549 using ::std::copy;
2550 using ::std::back_inserter;
2552 vector<ScDPCacheCell*> ps;
2553 ps.reserve(maCacheCellPool.size());
2554 copy(maCacheCellPool.begin(), maCacheCellPool.end(), back_inserter(ps));
2555 maCacheCellPool.clear();
2556 // for correctness' sake, delete the elements after clearing the hash_set
2557 for_each(ps.begin(), ps.end(), DeleteCacheCells());