Update to m13
[ooovba.git] / sc / source / core / data / dpobject.cxx
blob0c700daf0b1a8b08df6036f83951c0b98a22b1b6
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>
79 using namespace com::sun::star;
80 using ::std::vector;
81 using ::boost::shared_ptr;
82 using ::com::sun::star::uno::Sequence;
83 using ::com::sun::star::uno::Reference;
84 using ::com::sun::star::uno::UNO_QUERY;
85 using ::com::sun::star::uno::Any;
86 using ::com::sun::star::sheet::DataPilotTableHeaderData;
87 using ::com::sun::star::sheet::DataPilotTablePositionData;
88 using ::com::sun::star::beans::XPropertySet;
89 using ::rtl::OUString;
91 // -----------------------------------------------------------------------
93 #define MAX_LABELS 256 //!!! from fieldwnd.hxx, must be moved to global.hxx
95 // -----------------------------------------------------------------------
97 #define SCDPSOURCE_SERVICE "com.sun.star.sheet.DataPilotSource"
99 // -----------------------------------------------------------------------
101 // incompatible versions of data pilot files
102 #define SC_DP_VERSION_CURRENT 6
104 // type of source data
105 #define SC_DP_SOURCE_SHEET 0
106 #define SC_DP_SOURCE_DATABASE 1
107 #define SC_DP_SOURCE_SERVICE 2
109 // -----------------------------------------------------------------------
111 //! move to a header file
112 #define DP_PROP_COLUMNGRAND "ColumnGrand"
113 #define DP_PROP_FUNCTION "Function"
114 #define DP_PROP_IGNOREEMPTY "IgnoreEmptyRows"
115 #define DP_PROP_ISDATALAYOUT "IsDataLayoutDimension"
116 //#define DP_PROP_ISVISIBLE "IsVisible"
117 #define DP_PROP_ORIENTATION "Orientation"
118 #define DP_PROP_ORIGINAL "Original"
119 #define DP_PROP_POSITION "Position"
120 #define DP_PROP_REPEATIFEMPTY "RepeatIfEmpty"
121 #define DP_PROP_ROWGRAND "RowGrand"
122 #define DP_PROP_SHOWDETAILS "ShowDetails"
123 #define DP_PROP_SHOWEMPTY "ShowEmpty"
124 #define DP_PROP_SUBTOTALS "SubTotals"
125 #define DP_PROP_USEDHIERARCHY "UsedHierarchy"
127 // -----------------------------------------------------------------------
129 USHORT lcl_GetDataGetOrientation( const uno::Reference<sheet::XDimensionsSupplier>& xSource )
131 long nRet = sheet::DataPilotFieldOrientation_HIDDEN;
132 if ( xSource.is() )
134 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
135 uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
136 long nIntCount = xIntDims->getCount();
137 BOOL bFound = FALSE;
138 for (long nIntDim=0; nIntDim<nIntCount && !bFound; nIntDim++)
140 uno::Reference<uno::XInterface> xIntDim =
141 ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nIntDim) );
142 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
143 if ( xDimProp.is() )
145 bFound = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
146 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
147 //! error checking -- is "IsDataLayoutDimension" property required??
148 if (bFound)
149 nRet = ScUnoHelpFunctions::GetEnumProperty(
150 xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION),
151 sheet::DataPilotFieldOrientation_HIDDEN );
155 return static_cast< USHORT >( nRet );
158 // -----------------------------------------------------------------------
160 ScDPObject::ScDPObject( ScDocument* pD ) :
161 pDoc( pD ),
162 pSaveData( NULL ),
163 pSheetDesc( NULL ),
164 pImpDesc( NULL ),
165 pServDesc( NULL ),
166 mpTableData(static_cast<ScDPTableData*>(NULL)),
167 pOutput( NULL ),
168 bSettingsChanged( FALSE ),
169 bAlive( FALSE ),
170 nAutoFormatIndex( 65535 ),
171 bAllowMove( FALSE ),
172 bInfoValid( FALSE ),
173 nHeaderRows( 0 ),
174 bHeaderLayout( 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 nAutoFormatIndex( r.nAutoFormatIndex ),
193 bAllowMove( FALSE ),
194 bInfoValid( r.bInfoValid ),
195 nHeaderRows( r.nHeaderRows ),
196 bHeaderLayout( r.bHeaderLayout )
198 if (r.pSaveData)
199 pSaveData = new ScDPSaveData(*r.pSaveData);
200 if (r.pSheetDesc)
201 pSheetDesc = new ScSheetSourceDesc(*r.pSheetDesc);
202 if (r.pImpDesc)
203 pImpDesc = new ScImportSourceDesc(*r.pImpDesc);
204 if (r.pServDesc)
205 pServDesc = new ScDPServiceDesc(*r.pServDesc);
206 // xSource (and pOutput) is not copied
209 ScDPObject::~ScDPObject()
211 delete pOutput;
212 delete pSaveData;
213 delete pSheetDesc;
214 delete pImpDesc;
215 delete pServDesc;
218 ScDataObject* ScDPObject::Clone() const
220 return new ScDPObject(*this);
223 void ScDPObject::SetAlive(BOOL bSet)
225 bAlive = bSet;
228 void ScDPObject::SetAllowMove(BOOL bSet)
230 bAllowMove = bSet;
233 void ScDPObject::SetSaveData(const ScDPSaveData& rData)
235 if ( pSaveData != &rData ) // API implementation modifies the original SaveData object
237 delete pSaveData;
238 pSaveData = new ScDPSaveData( rData );
241 InvalidateData(); // re-init source from SaveData
244 void ScDPObject::SetAutoFormatIndex(const USHORT nIndex)
246 nAutoFormatIndex = nIndex;
249 void ScDPObject::SetHeaderLayout (bool bUseGrid)
251 bHeaderLayout = bUseGrid;
254 void ScDPObject::SetOutRange(const ScRange& rRange)
256 aOutRange = rRange;
258 if ( pOutput )
259 pOutput->SetPosition( rRange.aStart );
262 void ScDPObject::SetSheetDesc(const ScSheetSourceDesc& rDesc)
264 if ( pSheetDesc && rDesc == *pSheetDesc )
265 return; // nothing to do
267 DELETEZ( pImpDesc );
268 DELETEZ( pServDesc );
270 delete pImpDesc;
271 pSheetDesc = new ScSheetSourceDesc(rDesc);
273 // make valid QueryParam
275 pSheetDesc->aQueryParam.nCol1 = pSheetDesc->aSourceRange.aStart.Col();
276 pSheetDesc->aQueryParam.nRow1 = pSheetDesc->aSourceRange.aStart.Row();
277 pSheetDesc->aQueryParam.nCol2 = pSheetDesc->aSourceRange.aEnd.Col();
278 pSheetDesc->aQueryParam.nRow2 = pSheetDesc->aSourceRange.aEnd.Row();;
279 pSheetDesc->aQueryParam.bHasHeader = TRUE;
281 InvalidateSource(); // new source must be created
284 void ScDPObject::SetImportDesc(const ScImportSourceDesc& rDesc)
286 if ( pImpDesc && rDesc == *pImpDesc )
287 return; // nothing to do
289 DELETEZ( pSheetDesc );
290 DELETEZ( pServDesc );
292 delete pImpDesc;
293 pImpDesc = new ScImportSourceDesc(rDesc);
295 InvalidateSource(); // new source must be created
298 void ScDPObject::SetServiceData(const ScDPServiceDesc& rDesc)
300 if ( pServDesc && rDesc == *pServDesc )
301 return; // nothing to do
303 DELETEZ( pSheetDesc );
304 DELETEZ( pImpDesc );
306 delete pServDesc;
307 pServDesc = new ScDPServiceDesc(rDesc);
309 InvalidateSource(); // new source must be created
312 void ScDPObject::WriteSourceDataTo( ScDPObject& rDest ) const
314 if ( pSheetDesc )
315 rDest.SetSheetDesc( *pSheetDesc );
316 else if ( pImpDesc )
317 rDest.SetImportDesc( *pImpDesc );
318 else if ( pServDesc )
319 rDest.SetServiceData( *pServDesc );
321 // name/tag are not source data, but needed along with source data
323 rDest.aTableName = aTableName;
324 rDest.aTableTag = aTableTag;
327 void ScDPObject::WriteTempDataTo( ScDPObject& rDest ) const
329 rDest.nHeaderRows = nHeaderRows;
330 rDest.bInfoValid = bInfoValid;
333 BOOL ScDPObject::IsSheetData() const
335 return ( pSheetDesc != NULL );
338 void ScDPObject::SetName(const String& rNew)
340 aTableName = rNew;
343 void ScDPObject::SetTag(const String& rNew)
345 aTableTag = rNew;
348 bool ScDPObject::IsDataDescriptionCell(const ScAddress& rPos)
350 if (!pSaveData)
351 return false;
353 long nDataDimCount = pSaveData->GetDataDimensionCount();
354 if (nDataDimCount != 1)
355 // There has to be exactly one data dimension for the description to
356 // appear at top-left corner.
357 return false;
359 CreateOutput();
360 ScRange aTabRange = pOutput->GetOutputRange(sheet::DataPilotOutputRangeType::TABLE);
361 return (rPos == aTabRange.aStart);
364 uno::Reference<sheet::XDimensionsSupplier> ScDPObject::GetSource()
366 CreateObjects();
367 return xSource;
370 void ScDPObject::CreateOutput()
372 CreateObjects();
373 if (!pOutput)
375 BOOL bFilterButton = IsSheetData() && pSaveData && pSaveData->GetFilterButton();
376 pOutput = new ScDPOutput( pDoc, xSource, aOutRange.aStart, bFilterButton );
377 pOutput->SetHeaderLayout ( bHeaderLayout );
379 long nOldRows = nHeaderRows;
380 nHeaderRows = pOutput->GetHeaderRows();
381 bInfoValid = TRUE;
383 if ( bAllowMove && nHeaderRows != nOldRows )
385 long nDiff = nOldRows - nHeaderRows;
386 if ( nOldRows == 0 )
387 --nDiff;
388 if ( nHeaderRows == 0 )
389 ++nDiff;
391 long nNewRow = aOutRange.aStart.Row() + nDiff;
392 if ( nNewRow < 0 )
393 nNewRow = 0;
395 ScAddress aStart( aOutRange.aStart );
396 aStart.SetRow(nNewRow);
397 pOutput->SetPosition( aStart );
399 //! modify aOutRange?
401 bAllowMove = FALSE; // use only once
406 ScDPTableData* ScDPObject::GetTableData()
408 if (!mpTableData)
410 if ( pImpDesc )
412 // database data
413 mpTableData.reset(new ScDatabaseDPData(pDoc, *pImpDesc));
415 else
417 // cell data
418 if (!pSheetDesc)
420 DBG_ERROR("no source descriptor");
421 pSheetDesc = new ScSheetSourceDesc; // dummy defaults
423 mpTableData.reset(new ScSheetDPData(pDoc, *pSheetDesc));
426 // grouping (for cell or database data)
427 if ( pSaveData && pSaveData->GetExistingDimensionData() )
429 shared_ptr<ScDPGroupTableData> pGroupData(new ScDPGroupTableData(mpTableData, pDoc));
430 pSaveData->GetExistingDimensionData()->WriteToData(*pGroupData);
431 mpTableData = pGroupData;
435 return mpTableData.get();
438 void ScDPObject::CreateObjects()
440 // if groups are involved, create a new source with the ScDPGroupTableData
441 if ( bSettingsChanged && pSaveData && pSaveData->GetExistingDimensionData() )
442 InvalidateSource();
444 if (!xSource.is())
446 //! cache DPSource and/or Output?
448 DBG_ASSERT( bAlive, "CreateObjects on non-inserted DPObject" );
450 DELETEZ( pOutput ); // not valid when xSource is changed
452 if ( pServDesc )
454 xSource = CreateSource( *pServDesc );
457 if ( !xSource.is() ) // database or sheet data, or error in CreateSource
459 DBG_ASSERT( !pServDesc, "DPSource could not be created" );
460 ScDPTableData* pData = GetTableData();
461 ScDPSource* pSource = new ScDPSource( pData );
462 xSource = pSource;
465 if (pSaveData)
466 pSaveData->WriteToSource( xSource );
468 else if (bSettingsChanged)
470 DELETEZ( pOutput ); // not valid when xSource is changed
472 uno::Reference<util::XRefreshable> xRef( xSource, uno::UNO_QUERY );
473 if (xRef.is())
477 xRef->refresh();
479 catch(uno::Exception&)
481 DBG_ERROR("exception in refresh");
485 if (pSaveData)
486 pSaveData->WriteToSource( xSource );
488 bSettingsChanged = FALSE;
491 void ScDPObject::InvalidateData()
493 bSettingsChanged = TRUE;
494 bInfoValid = FALSE;
497 void ScDPObject::InvalidateSource()
499 xSource = NULL;
500 bInfoValid = FALSE;
501 mpTableData.reset();
504 ScRange ScDPObject::GetNewOutputRange( BOOL& rOverflow )
506 CreateOutput(); // create xSource and pOutput if not already done
508 rOverflow = pOutput->HasError(); // range overflow or exception from source
509 if ( rOverflow )
510 return ScRange( aOutRange.aStart );
511 else
513 // don't store the result in aOutRange, because nothing has been output yet
514 return pOutput->GetOutputRange();
518 void ScDPObject::Output()
520 // clear old output area
521 pDoc->DeleteAreaTab( aOutRange.aStart.Col(), aOutRange.aStart.Row(),
522 aOutRange.aEnd.Col(), aOutRange.aEnd.Row(),
523 aOutRange.aStart.Tab(), IDF_ALL );
524 pDoc->RemoveFlagsTab( aOutRange.aStart.Col(), aOutRange.aStart.Row(),
525 aOutRange.aEnd.Col(), aOutRange.aEnd.Row(),
526 aOutRange.aStart.Tab(), SC_MF_AUTO );
528 CreateOutput(); // create xSource and pOutput if not already done
530 pOutput->Output();
532 // aOutRange is always the range that was last output to the document
533 aOutRange = pOutput->GetOutputRange();
534 const ScAddress& s = aOutRange.aStart;
535 const ScAddress& e = aOutRange.aEnd;
536 pDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
539 const ScRange ScDPObject::GetOutputRangeByType( sal_Int32 nType )
541 CreateOutput();
543 if (pOutput->HasError())
544 return ScRange(aOutRange.aStart);
546 return pOutput->GetOutputRange(nType);
549 BOOL lcl_HasButton( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
551 return ((const ScMergeFlagAttr*)pDoc->GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG ))->HasButton();
554 void ScDPObject::RefreshAfterLoad()
556 // apply drop-down attribute, initialize nHeaderRows, without accessing the source
557 // (button attribute must be present)
559 // simple test: block of button cells at the top, followed by an empty cell
561 SCCOL nFirstCol = aOutRange.aStart.Col();
562 SCROW nFirstRow = aOutRange.aStart.Row();
563 SCTAB nTab = aOutRange.aStart.Tab();
565 SCROW nInitial = 0;
566 SCROW nOutRows = aOutRange.aEnd.Row() + 1 - aOutRange.aStart.Row();
567 while ( nInitial + 1 < nOutRows && lcl_HasButton( pDoc, nFirstCol, nFirstRow + nInitial, nTab ) )
568 ++nInitial;
570 if ( nInitial + 1 < nOutRows &&
571 pDoc->IsBlockEmpty( nTab, nFirstCol, nFirstRow + nInitial, nFirstCol, nFirstRow + nInitial ) &&
572 aOutRange.aEnd.Col() > nFirstCol )
574 BOOL bFilterButton = IsSheetData(); // when available, filter button setting must be checked here
576 SCROW nSkip = bFilterButton ? 1 : 0;
577 for (SCROW nPos=nSkip; nPos<nInitial; nPos++)
578 pDoc->ApplyAttr( nFirstCol + 1, nFirstRow + nPos, nTab, ScMergeFlagAttr(SC_MF_AUTO) );
580 nHeaderRows = nInitial;
582 else
583 nHeaderRows = 0; // nothing found, no drop-down lists
585 bInfoValid = TRUE;
588 void ScDPObject::BuildAllDimensionMembers()
590 if (!pSaveData)
591 return;
593 pSaveData->BuildAllDimensionMembers(GetTableData());
596 void ScDPObject::UpdateReference( UpdateRefMode eUpdateRefMode,
597 const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
599 // Output area
601 SCCOL nCol1 = aOutRange.aStart.Col();
602 SCROW nRow1 = aOutRange.aStart.Row();
603 SCTAB nTab1 = aOutRange.aStart.Tab();
604 SCCOL nCol2 = aOutRange.aEnd.Col();
605 SCROW nRow2 = aOutRange.aEnd.Row();
606 SCTAB nTab2 = aOutRange.aEnd.Tab();
608 ScRefUpdateRes eRes =
609 ScRefUpdate::Update( pDoc, eUpdateRefMode,
610 rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
611 rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz,
612 nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
613 if ( eRes != UR_NOTHING )
614 SetOutRange( ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ) );
616 // sheet source data
618 if ( pSheetDesc )
620 nCol1 = pSheetDesc->aSourceRange.aStart.Col();
621 nRow1 = pSheetDesc->aSourceRange.aStart.Row();
622 nTab1 = pSheetDesc->aSourceRange.aStart.Tab();
623 nCol2 = pSheetDesc->aSourceRange.aEnd.Col();
624 nRow2 = pSheetDesc->aSourceRange.aEnd.Row();
625 nTab2 = pSheetDesc->aSourceRange.aEnd.Tab();
627 eRes = ScRefUpdate::Update( pDoc, eUpdateRefMode,
628 rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
629 rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz,
630 nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
631 if ( eRes != UR_NOTHING )
633 ScSheetSourceDesc aNewDesc;
634 aNewDesc.aSourceRange = ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
636 SCsCOL nDiffX = nCol1 - (SCsCOL) pSheetDesc->aSourceRange.aStart.Col();
637 SCsROW nDiffY = nRow1 - (SCsROW) pSheetDesc->aSourceRange.aStart.Row();
639 aNewDesc.aQueryParam = pSheetDesc->aQueryParam;
640 aNewDesc.aQueryParam.nCol1 = sal::static_int_cast<SCCOL>( aNewDesc.aQueryParam.nCol1 + nDiffX );
641 aNewDesc.aQueryParam.nCol2 = sal::static_int_cast<SCCOL>( aNewDesc.aQueryParam.nCol2 + nDiffX );
642 aNewDesc.aQueryParam.nRow1 += nDiffY; //! used?
643 aNewDesc.aQueryParam.nRow2 += nDiffY; //! used?
644 SCSIZE nEC = aNewDesc.aQueryParam.GetEntryCount();
645 for (SCSIZE i=0; i<nEC; i++)
646 if (aNewDesc.aQueryParam.GetEntry(i).bDoQuery)
647 aNewDesc.aQueryParam.GetEntry(i).nField += nDiffX;
649 SetSheetDesc( aNewDesc ); // allocates new pSheetDesc
654 BOOL ScDPObject::RefsEqual( const ScDPObject& r ) const
656 if ( aOutRange != r.aOutRange )
657 return FALSE;
659 if ( pSheetDesc && r.pSheetDesc )
661 if ( pSheetDesc->aSourceRange != r.pSheetDesc->aSourceRange )
662 return FALSE;
664 else if ( pSheetDesc || r.pSheetDesc )
666 DBG_ERROR("RefsEqual: SheetDesc set at only one object");
667 return FALSE;
670 return TRUE;
673 void ScDPObject::WriteRefsTo( ScDPObject& r ) const
675 r.SetOutRange( aOutRange );
676 if ( pSheetDesc )
677 r.SetSheetDesc( *pSheetDesc );
680 void ScDPObject::GetPositionData(const ScAddress& rPos, DataPilotTablePositionData& rPosData)
682 CreateOutput();
683 pOutput->GetPositionData(rPos, rPosData);
686 bool ScDPObject::GetDataFieldPositionData(
687 const ScAddress& rPos, Sequence<sheet::DataPilotFieldFilter>& rFilters)
689 CreateOutput();
691 vector<sheet::DataPilotFieldFilter> aFilters;
692 if (!pOutput->GetDataResultPositionData(aFilters, rPos))
693 return false;
695 sal_Int32 n = static_cast<sal_Int32>(aFilters.size());
696 rFilters.realloc(n);
697 for (sal_Int32 i = 0; i < n; ++i)
698 rFilters[i] = aFilters[i];
700 return true;
703 void ScDPObject::GetDrillDownData(const ScAddress& rPos, Sequence< Sequence<Any> >& rTableData)
705 CreateOutput();
707 Reference<sheet::XDrillDownDataSupplier> xDrillDownData(xSource, UNO_QUERY);
708 if (!xDrillDownData.is())
709 return;
711 Sequence<sheet::DataPilotFieldFilter> filters;
712 if (!GetDataFieldPositionData(rPos, filters))
713 return;
715 rTableData = xDrillDownData->getDrillDownData(filters);
718 bool ScDPObject::IsDimNameInUse(const OUString& rName) const
720 if (!xSource.is())
721 return false;
723 Reference<container::XNameAccess> xDims = xSource->getDimensions();
724 Sequence<OUString> aDimNames = xDims->getElementNames();
725 sal_Int32 n = aDimNames.getLength();
726 for (sal_Int32 i = 0; i < n; ++i)
728 const OUString& rDimName = aDimNames[i];
729 if (rDimName.equalsIgnoreAsciiCase(rName))
730 return true;
732 Reference<beans::XPropertySet> xPropSet(xDims->getByName(rDimName), UNO_QUERY);
733 if (!xPropSet.is())
734 continue;
736 Any any = xPropSet->getPropertyValue(OUString::createFromAscii(SC_UNO_LAYOUTNAME));
737 OUString aLayoutName;
738 if (any >>= aLayoutName)
740 if (aLayoutName.equalsIgnoreAsciiCase(rName))
741 return true;
744 return false;
747 String ScDPObject::GetDimName( long nDim, BOOL& rIsDataLayout )
749 rIsDataLayout = FALSE;
750 String aRet;
752 if ( xSource.is() )
754 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
755 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
756 long nDimCount = xDims->getCount();
757 if ( nDim < nDimCount )
759 uno::Reference<uno::XInterface> xIntDim =
760 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
761 uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
762 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
763 if ( xDimName.is() && xDimProp.is() )
765 BOOL bData = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
766 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
767 //! error checking -- is "IsDataLayoutDimension" property required??
769 rtl::OUString aName;
772 aName = xDimName->getName();
774 catch(uno::Exception&)
777 if ( bData )
778 rIsDataLayout = TRUE;
779 else
780 aRet = String( aName );
785 return aRet;
788 BOOL ScDPObject::IsDuplicated( long nDim )
790 BOOL bDuplicated = FALSE;
791 if ( xSource.is() )
793 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
794 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
795 long nDimCount = xDims->getCount();
796 if ( nDim < nDimCount )
798 uno::Reference<uno::XInterface> xIntDim =
799 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
800 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
801 if ( xDimProp.is() )
805 uno::Any aOrigAny = xDimProp->getPropertyValue(
806 rtl::OUString::createFromAscii(DP_PROP_ORIGINAL) );
807 uno::Reference<uno::XInterface> xIntOrig;
808 if ( (aOrigAny >>= xIntOrig) && xIntOrig.is() )
809 bDuplicated = TRUE;
811 catch(uno::Exception&)
817 return bDuplicated;
820 long ScDPObject::GetDimCount()
822 long nRet = 0;
823 if ( xSource.is() )
827 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
828 if ( xDimsName.is() )
829 nRet = xDimsName->getElementNames().getLength();
831 catch(uno::Exception&)
835 return nRet;
838 void ScDPObject::FillPageList( TypedScStrCollection& rStrings, long nField )
840 //! merge members access with ToggleDetails?
842 //! convert field index to dimension index?
844 DBG_ASSERT( xSource.is(), "no source" );
845 if ( !xSource.is() ) return;
847 uno::Reference<container::XNamed> xDim;
848 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
849 uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
850 long nIntCount = xIntDims->getCount();
851 if ( nField < nIntCount )
853 uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface(
854 xIntDims->getByIndex(nField) );
855 xDim = uno::Reference<container::XNamed>( xIntDim, uno::UNO_QUERY );
857 DBG_ASSERT( xDim.is(), "dimension not found" );
858 if ( !xDim.is() ) return;
860 uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
861 long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
862 rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
863 long nLevel = 0;
865 long nHierCount = 0;
866 uno::Reference<container::XIndexAccess> xHiers;
867 uno::Reference<sheet::XHierarchiesSupplier> xHierSupp( xDim, uno::UNO_QUERY );
868 if ( xHierSupp.is() )
870 uno::Reference<container::XNameAccess> xHiersName = xHierSupp->getHierarchies();
871 xHiers = new ScNameToIndexAccess( xHiersName );
872 nHierCount = xHiers->getCount();
874 uno::Reference<uno::XInterface> xHier;
875 if ( nHierarchy < nHierCount )
876 xHier = ScUnoHelpFunctions::AnyToInterface( xHiers->getByIndex(nHierarchy) );
877 DBG_ASSERT( xHier.is(), "hierarchy not found" );
878 if ( !xHier.is() ) return;
880 long nLevCount = 0;
881 uno::Reference<container::XIndexAccess> xLevels;
882 uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHier, uno::UNO_QUERY );
883 if ( xLevSupp.is() )
885 uno::Reference<container::XNameAccess> xLevsName = xLevSupp->getLevels();
886 xLevels = new ScNameToIndexAccess( xLevsName );
887 nLevCount = xLevels->getCount();
889 uno::Reference<uno::XInterface> xLevel;
890 if ( nLevel < nLevCount )
891 xLevel = ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex(nLevel) );
892 DBG_ASSERT( xLevel.is(), "level not found" );
893 if ( !xLevel.is() ) return;
895 uno::Reference<container::XNameAccess> xMembers;
896 uno::Reference<sheet::XMembersSupplier> xMbrSupp( xLevel, uno::UNO_QUERY );
897 if ( xMbrSupp.is() )
898 xMembers = xMbrSupp->getMembers();
899 DBG_ASSERT( xMembers.is(), "members not found" );
900 if ( !xMembers.is() ) return;
902 uno::Sequence<rtl::OUString> aNames = xMembers->getElementNames();
903 long nNameCount = aNames.getLength();
904 const rtl::OUString* pNameArr = aNames.getConstArray();
905 for (long nPos = 0; nPos < nNameCount; ++nPos)
907 // Make sure to insert only visible members.
908 Reference<XPropertySet> xPropSet(xMembers->getByName(pNameArr[nPos]), UNO_QUERY);
909 sal_Bool bVisible = false;
910 if (xPropSet.is())
912 Any any = xPropSet->getPropertyValue(OUString::createFromAscii(SC_UNO_ISVISIBL));
913 any >>= bVisible;
916 if (bVisible)
918 // use the order from getElementNames
919 TypedStrData* pData = new TypedStrData( pNameArr[nPos] );
920 if ( !rStrings.AtInsert( rStrings.GetCount(), pData ) )
921 delete pData;
925 // add "-all-" entry to the top (unsorted)
926 TypedStrData* pAllData = new TypedStrData( String( ScResId( SCSTR_ALL ) ) ); //! separate string? (also output)
927 if ( !rStrings.AtInsert( 0, pAllData ) )
928 delete pAllData;
931 void ScDPObject::GetHeaderPositionData(const ScAddress& rPos, DataPilotTableHeaderData& rData)
933 using namespace ::com::sun::star::sheet::DataPilotTablePositionType;
935 CreateOutput(); // create xSource and pOutput if not already done
937 // Reset member values to invalid state.
938 rData.Dimension = rData.Hierarchy = rData.Level = -1;
939 rData.Flags = 0;
941 DataPilotTablePositionData aPosData;
942 pOutput->GetPositionData(rPos, aPosData);
943 const sal_Int32 nPosType = aPosData.PositionType;
944 if (nPosType == COLUMN_HEADER || nPosType == ROW_HEADER)
945 aPosData.PositionData >>= rData;
948 // Returns TRUE on success and stores the result in rTarget
949 BOOL ScDPObject::GetPivotData( ScDPGetPivotDataField& rTarget,
950 const std::vector< ScDPGetPivotDataField >& rFilters )
952 CreateOutput(); // create xSource and pOutput if not already done
954 return pOutput->GetPivotData( rTarget, rFilters );
957 BOOL ScDPObject::IsFilterButton( const ScAddress& rPos )
959 CreateOutput(); // create xSource and pOutput if not already done
961 return pOutput->IsFilterButton( rPos );
964 long ScDPObject::GetHeaderDim( const ScAddress& rPos, USHORT& rOrient )
966 CreateOutput(); // create xSource and pOutput if not already done
968 return pOutput->GetHeaderDim( rPos, rOrient );
971 BOOL ScDPObject::GetHeaderDrag( const ScAddress& rPos, BOOL bMouseLeft, BOOL bMouseTop, long nDragDim,
972 Rectangle& rPosRect, USHORT& rOrient, long& rDimPos )
974 CreateOutput(); // create xSource and pOutput if not already done
976 return pOutput->GetHeaderDrag( rPos, bMouseLeft, bMouseTop, nDragDim, rPosRect, rOrient, rDimPos );
979 void ScDPObject::GetMemberResultNames( ScStrCollection& rNames, long nDimension )
981 CreateOutput(); // create xSource and pOutput if not already done
983 pOutput->GetMemberResultNames( rNames, nDimension ); // used only with table data -> level not needed
986 bool lcl_Dequote( const String& rSource, xub_StrLen nStartPos, xub_StrLen& rEndPos, String& rResult )
988 // nStartPos has to point to opening quote
990 bool bRet = false;
991 const sal_Unicode cQuote = '\'';
993 if ( rSource.GetChar(nStartPos) == cQuote )
995 rtl::OUStringBuffer aBuffer;
996 xub_StrLen nPos = nStartPos + 1;
997 const xub_StrLen nLen = rSource.Len();
999 while ( nPos < nLen )
1001 const sal_Unicode cNext = rSource.GetChar(nPos);
1002 if ( cNext == cQuote )
1004 if ( nPos+1 < nLen && rSource.GetChar(nPos+1) == cQuote )
1006 // double quote is used for an embedded quote
1007 aBuffer.append( cNext ); // append one quote
1008 ++nPos; // skip the next one
1010 else
1012 // end of quoted string
1013 rResult = aBuffer.makeStringAndClear();
1014 rEndPos = nPos + 1; // behind closing quote
1015 return true;
1018 else
1019 aBuffer.append( cNext );
1021 ++nPos;
1023 // no closing quote before the end of the string -> error (bRet still false)
1026 return bRet;
1029 struct ScGetPivotDataFunctionEntry
1031 const sal_Char* pName;
1032 sheet::GeneralFunction eFunc;
1035 bool lcl_ParseFunction( const String& rList, xub_StrLen nStartPos, xub_StrLen& rEndPos, sheet::GeneralFunction& rFunc )
1037 static const ScGetPivotDataFunctionEntry aFunctions[] =
1039 // our names
1040 { "Sum", sheet::GeneralFunction_SUM },
1041 { "Count", sheet::GeneralFunction_COUNT },
1042 { "Average", sheet::GeneralFunction_AVERAGE },
1043 { "Max", sheet::GeneralFunction_MAX },
1044 { "Min", sheet::GeneralFunction_MIN },
1045 { "Product", sheet::GeneralFunction_PRODUCT },
1046 { "CountNums", sheet::GeneralFunction_COUNTNUMS },
1047 { "StDev", sheet::GeneralFunction_STDEV },
1048 { "StDevp", sheet::GeneralFunction_STDEVP },
1049 { "Var", sheet::GeneralFunction_VAR },
1050 { "VarP", sheet::GeneralFunction_VARP },
1051 // compatibility names
1052 { "Count Nums", sheet::GeneralFunction_COUNTNUMS },
1053 { "StdDev", sheet::GeneralFunction_STDEV },
1054 { "StdDevp", sheet::GeneralFunction_STDEVP }
1057 const xub_StrLen nListLen = rList.Len();
1058 while ( nStartPos < nListLen && rList.GetChar(nStartPos) == ' ' )
1059 ++nStartPos;
1061 bool bParsed = false;
1062 bool bFound = false;
1063 String aFuncStr;
1064 xub_StrLen nFuncEnd = 0;
1065 if ( nStartPos < nListLen && rList.GetChar(nStartPos) == '\'' )
1066 bParsed = lcl_Dequote( rList, nStartPos, nFuncEnd, aFuncStr );
1067 else
1069 nFuncEnd = rList.Search( static_cast<sal_Unicode>(']'), nStartPos );
1070 if ( nFuncEnd != STRING_NOTFOUND )
1072 aFuncStr = rList.Copy( nStartPos, nFuncEnd - nStartPos );
1073 bParsed = true;
1077 if ( bParsed )
1079 aFuncStr.EraseLeadingAndTrailingChars( ' ' );
1081 const sal_Int32 nFuncCount = sizeof(aFunctions) / sizeof(aFunctions[0]);
1082 for ( sal_Int32 nFunc=0; nFunc<nFuncCount && !bFound; nFunc++ )
1084 if ( aFuncStr.EqualsIgnoreCaseAscii( aFunctions[nFunc].pName ) )
1086 rFunc = aFunctions[nFunc].eFunc;
1087 bFound = true;
1089 while ( nFuncEnd < nListLen && rList.GetChar(nFuncEnd) == ' ' )
1090 ++nFuncEnd;
1091 rEndPos = nFuncEnd;
1096 return bFound;
1099 bool lcl_IsAtStart( const String& rList, const String& rSearch, sal_Int32& rMatched,
1100 bool bAllowBracket, sheet::GeneralFunction* pFunc )
1102 sal_Int32 nMatchList = 0;
1103 sal_Int32 nMatchSearch = 0;
1104 sal_Unicode cFirst = rList.GetChar(0);
1105 if ( cFirst == '\'' || cFirst == '[' )
1107 // quoted string or string in brackets must match completely
1109 String aDequoted;
1110 xub_StrLen nQuoteEnd = 0;
1111 bool bParsed = false;
1113 if ( cFirst == '\'' )
1114 bParsed = lcl_Dequote( rList, 0, nQuoteEnd, aDequoted );
1115 else if ( cFirst == '[' )
1117 // skip spaces after the opening bracket
1119 xub_StrLen nStartPos = 1;
1120 const xub_StrLen nListLen = rList.Len();
1121 while ( nStartPos < nListLen && rList.GetChar(nStartPos) == ' ' )
1122 ++nStartPos;
1124 if ( rList.GetChar(nStartPos) == '\'' ) // quoted within the brackets?
1126 if ( lcl_Dequote( rList, nStartPos, nQuoteEnd, aDequoted ) )
1128 // after the quoted string, there must be the closing bracket, optionally preceded by spaces,
1129 // and/or a function name
1130 while ( nQuoteEnd < nListLen && rList.GetChar(nQuoteEnd) == ' ' )
1131 ++nQuoteEnd;
1133 // semicolon separates function name
1134 if ( nQuoteEnd < nListLen && rList.GetChar(nQuoteEnd) == ';' && pFunc )
1136 xub_StrLen nFuncEnd = 0;
1137 if ( lcl_ParseFunction( rList, nQuoteEnd + 1, nFuncEnd, *pFunc ) )
1138 nQuoteEnd = nFuncEnd;
1140 if ( nQuoteEnd < nListLen && rList.GetChar(nQuoteEnd) == ']' )
1142 ++nQuoteEnd; // include the closing bracket for the matched length
1143 bParsed = true;
1147 else
1149 // implicit quoting to the closing bracket
1151 xub_StrLen nClosePos = rList.Search( static_cast<sal_Unicode>(']'), nStartPos );
1152 if ( nClosePos != STRING_NOTFOUND )
1154 xub_StrLen nNameEnd = nClosePos;
1155 xub_StrLen nSemiPos = rList.Search( static_cast<sal_Unicode>(';'), nStartPos );
1156 if ( nSemiPos != STRING_NOTFOUND && nSemiPos < nClosePos && pFunc )
1158 xub_StrLen nFuncEnd = 0;
1159 if ( lcl_ParseFunction( rList, nSemiPos + 1, nFuncEnd, *pFunc ) )
1160 nNameEnd = nSemiPos;
1163 aDequoted = rList.Copy( nStartPos, nNameEnd - nStartPos );
1164 aDequoted.EraseTrailingChars( ' ' ); // spaces before the closing bracket or semicolon
1165 nQuoteEnd = nClosePos + 1;
1166 bParsed = true;
1171 if ( bParsed && ScGlobal::pTransliteration->isEqual( aDequoted, rSearch ) )
1173 nMatchList = nQuoteEnd; // match count in the list string, including quotes
1174 nMatchSearch = rSearch.Len();
1177 else
1179 // otherwise look for search string at the start of rList
1180 ScGlobal::pTransliteration->equals( rList, 0, rList.Len(), nMatchList,
1181 rSearch, 0, rSearch.Len(), nMatchSearch );
1184 if ( nMatchSearch == rSearch.Len() )
1186 // search string is at start of rList - look for following space or end of string
1188 bool bValid = false;
1189 if ( sal::static_int_cast<xub_StrLen>(nMatchList) >= rList.Len() )
1190 bValid = true;
1191 else
1193 sal_Unicode cNext = rList.GetChar(sal::static_int_cast<xub_StrLen>(nMatchList));
1194 if ( cNext == ' ' || ( bAllowBracket && cNext == '[' ) )
1195 bValid = true;
1198 if ( bValid )
1200 rMatched = nMatchList;
1201 return true;
1205 return false;
1208 BOOL ScDPObject::ParseFilters( ScDPGetPivotDataField& rTarget,
1209 std::vector< ScDPGetPivotDataField >& rFilters,
1210 const String& rFilterList )
1212 // parse the string rFilterList into parameters for GetPivotData
1214 CreateObjects(); // create xSource if not already done
1216 std::vector<String> aDataNames; // data fields (source name)
1217 std::vector<String> aGivenNames; // data fields (compound name)
1218 std::vector<String> aFieldNames; // column/row/data fields
1219 std::vector< uno::Sequence<rtl::OUString> > aFieldValues;
1222 // get all the field and item names
1225 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1226 uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
1227 sal_Int32 nDimCount = xIntDims->getCount();
1228 for ( sal_Int32 nDim = 0; nDim<nDimCount; nDim++ )
1230 uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nDim) );
1231 uno::Reference<container::XNamed> xDim( xIntDim, uno::UNO_QUERY );
1232 uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
1233 uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDim, uno::UNO_QUERY );
1234 BOOL bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1235 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
1236 sal_Int32 nOrient = ScUnoHelpFunctions::GetEnumProperty(
1237 xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION),
1238 sheet::DataPilotFieldOrientation_HIDDEN );
1239 if ( !bDataLayout )
1241 if ( nOrient == sheet::DataPilotFieldOrientation_DATA )
1243 String aSourceName;
1244 String aGivenName;
1245 ScDPOutput::GetDataDimensionNames( aSourceName, aGivenName, xIntDim );
1246 aDataNames.push_back( aSourceName );
1247 aGivenNames.push_back( aGivenName );
1249 else if ( nOrient != sheet::DataPilotFieldOrientation_HIDDEN )
1251 // get level names, as in ScDPOutput
1253 uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
1254 sal_Int32 nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
1255 rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
1256 if ( nHierarchy >= xHiers->getCount() )
1257 nHierarchy = 0;
1259 uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
1260 xHiers->getByIndex(nHierarchy) );
1261 uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
1262 if ( xHierSupp.is() )
1264 uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
1265 sal_Int32 nLevCount = xLevels->getCount();
1266 for (sal_Int32 nLev=0; nLev<nLevCount; nLev++)
1268 uno::Reference<uno::XInterface> xLevel = ScUnoHelpFunctions::AnyToInterface(
1269 xLevels->getByIndex(nLev) );
1270 uno::Reference<container::XNamed> xLevNam( xLevel, uno::UNO_QUERY );
1271 uno::Reference<sheet::XMembersSupplier> xLevSupp( xLevel, uno::UNO_QUERY );
1272 if ( xLevNam.is() && xLevSupp.is() )
1274 uno::Reference<container::XNameAccess> xMembers = xLevSupp->getMembers();
1276 String aFieldName( xLevNam->getName() );
1277 uno::Sequence<rtl::OUString> aMemberNames( xMembers->getElementNames() );
1279 aFieldNames.push_back( aFieldName );
1280 aFieldValues.push_back( aMemberNames );
1289 // compare and build filters
1292 SCSIZE nDataFields = aDataNames.size();
1293 SCSIZE nFieldCount = aFieldNames.size();
1294 DBG_ASSERT( aGivenNames.size() == nDataFields && aFieldValues.size() == nFieldCount, "wrong count" );
1296 bool bError = false;
1297 bool bHasData = false;
1298 String aRemaining( rFilterList );
1299 aRemaining.EraseLeadingAndTrailingChars( ' ' );
1300 while ( aRemaining.Len() && !bError )
1302 bool bUsed = false;
1304 // look for data field name
1306 for ( SCSIZE nDataPos=0; nDataPos<nDataFields && !bUsed; nDataPos++ )
1308 String aFound;
1309 sal_Int32 nMatched = 0;
1310 if ( lcl_IsAtStart( aRemaining, aDataNames[nDataPos], nMatched, false, NULL ) )
1311 aFound = aDataNames[nDataPos];
1312 else if ( lcl_IsAtStart( aRemaining, aGivenNames[nDataPos], nMatched, false, NULL ) )
1313 aFound = aGivenNames[nDataPos];
1315 if ( aFound.Len() )
1317 rTarget.maFieldName = aFound;
1318 aRemaining.Erase( 0, sal::static_int_cast<xub_StrLen>(nMatched) );
1319 bHasData = true;
1320 bUsed = true;
1324 // look for field name
1326 String aSpecField;
1327 bool bHasFieldName = false;
1328 if ( !bUsed )
1330 sal_Int32 nMatched = 0;
1331 for ( SCSIZE nField=0; nField<nFieldCount && !bHasFieldName; nField++ )
1333 if ( lcl_IsAtStart( aRemaining, aFieldNames[nField], nMatched, true, NULL ) )
1335 aSpecField = aFieldNames[nField];
1336 aRemaining.Erase( 0, sal::static_int_cast<xub_StrLen>(nMatched) );
1337 aRemaining.EraseLeadingChars( ' ' );
1339 // field name has to be followed by item name in brackets
1340 if ( aRemaining.GetChar(0) == '[' )
1342 bHasFieldName = true;
1343 // bUsed remains false - still need the item
1345 else
1347 bUsed = true;
1348 bError = true;
1354 // look for field item
1356 if ( !bUsed )
1358 bool bItemFound = false;
1359 sal_Int32 nMatched = 0;
1360 String aFoundName;
1361 String aFoundValue;
1362 sheet::GeneralFunction eFunc = sheet::GeneralFunction_NONE;
1363 sheet::GeneralFunction eFoundFunc = sheet::GeneralFunction_NONE;
1365 for ( SCSIZE nField=0; nField<nFieldCount; nField++ )
1367 // If a field name is given, look in that field only, otherwise in all fields.
1368 // aSpecField is initialized from aFieldNames array, so exact comparison can be used.
1369 if ( !bHasFieldName || aFieldNames[nField] == aSpecField )
1371 const uno::Sequence<rtl::OUString>& rItems = aFieldValues[nField];
1372 sal_Int32 nItemCount = rItems.getLength();
1373 const rtl::OUString* pItemArr = rItems.getConstArray();
1374 for ( sal_Int32 nItem=0; nItem<nItemCount; nItem++ )
1376 if ( lcl_IsAtStart( aRemaining, pItemArr[nItem], nMatched, false, &eFunc ) )
1378 if ( bItemFound )
1379 bError = true; // duplicate (also across fields)
1380 else
1382 aFoundName = aFieldNames[nField];
1383 aFoundValue = pItemArr[nItem];
1384 eFoundFunc = eFunc;
1385 bItemFound = true;
1386 bUsed = true;
1393 if ( bItemFound && !bError )
1395 ScDPGetPivotDataField aField;
1396 aField.maFieldName = aFoundName;
1397 aField.meFunction = eFoundFunc;
1398 aField.mbValIsStr = true;
1399 aField.maValStr = aFoundValue;
1400 aField.mnValNum = 0.0;
1401 rFilters.push_back( aField );
1403 aRemaining.Erase( 0, sal::static_int_cast<xub_StrLen>(nMatched) );
1407 if ( !bUsed )
1408 bError = true;
1410 aRemaining.EraseLeadingChars( ' ' ); // remove any number of spaces between entries
1413 if ( !bError && !bHasData && aDataNames.size() == 1 )
1415 // if there's only one data field, its name need not be specified
1416 rTarget.maFieldName = aDataNames[0];
1417 bHasData = true;
1420 return bHasData && !bError;
1423 void ScDPObject::ToggleDetails(const DataPilotTableHeaderData& rElemDesc, ScDPObject* pDestObj)
1425 CreateObjects(); // create xSource if not already done
1427 // find dimension name
1429 uno::Reference<container::XNamed> xDim;
1430 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1431 uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
1432 long nIntCount = xIntDims->getCount();
1433 if ( rElemDesc.Dimension < nIntCount )
1435 uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface(
1436 xIntDims->getByIndex(rElemDesc.Dimension) );
1437 xDim = uno::Reference<container::XNamed>( xIntDim, uno::UNO_QUERY );
1439 DBG_ASSERT( xDim.is(), "dimension not found" );
1440 if ( !xDim.is() ) return;
1441 String aDimName = xDim->getName();
1443 uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
1444 BOOL bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1445 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
1446 if (bDataLayout)
1448 // the elements of the data layout dimension can't be found by their names
1449 // -> don't change anything
1450 return;
1453 // query old state
1455 long nHierCount = 0;
1456 uno::Reference<container::XIndexAccess> xHiers;
1457 uno::Reference<sheet::XHierarchiesSupplier> xHierSupp( xDim, uno::UNO_QUERY );
1458 if ( xHierSupp.is() )
1460 uno::Reference<container::XNameAccess> xHiersName = xHierSupp->getHierarchies();
1461 xHiers = new ScNameToIndexAccess( xHiersName );
1462 nHierCount = xHiers->getCount();
1464 uno::Reference<uno::XInterface> xHier;
1465 if ( rElemDesc.Hierarchy < nHierCount )
1466 xHier = ScUnoHelpFunctions::AnyToInterface( xHiers->getByIndex(rElemDesc.Hierarchy) );
1467 DBG_ASSERT( xHier.is(), "hierarchy not found" );
1468 if ( !xHier.is() ) return;
1470 long nLevCount = 0;
1471 uno::Reference<container::XIndexAccess> xLevels;
1472 uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHier, uno::UNO_QUERY );
1473 if ( xLevSupp.is() )
1475 uno::Reference<container::XNameAccess> xLevsName = xLevSupp->getLevels();
1476 xLevels = new ScNameToIndexAccess( xLevsName );
1477 nLevCount = xLevels->getCount();
1479 uno::Reference<uno::XInterface> xLevel;
1480 if ( rElemDesc.Level < nLevCount )
1481 xLevel = ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex(rElemDesc.Level) );
1482 DBG_ASSERT( xLevel.is(), "level not found" );
1483 if ( !xLevel.is() ) return;
1485 uno::Reference<container::XNameAccess> xMembers;
1486 uno::Reference<sheet::XMembersSupplier> xMbrSupp( xLevel, uno::UNO_QUERY );
1487 if ( xMbrSupp.is() )
1488 xMembers = xMbrSupp->getMembers();
1490 BOOL bFound = FALSE;
1491 BOOL bShowDetails = TRUE;
1493 if ( xMembers.is() )
1495 if ( xMembers->hasByName(rElemDesc.MemberName) )
1497 uno::Reference<uno::XInterface> xMemberInt = ScUnoHelpFunctions::AnyToInterface(
1498 xMembers->getByName(rElemDesc.MemberName) );
1499 uno::Reference<beans::XPropertySet> xMbrProp( xMemberInt, uno::UNO_QUERY );
1500 if ( xMbrProp.is() )
1502 bShowDetails = ScUnoHelpFunctions::GetBoolProperty( xMbrProp,
1503 rtl::OUString::createFromAscii(DP_PROP_SHOWDETAILS) );
1504 //! don't set bFound if property is unknown?
1505 bFound = TRUE;
1510 DBG_ASSERT( bFound, "member not found" );
1512 //! use Hierarchy and Level in SaveData !!!!
1514 // modify pDestObj if set, this object otherwise
1515 ScDPSaveData* pModifyData = pDestObj ? ( pDestObj->pSaveData ) : pSaveData;
1516 DBG_ASSERT( pModifyData, "no data?" );
1517 if ( pModifyData )
1519 const String aName = rElemDesc.MemberName;
1520 pModifyData->GetDimensionByName(aDimName)->
1521 GetMemberByName(aName)->SetShowDetails( !bShowDetails ); // toggle
1523 if ( pDestObj )
1524 pDestObj->InvalidateData(); // re-init source from SaveData
1525 else
1526 InvalidateData(); // re-init source from SaveData
1530 long lcl_FindName( const rtl::OUString& rString, const uno::Reference<container::XNameAccess>& xCollection )
1532 if ( xCollection.is() )
1534 uno::Sequence<rtl::OUString> aSeq = xCollection->getElementNames();
1535 long nCount = aSeq.getLength();
1536 const rtl::OUString* pArr = aSeq.getConstArray();
1537 for (long nPos=0; nPos<nCount; nPos++)
1538 if ( pArr[nPos] == rString )
1539 return nPos;
1541 return -1; // not found
1544 USHORT lcl_FirstSubTotal( const uno::Reference<beans::XPropertySet>& xDimProp ) // PIVOT_FUNC mask
1546 uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDimProp, uno::UNO_QUERY );
1547 if ( xDimProp.is() && xDimSupp.is() )
1549 uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
1550 long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
1551 rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
1552 if ( nHierarchy >= xHiers->getCount() )
1553 nHierarchy = 0;
1555 uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
1556 xHiers->getByIndex(nHierarchy) );
1557 uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
1558 if ( xHierSupp.is() )
1560 uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
1561 uno::Reference<uno::XInterface> xLevel =
1562 ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex( 0 ) );
1563 uno::Reference<beans::XPropertySet> xLevProp( xLevel, uno::UNO_QUERY );
1564 if ( xLevProp.is() )
1566 uno::Any aSubAny;
1569 aSubAny = xLevProp->getPropertyValue(
1570 rtl::OUString::createFromAscii(DP_PROP_SUBTOTALS) );
1572 catch(uno::Exception&)
1575 uno::Sequence<sheet::GeneralFunction> aSeq;
1576 if ( aSubAny >>= aSeq )
1578 USHORT nMask = 0;
1579 const sheet::GeneralFunction* pArray = aSeq.getConstArray();
1580 long nCount = aSeq.getLength();
1581 for (long i=0; i<nCount; i++)
1582 nMask |= ScDataPilotConversion::FunctionBit(pArray[i]);
1583 return nMask;
1589 DBG_ERROR("FirstSubTotal: NULL");
1590 return 0;
1593 USHORT lcl_CountBits( USHORT nBits )
1595 if (!nBits) return 0;
1597 USHORT nCount = 0;
1598 USHORT nMask = 1;
1599 for (USHORT i=0; i<16; i++)
1601 if ( nBits & nMask )
1602 ++nCount;
1603 nMask <<= 1;
1605 return nCount;
1608 SCSIZE lcl_FillOldFields( PivotField* pFields,
1609 const uno::Reference<sheet::XDimensionsSupplier>& xSource,
1610 USHORT nOrient, SCCOL nColAdd, BOOL bAddData )
1612 SCSIZE nOutCount = 0;
1613 BOOL bDataFound = FALSE;
1615 SCSIZE nCount = (nOrient == sheet::DataPilotFieldOrientation_PAGE) ? PIVOT_MAXPAGEFIELD : PIVOT_MAXFIELD;
1617 //! merge multiple occurences (data field with different functions)
1618 //! force data field in one dimension
1620 std::vector< long > aPos( nCount, 0 );
1622 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1623 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
1624 long nDimCount = xDims->getCount();
1625 for (long nDim=0; nDim < nDimCount && nOutCount < nCount; nDim++)
1627 uno::Reference<uno::XInterface> xIntDim =
1628 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
1629 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
1630 long nDimOrient = ScUnoHelpFunctions::GetEnumProperty(
1631 xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION),
1632 sheet::DataPilotFieldOrientation_HIDDEN );
1633 if ( xDimProp.is() && nDimOrient == nOrient )
1635 USHORT nMask = 0;
1636 if ( nOrient == sheet::DataPilotFieldOrientation_DATA )
1638 sheet::GeneralFunction eFunc = (sheet::GeneralFunction)ScUnoHelpFunctions::GetEnumProperty(
1639 xDimProp, rtl::OUString::createFromAscii(DP_PROP_FUNCTION),
1640 sheet::GeneralFunction_NONE );
1641 if ( eFunc == sheet::GeneralFunction_AUTO )
1643 //! test for numeric data
1644 eFunc = sheet::GeneralFunction_SUM;
1646 nMask = ScDataPilotConversion::FunctionBit(eFunc);
1648 else
1649 nMask = lcl_FirstSubTotal( xDimProp ); // from first hierarchy
1651 BOOL bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1652 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
1653 uno::Any aOrigAny;
1656 aOrigAny = xDimProp->getPropertyValue(
1657 rtl::OUString::createFromAscii(DP_PROP_ORIGINAL) );
1659 catch(uno::Exception&)
1663 long nDupSource = -1;
1664 uno::Reference<uno::XInterface> xIntOrig = ScUnoHelpFunctions::AnyToInterface( aOrigAny );
1665 if ( xIntOrig.is() )
1667 uno::Reference<container::XNamed> xNameOrig( xIntOrig, uno::UNO_QUERY );
1668 if ( xNameOrig.is() )
1669 nDupSource = lcl_FindName( xNameOrig->getName(), xDimsName );
1672 BOOL bDupUsed = FALSE;
1673 if ( nDupSource >= 0 )
1675 // add function bit to previous entry
1677 SCsCOL nCompCol;
1678 if ( bDataLayout )
1679 nCompCol = PIVOT_DATA_FIELD;
1680 else
1681 nCompCol = static_cast<SCsCOL>(nDupSource)+nColAdd; //! seek source column from name
1683 for (SCSIZE nOld=0; nOld<nOutCount && !bDupUsed; nOld++)
1684 if ( pFields[nOld].nCol == nCompCol )
1686 // add to previous column only if new bits aren't already set there
1687 if ( ( pFields[nOld].nFuncMask & nMask ) == 0 )
1689 pFields[nOld].nFuncMask |= nMask;
1690 pFields[nOld].nFuncCount = lcl_CountBits( pFields[nOld].nFuncMask );
1691 bDupUsed = TRUE;
1696 if ( !bDupUsed ) // also for duplicated dim if original has different orientation
1698 if ( bDataLayout )
1700 pFields[nOutCount].nCol = PIVOT_DATA_FIELD;
1701 bDataFound = TRUE;
1703 else if ( nDupSource >= 0 ) // if source was not found (different orientation)
1704 pFields[nOutCount].nCol = static_cast<SCsCOL>(nDupSource)+nColAdd; //! seek from name
1705 else
1706 pFields[nOutCount].nCol = static_cast<SCsCOL>(nDim)+nColAdd; //! seek source column from name
1708 pFields[nOutCount].nFuncMask = nMask;
1709 pFields[nOutCount].nFuncCount = lcl_CountBits( nMask );
1710 aPos[nOutCount] = ScUnoHelpFunctions::GetLongProperty( xDimProp,
1711 rtl::OUString::createFromAscii(DP_PROP_POSITION) );
1715 if( nOrient == sheet::DataPilotFieldOrientation_DATA )
1716 xDimProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_REFVALUE ) ) )
1717 >>= pFields[nOutCount].maFieldRef;
1719 catch( uno::Exception& )
1723 ++nOutCount;
1728 // sort by getPosition() value
1730 for (SCSIZE i=0; i+1<nOutCount; i++)
1732 for (SCSIZE j=0; j+i+1<nOutCount; j++)
1733 if ( aPos[j+1] < aPos[j] )
1735 std::swap( aPos[j], aPos[j+1] );
1736 std::swap( pFields[j], pFields[j+1] );
1740 if ( bAddData && !bDataFound )
1742 if ( nOutCount >= nCount ) // space for data field?
1743 --nOutCount; //! error?
1744 pFields[nOutCount].nCol = PIVOT_DATA_FIELD;
1745 pFields[nOutCount].nFuncMask = 0;
1746 pFields[nOutCount].nFuncCount = 0;
1747 ++nOutCount;
1750 return nOutCount;
1753 BOOL ScDPObject::FillOldParam(ScPivotParam& rParam, BOOL bForFile) const
1755 ((ScDPObject*)this)->CreateObjects(); // xSource is needed for field numbers
1757 rParam.nCol = aOutRange.aStart.Col();
1758 rParam.nRow = aOutRange.aStart.Row();
1759 rParam.nTab = aOutRange.aStart.Tab();
1760 // ppLabelArr / nLabels is not changed
1762 SCCOL nColAdd = 0;
1763 if ( bForFile )
1765 // in old file format, columns are within document, not within source range
1767 DBG_ASSERT( pSheetDesc, "FillOldParam: bForFile, !pSheetDesc" );
1768 nColAdd = pSheetDesc->aSourceRange.aStart.Col();
1771 BOOL bAddData = ( lcl_GetDataGetOrientation( xSource ) == sheet::DataPilotFieldOrientation_HIDDEN );
1772 rParam.nPageCount = lcl_FillOldFields( rParam.aPageArr,
1773 xSource, sheet::DataPilotFieldOrientation_PAGE, nColAdd, FALSE );
1774 rParam.nColCount = lcl_FillOldFields( rParam.aColArr,
1775 xSource, sheet::DataPilotFieldOrientation_COLUMN, nColAdd, bAddData );
1776 rParam.nRowCount = lcl_FillOldFields( rParam.aRowArr,
1777 xSource, sheet::DataPilotFieldOrientation_ROW, nColAdd, FALSE );
1778 rParam.nDataCount = lcl_FillOldFields( rParam.aDataArr,
1779 xSource, sheet::DataPilotFieldOrientation_DATA, nColAdd, FALSE );
1781 uno::Reference<beans::XPropertySet> xProp( xSource, uno::UNO_QUERY );
1782 if (xProp.is())
1786 rParam.bMakeTotalCol = ScUnoHelpFunctions::GetBoolProperty( xProp,
1787 rtl::OUString::createFromAscii(DP_PROP_COLUMNGRAND), TRUE );
1788 rParam.bMakeTotalRow = ScUnoHelpFunctions::GetBoolProperty( xProp,
1789 rtl::OUString::createFromAscii(DP_PROP_ROWGRAND), TRUE );
1791 // following properties may be missing for external sources
1792 rParam.bIgnoreEmptyRows = ScUnoHelpFunctions::GetBoolProperty( xProp,
1793 rtl::OUString::createFromAscii(DP_PROP_IGNOREEMPTY) );
1794 rParam.bDetectCategories = ScUnoHelpFunctions::GetBoolProperty( xProp,
1795 rtl::OUString::createFromAscii(DP_PROP_REPEATIFEMPTY) );
1797 catch(uno::Exception&)
1799 // no error
1802 return TRUE;
1805 void lcl_FillLabelData( ScDPLabelData& rData, const uno::Reference< beans::XPropertySet >& xDimProp )
1807 uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDimProp, uno::UNO_QUERY );
1808 if ( xDimProp.is() && xDimSupp.is() )
1810 uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
1811 long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
1812 rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
1813 if ( nHierarchy >= xHiers->getCount() )
1814 nHierarchy = 0;
1815 rData.mnUsedHier = nHierarchy;
1817 uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
1818 xHiers->getByIndex(nHierarchy) );
1820 uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
1821 if ( xHierSupp.is() )
1823 uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
1824 uno::Reference<uno::XInterface> xLevel =
1825 ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex( 0 ) );
1826 uno::Reference<beans::XPropertySet> xLevProp( xLevel, uno::UNO_QUERY );
1827 if ( xLevProp.is() )
1829 rData.mbShowAll = ScUnoHelpFunctions::GetBoolProperty( xLevProp,
1830 rtl::OUString::createFromAscii(DP_PROP_SHOWEMPTY) );
1834 xLevProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_SORTING ) ) )
1835 >>= rData.maSortInfo;
1836 xLevProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_LAYOUT ) ) )
1837 >>= rData.maLayoutInfo;
1838 xLevProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_AUTOSHOW ) ) )
1839 >>= rData.maShowInfo;
1841 catch(uno::Exception&)
1849 BOOL ScDPObject::FillLabelData(ScPivotParam& rParam)
1851 rParam.maLabelArray.clear();
1853 ((ScDPObject*)this)->CreateObjects();
1855 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1856 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
1857 long nDimCount = xDims->getCount();
1858 if ( nDimCount > MAX_LABELS )
1859 nDimCount = MAX_LABELS;
1860 if (!nDimCount)
1861 return FALSE;
1863 for (long nDim=0; nDim < nDimCount; nDim++)
1865 String aFieldName;
1866 uno::Reference<uno::XInterface> xIntDim =
1867 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
1868 uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
1869 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
1871 if ( xDimName.is() && xDimProp.is() )
1873 BOOL bDuplicated = FALSE;
1874 BOOL bData = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1875 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
1876 //! error checking -- is "IsDataLayoutDimension" property required??
1880 aFieldName = String( xDimName->getName() );
1882 uno::Any aOrigAny = xDimProp->getPropertyValue(
1883 rtl::OUString::createFromAscii(DP_PROP_ORIGINAL) );
1884 uno::Reference<uno::XInterface> xIntOrig;
1885 if ( (aOrigAny >>= xIntOrig) && xIntOrig.is() )
1886 bDuplicated = TRUE;
1888 catch(uno::Exception&)
1892 if ( aFieldName.Len() && !bData && !bDuplicated )
1894 SCsCOL nCol = static_cast< SCsCOL >( nDim ); //! ???
1895 bool bIsValue = true; //! check
1897 ScDPLabelDataRef pNewLabel(new ScDPLabelData(aFieldName, nCol, bIsValue));
1898 GetHierarchies(nDim, pNewLabel->maHiers);
1899 GetMembers(nDim, pNewLabel->maMembers, &pNewLabel->maVisible, &pNewLabel->maShowDet);
1900 lcl_FillLabelData(*pNewLabel, xDimProp);
1901 rParam.maLabelArray.push_back(pNewLabel);
1906 return TRUE;
1909 BOOL ScDPObject::GetHierarchiesNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xHiers )
1911 BOOL bRet = FALSE;
1912 uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
1913 uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
1914 if( xIntDims.is() )
1916 uno::Reference<sheet::XHierarchiesSupplier> xHierSup(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
1917 if (xHierSup.is())
1919 xHiers.set( xHierSup->getHierarchies() );
1920 bRet = xHiers.is();
1923 return bRet;
1926 BOOL ScDPObject::GetHierarchies( sal_Int32 nDim, uno::Sequence< rtl::OUString >& rHiers )
1928 BOOL bRet = FALSE;
1929 uno::Reference< container::XNameAccess > xHiersNA;
1930 if( GetHierarchiesNA( nDim, xHiersNA ) )
1932 rHiers = xHiersNA->getElementNames();
1933 bRet = TRUE;
1935 return bRet;
1938 sal_Int32 ScDPObject::GetUsedHierarchy( sal_Int32 nDim )
1940 sal_Int32 nHier = 0;
1941 uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
1942 uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
1943 uno::Reference<beans::XPropertySet> xDim(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
1944 if (xDim.is())
1945 nHier = ScUnoHelpFunctions::GetLongProperty( xDim, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( SC_UNO_USEDHIER ) ) );
1946 return nHier;
1949 BOOL ScDPObject::GetMembersNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xMembers )
1951 return GetMembersNA( nDim, GetUsedHierarchy( nDim ), xMembers );
1954 BOOL ScDPObject::GetMembers( sal_Int32 nDim,
1955 uno::Sequence< rtl::OUString >& rMembers,
1956 uno::Sequence< sal_Bool >* pVisible,
1957 uno::Sequence< sal_Bool >* pShowDet )
1959 return GetMembers( nDim, GetUsedHierarchy( nDim ), rMembers, pVisible, pShowDet );
1962 BOOL ScDPObject::GetMembersNA( sal_Int32 nDim, sal_Int32 nHier, uno::Reference< container::XNameAccess >& xMembers )
1964 BOOL bRet = FALSE;
1965 uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
1966 uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
1967 uno::Reference<beans::XPropertySet> xDim(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
1968 if (xDim.is())
1970 uno::Reference<sheet::XHierarchiesSupplier> xHierSup(xDim, uno::UNO_QUERY);
1971 if (xHierSup.is())
1973 uno::Reference<container::XIndexAccess> xHiers(new ScNameToIndexAccess(xHierSup->getHierarchies()));
1974 uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHiers->getByIndex(nHier), uno::UNO_QUERY );
1975 if ( xLevSupp.is() )
1977 uno::Reference<container::XIndexAccess> xLevels(new ScNameToIndexAccess( xLevSupp->getLevels()));
1978 if (xLevels.is())
1980 sal_Int32 nLevCount = xLevels->getCount();
1981 if (nLevCount > 0)
1983 uno::Reference<sheet::XMembersSupplier> xMembSupp( xLevels->getByIndex(0), uno::UNO_QUERY );
1984 if ( xMembSupp.is() )
1986 xMembers.set(xMembSupp->getMembers());
1987 bRet = TRUE;
1994 return bRet;
1997 BOOL ScDPObject::GetMembers( sal_Int32 nDim, sal_Int32 nHier,
1998 uno::Sequence< rtl::OUString >& rMembers,
1999 uno::Sequence< sal_Bool >* pVisible,
2000 uno::Sequence< sal_Bool >* pShowDet )
2002 BOOL bRet = FALSE;
2003 uno::Reference< container::XNameAccess > xMembersNA;
2004 if( GetMembersNA( nDim, nHier, xMembersNA ) )
2006 uno::Reference< container::XIndexAccess > xMembersIA( new ScNameToIndexAccess( xMembersNA ) );
2007 sal_Int32 nCount = xMembersIA->getCount();
2008 rMembers.realloc( nCount );
2009 if( pVisible )
2010 pVisible->realloc( nCount );
2011 if( pShowDet )
2012 pShowDet->realloc( nCount );
2014 rtl::OUString* pAry = rMembers.getArray();
2015 for( sal_Int32 nItem = 0; nItem < nCount; ++nItem )
2017 uno::Reference< container::XNamed > xMember( xMembersIA->getByIndex( nItem ), uno::UNO_QUERY );
2018 if( xMember.is() )
2019 pAry[ nItem ] = xMember->getName();
2020 if( pVisible || pShowDet )
2022 uno::Reference< beans::XPropertySet > xMemProp( xMember, uno::UNO_QUERY );
2023 if( pVisible )
2025 sal_Bool bVis = sal_True;
2026 if( xMemProp.is() )
2027 bVis = ScUnoHelpFunctions::GetBoolProperty( xMemProp,
2028 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_ISVISIBL ) ) );
2029 (*pVisible)[ nItem ] = bVis;
2031 if( pShowDet )
2033 sal_Bool bShow = sal_True;
2034 if( xMemProp.is() )
2035 bShow = ScUnoHelpFunctions::GetBoolProperty( xMemProp,
2036 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_SHOWDETA ) ) );
2037 (*pShowDet)[ nItem ] = bShow;
2041 bRet = TRUE;
2043 return bRet;
2046 //------------------------------------------------------------------------
2047 // convert old pivot tables into new datapilot tables
2049 String lcl_GetDimName( const uno::Reference<sheet::XDimensionsSupplier>& xSource, long nDim )
2051 rtl::OUString aName;
2052 if ( xSource.is() )
2054 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
2055 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
2056 long nDimCount = xDims->getCount();
2057 if ( nDim < nDimCount )
2059 uno::Reference<uno::XInterface> xIntDim =
2060 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
2061 uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
2062 if (xDimName.is())
2066 aName = xDimName->getName();
2068 catch(uno::Exception&)
2074 return aName;
2077 // static
2078 void ScDPObject::ConvertOrientation( ScDPSaveData& rSaveData,
2079 PivotField* pFields, SCSIZE nCount, USHORT nOrient,
2080 ScDocument* pDoc, SCROW nRow, SCTAB nTab,
2081 const uno::Reference<sheet::XDimensionsSupplier>& xSource,
2082 BOOL bOldDefaults,
2083 PivotField* pRefColFields, SCSIZE nRefColCount,
2084 PivotField* pRefRowFields, SCSIZE nRefRowCount,
2085 PivotField* pRefPageFields, SCSIZE nRefPageCount )
2087 // pDoc or xSource must be set
2088 DBG_ASSERT( pDoc || xSource.is(), "missing string source" );
2090 String aDocStr;
2091 ScDPSaveDimension* pDim;
2093 for (SCSIZE i=0; i<nCount; i++)
2095 SCCOL nCol = pFields[i].nCol;
2096 USHORT nFuncs = pFields[i].nFuncMask;
2097 const sheet::DataPilotFieldReference& rFieldRef = pFields[i].maFieldRef;
2099 if ( nCol == PIVOT_DATA_FIELD )
2100 pDim = rSaveData.GetDataLayoutDimension();
2101 else
2103 if ( pDoc )
2104 pDoc->GetString( nCol, nRow, nTab, aDocStr );
2105 else
2106 aDocStr = lcl_GetDimName( xSource, nCol ); // cols must start at 0
2108 if ( aDocStr.Len() )
2109 pDim = rSaveData.GetDimensionByName(aDocStr);
2110 else
2111 pDim = NULL;
2114 if ( pDim )
2116 if ( nOrient == sheet::DataPilotFieldOrientation_DATA ) // set summary function
2118 // generate an individual entry for each function
2119 BOOL bFirst = TRUE;
2121 // if a dimension is used for column/row/page and data,
2122 // use duplicated dimensions for all data occurrences
2123 if (pRefColFields)
2124 for (SCSIZE nRefCol=0; nRefCol<nRefColCount; nRefCol++)
2125 if (pRefColFields[nRefCol].nCol == nCol)
2126 bFirst = FALSE;
2127 if (pRefRowFields)
2128 for (SCSIZE nRefRow=0; nRefRow<nRefRowCount; nRefRow++)
2129 if (pRefRowFields[nRefRow].nCol == nCol)
2130 bFirst = FALSE;
2131 if (pRefPageFields)
2132 for (USHORT nRefPage=0; nRefPage<nRefPageCount; ++nRefPage)
2133 if (pRefPageFields[nRefPage].nCol == nCol)
2134 bFirst = FALSE;
2136 // if set via api, a data column may occur several times
2137 // (if the function hasn't been changed yet) -> also look for duplicate data column
2138 for (SCSIZE nPrevData=0; nPrevData<i; nPrevData++)
2139 if (pFields[nPrevData].nCol == nCol)
2140 bFirst = FALSE;
2142 USHORT nMask = 1;
2143 for (USHORT nBit=0; nBit<16; nBit++)
2145 if ( nFuncs & nMask )
2147 sheet::GeneralFunction eFunc = ScDataPilotConversion::FirstFunc( nMask );
2148 ScDPSaveDimension* pCurrDim = bFirst ? pDim : rSaveData.DuplicateDimension(pDim->GetName());
2149 pCurrDim->SetOrientation( nOrient );
2150 pCurrDim->SetFunction( sal::static_int_cast<USHORT>(eFunc) );
2152 if( rFieldRef.ReferenceType == sheet::DataPilotFieldReferenceType::NONE )
2153 pCurrDim->SetReferenceValue( 0 );
2154 else
2155 pCurrDim->SetReferenceValue( &rFieldRef );
2157 bFirst = FALSE;
2159 nMask *= 2;
2162 else // set SubTotals
2164 pDim->SetOrientation( nOrient );
2166 USHORT nFuncArray[16];
2167 USHORT nFuncCount = 0;
2168 USHORT nMask = 1;
2169 for (USHORT nBit=0; nBit<16; nBit++)
2171 if ( nFuncs & nMask )
2172 nFuncArray[nFuncCount++] = sal::static_int_cast<USHORT>(ScDataPilotConversion::FirstFunc( nMask ));
2173 nMask *= 2;
2175 pDim->SetSubTotals( nFuncCount, nFuncArray );
2177 // ShowEmpty was implicit in old tables,
2178 // must be set for data layout dimension (not accessible in dialog)
2179 if ( bOldDefaults || nCol == PIVOT_DATA_FIELD )
2180 pDim->SetShowEmpty( TRUE );
2186 #if OLD_PIVOT_IMPLEMENTATION
2187 void ScDPObject::InitFromOldPivot( const ScPivot& rOld, ScDocument* pDocP, BOOL bSetSource )
2189 ScDPSaveData aSaveData;
2191 ScPivotParam aParam;
2192 ScQueryParam aQuery;
2193 ScArea aArea;
2194 rOld.GetParam( aParam, aQuery, aArea );
2196 ConvertOrientation( aSaveData, aParam.aPageArr, aParam.nPageCount,
2197 sheet::DataPilotFieldOrientation_PAGE, pDocP, aArea.nRowStart, aArea.nTab,
2198 uno::Reference<sheet::XDimensionsSupplier>(), TRUE );
2199 ConvertOrientation( aSaveData, aParam.aColArr, aParam.nColCount,
2200 sheet::DataPilotFieldOrientation_COLUMN, pDocP, aArea.nRowStart, aArea.nTab,
2201 uno::Reference<sheet::XDimensionsSupplier>(), TRUE );
2202 ConvertOrientation( aSaveData, aParam.aRowArr, aParam.nRowCount,
2203 sheet::DataPilotFieldOrientation_ROW, pDocP, aArea.nRowStart, aArea.nTab,
2204 uno::Reference<sheet::XDimensionsSupplier>(), TRUE );
2205 ConvertOrientation( aSaveData, aParam.aDataArr, aParam.nDataCount,
2206 sheet::DataPilotFieldOrientation_DATA, pDocP, aArea.nRowStart, aArea.nTab,
2207 uno::Reference<sheet::XDimensionsSupplier>(), TRUE,
2208 aParam.aColArr, aParam.nColCount, aParam.aRowArr, aParam.nRowCount );
2210 aSaveData.SetIgnoreEmptyRows( rOld.GetIgnoreEmpty() );
2211 aSaveData.SetRepeatIfEmpty( rOld.GetDetectCat() );
2212 aSaveData.SetColumnGrand( rOld.GetMakeTotalCol() );
2213 aSaveData.SetRowGrand( rOld.GetMakeTotalRow() );
2215 SetSaveData( aSaveData );
2216 if (bSetSource)
2218 ScSheetSourceDesc aDesc;
2219 aDesc.aSourceRange = rOld.GetSrcArea();
2220 rOld.GetQuery( aDesc.aQueryParam );
2221 SetSheetDesc( aDesc );
2223 SetOutRange( rOld.GetDestArea() );
2225 aTableName = rOld.GetName();
2226 aTableTag = rOld.GetTag();
2228 #endif
2230 // -----------------------------------------------------------------------
2232 // static
2233 BOOL ScDPObject::HasRegisteredSources()
2235 BOOL bFound = FALSE;
2237 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
2238 uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
2239 if ( xEnAc.is() )
2241 uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
2242 rtl::OUString::createFromAscii( SCDPSOURCE_SERVICE ) );
2243 if ( xEnum.is() && xEnum->hasMoreElements() )
2244 bFound = TRUE;
2247 return bFound;
2250 // static
2251 uno::Sequence<rtl::OUString> ScDPObject::GetRegisteredSources()
2253 long nCount = 0;
2254 uno::Sequence<rtl::OUString> aSeq(0);
2256 // use implementation names...
2258 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
2259 uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
2260 if ( xEnAc.is() )
2262 uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
2263 rtl::OUString::createFromAscii( SCDPSOURCE_SERVICE ) );
2264 if ( xEnum.is() )
2266 while ( xEnum->hasMoreElements() )
2268 uno::Any aAddInAny = xEnum->nextElement();
2269 // if ( aAddInAny.getReflection()->getTypeClass() == TypeClass_INTERFACE )
2271 uno::Reference<uno::XInterface> xIntFac;
2272 aAddInAny >>= xIntFac;
2273 if ( xIntFac.is() )
2275 uno::Reference<lang::XServiceInfo> xInfo( xIntFac, uno::UNO_QUERY );
2276 if ( xInfo.is() )
2278 rtl::OUString sName = xInfo->getImplementationName();
2280 aSeq.realloc( nCount+1 );
2281 aSeq.getArray()[nCount] = sName;
2282 ++nCount;
2290 return aSeq;
2293 // static
2294 uno::Reference<sheet::XDimensionsSupplier> ScDPObject::CreateSource( const ScDPServiceDesc& rDesc )
2296 rtl::OUString aImplName = rDesc.aServiceName;
2297 uno::Reference<sheet::XDimensionsSupplier> xRet = NULL;
2299 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
2300 uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
2301 if ( xEnAc.is() )
2303 uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
2304 rtl::OUString::createFromAscii( SCDPSOURCE_SERVICE ) );
2305 if ( xEnum.is() )
2307 while ( xEnum->hasMoreElements() && !xRet.is() )
2309 uno::Any aAddInAny = xEnum->nextElement();
2310 // if ( aAddInAny.getReflection()->getTypeClass() == TypeClass_INTERFACE )
2312 uno::Reference<uno::XInterface> xIntFac;
2313 aAddInAny >>= xIntFac;
2314 if ( xIntFac.is() )
2316 uno::Reference<lang::XServiceInfo> xInfo( xIntFac, uno::UNO_QUERY );
2317 uno::Reference<lang::XSingleServiceFactory> xFac( xIntFac, uno::UNO_QUERY );
2318 if ( xFac.is() && xInfo.is() && xInfo->getImplementationName() == aImplName )
2322 uno::Reference<uno::XInterface> xInterface = xFac->createInstance();
2323 uno::Reference<lang::XInitialization> xInit( xInterface, uno::UNO_QUERY );
2324 if (xInit.is())
2326 // initialize
2327 uno::Sequence<uno::Any> aSeq(4);
2328 uno::Any* pArray = aSeq.getArray();
2329 pArray[0] <<= rtl::OUString( rDesc.aParSource );
2330 pArray[1] <<= rtl::OUString( rDesc.aParName );
2331 pArray[2] <<= rtl::OUString( rDesc.aParUser );
2332 pArray[3] <<= rtl::OUString( rDesc.aParPass );
2333 xInit->initialize( aSeq );
2335 xRet = uno::Reference<sheet::XDimensionsSupplier>( xInterface, uno::UNO_QUERY );
2337 catch(uno::Exception&)
2347 return xRet;
2350 // ============================================================================
2352 ScDPCacheCell::ScDPCacheCell() :
2353 mnStrId(ScSimpleSharedString::EMPTY),
2354 mnType(SC_VALTYPE_EMPTY),
2355 mfValue(0.0),
2356 mbNumeric(false)
2360 ScDPCacheCell::ScDPCacheCell(const ScDPCacheCell& r) :
2361 mnStrId(r.mnStrId),
2362 mnType(r.mnType),
2363 mfValue(r.mfValue),
2364 mbNumeric(r.mbNumeric)
2368 ScDPCacheCell::~ScDPCacheCell()
2372 // ============================================================================
2374 size_t ScDPCollection::CacheCellHash::operator()(const ScDPCacheCell* pCell) const
2376 return pCell->mnStrId + static_cast<size_t>(pCell->mnType) +
2377 static_cast<size_t>(pCell->mfValue) + static_cast<size_t>(pCell->mbNumeric);
2380 bool ScDPCollection::CacheCellEqual::operator()(const ScDPCacheCell* p1, const ScDPCacheCell* p2) const
2382 if (!p1 && !p2)
2383 return true;
2385 if ((!p1 && p2) || (p1 && !p2))
2386 return false;
2388 return p1->mnStrId == p2->mnStrId && p1->mfValue == p2->mfValue &&
2389 p1->mbNumeric == p2->mbNumeric && p1->mnType == p2->mnType;
2392 // ----------------------------------------------------------------------------
2394 ScDPCollection::ScDPCollection(ScDocument* pDocument) :
2395 pDoc( pDocument )
2399 ScDPCollection::ScDPCollection(const ScDPCollection& r) :
2400 ScCollection(r),
2401 pDoc(r.pDoc),
2402 maSharedString(r.maSharedString),
2403 maCacheCellPool() // #i101725# don't copy hash_set with pointers from the other collection
2407 ScDPCollection::~ScDPCollection()
2409 clearCacheCellPool();
2412 ScDataObject* ScDPCollection::Clone() const
2414 return new ScDPCollection(*this);
2417 void ScDPCollection::DeleteOnTab( SCTAB nTab )
2419 USHORT nPos = 0;
2420 while ( nPos < nCount )
2422 // look for output positions on the deleted sheet
2423 if ( static_cast<const ScDPObject*>(At(nPos))->GetOutRange().aStart.Tab() == nTab )
2424 AtFree(nPos);
2425 else
2426 ++nPos;
2430 void ScDPCollection::UpdateReference( UpdateRefMode eUpdateRefMode,
2431 const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
2433 for (USHORT i=0; i<nCount; i++)
2434 ((ScDPObject*)At(i))->UpdateReference( eUpdateRefMode, r, nDx, nDy, nDz );
2437 BOOL ScDPCollection::RefsEqual( const ScDPCollection& r ) const
2439 if ( nCount != r.nCount )
2440 return FALSE;
2442 for (USHORT i=0; i<nCount; i++)
2443 if ( ! ((const ScDPObject*)At(i))->RefsEqual( *((const ScDPObject*)r.At(i)) ) )
2444 return FALSE;
2446 return TRUE; // all equal
2449 void ScDPCollection::WriteRefsTo( ScDPCollection& r ) const
2451 if ( nCount == r.nCount )
2453 //! assert equal names?
2454 for (USHORT i=0; i<nCount; i++)
2455 ((const ScDPObject*)At(i))->WriteRefsTo( *((ScDPObject*)r.At(i)) );
2457 else
2459 // #i8180# If data pilot tables were deleted with their sheet,
2460 // this collection contains extra entries that must be restored.
2461 // Matching objects are found by their names.
2463 DBG_ASSERT( nCount >= r.nCount, "WriteRefsTo: missing entries in document" );
2464 for (USHORT nSourcePos=0; nSourcePos<nCount; nSourcePos++)
2466 const ScDPObject* pSourceObj = static_cast<const ScDPObject*>(At(nSourcePos));
2467 String aName = pSourceObj->GetName();
2468 bool bFound = false;
2469 for (USHORT nDestPos=0; nDestPos<r.nCount && !bFound; nDestPos++)
2471 ScDPObject* pDestObj = static_cast<ScDPObject*>(r.At(nDestPos));
2472 if ( pDestObj->GetName() == aName )
2474 pSourceObj->WriteRefsTo( *pDestObj ); // found object, copy refs
2475 bFound = true;
2478 if ( !bFound )
2480 // none found, re-insert deleted object (see ScUndoDataPilot::Undo)
2482 ScDPObject* pDestObj = new ScDPObject( *pSourceObj );
2483 pDestObj->SetAlive(TRUE);
2484 if ( !r.InsertNewTable(pDestObj) )
2486 DBG_ERROR("cannot insert DPObject");
2487 DELETEZ( pDestObj );
2491 DBG_ASSERT( nCount == r.nCount, "WriteRefsTo: couldn't restore all entries" );
2495 String ScDPCollection::CreateNewName( USHORT nMin ) const
2497 String aBase = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("DataPilot"));
2498 //! from Resource?
2500 for (USHORT nAdd=0; nAdd<=nCount; nAdd++) // nCount+1 tries
2502 String aNewName = aBase;
2503 aNewName += String::CreateFromInt32( nMin + nAdd );
2504 BOOL bFound = FALSE;
2505 for (USHORT i=0; i<nCount && !bFound; i++)
2506 if (((const ScDPObject*)pItems[i])->GetName() == aNewName)
2507 bFound = TRUE;
2508 if (!bFound)
2509 return aNewName; // found unused Name
2511 return String(); // should not happen
2514 ScSimpleSharedString& ScDPCollection::GetSharedString()
2516 return maSharedString;
2519 void ScDPCollection::FreeTable(ScDPObject* pDPObj)
2521 const ScRange& rOutRange = pDPObj->GetOutRange();
2522 const ScAddress& s = rOutRange.aStart;
2523 const ScAddress& e = rOutRange.aEnd;
2524 pDoc->RemoveFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
2525 Free(pDPObj);
2528 bool ScDPCollection::InsertNewTable(ScDPObject* pDPObj)
2530 bool bSuccess = Insert(pDPObj);
2531 if (bSuccess)
2533 const ScRange& rOutRange = pDPObj->GetOutRange();
2534 const ScAddress& s = rOutRange.aStart;
2535 const ScAddress& e = rOutRange.aEnd;
2536 pDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
2538 return bSuccess;
2541 bool ScDPCollection::HasDPTable(SCCOL nCol, SCROW nRow, SCTAB nTab) const
2543 const ScMergeFlagAttr* pMergeAttr = static_cast<const ScMergeFlagAttr*>(
2544 pDoc->GetAttr(nCol, nRow, nTab, ATTR_MERGE_FLAG));
2546 if (!pMergeAttr)
2547 return false;
2549 return pMergeAttr->HasDPTable();
2552 ScDPCacheCell* ScDPCollection::getCacheCellFromPool(const ScDPCacheCell& rCell)
2554 ScDPCacheCell aCell(rCell);
2555 CacheCellPoolType::iterator itr = maCacheCellPool.find(&aCell);
2556 if (itr == maCacheCellPool.end())
2558 // Insert a new instance.
2559 ScDPCacheCell* p = new ScDPCacheCell(rCell);
2560 ::std::pair<CacheCellPoolType::iterator, bool> r =
2561 maCacheCellPool.insert(p);
2562 if (!r.second)
2563 delete p;
2565 ScDPCacheCell* p2 = r.second ? *r.first : NULL;
2566 DBG_ASSERT(p == p2, "ScDPCollection::getCacheCellFromPool: pointer addresses differ");
2567 return p2;
2569 return *itr;
2572 namespace {
2574 class DeleteCacheCells : public ::std::unary_function<ScDPCacheCell*, void>
2576 public:
2577 void operator()(ScDPCacheCell* p) const
2579 delete p;
2585 void ScDPCollection::clearCacheCellPool()
2587 // Transferring all stored pointers to a vector first. For some unknown
2588 // reason, deleting cell content instances by directly iterating through
2589 // the hash set causes the iteration to return an identical pointer
2590 // value twice, causing a double-delete. I have no idea why this happens.
2592 using ::std::copy;
2593 using ::std::back_inserter;
2595 vector<ScDPCacheCell*> ps;
2596 ps.reserve(maCacheCellPool.size());
2597 copy(maCacheCellPool.begin(), maCacheCellPool.end(), back_inserter(ps));
2598 maCacheCellPool.clear();
2599 // for correctness' sake, delete the elements after clearing the hash_set
2600 for_each(ps.begin(), ps.end(), DeleteCacheCells());
2603 //------------------------------------------------------------------------
2604 // convert old pivot tables into new datapilot tables
2606 #if OLD_PIVOT_IMPLEMENTATION
2607 void ScDPCollection::ConvertOldTables( ScPivotCollection& rOldColl )
2609 // convert old pivot tables into new datapilot tables
2611 USHORT nOldCount = rOldColl.GetCount();
2612 for (USHORT i=0; i<nOldCount; i++)
2614 ScDPObject* pNewObj = new ScDPObject(pDoc);
2615 pNewObj->InitFromOldPivot( *(rOldColl)[i], pDoc, TRUE );
2616 pNewObj->SetAlive( TRUE );
2617 Insert( pNewObj );
2619 rOldColl.FreeAll();
2621 #endif