update dev300-m57
[ooovba.git] / sc / source / core / data / dpobject.cxx
blob320ac72a4129f1522671fc8d37c4a52b2c7c3b46
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 nHeaderRows( 0 ),
173 bHeaderLayout( false )
177 ScDPObject::ScDPObject(const ScDPObject& r) :
178 ScDataObject(),
179 pDoc( r.pDoc ),
180 pSaveData( NULL ),
181 aTableName( r.aTableName ),
182 aTableTag( r.aTableTag ),
183 aOutRange( r.aOutRange ),
184 pSheetDesc( NULL ),
185 pImpDesc( NULL ),
186 pServDesc( NULL ),
187 mpTableData(static_cast<ScDPTableData*>(NULL)),
188 pOutput( NULL ),
189 bSettingsChanged( FALSE ),
190 bAlive( FALSE ),
191 nAutoFormatIndex( r.nAutoFormatIndex ),
192 bAllowMove( FALSE ),
193 nHeaderRows( r.nHeaderRows ),
194 bHeaderLayout( r.bHeaderLayout )
196 if (r.pSaveData)
197 pSaveData = new ScDPSaveData(*r.pSaveData);
198 if (r.pSheetDesc)
199 pSheetDesc = new ScSheetSourceDesc(*r.pSheetDesc);
200 if (r.pImpDesc)
201 pImpDesc = new ScImportSourceDesc(*r.pImpDesc);
202 if (r.pServDesc)
203 pServDesc = new ScDPServiceDesc(*r.pServDesc);
204 // xSource (and pOutput) is not copied
207 ScDPObject::~ScDPObject()
209 delete pOutput;
210 delete pSaveData;
211 delete pSheetDesc;
212 delete pImpDesc;
213 delete pServDesc;
216 ScDataObject* ScDPObject::Clone() const
218 return new ScDPObject(*this);
221 void ScDPObject::SetAlive(BOOL bSet)
223 bAlive = bSet;
226 void ScDPObject::SetAllowMove(BOOL bSet)
228 bAllowMove = bSet;
231 void ScDPObject::SetSaveData(const ScDPSaveData& rData)
233 if ( pSaveData != &rData ) // API implementation modifies the original SaveData object
235 delete pSaveData;
236 pSaveData = new ScDPSaveData( rData );
239 InvalidateData(); // re-init source from SaveData
242 void ScDPObject::SetAutoFormatIndex(const USHORT nIndex)
244 nAutoFormatIndex = nIndex;
247 void ScDPObject::SetHeaderLayout (bool bUseGrid)
249 bHeaderLayout = bUseGrid;
252 void ScDPObject::SetOutRange(const ScRange& rRange)
254 aOutRange = rRange;
256 if ( pOutput )
257 pOutput->SetPosition( rRange.aStart );
260 void ScDPObject::SetSheetDesc(const ScSheetSourceDesc& rDesc)
262 if ( pSheetDesc && rDesc == *pSheetDesc )
263 return; // nothing to do
265 DELETEZ( pImpDesc );
266 DELETEZ( pServDesc );
268 delete pImpDesc;
269 pSheetDesc = new ScSheetSourceDesc(rDesc);
271 // make valid QueryParam
273 pSheetDesc->aQueryParam.nCol1 = pSheetDesc->aSourceRange.aStart.Col();
274 pSheetDesc->aQueryParam.nRow1 = pSheetDesc->aSourceRange.aStart.Row();
275 pSheetDesc->aQueryParam.nCol2 = pSheetDesc->aSourceRange.aEnd.Col();
276 pSheetDesc->aQueryParam.nRow2 = pSheetDesc->aSourceRange.aEnd.Row();;
277 pSheetDesc->aQueryParam.bHasHeader = TRUE;
279 InvalidateSource(); // new source must be created
282 void ScDPObject::SetImportDesc(const ScImportSourceDesc& rDesc)
284 if ( pImpDesc && rDesc == *pImpDesc )
285 return; // nothing to do
287 DELETEZ( pSheetDesc );
288 DELETEZ( pServDesc );
290 delete pImpDesc;
291 pImpDesc = new ScImportSourceDesc(rDesc);
293 InvalidateSource(); // new source must be created
296 void ScDPObject::SetServiceData(const ScDPServiceDesc& rDesc)
298 if ( pServDesc && rDesc == *pServDesc )
299 return; // nothing to do
301 DELETEZ( pSheetDesc );
302 DELETEZ( pImpDesc );
304 delete pServDesc;
305 pServDesc = new ScDPServiceDesc(rDesc);
307 InvalidateSource(); // new source must be created
310 void ScDPObject::WriteSourceDataTo( ScDPObject& rDest ) const
312 if ( pSheetDesc )
313 rDest.SetSheetDesc( *pSheetDesc );
314 else if ( pImpDesc )
315 rDest.SetImportDesc( *pImpDesc );
316 else if ( pServDesc )
317 rDest.SetServiceData( *pServDesc );
319 // name/tag are not source data, but needed along with source data
321 rDest.aTableName = aTableName;
322 rDest.aTableTag = aTableTag;
325 void ScDPObject::WriteTempDataTo( ScDPObject& rDest ) const
327 rDest.nHeaderRows = nHeaderRows;
330 BOOL ScDPObject::IsSheetData() const
332 return ( pSheetDesc != NULL );
335 void ScDPObject::SetName(const String& rNew)
337 aTableName = rNew;
340 void ScDPObject::SetTag(const String& rNew)
342 aTableTag = rNew;
345 bool ScDPObject::IsDataDescriptionCell(const ScAddress& rPos)
347 if (!pSaveData)
348 return false;
350 long nDataDimCount = pSaveData->GetDataDimensionCount();
351 if (nDataDimCount != 1)
352 // There has to be exactly one data dimension for the description to
353 // appear at top-left corner.
354 return false;
356 CreateOutput();
357 ScRange aTabRange = pOutput->GetOutputRange(sheet::DataPilotOutputRangeType::TABLE);
358 return (rPos == aTabRange.aStart);
361 uno::Reference<sheet::XDimensionsSupplier> ScDPObject::GetSource()
363 CreateObjects();
364 return xSource;
367 void ScDPObject::CreateOutput()
369 CreateObjects();
370 if (!pOutput)
372 BOOL bFilterButton = IsSheetData() && pSaveData && pSaveData->GetFilterButton();
373 pOutput = new ScDPOutput( pDoc, xSource, aOutRange.aStart, bFilterButton );
374 pOutput->SetHeaderLayout ( bHeaderLayout );
376 long nOldRows = nHeaderRows;
377 nHeaderRows = pOutput->GetHeaderRows();
379 if ( bAllowMove && nHeaderRows != nOldRows )
381 long nDiff = nOldRows - nHeaderRows;
382 if ( nOldRows == 0 )
383 --nDiff;
384 if ( nHeaderRows == 0 )
385 ++nDiff;
387 long nNewRow = aOutRange.aStart.Row() + nDiff;
388 if ( nNewRow < 0 )
389 nNewRow = 0;
391 ScAddress aStart( aOutRange.aStart );
392 aStart.SetRow(nNewRow);
393 pOutput->SetPosition( aStart );
395 //! modify aOutRange?
397 bAllowMove = FALSE; // use only once
402 ScDPTableData* ScDPObject::GetTableData()
404 if (!mpTableData)
406 if ( pImpDesc )
408 // database data
409 mpTableData.reset(new ScDatabaseDPData(pDoc, *pImpDesc));
411 else
413 // cell data
414 if (!pSheetDesc)
416 DBG_ERROR("no source descriptor");
417 pSheetDesc = new ScSheetSourceDesc; // dummy defaults
419 mpTableData.reset(new ScSheetDPData(pDoc, *pSheetDesc));
422 // grouping (for cell or database data)
423 if ( pSaveData && pSaveData->GetExistingDimensionData() )
425 shared_ptr<ScDPGroupTableData> pGroupData(new ScDPGroupTableData(mpTableData, pDoc));
426 pSaveData->GetExistingDimensionData()->WriteToData(*pGroupData);
427 mpTableData = pGroupData;
431 return mpTableData.get();
434 void ScDPObject::CreateObjects()
436 // if groups are involved, create a new source with the ScDPGroupTableData
437 if ( bSettingsChanged && pSaveData && pSaveData->GetExistingDimensionData() )
438 InvalidateSource();
440 if (!xSource.is())
442 //! cache DPSource and/or Output?
444 DBG_ASSERT( bAlive, "CreateObjects on non-inserted DPObject" );
446 DELETEZ( pOutput ); // not valid when xSource is changed
448 if ( pServDesc )
450 xSource = CreateSource( *pServDesc );
453 if ( !xSource.is() ) // database or sheet data, or error in CreateSource
455 DBG_ASSERT( !pServDesc, "DPSource could not be created" );
456 ScDPTableData* pData = GetTableData();
457 ScDPSource* pSource = new ScDPSource( pData );
458 xSource = pSource;
461 if (pSaveData)
462 pSaveData->WriteToSource( xSource );
464 else if (bSettingsChanged)
466 DELETEZ( pOutput ); // not valid when xSource is changed
468 uno::Reference<util::XRefreshable> xRef( xSource, uno::UNO_QUERY );
469 if (xRef.is())
473 xRef->refresh();
475 catch(uno::Exception&)
477 DBG_ERROR("exception in refresh");
481 if (pSaveData)
482 pSaveData->WriteToSource( xSource );
484 bSettingsChanged = FALSE;
487 void ScDPObject::InvalidateData()
489 bSettingsChanged = TRUE;
492 void ScDPObject::InvalidateSource()
494 xSource = NULL;
495 mpTableData.reset();
498 ScRange ScDPObject::GetNewOutputRange( BOOL& rOverflow )
500 CreateOutput(); // create xSource and pOutput if not already done
502 rOverflow = pOutput->HasError(); // range overflow or exception from source
503 if ( rOverflow )
504 return ScRange( aOutRange.aStart );
505 else
507 // don't store the result in aOutRange, because nothing has been output yet
508 return pOutput->GetOutputRange();
512 void ScDPObject::Output( const ScAddress& rPos )
514 // clear old output area
515 pDoc->DeleteAreaTab( aOutRange.aStart.Col(), aOutRange.aStart.Row(),
516 aOutRange.aEnd.Col(), aOutRange.aEnd.Row(),
517 aOutRange.aStart.Tab(), IDF_ALL );
518 pDoc->RemoveFlagsTab( aOutRange.aStart.Col(), aOutRange.aStart.Row(),
519 aOutRange.aEnd.Col(), aOutRange.aEnd.Row(),
520 aOutRange.aStart.Tab(), SC_MF_AUTO );
522 CreateOutput(); // create xSource and pOutput if not already done
524 pOutput->SetPosition( rPos );
526 pOutput->Output();
528 // aOutRange is always the range that was last output to the document
529 aOutRange = pOutput->GetOutputRange();
532 const ScRange ScDPObject::GetOutputRangeByType( sal_Int32 nType )
534 CreateOutput();
536 if (pOutput->HasError())
537 return ScRange(aOutRange.aStart);
539 return pOutput->GetOutputRange(nType);
542 BOOL lcl_HasButton( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
544 return ((const ScMergeFlagAttr*)pDoc->GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG ))->HasButton();
547 void ScDPObject::RefreshAfterLoad()
549 // apply drop-down attribute, initialize nHeaderRows, without accessing the source
550 // (button attribute must be present)
552 // simple test: block of button cells at the top, followed by an empty cell
554 SCCOL nFirstCol = aOutRange.aStart.Col();
555 SCROW nFirstRow = aOutRange.aStart.Row();
556 SCTAB nTab = aOutRange.aStart.Tab();
558 SCROW nInitial = 0;
559 SCROW nOutRows = aOutRange.aEnd.Row() + 1 - aOutRange.aStart.Row();
560 while ( nInitial + 1 < nOutRows && lcl_HasButton( pDoc, nFirstCol, nFirstRow + nInitial, nTab ) )
561 ++nInitial;
563 if ( nInitial + 1 < nOutRows &&
564 pDoc->IsBlockEmpty( nTab, nFirstCol, nFirstRow + nInitial, nFirstCol, nFirstRow + nInitial ) &&
565 aOutRange.aEnd.Col() > nFirstCol )
567 BOOL bFilterButton = IsSheetData(); // when available, filter button setting must be checked here
569 SCROW nSkip = bFilterButton ? 1 : 0;
570 for (SCROW nPos=nSkip; nPos<nInitial; nPos++)
571 pDoc->ApplyAttr( nFirstCol + 1, nFirstRow + nPos, nTab, ScMergeFlagAttr(SC_MF_AUTO) );
573 nHeaderRows = nInitial;
575 else
576 nHeaderRows = 0; // nothing found, no drop-down lists
579 void ScDPObject::BuildAllDimensionMembers()
581 if (!pSaveData)
582 return;
584 pSaveData->BuildAllDimensionMembers(GetTableData());
587 void ScDPObject::UpdateReference( UpdateRefMode eUpdateRefMode,
588 const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
590 // Output area
592 SCCOL nCol1 = aOutRange.aStart.Col();
593 SCROW nRow1 = aOutRange.aStart.Row();
594 SCTAB nTab1 = aOutRange.aStart.Tab();
595 SCCOL nCol2 = aOutRange.aEnd.Col();
596 SCROW nRow2 = aOutRange.aEnd.Row();
597 SCTAB nTab2 = aOutRange.aEnd.Tab();
599 ScRefUpdateRes eRes =
600 ScRefUpdate::Update( pDoc, eUpdateRefMode,
601 rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
602 rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz,
603 nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
604 if ( eRes != UR_NOTHING )
605 SetOutRange( ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ) );
607 // sheet source data
609 if ( pSheetDesc )
611 nCol1 = pSheetDesc->aSourceRange.aStart.Col();
612 nRow1 = pSheetDesc->aSourceRange.aStart.Row();
613 nTab1 = pSheetDesc->aSourceRange.aStart.Tab();
614 nCol2 = pSheetDesc->aSourceRange.aEnd.Col();
615 nRow2 = pSheetDesc->aSourceRange.aEnd.Row();
616 nTab2 = pSheetDesc->aSourceRange.aEnd.Tab();
618 eRes = ScRefUpdate::Update( pDoc, eUpdateRefMode,
619 rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
620 rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz,
621 nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
622 if ( eRes != UR_NOTHING )
624 ScSheetSourceDesc aNewDesc;
625 aNewDesc.aSourceRange = ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
627 SCsCOL nDiffX = nCol1 - (SCsCOL) pSheetDesc->aSourceRange.aStart.Col();
628 SCsROW nDiffY = nRow1 - (SCsROW) pSheetDesc->aSourceRange.aStart.Row();
630 aNewDesc.aQueryParam = pSheetDesc->aQueryParam;
631 aNewDesc.aQueryParam.nCol1 = sal::static_int_cast<SCCOL>( aNewDesc.aQueryParam.nCol1 + nDiffX );
632 aNewDesc.aQueryParam.nCol2 = sal::static_int_cast<SCCOL>( aNewDesc.aQueryParam.nCol2 + nDiffX );
633 aNewDesc.aQueryParam.nRow1 += nDiffY; //! used?
634 aNewDesc.aQueryParam.nRow2 += nDiffY; //! used?
635 SCSIZE nEC = aNewDesc.aQueryParam.GetEntryCount();
636 for (SCSIZE i=0; i<nEC; i++)
637 if (aNewDesc.aQueryParam.GetEntry(i).bDoQuery)
638 aNewDesc.aQueryParam.GetEntry(i).nField += nDiffX;
640 SetSheetDesc( aNewDesc ); // allocates new pSheetDesc
645 BOOL ScDPObject::RefsEqual( const ScDPObject& r ) const
647 if ( aOutRange != r.aOutRange )
648 return FALSE;
650 if ( pSheetDesc && r.pSheetDesc )
652 if ( pSheetDesc->aSourceRange != r.pSheetDesc->aSourceRange )
653 return FALSE;
655 else if ( pSheetDesc || r.pSheetDesc )
657 DBG_ERROR("RefsEqual: SheetDesc set at only one object");
658 return FALSE;
661 return TRUE;
664 void ScDPObject::WriteRefsTo( ScDPObject& r ) const
666 r.SetOutRange( aOutRange );
667 if ( pSheetDesc )
668 r.SetSheetDesc( *pSheetDesc );
671 void ScDPObject::GetPositionData(const ScAddress& rPos, DataPilotTablePositionData& rPosData)
673 CreateOutput();
674 pOutput->GetPositionData(rPos, rPosData);
677 bool ScDPObject::GetDataFieldPositionData(
678 const ScAddress& rPos, Sequence<sheet::DataPilotFieldFilter>& rFilters)
680 CreateOutput();
682 vector<sheet::DataPilotFieldFilter> aFilters;
683 if (!pOutput->GetDataResultPositionData(aFilters, rPos))
684 return false;
686 sal_Int32 n = static_cast<sal_Int32>(aFilters.size());
687 rFilters.realloc(n);
688 for (sal_Int32 i = 0; i < n; ++i)
689 rFilters[i] = aFilters[i];
691 return true;
694 void ScDPObject::GetDrillDownData(const ScAddress& rPos, Sequence< Sequence<Any> >& rTableData)
696 CreateOutput();
698 Reference<sheet::XDrillDownDataSupplier> xDrillDownData(xSource, UNO_QUERY);
699 if (!xDrillDownData.is())
700 return;
702 Sequence<sheet::DataPilotFieldFilter> filters;
703 if (!GetDataFieldPositionData(rPos, filters))
704 return;
706 rTableData = xDrillDownData->getDrillDownData(filters);
709 bool ScDPObject::IsDimNameInUse(const OUString& rName) const
711 if (!xSource.is())
712 return false;
714 Reference<container::XNameAccess> xDims = xSource->getDimensions();
715 Sequence<OUString> aDimNames = xDims->getElementNames();
716 sal_Int32 n = aDimNames.getLength();
717 for (sal_Int32 i = 0; i < n; ++i)
719 const OUString& rDimName = aDimNames[i];
720 if (rDimName.equalsIgnoreAsciiCase(rName))
721 return true;
723 Reference<beans::XPropertySet> xPropSet(xDims->getByName(rDimName), UNO_QUERY);
724 if (!xPropSet.is())
725 continue;
727 Any any = xPropSet->getPropertyValue(OUString::createFromAscii(SC_UNO_LAYOUTNAME));
728 OUString aLayoutName;
729 if (any >>= aLayoutName)
731 if (aLayoutName.equalsIgnoreAsciiCase(rName))
732 return true;
735 return false;
738 String ScDPObject::GetDimName( long nDim, BOOL& rIsDataLayout )
740 rIsDataLayout = FALSE;
741 String aRet;
743 if ( xSource.is() )
745 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
746 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
747 long nDimCount = xDims->getCount();
748 if ( nDim < nDimCount )
750 uno::Reference<uno::XInterface> xIntDim =
751 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
752 uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
753 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
754 if ( xDimName.is() && xDimProp.is() )
756 BOOL bData = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
757 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
758 //! error checking -- is "IsDataLayoutDimension" property required??
760 rtl::OUString aName;
763 aName = xDimName->getName();
765 catch(uno::Exception&)
768 if ( bData )
769 rIsDataLayout = TRUE;
770 else
771 aRet = String( aName );
776 return aRet;
779 BOOL ScDPObject::IsDuplicated( long nDim )
781 BOOL bDuplicated = FALSE;
782 if ( xSource.is() )
784 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
785 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
786 long nDimCount = xDims->getCount();
787 if ( nDim < nDimCount )
789 uno::Reference<uno::XInterface> xIntDim =
790 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
791 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
792 if ( xDimProp.is() )
796 uno::Any aOrigAny = xDimProp->getPropertyValue(
797 rtl::OUString::createFromAscii(DP_PROP_ORIGINAL) );
798 uno::Reference<uno::XInterface> xIntOrig;
799 if ( (aOrigAny >>= xIntOrig) && xIntOrig.is() )
800 bDuplicated = TRUE;
802 catch(uno::Exception&)
808 return bDuplicated;
811 long ScDPObject::GetDimCount()
813 long nRet = 0;
814 if ( xSource.is() )
818 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
819 if ( xDimsName.is() )
820 nRet = xDimsName->getElementNames().getLength();
822 catch(uno::Exception&)
826 return nRet;
829 void ScDPObject::FillPageList( TypedScStrCollection& rStrings, long nField )
831 //! merge members access with ToggleDetails?
833 //! convert field index to dimension index?
835 DBG_ASSERT( xSource.is(), "no source" );
836 if ( !xSource.is() ) return;
838 uno::Reference<container::XNamed> xDim;
839 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
840 uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
841 long nIntCount = xIntDims->getCount();
842 if ( nField < nIntCount )
844 uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface(
845 xIntDims->getByIndex(nField) );
846 xDim = uno::Reference<container::XNamed>( xIntDim, uno::UNO_QUERY );
848 DBG_ASSERT( xDim.is(), "dimension not found" );
849 if ( !xDim.is() ) return;
851 uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
852 long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
853 rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
854 long nLevel = 0;
856 long nHierCount = 0;
857 uno::Reference<container::XIndexAccess> xHiers;
858 uno::Reference<sheet::XHierarchiesSupplier> xHierSupp( xDim, uno::UNO_QUERY );
859 if ( xHierSupp.is() )
861 uno::Reference<container::XNameAccess> xHiersName = xHierSupp->getHierarchies();
862 xHiers = new ScNameToIndexAccess( xHiersName );
863 nHierCount = xHiers->getCount();
865 uno::Reference<uno::XInterface> xHier;
866 if ( nHierarchy < nHierCount )
867 xHier = ScUnoHelpFunctions::AnyToInterface( xHiers->getByIndex(nHierarchy) );
868 DBG_ASSERT( xHier.is(), "hierarchy not found" );
869 if ( !xHier.is() ) return;
871 long nLevCount = 0;
872 uno::Reference<container::XIndexAccess> xLevels;
873 uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHier, uno::UNO_QUERY );
874 if ( xLevSupp.is() )
876 uno::Reference<container::XNameAccess> xLevsName = xLevSupp->getLevels();
877 xLevels = new ScNameToIndexAccess( xLevsName );
878 nLevCount = xLevels->getCount();
880 uno::Reference<uno::XInterface> xLevel;
881 if ( nLevel < nLevCount )
882 xLevel = ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex(nLevel) );
883 DBG_ASSERT( xLevel.is(), "level not found" );
884 if ( !xLevel.is() ) return;
886 uno::Reference<container::XNameAccess> xMembers;
887 uno::Reference<sheet::XMembersSupplier> xMbrSupp( xLevel, uno::UNO_QUERY );
888 if ( xMbrSupp.is() )
889 xMembers = xMbrSupp->getMembers();
890 DBG_ASSERT( xMembers.is(), "members not found" );
891 if ( !xMembers.is() ) return;
893 uno::Sequence<rtl::OUString> aNames = xMembers->getElementNames();
894 long nNameCount = aNames.getLength();
895 const rtl::OUString* pNameArr = aNames.getConstArray();
896 for (long nPos = 0; nPos < nNameCount; ++nPos)
898 // Make sure to insert only visible members.
899 Reference<XPropertySet> xPropSet(xMembers->getByName(pNameArr[nPos]), UNO_QUERY);
900 sal_Bool bVisible = false;
901 if (xPropSet.is())
903 Any any = xPropSet->getPropertyValue(OUString::createFromAscii(SC_UNO_ISVISIBL));
904 any >>= bVisible;
907 if (bVisible)
909 // use the order from getElementNames
910 TypedStrData* pData = new TypedStrData( pNameArr[nPos] );
911 if ( !rStrings.AtInsert( rStrings.GetCount(), pData ) )
912 delete pData;
916 // add "-all-" entry to the top (unsorted)
917 TypedStrData* pAllData = new TypedStrData( String( ScResId( SCSTR_ALL ) ) ); //! separate string? (also output)
918 if ( !rStrings.AtInsert( 0, pAllData ) )
919 delete pAllData;
922 void ScDPObject::GetHeaderPositionData(const ScAddress& rPos, DataPilotTableHeaderData& rData)
924 using namespace ::com::sun::star::sheet::DataPilotTablePositionType;
926 CreateOutput(); // create xSource and pOutput if not already done
928 // Reset member values to invalid state.
929 rData.Dimension = rData.Hierarchy = rData.Level = -1;
930 rData.Flags = 0;
932 DataPilotTablePositionData aPosData;
933 pOutput->GetPositionData(rPos, aPosData);
934 const sal_Int32 nPosType = aPosData.PositionType;
935 if (nPosType == COLUMN_HEADER || nPosType == ROW_HEADER)
936 aPosData.PositionData >>= rData;
939 // Returns TRUE on success and stores the result in rTarget
940 BOOL ScDPObject::GetPivotData( ScDPGetPivotDataField& rTarget,
941 const std::vector< ScDPGetPivotDataField >& rFilters )
943 CreateOutput(); // create xSource and pOutput if not already done
945 return pOutput->GetPivotData( rTarget, rFilters );
948 BOOL ScDPObject::IsFilterButton( const ScAddress& rPos )
950 CreateOutput(); // create xSource and pOutput if not already done
952 return pOutput->IsFilterButton( rPos );
955 long ScDPObject::GetHeaderDim( const ScAddress& rPos, USHORT& rOrient )
957 CreateOutput(); // create xSource and pOutput if not already done
959 return pOutput->GetHeaderDim( rPos, rOrient );
962 BOOL ScDPObject::GetHeaderDrag( const ScAddress& rPos, BOOL bMouseLeft, BOOL bMouseTop, long nDragDim,
963 Rectangle& rPosRect, USHORT& rOrient, long& rDimPos )
965 CreateOutput(); // create xSource and pOutput if not already done
967 return pOutput->GetHeaderDrag( rPos, bMouseLeft, bMouseTop, nDragDim, rPosRect, rOrient, rDimPos );
970 void ScDPObject::GetMemberResultNames( ScStrCollection& rNames, long nDimension )
972 CreateOutput(); // create xSource and pOutput if not already done
974 pOutput->GetMemberResultNames( rNames, nDimension ); // used only with table data -> level not needed
977 bool lcl_Dequote( const String& rSource, xub_StrLen nStartPos, xub_StrLen& rEndPos, String& rResult )
979 // nStartPos has to point to opening quote
981 bool bRet = false;
982 const sal_Unicode cQuote = '\'';
984 if ( rSource.GetChar(nStartPos) == cQuote )
986 rtl::OUStringBuffer aBuffer;
987 xub_StrLen nPos = nStartPos + 1;
988 const xub_StrLen nLen = rSource.Len();
990 while ( nPos < nLen )
992 const sal_Unicode cNext = rSource.GetChar(nPos);
993 if ( cNext == cQuote )
995 if ( nPos+1 < nLen && rSource.GetChar(nPos+1) == cQuote )
997 // double quote is used for an embedded quote
998 aBuffer.append( cNext ); // append one quote
999 ++nPos; // skip the next one
1001 else
1003 // end of quoted string
1004 rResult = aBuffer.makeStringAndClear();
1005 rEndPos = nPos + 1; // behind closing quote
1006 return true;
1009 else
1010 aBuffer.append( cNext );
1012 ++nPos;
1014 // no closing quote before the end of the string -> error (bRet still false)
1017 return bRet;
1020 struct ScGetPivotDataFunctionEntry
1022 const sal_Char* pName;
1023 sheet::GeneralFunction eFunc;
1026 bool lcl_ParseFunction( const String& rList, xub_StrLen nStartPos, xub_StrLen& rEndPos, sheet::GeneralFunction& rFunc )
1028 static const ScGetPivotDataFunctionEntry aFunctions[] =
1030 // our names
1031 { "Sum", sheet::GeneralFunction_SUM },
1032 { "Count", sheet::GeneralFunction_COUNT },
1033 { "Average", sheet::GeneralFunction_AVERAGE },
1034 { "Max", sheet::GeneralFunction_MAX },
1035 { "Min", sheet::GeneralFunction_MIN },
1036 { "Product", sheet::GeneralFunction_PRODUCT },
1037 { "CountNums", sheet::GeneralFunction_COUNTNUMS },
1038 { "StDev", sheet::GeneralFunction_STDEV },
1039 { "StDevp", sheet::GeneralFunction_STDEVP },
1040 { "Var", sheet::GeneralFunction_VAR },
1041 { "VarP", sheet::GeneralFunction_VARP },
1042 // compatibility names
1043 { "Count Nums", sheet::GeneralFunction_COUNTNUMS },
1044 { "StdDev", sheet::GeneralFunction_STDEV },
1045 { "StdDevp", sheet::GeneralFunction_STDEVP }
1048 const xub_StrLen nListLen = rList.Len();
1049 while ( nStartPos < nListLen && rList.GetChar(nStartPos) == ' ' )
1050 ++nStartPos;
1052 bool bParsed = false;
1053 bool bFound = false;
1054 String aFuncStr;
1055 xub_StrLen nFuncEnd = 0;
1056 if ( nStartPos < nListLen && rList.GetChar(nStartPos) == '\'' )
1057 bParsed = lcl_Dequote( rList, nStartPos, nFuncEnd, aFuncStr );
1058 else
1060 nFuncEnd = rList.Search( static_cast<sal_Unicode>(']'), nStartPos );
1061 if ( nFuncEnd != STRING_NOTFOUND )
1063 aFuncStr = rList.Copy( nStartPos, nFuncEnd - nStartPos );
1064 bParsed = true;
1068 if ( bParsed )
1070 aFuncStr.EraseLeadingAndTrailingChars( ' ' );
1072 const sal_Int32 nFuncCount = sizeof(aFunctions) / sizeof(aFunctions[0]);
1073 for ( sal_Int32 nFunc=0; nFunc<nFuncCount && !bFound; nFunc++ )
1075 if ( aFuncStr.EqualsIgnoreCaseAscii( aFunctions[nFunc].pName ) )
1077 rFunc = aFunctions[nFunc].eFunc;
1078 bFound = true;
1080 while ( nFuncEnd < nListLen && rList.GetChar(nFuncEnd) == ' ' )
1081 ++nFuncEnd;
1082 rEndPos = nFuncEnd;
1087 return bFound;
1090 bool lcl_IsAtStart( const String& rList, const String& rSearch, sal_Int32& rMatched,
1091 bool bAllowBracket, sheet::GeneralFunction* pFunc )
1093 sal_Int32 nMatchList = 0;
1094 sal_Int32 nMatchSearch = 0;
1095 sal_Unicode cFirst = rList.GetChar(0);
1096 if ( cFirst == '\'' || cFirst == '[' )
1098 // quoted string or string in brackets must match completely
1100 String aDequoted;
1101 xub_StrLen nQuoteEnd = 0;
1102 bool bParsed = false;
1104 if ( cFirst == '\'' )
1105 bParsed = lcl_Dequote( rList, 0, nQuoteEnd, aDequoted );
1106 else if ( cFirst == '[' )
1108 // skip spaces after the opening bracket
1110 xub_StrLen nStartPos = 1;
1111 const xub_StrLen nListLen = rList.Len();
1112 while ( nStartPos < nListLen && rList.GetChar(nStartPos) == ' ' )
1113 ++nStartPos;
1115 if ( rList.GetChar(nStartPos) == '\'' ) // quoted within the brackets?
1117 if ( lcl_Dequote( rList, nStartPos, nQuoteEnd, aDequoted ) )
1119 // after the quoted string, there must be the closing bracket, optionally preceded by spaces,
1120 // and/or a function name
1121 while ( nQuoteEnd < nListLen && rList.GetChar(nQuoteEnd) == ' ' )
1122 ++nQuoteEnd;
1124 // semicolon separates function name
1125 if ( nQuoteEnd < nListLen && rList.GetChar(nQuoteEnd) == ';' && pFunc )
1127 xub_StrLen nFuncEnd = 0;
1128 if ( lcl_ParseFunction( rList, nQuoteEnd + 1, nFuncEnd, *pFunc ) )
1129 nQuoteEnd = nFuncEnd;
1131 if ( nQuoteEnd < nListLen && rList.GetChar(nQuoteEnd) == ']' )
1133 ++nQuoteEnd; // include the closing bracket for the matched length
1134 bParsed = true;
1138 else
1140 // implicit quoting to the closing bracket
1142 xub_StrLen nClosePos = rList.Search( static_cast<sal_Unicode>(']'), nStartPos );
1143 if ( nClosePos != STRING_NOTFOUND )
1145 xub_StrLen nNameEnd = nClosePos;
1146 xub_StrLen nSemiPos = rList.Search( static_cast<sal_Unicode>(';'), nStartPos );
1147 if ( nSemiPos != STRING_NOTFOUND && nSemiPos < nClosePos && pFunc )
1149 xub_StrLen nFuncEnd = 0;
1150 if ( lcl_ParseFunction( rList, nSemiPos + 1, nFuncEnd, *pFunc ) )
1151 nNameEnd = nSemiPos;
1154 aDequoted = rList.Copy( nStartPos, nNameEnd - nStartPos );
1155 aDequoted.EraseTrailingChars( ' ' ); // spaces before the closing bracket or semicolon
1156 nQuoteEnd = nClosePos + 1;
1157 bParsed = true;
1162 if ( bParsed && ScGlobal::pTransliteration->isEqual( aDequoted, rSearch ) )
1164 nMatchList = nQuoteEnd; // match count in the list string, including quotes
1165 nMatchSearch = rSearch.Len();
1168 else
1170 // otherwise look for search string at the start of rList
1171 ScGlobal::pTransliteration->equals( rList, 0, rList.Len(), nMatchList,
1172 rSearch, 0, rSearch.Len(), nMatchSearch );
1175 if ( nMatchSearch == rSearch.Len() )
1177 // search string is at start of rList - look for following space or end of string
1179 bool bValid = false;
1180 if ( sal::static_int_cast<xub_StrLen>(nMatchList) >= rList.Len() )
1181 bValid = true;
1182 else
1184 sal_Unicode cNext = rList.GetChar(sal::static_int_cast<xub_StrLen>(nMatchList));
1185 if ( cNext == ' ' || ( bAllowBracket && cNext == '[' ) )
1186 bValid = true;
1189 if ( bValid )
1191 rMatched = nMatchList;
1192 return true;
1196 return false;
1199 BOOL ScDPObject::ParseFilters( ScDPGetPivotDataField& rTarget,
1200 std::vector< ScDPGetPivotDataField >& rFilters,
1201 const String& rFilterList )
1203 // parse the string rFilterList into parameters for GetPivotData
1205 CreateObjects(); // create xSource if not already done
1207 std::vector<String> aDataNames; // data fields (source name)
1208 std::vector<String> aGivenNames; // data fields (compound name)
1209 std::vector<String> aFieldNames; // column/row/data fields
1210 std::vector< uno::Sequence<rtl::OUString> > aFieldValues;
1213 // get all the field and item names
1216 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1217 uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
1218 sal_Int32 nDimCount = xIntDims->getCount();
1219 for ( sal_Int32 nDim = 0; nDim<nDimCount; nDim++ )
1221 uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nDim) );
1222 uno::Reference<container::XNamed> xDim( xIntDim, uno::UNO_QUERY );
1223 uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
1224 uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDim, uno::UNO_QUERY );
1225 BOOL bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1226 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
1227 sal_Int32 nOrient = ScUnoHelpFunctions::GetEnumProperty(
1228 xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION),
1229 sheet::DataPilotFieldOrientation_HIDDEN );
1230 if ( !bDataLayout )
1232 if ( nOrient == sheet::DataPilotFieldOrientation_DATA )
1234 String aSourceName;
1235 String aGivenName;
1236 ScDPOutput::GetDataDimensionNames( aSourceName, aGivenName, xIntDim );
1237 aDataNames.push_back( aSourceName );
1238 aGivenNames.push_back( aGivenName );
1240 else if ( nOrient != sheet::DataPilotFieldOrientation_HIDDEN )
1242 // get level names, as in ScDPOutput
1244 uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
1245 sal_Int32 nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
1246 rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
1247 if ( nHierarchy >= xHiers->getCount() )
1248 nHierarchy = 0;
1250 uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
1251 xHiers->getByIndex(nHierarchy) );
1252 uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
1253 if ( xHierSupp.is() )
1255 uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
1256 sal_Int32 nLevCount = xLevels->getCount();
1257 for (sal_Int32 nLev=0; nLev<nLevCount; nLev++)
1259 uno::Reference<uno::XInterface> xLevel = ScUnoHelpFunctions::AnyToInterface(
1260 xLevels->getByIndex(nLev) );
1261 uno::Reference<container::XNamed> xLevNam( xLevel, uno::UNO_QUERY );
1262 uno::Reference<sheet::XMembersSupplier> xLevSupp( xLevel, uno::UNO_QUERY );
1263 if ( xLevNam.is() && xLevSupp.is() )
1265 uno::Reference<container::XNameAccess> xMembers = xLevSupp->getMembers();
1267 String aFieldName( xLevNam->getName() );
1268 uno::Sequence<rtl::OUString> aMemberNames( xMembers->getElementNames() );
1270 aFieldNames.push_back( aFieldName );
1271 aFieldValues.push_back( aMemberNames );
1280 // compare and build filters
1283 SCSIZE nDataFields = aDataNames.size();
1284 SCSIZE nFieldCount = aFieldNames.size();
1285 DBG_ASSERT( aGivenNames.size() == nDataFields && aFieldValues.size() == nFieldCount, "wrong count" );
1287 bool bError = false;
1288 bool bHasData = false;
1289 String aRemaining( rFilterList );
1290 aRemaining.EraseLeadingAndTrailingChars( ' ' );
1291 while ( aRemaining.Len() && !bError )
1293 bool bUsed = false;
1295 // look for data field name
1297 for ( SCSIZE nDataPos=0; nDataPos<nDataFields && !bUsed; nDataPos++ )
1299 String aFound;
1300 sal_Int32 nMatched = 0;
1301 if ( lcl_IsAtStart( aRemaining, aDataNames[nDataPos], nMatched, false, NULL ) )
1302 aFound = aDataNames[nDataPos];
1303 else if ( lcl_IsAtStart( aRemaining, aGivenNames[nDataPos], nMatched, false, NULL ) )
1304 aFound = aGivenNames[nDataPos];
1306 if ( aFound.Len() )
1308 rTarget.maFieldName = aFound;
1309 aRemaining.Erase( 0, sal::static_int_cast<xub_StrLen>(nMatched) );
1310 bHasData = true;
1311 bUsed = true;
1315 // look for field name
1317 String aSpecField;
1318 bool bHasFieldName = false;
1319 if ( !bUsed )
1321 sal_Int32 nMatched = 0;
1322 for ( SCSIZE nField=0; nField<nFieldCount && !bHasFieldName; nField++ )
1324 if ( lcl_IsAtStart( aRemaining, aFieldNames[nField], nMatched, true, NULL ) )
1326 aSpecField = aFieldNames[nField];
1327 aRemaining.Erase( 0, sal::static_int_cast<xub_StrLen>(nMatched) );
1328 aRemaining.EraseLeadingChars( ' ' );
1330 // field name has to be followed by item name in brackets
1331 if ( aRemaining.GetChar(0) == '[' )
1333 bHasFieldName = true;
1334 // bUsed remains false - still need the item
1336 else
1338 bUsed = true;
1339 bError = true;
1345 // look for field item
1347 if ( !bUsed )
1349 bool bItemFound = false;
1350 sal_Int32 nMatched = 0;
1351 String aFoundName;
1352 String aFoundValue;
1353 sheet::GeneralFunction eFunc = sheet::GeneralFunction_NONE;
1354 sheet::GeneralFunction eFoundFunc = sheet::GeneralFunction_NONE;
1356 for ( SCSIZE nField=0; nField<nFieldCount; nField++ )
1358 // If a field name is given, look in that field only, otherwise in all fields.
1359 // aSpecField is initialized from aFieldNames array, so exact comparison can be used.
1360 if ( !bHasFieldName || aFieldNames[nField] == aSpecField )
1362 const uno::Sequence<rtl::OUString>& rItems = aFieldValues[nField];
1363 sal_Int32 nItemCount = rItems.getLength();
1364 const rtl::OUString* pItemArr = rItems.getConstArray();
1365 for ( sal_Int32 nItem=0; nItem<nItemCount; nItem++ )
1367 if ( lcl_IsAtStart( aRemaining, pItemArr[nItem], nMatched, false, &eFunc ) )
1369 if ( bItemFound )
1370 bError = true; // duplicate (also across fields)
1371 else
1373 aFoundName = aFieldNames[nField];
1374 aFoundValue = pItemArr[nItem];
1375 eFoundFunc = eFunc;
1376 bItemFound = true;
1377 bUsed = true;
1384 if ( bItemFound && !bError )
1386 ScDPGetPivotDataField aField;
1387 aField.maFieldName = aFoundName;
1388 aField.meFunction = eFoundFunc;
1389 aField.mbValIsStr = true;
1390 aField.maValStr = aFoundValue;
1391 aField.mnValNum = 0.0;
1392 rFilters.push_back( aField );
1394 aRemaining.Erase( 0, sal::static_int_cast<xub_StrLen>(nMatched) );
1398 if ( !bUsed )
1399 bError = true;
1401 aRemaining.EraseLeadingChars( ' ' ); // remove any number of spaces between entries
1404 if ( !bError && !bHasData && aDataNames.size() == 1 )
1406 // if there's only one data field, its name need not be specified
1407 rTarget.maFieldName = aDataNames[0];
1408 bHasData = true;
1411 return bHasData && !bError;
1414 void ScDPObject::ToggleDetails(const DataPilotTableHeaderData& rElemDesc, ScDPObject* pDestObj)
1416 CreateObjects(); // create xSource if not already done
1418 // find dimension name
1420 uno::Reference<container::XNamed> xDim;
1421 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1422 uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
1423 long nIntCount = xIntDims->getCount();
1424 if ( rElemDesc.Dimension < nIntCount )
1426 uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface(
1427 xIntDims->getByIndex(rElemDesc.Dimension) );
1428 xDim = uno::Reference<container::XNamed>( xIntDim, uno::UNO_QUERY );
1430 DBG_ASSERT( xDim.is(), "dimension not found" );
1431 if ( !xDim.is() ) return;
1432 String aDimName = xDim->getName();
1434 uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
1435 BOOL bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1436 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
1437 if (bDataLayout)
1439 // the elements of the data layout dimension can't be found by their names
1440 // -> don't change anything
1441 return;
1444 // query old state
1446 long nHierCount = 0;
1447 uno::Reference<container::XIndexAccess> xHiers;
1448 uno::Reference<sheet::XHierarchiesSupplier> xHierSupp( xDim, uno::UNO_QUERY );
1449 if ( xHierSupp.is() )
1451 uno::Reference<container::XNameAccess> xHiersName = xHierSupp->getHierarchies();
1452 xHiers = new ScNameToIndexAccess( xHiersName );
1453 nHierCount = xHiers->getCount();
1455 uno::Reference<uno::XInterface> xHier;
1456 if ( rElemDesc.Hierarchy < nHierCount )
1457 xHier = ScUnoHelpFunctions::AnyToInterface( xHiers->getByIndex(rElemDesc.Hierarchy) );
1458 DBG_ASSERT( xHier.is(), "hierarchy not found" );
1459 if ( !xHier.is() ) return;
1461 long nLevCount = 0;
1462 uno::Reference<container::XIndexAccess> xLevels;
1463 uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHier, uno::UNO_QUERY );
1464 if ( xLevSupp.is() )
1466 uno::Reference<container::XNameAccess> xLevsName = xLevSupp->getLevels();
1467 xLevels = new ScNameToIndexAccess( xLevsName );
1468 nLevCount = xLevels->getCount();
1470 uno::Reference<uno::XInterface> xLevel;
1471 if ( rElemDesc.Level < nLevCount )
1472 xLevel = ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex(rElemDesc.Level) );
1473 DBG_ASSERT( xLevel.is(), "level not found" );
1474 if ( !xLevel.is() ) return;
1476 uno::Reference<container::XNameAccess> xMembers;
1477 uno::Reference<sheet::XMembersSupplier> xMbrSupp( xLevel, uno::UNO_QUERY );
1478 if ( xMbrSupp.is() )
1479 xMembers = xMbrSupp->getMembers();
1481 BOOL bFound = FALSE;
1482 BOOL bShowDetails = TRUE;
1484 if ( xMembers.is() )
1486 if ( xMembers->hasByName(rElemDesc.MemberName) )
1488 uno::Reference<uno::XInterface> xMemberInt = ScUnoHelpFunctions::AnyToInterface(
1489 xMembers->getByName(rElemDesc.MemberName) );
1490 uno::Reference<beans::XPropertySet> xMbrProp( xMemberInt, uno::UNO_QUERY );
1491 if ( xMbrProp.is() )
1493 bShowDetails = ScUnoHelpFunctions::GetBoolProperty( xMbrProp,
1494 rtl::OUString::createFromAscii(DP_PROP_SHOWDETAILS) );
1495 //! don't set bFound if property is unknown?
1496 bFound = TRUE;
1501 DBG_ASSERT( bFound, "member not found" );
1503 //! use Hierarchy and Level in SaveData !!!!
1505 // modify pDestObj if set, this object otherwise
1506 ScDPSaveData* pModifyData = pDestObj ? ( pDestObj->pSaveData ) : pSaveData;
1507 DBG_ASSERT( pModifyData, "no data?" );
1508 if ( pModifyData )
1510 const String aName = rElemDesc.MemberName;
1511 pModifyData->GetDimensionByName(aDimName)->
1512 GetMemberByName(aName)->SetShowDetails( !bShowDetails ); // toggle
1514 if ( pDestObj )
1515 pDestObj->InvalidateData(); // re-init source from SaveData
1516 else
1517 InvalidateData(); // re-init source from SaveData
1521 long lcl_FindName( const rtl::OUString& rString, const uno::Reference<container::XNameAccess>& xCollection )
1523 if ( xCollection.is() )
1525 uno::Sequence<rtl::OUString> aSeq = xCollection->getElementNames();
1526 long nCount = aSeq.getLength();
1527 const rtl::OUString* pArr = aSeq.getConstArray();
1528 for (long nPos=0; nPos<nCount; nPos++)
1529 if ( pArr[nPos] == rString )
1530 return nPos;
1532 return -1; // not found
1535 USHORT lcl_FirstSubTotal( const uno::Reference<beans::XPropertySet>& xDimProp ) // PIVOT_FUNC mask
1537 uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDimProp, uno::UNO_QUERY );
1538 if ( xDimProp.is() && xDimSupp.is() )
1540 uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
1541 long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
1542 rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
1543 if ( nHierarchy >= xHiers->getCount() )
1544 nHierarchy = 0;
1546 uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
1547 xHiers->getByIndex(nHierarchy) );
1548 uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
1549 if ( xHierSupp.is() )
1551 uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
1552 uno::Reference<uno::XInterface> xLevel =
1553 ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex( 0 ) );
1554 uno::Reference<beans::XPropertySet> xLevProp( xLevel, uno::UNO_QUERY );
1555 if ( xLevProp.is() )
1557 uno::Any aSubAny;
1560 aSubAny = xLevProp->getPropertyValue(
1561 rtl::OUString::createFromAscii(DP_PROP_SUBTOTALS) );
1563 catch(uno::Exception&)
1566 uno::Sequence<sheet::GeneralFunction> aSeq;
1567 if ( aSubAny >>= aSeq )
1569 USHORT nMask = 0;
1570 const sheet::GeneralFunction* pArray = aSeq.getConstArray();
1571 long nCount = aSeq.getLength();
1572 for (long i=0; i<nCount; i++)
1573 nMask |= ScDataPilotConversion::FunctionBit(pArray[i]);
1574 return nMask;
1580 DBG_ERROR("FirstSubTotal: NULL");
1581 return 0;
1584 USHORT lcl_CountBits( USHORT nBits )
1586 if (!nBits) return 0;
1588 USHORT nCount = 0;
1589 USHORT nMask = 1;
1590 for (USHORT i=0; i<16; i++)
1592 if ( nBits & nMask )
1593 ++nCount;
1594 nMask <<= 1;
1596 return nCount;
1599 SCSIZE lcl_FillOldFields( PivotField* pFields,
1600 const uno::Reference<sheet::XDimensionsSupplier>& xSource,
1601 USHORT nOrient, SCCOL nColAdd, BOOL bAddData )
1603 SCSIZE nOutCount = 0;
1604 BOOL bDataFound = FALSE;
1606 SCSIZE nCount = (nOrient == sheet::DataPilotFieldOrientation_PAGE) ? PIVOT_MAXPAGEFIELD : PIVOT_MAXFIELD;
1608 //! merge multiple occurences (data field with different functions)
1609 //! force data field in one dimension
1611 std::vector< long > aPos( nCount, 0 );
1613 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1614 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
1615 long nDimCount = xDims->getCount();
1616 for (long nDim=0; nDim < nDimCount && nOutCount < nCount; nDim++)
1618 uno::Reference<uno::XInterface> xIntDim =
1619 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
1620 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
1621 long nDimOrient = ScUnoHelpFunctions::GetEnumProperty(
1622 xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION),
1623 sheet::DataPilotFieldOrientation_HIDDEN );
1624 if ( xDimProp.is() && nDimOrient == nOrient )
1626 USHORT nMask = 0;
1627 if ( nOrient == sheet::DataPilotFieldOrientation_DATA )
1629 sheet::GeneralFunction eFunc = (sheet::GeneralFunction)ScUnoHelpFunctions::GetEnumProperty(
1630 xDimProp, rtl::OUString::createFromAscii(DP_PROP_FUNCTION),
1631 sheet::GeneralFunction_NONE );
1632 if ( eFunc == sheet::GeneralFunction_AUTO )
1634 //! test for numeric data
1635 eFunc = sheet::GeneralFunction_SUM;
1637 nMask = ScDataPilotConversion::FunctionBit(eFunc);
1639 else
1640 nMask = lcl_FirstSubTotal( xDimProp ); // from first hierarchy
1642 BOOL bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1643 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
1644 uno::Any aOrigAny;
1647 aOrigAny = xDimProp->getPropertyValue(
1648 rtl::OUString::createFromAscii(DP_PROP_ORIGINAL) );
1650 catch(uno::Exception&)
1654 long nDupSource = -1;
1655 uno::Reference<uno::XInterface> xIntOrig = ScUnoHelpFunctions::AnyToInterface( aOrigAny );
1656 if ( xIntOrig.is() )
1658 uno::Reference<container::XNamed> xNameOrig( xIntOrig, uno::UNO_QUERY );
1659 if ( xNameOrig.is() )
1660 nDupSource = lcl_FindName( xNameOrig->getName(), xDimsName );
1663 BOOL bDupUsed = FALSE;
1664 if ( nDupSource >= 0 )
1666 // add function bit to previous entry
1668 SCsCOL nCompCol;
1669 if ( bDataLayout )
1670 nCompCol = PIVOT_DATA_FIELD;
1671 else
1672 nCompCol = static_cast<SCsCOL>(nDupSource)+nColAdd; //! seek source column from name
1674 for (SCSIZE nOld=0; nOld<nOutCount && !bDupUsed; nOld++)
1675 if ( pFields[nOld].nCol == nCompCol )
1677 // add to previous column only if new bits aren't already set there
1678 if ( ( pFields[nOld].nFuncMask & nMask ) == 0 )
1680 pFields[nOld].nFuncMask |= nMask;
1681 pFields[nOld].nFuncCount = lcl_CountBits( pFields[nOld].nFuncMask );
1682 bDupUsed = TRUE;
1687 if ( !bDupUsed ) // also for duplicated dim if original has different orientation
1689 if ( bDataLayout )
1691 pFields[nOutCount].nCol = PIVOT_DATA_FIELD;
1692 bDataFound = TRUE;
1694 else if ( nDupSource >= 0 ) // if source was not found (different orientation)
1695 pFields[nOutCount].nCol = static_cast<SCsCOL>(nDupSource)+nColAdd; //! seek from name
1696 else
1697 pFields[nOutCount].nCol = static_cast<SCsCOL>(nDim)+nColAdd; //! seek source column from name
1699 pFields[nOutCount].nFuncMask = nMask;
1700 pFields[nOutCount].nFuncCount = lcl_CountBits( nMask );
1701 aPos[nOutCount] = ScUnoHelpFunctions::GetLongProperty( xDimProp,
1702 rtl::OUString::createFromAscii(DP_PROP_POSITION) );
1706 if( nOrient == sheet::DataPilotFieldOrientation_DATA )
1707 xDimProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_REFVALUE ) ) )
1708 >>= pFields[nOutCount].maFieldRef;
1710 catch( uno::Exception& )
1714 ++nOutCount;
1719 // sort by getPosition() value
1721 for (SCSIZE i=0; i+1<nOutCount; i++)
1723 for (SCSIZE j=0; j+i+1<nOutCount; j++)
1724 if ( aPos[j+1] < aPos[j] )
1726 std::swap( aPos[j], aPos[j+1] );
1727 std::swap( pFields[j], pFields[j+1] );
1731 if ( bAddData && !bDataFound )
1733 if ( nOutCount >= nCount ) // space for data field?
1734 --nOutCount; //! error?
1735 pFields[nOutCount].nCol = PIVOT_DATA_FIELD;
1736 pFields[nOutCount].nFuncMask = 0;
1737 pFields[nOutCount].nFuncCount = 0;
1738 ++nOutCount;
1741 return nOutCount;
1744 BOOL ScDPObject::FillOldParam(ScPivotParam& rParam, BOOL bForFile) const
1746 ((ScDPObject*)this)->CreateObjects(); // xSource is needed for field numbers
1748 rParam.nCol = aOutRange.aStart.Col();
1749 rParam.nRow = aOutRange.aStart.Row();
1750 rParam.nTab = aOutRange.aStart.Tab();
1751 // ppLabelArr / nLabels is not changed
1753 SCCOL nColAdd = 0;
1754 if ( bForFile )
1756 // in old file format, columns are within document, not within source range
1758 DBG_ASSERT( pSheetDesc, "FillOldParam: bForFile, !pSheetDesc" );
1759 nColAdd = pSheetDesc->aSourceRange.aStart.Col();
1762 BOOL bAddData = ( lcl_GetDataGetOrientation( xSource ) == sheet::DataPilotFieldOrientation_HIDDEN );
1763 rParam.nPageCount = lcl_FillOldFields( rParam.aPageArr,
1764 xSource, sheet::DataPilotFieldOrientation_PAGE, nColAdd, FALSE );
1765 rParam.nColCount = lcl_FillOldFields( rParam.aColArr,
1766 xSource, sheet::DataPilotFieldOrientation_COLUMN, nColAdd, bAddData );
1767 rParam.nRowCount = lcl_FillOldFields( rParam.aRowArr,
1768 xSource, sheet::DataPilotFieldOrientation_ROW, nColAdd, FALSE );
1769 rParam.nDataCount = lcl_FillOldFields( rParam.aDataArr,
1770 xSource, sheet::DataPilotFieldOrientation_DATA, nColAdd, FALSE );
1772 uno::Reference<beans::XPropertySet> xProp( xSource, uno::UNO_QUERY );
1773 if (xProp.is())
1777 rParam.bMakeTotalCol = ScUnoHelpFunctions::GetBoolProperty( xProp,
1778 rtl::OUString::createFromAscii(DP_PROP_COLUMNGRAND), TRUE );
1779 rParam.bMakeTotalRow = ScUnoHelpFunctions::GetBoolProperty( xProp,
1780 rtl::OUString::createFromAscii(DP_PROP_ROWGRAND), TRUE );
1782 // following properties may be missing for external sources
1783 rParam.bIgnoreEmptyRows = ScUnoHelpFunctions::GetBoolProperty( xProp,
1784 rtl::OUString::createFromAscii(DP_PROP_IGNOREEMPTY) );
1785 rParam.bDetectCategories = ScUnoHelpFunctions::GetBoolProperty( xProp,
1786 rtl::OUString::createFromAscii(DP_PROP_REPEATIFEMPTY) );
1788 catch(uno::Exception&)
1790 // no error
1793 return TRUE;
1796 void lcl_FillLabelData( ScDPLabelData& rData, const uno::Reference< beans::XPropertySet >& xDimProp )
1798 uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDimProp, uno::UNO_QUERY );
1799 if ( xDimProp.is() && xDimSupp.is() )
1801 uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
1802 long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
1803 rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
1804 if ( nHierarchy >= xHiers->getCount() )
1805 nHierarchy = 0;
1806 rData.mnUsedHier = nHierarchy;
1808 uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
1809 xHiers->getByIndex(nHierarchy) );
1811 uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
1812 if ( xHierSupp.is() )
1814 uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
1815 uno::Reference<uno::XInterface> xLevel =
1816 ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex( 0 ) );
1817 uno::Reference<beans::XPropertySet> xLevProp( xLevel, uno::UNO_QUERY );
1818 if ( xLevProp.is() )
1820 rData.mbShowAll = ScUnoHelpFunctions::GetBoolProperty( xLevProp,
1821 rtl::OUString::createFromAscii(DP_PROP_SHOWEMPTY) );
1825 xLevProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_SORTING ) ) )
1826 >>= rData.maSortInfo;
1827 xLevProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_LAYOUT ) ) )
1828 >>= rData.maLayoutInfo;
1829 xLevProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_AUTOSHOW ) ) )
1830 >>= rData.maShowInfo;
1832 catch(uno::Exception&)
1840 BOOL ScDPObject::FillLabelData(ScPivotParam& rParam)
1842 rParam.maLabelArray.clear();
1844 ((ScDPObject*)this)->CreateObjects();
1846 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1847 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
1848 long nDimCount = xDims->getCount();
1849 if ( nDimCount > MAX_LABELS )
1850 nDimCount = MAX_LABELS;
1851 if (!nDimCount)
1852 return FALSE;
1854 for (long nDim=0; nDim < nDimCount; nDim++)
1856 String aFieldName;
1857 uno::Reference<uno::XInterface> xIntDim =
1858 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
1859 uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
1860 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
1862 if ( xDimName.is() && xDimProp.is() )
1864 BOOL bDuplicated = FALSE;
1865 BOOL bData = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1866 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
1867 //! error checking -- is "IsDataLayoutDimension" property required??
1871 aFieldName = String( xDimName->getName() );
1873 uno::Any aOrigAny = xDimProp->getPropertyValue(
1874 rtl::OUString::createFromAscii(DP_PROP_ORIGINAL) );
1875 uno::Reference<uno::XInterface> xIntOrig;
1876 if ( (aOrigAny >>= xIntOrig) && xIntOrig.is() )
1877 bDuplicated = TRUE;
1879 catch(uno::Exception&)
1883 if ( aFieldName.Len() && !bData && !bDuplicated )
1885 SCsCOL nCol = static_cast< SCsCOL >( nDim ); //! ???
1886 bool bIsValue = true; //! check
1888 ScDPLabelDataRef pNewLabel(new ScDPLabelData(aFieldName, nCol, bIsValue));
1889 GetHierarchies(nDim, pNewLabel->maHiers);
1890 GetMembers(nDim, pNewLabel->maMembers, &pNewLabel->maVisible, &pNewLabel->maShowDet);
1891 lcl_FillLabelData(*pNewLabel, xDimProp);
1892 rParam.maLabelArray.push_back(pNewLabel);
1897 return TRUE;
1900 BOOL ScDPObject::GetHierarchiesNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xHiers )
1902 BOOL bRet = FALSE;
1903 uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
1904 uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
1905 if( xIntDims.is() )
1907 uno::Reference<sheet::XHierarchiesSupplier> xHierSup(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
1908 if (xHierSup.is())
1910 xHiers.set( xHierSup->getHierarchies() );
1911 bRet = xHiers.is();
1914 return bRet;
1917 BOOL ScDPObject::GetHierarchies( sal_Int32 nDim, uno::Sequence< rtl::OUString >& rHiers )
1919 BOOL bRet = FALSE;
1920 uno::Reference< container::XNameAccess > xHiersNA;
1921 if( GetHierarchiesNA( nDim, xHiersNA ) )
1923 rHiers = xHiersNA->getElementNames();
1924 bRet = TRUE;
1926 return bRet;
1929 sal_Int32 ScDPObject::GetUsedHierarchy( sal_Int32 nDim )
1931 sal_Int32 nHier = 0;
1932 uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
1933 uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
1934 uno::Reference<beans::XPropertySet> xDim(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
1935 if (xDim.is())
1936 nHier = ScUnoHelpFunctions::GetLongProperty( xDim, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( SC_UNO_USEDHIER ) ) );
1937 return nHier;
1940 BOOL ScDPObject::GetMembersNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xMembers )
1942 return GetMembersNA( nDim, GetUsedHierarchy( nDim ), xMembers );
1945 BOOL ScDPObject::GetMembers( sal_Int32 nDim,
1946 uno::Sequence< rtl::OUString >& rMembers,
1947 uno::Sequence< sal_Bool >* pVisible,
1948 uno::Sequence< sal_Bool >* pShowDet )
1950 return GetMembers( nDim, GetUsedHierarchy( nDim ), rMembers, pVisible, pShowDet );
1953 BOOL ScDPObject::GetMembersNA( sal_Int32 nDim, sal_Int32 nHier, uno::Reference< container::XNameAccess >& xMembers )
1955 BOOL bRet = FALSE;
1956 uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
1957 uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
1958 uno::Reference<beans::XPropertySet> xDim(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
1959 if (xDim.is())
1961 uno::Reference<sheet::XHierarchiesSupplier> xHierSup(xDim, uno::UNO_QUERY);
1962 if (xHierSup.is())
1964 uno::Reference<container::XIndexAccess> xHiers(new ScNameToIndexAccess(xHierSup->getHierarchies()));
1965 uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHiers->getByIndex(nHier), uno::UNO_QUERY );
1966 if ( xLevSupp.is() )
1968 uno::Reference<container::XIndexAccess> xLevels(new ScNameToIndexAccess( xLevSupp->getLevels()));
1969 if (xLevels.is())
1971 sal_Int32 nLevCount = xLevels->getCount();
1972 if (nLevCount > 0)
1974 uno::Reference<sheet::XMembersSupplier> xMembSupp( xLevels->getByIndex(0), uno::UNO_QUERY );
1975 if ( xMembSupp.is() )
1977 xMembers.set(xMembSupp->getMembers());
1978 bRet = TRUE;
1985 return bRet;
1988 BOOL ScDPObject::GetMembers( sal_Int32 nDim, sal_Int32 nHier,
1989 uno::Sequence< rtl::OUString >& rMembers,
1990 uno::Sequence< sal_Bool >* pVisible,
1991 uno::Sequence< sal_Bool >* pShowDet )
1993 BOOL bRet = FALSE;
1994 uno::Reference< container::XNameAccess > xMembersNA;
1995 if( GetMembersNA( nDim, nHier, xMembersNA ) )
1997 uno::Reference< container::XIndexAccess > xMembersIA( new ScNameToIndexAccess( xMembersNA ) );
1998 sal_Int32 nCount = xMembersIA->getCount();
1999 rMembers.realloc( nCount );
2000 if( pVisible )
2001 pVisible->realloc( nCount );
2002 if( pShowDet )
2003 pShowDet->realloc( nCount );
2005 rtl::OUString* pAry = rMembers.getArray();
2006 for( sal_Int32 nItem = 0; nItem < nCount; ++nItem )
2008 uno::Reference< container::XNamed > xMember( xMembersIA->getByIndex( nItem ), uno::UNO_QUERY );
2009 if( xMember.is() )
2010 pAry[ nItem ] = xMember->getName();
2011 if( pVisible || pShowDet )
2013 uno::Reference< beans::XPropertySet > xMemProp( xMember, uno::UNO_QUERY );
2014 if( pVisible )
2016 sal_Bool bVis = sal_True;
2017 if( xMemProp.is() )
2018 bVis = ScUnoHelpFunctions::GetBoolProperty( xMemProp,
2019 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_ISVISIBL ) ) );
2020 (*pVisible)[ nItem ] = bVis;
2022 if( pShowDet )
2024 sal_Bool bShow = sal_True;
2025 if( xMemProp.is() )
2026 bShow = ScUnoHelpFunctions::GetBoolProperty( xMemProp,
2027 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_SHOWDETA ) ) );
2028 (*pShowDet)[ nItem ] = bShow;
2032 bRet = TRUE;
2034 return bRet;
2037 //------------------------------------------------------------------------
2038 // convert old pivot tables into new datapilot tables
2040 String lcl_GetDimName( const uno::Reference<sheet::XDimensionsSupplier>& xSource, long nDim )
2042 rtl::OUString aName;
2043 if ( xSource.is() )
2045 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
2046 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
2047 long nDimCount = xDims->getCount();
2048 if ( nDim < nDimCount )
2050 uno::Reference<uno::XInterface> xIntDim =
2051 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
2052 uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
2053 if (xDimName.is())
2057 aName = xDimName->getName();
2059 catch(uno::Exception&)
2065 return aName;
2068 // static
2069 void ScDPObject::ConvertOrientation( ScDPSaveData& rSaveData,
2070 PivotField* pFields, SCSIZE nCount, USHORT nOrient,
2071 ScDocument* pDoc, SCROW nRow, SCTAB nTab,
2072 const uno::Reference<sheet::XDimensionsSupplier>& xSource,
2073 BOOL bOldDefaults,
2074 PivotField* pRefColFields, SCSIZE nRefColCount,
2075 PivotField* pRefRowFields, SCSIZE nRefRowCount,
2076 PivotField* pRefPageFields, SCSIZE nRefPageCount )
2078 // pDoc or xSource must be set
2079 DBG_ASSERT( pDoc || xSource.is(), "missing string source" );
2081 String aDocStr;
2082 ScDPSaveDimension* pDim;
2084 for (SCSIZE i=0; i<nCount; i++)
2086 SCCOL nCol = pFields[i].nCol;
2087 USHORT nFuncs = pFields[i].nFuncMask;
2088 const sheet::DataPilotFieldReference& rFieldRef = pFields[i].maFieldRef;
2090 if ( nCol == PIVOT_DATA_FIELD )
2091 pDim = rSaveData.GetDataLayoutDimension();
2092 else
2094 if ( pDoc )
2095 pDoc->GetString( nCol, nRow, nTab, aDocStr );
2096 else
2097 aDocStr = lcl_GetDimName( xSource, nCol ); // cols must start at 0
2099 if ( aDocStr.Len() )
2100 pDim = rSaveData.GetDimensionByName(aDocStr);
2101 else
2102 pDim = NULL;
2105 if ( pDim )
2107 if ( nOrient == sheet::DataPilotFieldOrientation_DATA ) // set summary function
2109 // generate an individual entry for each function
2110 BOOL bFirst = TRUE;
2112 // if a dimension is used for column/row/page and data,
2113 // use duplicated dimensions for all data occurrences
2114 if (pRefColFields)
2115 for (SCSIZE nRefCol=0; nRefCol<nRefColCount; nRefCol++)
2116 if (pRefColFields[nRefCol].nCol == nCol)
2117 bFirst = FALSE;
2118 if (pRefRowFields)
2119 for (SCSIZE nRefRow=0; nRefRow<nRefRowCount; nRefRow++)
2120 if (pRefRowFields[nRefRow].nCol == nCol)
2121 bFirst = FALSE;
2122 if (pRefPageFields)
2123 for (USHORT nRefPage=0; nRefPage<nRefPageCount; ++nRefPage)
2124 if (pRefPageFields[nRefPage].nCol == nCol)
2125 bFirst = FALSE;
2127 // if set via api, a data column may occur several times
2128 // (if the function hasn't been changed yet) -> also look for duplicate data column
2129 for (SCSIZE nPrevData=0; nPrevData<i; nPrevData++)
2130 if (pFields[nPrevData].nCol == nCol)
2131 bFirst = FALSE;
2133 USHORT nMask = 1;
2134 for (USHORT nBit=0; nBit<16; nBit++)
2136 if ( nFuncs & nMask )
2138 sheet::GeneralFunction eFunc = ScDataPilotConversion::FirstFunc( nMask );
2139 ScDPSaveDimension* pCurrDim = bFirst ? pDim : rSaveData.DuplicateDimension(pDim->GetName());
2140 pCurrDim->SetOrientation( nOrient );
2141 pCurrDim->SetFunction( sal::static_int_cast<USHORT>(eFunc) );
2143 if( rFieldRef.ReferenceType == sheet::DataPilotFieldReferenceType::NONE )
2144 pCurrDim->SetReferenceValue( 0 );
2145 else
2146 pCurrDim->SetReferenceValue( &rFieldRef );
2148 bFirst = FALSE;
2150 nMask *= 2;
2153 else // set SubTotals
2155 pDim->SetOrientation( nOrient );
2157 USHORT nFuncArray[16];
2158 USHORT nFuncCount = 0;
2159 USHORT nMask = 1;
2160 for (USHORT nBit=0; nBit<16; nBit++)
2162 if ( nFuncs & nMask )
2163 nFuncArray[nFuncCount++] = sal::static_int_cast<USHORT>(ScDataPilotConversion::FirstFunc( nMask ));
2164 nMask *= 2;
2166 pDim->SetSubTotals( nFuncCount, nFuncArray );
2168 // ShowEmpty was implicit in old tables,
2169 // must be set for data layout dimension (not accessible in dialog)
2170 if ( bOldDefaults || nCol == PIVOT_DATA_FIELD )
2171 pDim->SetShowEmpty( TRUE );
2177 // -----------------------------------------------------------------------
2179 // static
2180 BOOL ScDPObject::HasRegisteredSources()
2182 BOOL bFound = FALSE;
2184 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
2185 uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
2186 if ( xEnAc.is() )
2188 uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
2189 rtl::OUString::createFromAscii( SCDPSOURCE_SERVICE ) );
2190 if ( xEnum.is() && xEnum->hasMoreElements() )
2191 bFound = TRUE;
2194 return bFound;
2197 // static
2198 uno::Sequence<rtl::OUString> ScDPObject::GetRegisteredSources()
2200 long nCount = 0;
2201 uno::Sequence<rtl::OUString> aSeq(0);
2203 // use implementation names...
2205 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
2206 uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
2207 if ( xEnAc.is() )
2209 uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
2210 rtl::OUString::createFromAscii( SCDPSOURCE_SERVICE ) );
2211 if ( xEnum.is() )
2213 while ( xEnum->hasMoreElements() )
2215 uno::Any aAddInAny = xEnum->nextElement();
2216 // if ( aAddInAny.getReflection()->getTypeClass() == TypeClass_INTERFACE )
2218 uno::Reference<uno::XInterface> xIntFac;
2219 aAddInAny >>= xIntFac;
2220 if ( xIntFac.is() )
2222 uno::Reference<lang::XServiceInfo> xInfo( xIntFac, uno::UNO_QUERY );
2223 if ( xInfo.is() )
2225 rtl::OUString sName = xInfo->getImplementationName();
2227 aSeq.realloc( nCount+1 );
2228 aSeq.getArray()[nCount] = sName;
2229 ++nCount;
2237 return aSeq;
2240 // static
2241 uno::Reference<sheet::XDimensionsSupplier> ScDPObject::CreateSource( const ScDPServiceDesc& rDesc )
2243 rtl::OUString aImplName = rDesc.aServiceName;
2244 uno::Reference<sheet::XDimensionsSupplier> xRet = NULL;
2246 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
2247 uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
2248 if ( xEnAc.is() )
2250 uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
2251 rtl::OUString::createFromAscii( SCDPSOURCE_SERVICE ) );
2252 if ( xEnum.is() )
2254 while ( xEnum->hasMoreElements() && !xRet.is() )
2256 uno::Any aAddInAny = xEnum->nextElement();
2257 // if ( aAddInAny.getReflection()->getTypeClass() == TypeClass_INTERFACE )
2259 uno::Reference<uno::XInterface> xIntFac;
2260 aAddInAny >>= xIntFac;
2261 if ( xIntFac.is() )
2263 uno::Reference<lang::XServiceInfo> xInfo( xIntFac, uno::UNO_QUERY );
2264 uno::Reference<lang::XSingleServiceFactory> xFac( xIntFac, uno::UNO_QUERY );
2265 if ( xFac.is() && xInfo.is() && xInfo->getImplementationName() == aImplName )
2269 uno::Reference<uno::XInterface> xInterface = xFac->createInstance();
2270 uno::Reference<lang::XInitialization> xInit( xInterface, uno::UNO_QUERY );
2271 if (xInit.is())
2273 // initialize
2274 uno::Sequence<uno::Any> aSeq(4);
2275 uno::Any* pArray = aSeq.getArray();
2276 pArray[0] <<= rtl::OUString( rDesc.aParSource );
2277 pArray[1] <<= rtl::OUString( rDesc.aParName );
2278 pArray[2] <<= rtl::OUString( rDesc.aParUser );
2279 pArray[3] <<= rtl::OUString( rDesc.aParPass );
2280 xInit->initialize( aSeq );
2282 xRet = uno::Reference<sheet::XDimensionsSupplier>( xInterface, uno::UNO_QUERY );
2284 catch(uno::Exception&)
2294 return xRet;
2297 // ============================================================================
2299 ScDPCacheCell::ScDPCacheCell() :
2300 mnStrId(ScSimpleSharedString::EMPTY),
2301 mnType(SC_VALTYPE_EMPTY),
2302 mfValue(0.0),
2303 mbNumeric(false)
2307 ScDPCacheCell::ScDPCacheCell(const ScDPCacheCell& r) :
2308 mnStrId(r.mnStrId),
2309 mnType(r.mnType),
2310 mfValue(r.mfValue),
2311 mbNumeric(r.mbNumeric)
2315 ScDPCacheCell::~ScDPCacheCell()
2319 // ============================================================================
2321 size_t ScDPCollection::CacheCellHash::operator()(const ScDPCacheCell* pCell) const
2323 return pCell->mnStrId + static_cast<size_t>(pCell->mnType) +
2324 static_cast<size_t>(pCell->mfValue) + static_cast<size_t>(pCell->mbNumeric);
2327 bool ScDPCollection::CacheCellEqual::operator()(const ScDPCacheCell* p1, const ScDPCacheCell* p2) const
2329 if (!p1 && !p2)
2330 return true;
2332 if ((!p1 && p2) || (p1 && !p2))
2333 return false;
2335 return p1->mnStrId == p2->mnStrId && p1->mfValue == p2->mfValue &&
2336 p1->mbNumeric == p2->mbNumeric && p1->mnType == p2->mnType;
2339 // ----------------------------------------------------------------------------
2341 ScDPCollection::ScDPCollection(ScDocument* pDocument) :
2342 pDoc( pDocument )
2346 ScDPCollection::ScDPCollection(const ScDPCollection& r) :
2347 ScCollection(r),
2348 pDoc(r.pDoc),
2349 maSharedString(r.maSharedString),
2350 maCacheCellPool() // #i101725# don't copy hash_set with pointers from the other collection
2354 ScDPCollection::~ScDPCollection()
2356 clearCacheCellPool();
2359 ScDataObject* ScDPCollection::Clone() const
2361 return new ScDPCollection(*this);
2364 void ScDPCollection::DeleteOnTab( SCTAB nTab )
2366 USHORT nPos = 0;
2367 while ( nPos < nCount )
2369 // look for output positions on the deleted sheet
2370 if ( static_cast<const ScDPObject*>(At(nPos))->GetOutRange().aStart.Tab() == nTab )
2371 AtFree(nPos);
2372 else
2373 ++nPos;
2377 void ScDPCollection::UpdateReference( UpdateRefMode eUpdateRefMode,
2378 const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
2380 for (USHORT i=0; i<nCount; i++)
2381 ((ScDPObject*)At(i))->UpdateReference( eUpdateRefMode, r, nDx, nDy, nDz );
2384 BOOL ScDPCollection::RefsEqual( const ScDPCollection& r ) const
2386 if ( nCount != r.nCount )
2387 return FALSE;
2389 for (USHORT i=0; i<nCount; i++)
2390 if ( ! ((const ScDPObject*)At(i))->RefsEqual( *((const ScDPObject*)r.At(i)) ) )
2391 return FALSE;
2393 return TRUE; // all equal
2396 void ScDPCollection::WriteRefsTo( ScDPCollection& r ) const
2398 if ( nCount == r.nCount )
2400 //! assert equal names?
2401 for (USHORT i=0; i<nCount; i++)
2402 ((const ScDPObject*)At(i))->WriteRefsTo( *((ScDPObject*)r.At(i)) );
2404 else
2406 // #i8180# If data pilot tables were deleted with their sheet,
2407 // this collection contains extra entries that must be restored.
2408 // Matching objects are found by their names.
2410 DBG_ASSERT( nCount >= r.nCount, "WriteRefsTo: missing entries in document" );
2411 for (USHORT nSourcePos=0; nSourcePos<nCount; nSourcePos++)
2413 const ScDPObject* pSourceObj = static_cast<const ScDPObject*>(At(nSourcePos));
2414 String aName = pSourceObj->GetName();
2415 bool bFound = false;
2416 for (USHORT nDestPos=0; nDestPos<r.nCount && !bFound; nDestPos++)
2418 ScDPObject* pDestObj = static_cast<ScDPObject*>(r.At(nDestPos));
2419 if ( pDestObj->GetName() == aName )
2421 pSourceObj->WriteRefsTo( *pDestObj ); // found object, copy refs
2422 bFound = true;
2425 if ( !bFound )
2427 // none found, re-insert deleted object (see ScUndoDataPilot::Undo)
2429 ScDPObject* pDestObj = new ScDPObject( *pSourceObj );
2430 pDestObj->SetAlive(TRUE);
2431 if ( !r.Insert(pDestObj) )
2433 DBG_ERROR("cannot insert DPObject");
2434 DELETEZ( pDestObj );
2438 DBG_ASSERT( nCount == r.nCount, "WriteRefsTo: couldn't restore all entries" );
2442 String ScDPCollection::CreateNewName( USHORT nMin ) const
2444 String aBase = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("DataPilot"));
2445 //! from Resource?
2447 for (USHORT nAdd=0; nAdd<=nCount; nAdd++) // nCount+1 tries
2449 String aNewName = aBase;
2450 aNewName += String::CreateFromInt32( nMin + nAdd );
2451 BOOL bFound = FALSE;
2452 for (USHORT i=0; i<nCount && !bFound; i++)
2453 if (((const ScDPObject*)pItems[i])->GetName() == aNewName)
2454 bFound = TRUE;
2455 if (!bFound)
2456 return aNewName; // found unused Name
2458 return String(); // should not happen
2461 ScSimpleSharedString& ScDPCollection::GetSharedString()
2463 return maSharedString;
2466 ScDPCacheCell* ScDPCollection::getCacheCellFromPool(const ScDPCacheCell& rCell)
2468 ScDPCacheCell aCell(rCell);
2469 CacheCellPoolType::iterator itr = maCacheCellPool.find(&aCell);
2470 if (itr == maCacheCellPool.end())
2472 // Insert a new instance.
2473 ScDPCacheCell* p = new ScDPCacheCell(rCell);
2474 ::std::pair<CacheCellPoolType::iterator, bool> r =
2475 maCacheCellPool.insert(p);
2476 if (!r.second)
2477 delete p;
2479 ScDPCacheCell* p2 = r.second ? *r.first : NULL;
2480 DBG_ASSERT(p == p2, "ScDPCollection::getCacheCellFromPool: pointer addresses differ");
2481 return p2;
2483 return *itr;
2486 namespace {
2488 class DeleteCacheCells : public ::std::unary_function<ScDPCacheCell*, void>
2490 public:
2491 void operator()(ScDPCacheCell* p) const
2493 delete p;
2499 void ScDPCollection::clearCacheCellPool()
2501 // Transferring all stored pointers to a vector first. For some unknown
2502 // reason, deleting cell content instances by directly iterating through
2503 // the hash set causes the iteration to return an identical pointer
2504 // value twice, causing a double-delete. I have no idea why this happens.
2506 using ::std::copy;
2507 using ::std::back_inserter;
2509 vector<ScDPCacheCell*> ps;
2510 ps.reserve(maCacheCellPool.size());
2511 copy(maCacheCellPool.begin(), maCacheCellPool.end(), back_inserter(ps));
2512 maCacheCellPool.clear();
2513 // for correctness' sake, delete the elements after clearing the hash_set
2514 for_each(ps.begin(), ps.end(), DeleteCacheCells());