tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / unoobj / dapiuno.cxx
blobe8ace63308bd13f11be44457ea6c8d9f96cf700c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <algorithm>
21 #include <cmath>
23 #include <o3tl/safeint.hxx>
24 #include <svl/hint.hxx>
25 #include <utility>
26 #include <vcl/svapp.hxx>
27 #include <sal/log.hxx>
29 #include <dapiuno.hxx>
30 #include <datauno.hxx>
31 #include <miscuno.hxx>
32 #include <convuno.hxx>
33 #include <docsh.hxx>
34 #include <tabvwsh.hxx>
35 #include <rangeutl.hxx>
36 #include <dpobject.hxx>
37 #include <dpshttab.hxx>
38 #include <dpsdbtab.hxx>
39 #include <dpsave.hxx>
40 #include <dbdocfun.hxx>
41 #include <unonames.hxx>
42 #include <dpdimsave.hxx>
43 #include <hints.hxx>
44 #include <dputil.hxx>
45 #include <globstr.hrc>
46 #include <scresid.hxx>
47 #include <generalfunction.hxx>
49 #include <com/sun/star/container/XNameAccess.hpp>
50 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
51 #include <com/sun/star/lang/IllegalArgumentException.hpp>
52 #include <com/sun/star/lang/NullPointerException.hpp>
53 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
54 #include <com/sun/star/sheet/XDimensionsSupplier.hpp>
55 #include <com/sun/star/sheet/XLevelsSupplier.hpp>
56 #include <com/sun/star/sheet/XMembersAccess.hpp>
57 #include <com/sun/star/beans/PropertyAttribute.hpp>
58 #include <com/sun/star/sheet/DataImportMode.hpp>
59 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
60 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
61 #include <com/sun/star/sheet/DataPilotOutputRangeType.hpp>
62 #include <com/sun/star/sheet/DataPilotTablePositionData.hpp>
63 #include <com/sun/star/sheet/GeneralFunction2.hpp>
65 #include <comphelper/extract.hxx>
66 #include <comphelper/propertysequence.hxx>
67 #include <cppuhelper/queryinterface.hxx>
68 #include <comphelper/sequence.hxx>
69 #include <cppuhelper/exc_hlp.hxx>
71 using namespace com::sun::star;
72 using namespace com::sun::star::sheet;
74 using ::com::sun::star::uno::Any;
75 using ::com::sun::star::uno::Exception;
76 using ::com::sun::star::uno::Reference;
77 using ::com::sun::star::uno::RuntimeException;
78 using ::com::sun::star::uno::Sequence;
79 using ::com::sun::star::uno::UNO_QUERY;
80 using ::com::sun::star::uno::UNO_QUERY_THROW;
82 using ::com::sun::star::container::ElementExistException;
83 using ::com::sun::star::container::NoSuchElementException;
84 using ::com::sun::star::container::XEnumeration;
85 using ::com::sun::star::container::XIndexAccess;
86 using ::com::sun::star::container::XNameAccess;
87 using ::com::sun::star::container::XNamed;
89 using ::com::sun::star::beans::UnknownPropertyException;
90 using ::com::sun::star::beans::XPropertyChangeListener;
91 using ::com::sun::star::beans::XPropertySet;
92 using ::com::sun::star::beans::XPropertySetInfo;
93 using ::com::sun::star::beans::XVetoableChangeListener;
95 using ::com::sun::star::lang::IllegalArgumentException;
96 using ::com::sun::star::lang::IndexOutOfBoundsException;
97 using ::com::sun::star::lang::NullPointerException;
99 using ::com::sun::star::table::CellAddress;
100 using ::com::sun::star::table::CellRangeAddress;
102 namespace {
104 std::span<const SfxItemPropertyMapEntry> lcl_GetDataPilotDescriptorBaseMap()
106 static const SfxItemPropertyMapEntry aDataPilotDescriptorBaseMap_Impl[] =
108 { SC_UNO_DP_COLGRAND, 0, cppu::UnoType<bool>::get(), 0, 0 },
109 { SC_UNO_DP_DRILLDOWN, 0, cppu::UnoType<bool>::get(), 0, 0 },
110 { SC_UNO_DP_GRANDTOTAL_NAME,0,cppu::UnoType<OUString>::get(), beans::PropertyAttribute::MAYBEVOID, 0 },
111 { SC_UNO_DP_IGNORE_EMPTYROWS, 0, cppu::UnoType<bool>::get(), 0, 0 },
112 { SC_UNO_DP_IMPORTDESC, 0, cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get(), 0, 0 },
113 { SC_UNO_DP_REPEATEMPTY, 0, cppu::UnoType<bool>::get(), 0, 0 },
114 { SC_UNO_DP_ROWGRAND, 0, cppu::UnoType<bool>::get(), 0, 0 },
115 { SC_UNO_DP_SERVICEARG, 0, cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get(), 0, 0 },
116 { SC_UNO_DP_SHOWFILTER, 0, cppu::UnoType<bool>::get(), 0, 0 },
117 { SC_UNO_DP_SOURCESERVICE, 0, cppu::UnoType<OUString>::get(), 0, 0 },
119 return aDataPilotDescriptorBaseMap_Impl;
122 std::span<const SfxItemPropertyMapEntry> lcl_GetDataPilotFieldMap()
124 using namespace ::com::sun::star::beans::PropertyAttribute;
125 static const SfxItemPropertyMapEntry aDataPilotFieldMap_Impl[] =
127 { SC_UNONAME_AUTOSHOW, 0, cppu::UnoType<DataPilotFieldAutoShowInfo>::get(), MAYBEVOID, 0 },
128 { SC_UNONAME_FUNCTION, 0, cppu::UnoType<GeneralFunction>::get(), 0, 0 },
129 { SC_UNONAME_FUNCTION2, 0, cppu::UnoType<sal_Int16>::get(), 0, 0 },
130 { SC_UNONAME_GROUPINFO, 0, cppu::UnoType<DataPilotFieldGroupInfo>::get(), MAYBEVOID, 0 },
131 { SC_UNONAME_HASAUTOSHOW, 0, cppu::UnoType<bool>::get(), 0, 0 },
132 { SC_UNONAME_HASLAYOUTINFO,0, cppu::UnoType<bool>::get(), 0, 0 },
133 { SC_UNONAME_HASREFERENCE, 0, cppu::UnoType<bool>::get(), 0, 0 },
134 { SC_UNONAME_HASSORTINFO, 0, cppu::UnoType<bool>::get(), 0, 0 },
135 { SC_UNONAME_ISGROUP, 0, cppu::UnoType<bool>::get(), 0, 0 },
136 { SC_UNONAME_LAYOUTINFO, 0, cppu::UnoType<DataPilotFieldLayoutInfo>::get(), MAYBEVOID, 0 },
137 { SC_UNONAME_ORIENT, 0, cppu::UnoType<DataPilotFieldOrientation>::get(), MAYBEVOID, 0 },
138 { SC_UNONAME_REFERENCE, 0, cppu::UnoType<DataPilotFieldReference>::get(), MAYBEVOID, 0 },
139 { SC_UNONAME_SELPAGE, 0, cppu::UnoType<OUString>::get(), 0, 0 },
140 { SC_UNONAME_SHOWEMPTY, 0, cppu::UnoType<bool>::get(), 0, 0 },
141 { SC_UNONAME_REPEATITEMLABELS, 0, cppu::UnoType<bool>::get(), 0, 0 },
142 { SC_UNONAME_SORTINFO, 0, cppu::UnoType<DataPilotFieldSortInfo>::get(), MAYBEVOID, 0 },
143 { SC_UNONAME_SUBTOTALS, 0, cppu::UnoType<Sequence<GeneralFunction>>::get(), 0, 0 },
144 { SC_UNONAME_SUBTOTALS2, 0, cppu::UnoType<Sequence<sal_Int16>>::get(), 0, 0 },
145 { SC_UNONAME_USESELPAGE, 0, cppu::UnoType<bool>::get(), 0, 0 },
147 return aDataPilotFieldMap_Impl;
150 std::span<const SfxItemPropertyMapEntry> lcl_GetDataPilotItemMap()
152 static const SfxItemPropertyMapEntry aDataPilotItemMap_Impl[] =
154 { SC_UNONAME_ISHIDDEN, 0, cppu::UnoType<bool>::get(), 0, 0 },
155 { SC_UNONAME_POS, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
156 { SC_UNONAME_SHOWDETAIL, 0, cppu::UnoType<bool>::get(), 0, 0 },
158 return aDataPilotItemMap_Impl;
161 bool lclCheckValidDouble( double fValue, bool bAuto )
163 return bAuto || std::isfinite( fValue );
166 bool lclCheckMinMaxStep( const DataPilotFieldGroupInfo& rInfo )
168 return
169 lclCheckValidDouble( rInfo.Start, rInfo.HasAutoStart ) &&
170 lclCheckValidDouble( rInfo.End, rInfo.HasAutoEnd ) &&
171 (rInfo.HasAutoStart || rInfo.HasAutoEnd || (rInfo.Start <= rInfo.End)) &&
172 lclCheckValidDouble( rInfo.Step, false ) &&
173 (0.0 <= rInfo.Step);
176 } // namespace
178 SC_SIMPLE_SERVICE_INFO( ScDataPilotDescriptor, u"ScDataPilotDescriptor"_ustr, u"stardiv::one::sheet::DataPilotDescriptor"_ustr )
179 SC_SIMPLE_SERVICE_INFO( ScDataPilotFieldObj, u"ScDataPilotFieldObj"_ustr, u"com.sun.star.sheet.DataPilotField"_ustr )
180 SC_SIMPLE_SERVICE_INFO( ScDataPilotFieldsObj, u"ScDataPilotFieldsObj"_ustr, u"com.sun.star.sheet.DataPilotFields"_ustr )
181 SC_SIMPLE_SERVICE_INFO( ScDataPilotTableObj, u"ScDataPilotTableObj"_ustr, u"com.sun.star.sheet.DataPilotTable"_ustr )
182 SC_SIMPLE_SERVICE_INFO( ScDataPilotTablesObj, u"ScDataPilotTablesObj"_ustr, u"com.sun.star.sheet.DataPilotTables"_ustr )
183 SC_SIMPLE_SERVICE_INFO( ScDataPilotItemsObj, u"ScDataPilotItemsObj"_ustr, u"com.sun.star.sheet.DataPilotItems"_ustr )
184 SC_SIMPLE_SERVICE_INFO( ScDataPilotItemObj, u"ScDataPilotItemObj"_ustr, u"com.sun.star.sheet.DataPilotItem"_ustr )
186 SC_SIMPLE_SERVICE_INFO( ScDataPilotFieldGroupsObj, u"ScDataPilotFieldGroupsObj"_ustr, u"com.sun.star.sheet.DataPilotFieldGroups"_ustr )
187 SC_SIMPLE_SERVICE_INFO( ScDataPilotFieldGroupObj, u"ScDataPilotFieldGroupObj"_ustr, u"com.sun.star.sheet.DataPilotFieldGroup"_ustr )
188 SC_SIMPLE_SERVICE_INFO( ScDataPilotFieldGroupItemObj, u"ScDataPilotFieldGroupItemObj"_ustr, u"com.sun.star.sheet.DataPilotFieldGroupItem"_ustr )
190 // name that is used in the API for the data layout field
191 constexpr OUString SC_DATALAYOUT_NAME = u"Data"_ustr;
193 ScGeneralFunction ScDataPilotConversion::FirstFunc( PivotFunc nBits )
195 if ( nBits & PivotFunc::Sum ) return ScGeneralFunction::SUM;
196 if ( nBits & PivotFunc::Count ) return ScGeneralFunction::COUNT;
197 if ( nBits & PivotFunc::Average ) return ScGeneralFunction::AVERAGE;
198 if ( nBits & PivotFunc::Median ) return ScGeneralFunction::MEDIAN;
199 if ( nBits & PivotFunc::Max ) return ScGeneralFunction::MAX;
200 if ( nBits & PivotFunc::Min ) return ScGeneralFunction::MIN;
201 if ( nBits & PivotFunc::Product ) return ScGeneralFunction::PRODUCT;
202 if ( nBits & PivotFunc::CountNum ) return ScGeneralFunction::COUNTNUMS;
203 if ( nBits & PivotFunc::StdDev ) return ScGeneralFunction::STDEV;
204 if ( nBits & PivotFunc::StdDevP ) return ScGeneralFunction::STDEVP;
205 if ( nBits & PivotFunc::StdVar ) return ScGeneralFunction::VAR;
206 if ( nBits & PivotFunc::StdVarP ) return ScGeneralFunction::VARP;
207 if ( nBits & PivotFunc::Auto ) return ScGeneralFunction::AUTO;
208 return ScGeneralFunction::NONE;
211 PivotFunc ScDataPilotConversion::FunctionBit( sal_Int16 eFunc )
213 PivotFunc nRet = PivotFunc::NONE; // 0
214 switch (eFunc)
216 case GeneralFunction2::SUM: nRet = PivotFunc::Sum; break;
217 case GeneralFunction2::COUNT: nRet = PivotFunc::Count; break;
218 case GeneralFunction2::AVERAGE: nRet = PivotFunc::Average; break;
219 case GeneralFunction2::MEDIAN: nRet = PivotFunc::Median; break;
220 case GeneralFunction2::MAX: nRet = PivotFunc::Max; break;
221 case GeneralFunction2::MIN: nRet = PivotFunc::Min; break;
222 case GeneralFunction2::PRODUCT: nRet = PivotFunc::Product; break;
223 case GeneralFunction2::COUNTNUMS: nRet = PivotFunc::CountNum; break;
224 case GeneralFunction2::STDEV: nRet = PivotFunc::StdDev; break;
225 case GeneralFunction2::STDEVP: nRet = PivotFunc::StdDevP; break;
226 case GeneralFunction2::VAR: nRet = PivotFunc::StdVar; break;
227 case GeneralFunction2::VARP: nRet = PivotFunc::StdVarP; break;
228 case GeneralFunction2::AUTO: nRet = PivotFunc::Auto; break;
229 default:
231 assert(false);
234 return nRet;
237 void ScDataPilotConversion::FillGroupInfo( DataPilotFieldGroupInfo& rInfo, const ScDPNumGroupInfo& rGroupInfo )
239 rInfo.HasDateValues = rGroupInfo.mbDateValues;
240 rInfo.HasAutoStart = rGroupInfo.mbAutoStart;
241 rInfo.Start = rGroupInfo.mfStart;
242 rInfo.HasAutoEnd = rGroupInfo.mbAutoEnd;
243 rInfo.End = rGroupInfo.mfEnd;
244 rInfo.Step = rGroupInfo.mfStep;
247 static ScDPObject* lcl_GetDPObject( ScDocShell* pDocShell, SCTAB nTab, std::u16string_view rName )
249 if (pDocShell)
251 ScDocument& rDoc = pDocShell->GetDocument();
252 ScDPCollection* pColl = rDoc.GetDPCollection();
253 if ( pColl )
255 size_t nCount = pColl->GetCount();
256 for (size_t i=0; i<nCount; ++i)
258 ScDPObject& rDPObj = (*pColl)[i];
259 if ( rDPObj.GetOutRange().aStart.Tab() == nTab &&
260 rDPObj.GetName() == rName )
261 return &rDPObj;
265 return nullptr; // not found
268 static OUString lcl_CreatePivotName( ScDocShell* pDocShell )
270 if (pDocShell)
272 ScDocument& rDoc = pDocShell->GetDocument();
273 ScDPCollection* pColl = rDoc.GetDPCollection();
274 if ( pColl )
275 return pColl->CreateNewName();
277 return OUString(); // shouldn't happen
280 static sal_Int32 lcl_GetObjectIndex( ScDPObject* pDPObj, const ScFieldIdentifier& rFieldId )
282 // used for items - nRepeat in identifier can be ignored
283 if ( pDPObj )
285 sal_Int32 nCount = pDPObj->GetDimCount();
286 for ( sal_Int32 nDim = 0; nDim < nCount; ++nDim )
288 bool bIsDataLayout = false;
289 OUString aDimName( pDPObj->GetDimName( nDim, bIsDataLayout ) );
290 if ( rFieldId.mbDataLayout ? bIsDataLayout : (aDimName == rFieldId.maFieldName) )
291 return nDim;
294 return -1; // none
297 ScDataPilotTablesObj::ScDataPilotTablesObj(ScDocShell& rDocSh, SCTAB nT) :
298 pDocShell( &rDocSh ),
299 nTab( nT )
301 pDocShell->GetDocument().AddUnoObject(*this);
304 ScDataPilotTablesObj::~ScDataPilotTablesObj()
306 SolarMutexGuard g;
308 if (pDocShell)
309 pDocShell->GetDocument().RemoveUnoObject(*this);
312 void ScDataPilotTablesObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
314 //! update of references
316 if ( rHint.GetId() == SfxHintId::Dying )
318 pDocShell = nullptr; // became invalid
322 // XDataPilotTables
324 rtl::Reference<ScDataPilotTableObj> ScDataPilotTablesObj::GetObjectByIndex_Impl( sal_Int32 nIndex )
326 if (pDocShell)
328 ScDocument& rDoc = pDocShell->GetDocument();
329 ScDPCollection* pColl = rDoc.GetDPCollection();
330 if ( pColl )
332 // count tables on this sheet
333 sal_Int32 nFound = 0;
334 size_t nCount = pColl->GetCount();
335 for (size_t i=0; i<nCount; ++i)
337 ScDPObject& rDPObj = (*pColl)[i];
338 if ( rDPObj.GetOutRange().aStart.Tab() == nTab )
340 if ( nFound == nIndex )
342 return new ScDataPilotTableObj(*pDocShell, nTab, rDPObj.GetName());
344 ++nFound;
349 return nullptr;
352 rtl::Reference<ScDataPilotTableObj> ScDataPilotTablesObj::GetObjectByName_Impl(const OUString& rName)
354 if (hasByName(rName))
355 return new ScDataPilotTableObj(*pDocShell, nTab, rName);
356 return nullptr;
359 Reference<XDataPilotDescriptor> SAL_CALL ScDataPilotTablesObj::createDataPilotDescriptor()
361 SolarMutexGuard aGuard;
362 if (pDocShell)
363 return new ScDataPilotDescriptor(*pDocShell);
364 return nullptr;
367 static bool lcl_IsDuplicated(const Reference<XPropertySet>& rDimProps)
371 Any aAny = rDimProps->getPropertyValue( SC_UNO_DP_ORIGINAL );
372 Reference< XNamed > xOriginal( aAny, UNO_QUERY );
373 return xOriginal.is();
375 catch( Exception& )
378 return false;
381 static OUString lcl_GetOriginalName(const Reference< XNamed >& rDim)
383 Reference< XNamed > xOriginal;
385 Reference< XPropertySet > xDimProps(rDim, UNO_QUERY);
386 if ( xDimProps.is() )
390 Any aAny = xDimProps->getPropertyValue(SC_UNO_DP_ORIGINAL);
391 aAny >>= xOriginal;
393 catch( Exception& )
398 if ( !xOriginal.is() )
399 xOriginal = rDim;
401 return xOriginal->getName();
404 void SAL_CALL ScDataPilotTablesObj::insertNewByName( const OUString& aNewName,
405 const CellAddress& aOutputAddress,
406 const Reference<XDataPilotDescriptor>& xDescriptor )
408 SolarMutexGuard aGuard;
409 if (!xDescriptor.is()) return;
411 if ( !aNewName.isEmpty() && hasByName( aNewName ) )
412 throw IllegalArgumentException("Name \"" + aNewName + "\" already exists", getXWeak(), 0);
414 if (!pDocShell)
415 throw RuntimeException(u"DocShell is null"_ustr, getXWeak());
417 auto pImp = dynamic_cast<ScDataPilotDescriptorBase*>( xDescriptor.get() );
418 if (!pImp)
419 throw RuntimeException(u"Failed to get ScDataPilotDescriptor"_ustr, getXWeak());
421 ScDPObject* pNewObj = pImp->GetDPObject();
422 if (!pNewObj)
423 throw RuntimeException(u"Failed to get DPObject"_ustr, getXWeak());
425 ScRange aOutputRange(static_cast<SCCOL>(aOutputAddress.Column), static_cast<SCROW>(aOutputAddress.Row), static_cast<SCTAB>(aOutputAddress.Sheet),
426 static_cast<SCCOL>(aOutputAddress.Column), static_cast<SCROW>(aOutputAddress.Row), static_cast<SCTAB>(aOutputAddress.Sheet));
427 pNewObj->SetOutRange(aOutputRange);
428 OUString aName = aNewName;
429 if (aName.isEmpty())
430 aName = lcl_CreatePivotName( pDocShell );
431 pNewObj->SetName(aName);
432 OUString aTag = xDescriptor->getTag();
433 pNewObj->SetTag(aTag);
435 // todo: handle double fields (for more information see ScDPObject)
437 ScDBDocFunc aFunc(*pDocShell);
438 if (!aFunc.CreatePivotTable(*pNewObj, true, true))
439 throw RuntimeException(u"Failed to create pivot table"_ustr, getXWeak());
442 void SAL_CALL ScDataPilotTablesObj::removeByName( const OUString& aName )
444 SolarMutexGuard aGuard;
445 ScDPObject* pDPObj = lcl_GetDPObject( pDocShell, nTab, aName );
446 if (!pDPObj || !pDocShell)
447 throw RuntimeException(); // no other exceptions specified
449 ScDBDocFunc aFunc(*pDocShell);
450 aFunc.RemovePivotTable(*pDPObj, true, true); // remove - incl. undo etc.
454 // XEnumerationAccess
456 Reference< XEnumeration > SAL_CALL ScDataPilotTablesObj::createEnumeration()
458 SolarMutexGuard aGuard;
459 return new ScIndexEnumeration(this, u"com.sun.star.sheet.DataPilotTablesEnumeration"_ustr);
462 // XIndexAccess
464 sal_Int32 SAL_CALL ScDataPilotTablesObj::getCount()
466 SolarMutexGuard aGuard;
467 if ( pDocShell )
469 ScDocument& rDoc = pDocShell->GetDocument();
470 ScDPCollection* pColl = rDoc.GetDPCollection();
471 if ( pColl )
473 // count tables on this sheet
475 sal_uInt16 nFound = 0;
476 size_t nCount = pColl->GetCount();
477 for (size_t i=0; i<nCount; ++i)
479 ScDPObject& rDPObj = (*pColl)[i];
480 if ( rDPObj.GetOutRange().aStart.Tab() == nTab )
481 ++nFound;
483 return nFound;
487 return 0;
490 Any SAL_CALL ScDataPilotTablesObj::getByIndex( sal_Int32 nIndex )
492 SolarMutexGuard aGuard;
493 Reference<XDataPilotTable2> xTable(GetObjectByIndex_Impl(nIndex));
494 if (!xTable.is())
495 throw IndexOutOfBoundsException();
496 return Any( xTable );
499 uno::Type SAL_CALL ScDataPilotTablesObj::getElementType()
501 return cppu::UnoType<XDataPilotTable2>::get();
504 sal_Bool SAL_CALL ScDataPilotTablesObj::hasElements()
506 SolarMutexGuard aGuard;
507 return ( getCount() != 0 );
510 // XNameAccess
512 Any SAL_CALL ScDataPilotTablesObj::getByName( const OUString& aName )
514 SolarMutexGuard aGuard;
515 Reference<XDataPilotTable2> xTable(GetObjectByName_Impl(aName));
516 if (!xTable.is())
517 throw NoSuchElementException();
518 return Any( xTable );
521 Sequence<OUString> SAL_CALL ScDataPilotTablesObj::getElementNames()
523 SolarMutexGuard aGuard;
524 if (pDocShell)
526 ScDocument& rDoc = pDocShell->GetDocument();
527 ScDPCollection* pColl = rDoc.GetDPCollection();
528 if ( pColl )
530 // count tables on this sheet
532 sal_uInt16 nFound = 0;
533 size_t nCount = pColl->GetCount();
534 size_t i;
535 for (i=0; i<nCount; ++i)
537 ScDPObject& rDPObj = (*pColl)[i];
538 if ( rDPObj.GetOutRange().aStart.Tab() == nTab )
539 ++nFound;
542 sal_uInt16 nPos = 0;
543 Sequence<OUString> aSeq(nFound);
544 OUString* pAry = aSeq.getArray();
545 for (i=0; i<nCount; ++i)
547 ScDPObject& rDPObj = (*pColl)[i];
548 if ( rDPObj.GetOutRange().aStart.Tab() == nTab )
549 pAry[nPos++] = rDPObj.GetName();
552 return aSeq;
555 return {};
558 sal_Bool SAL_CALL ScDataPilotTablesObj::hasByName( const OUString& aName )
560 SolarMutexGuard aGuard;
561 if (pDocShell)
563 ScDocument& rDoc = pDocShell->GetDocument();
564 ScDPCollection* pColl = rDoc.GetDPCollection();
565 if ( pColl )
567 size_t nCount = pColl->GetCount();
568 for (size_t i=0; i<nCount; ++i)
570 ScDPObject& rDPObj = (*pColl)[i];
571 if ( rDPObj.GetOutRange().aStart.Tab() == nTab &&
572 rDPObj.GetName() == aName )
573 return true;
577 return false;
580 ScDataPilotDescriptorBase::ScDataPilotDescriptorBase(ScDocShell& rDocSh) :
581 maPropSet( lcl_GetDataPilotDescriptorBaseMap() ),
582 pDocShell( &rDocSh )
584 pDocShell->GetDocument().AddUnoObject(*this);
587 ScDataPilotDescriptorBase::~ScDataPilotDescriptorBase()
589 SolarMutexGuard g;
591 if (pDocShell)
592 pDocShell->GetDocument().RemoveUnoObject(*this);
595 void ScDataPilotDescriptorBase::Notify( SfxBroadcaster&, const SfxHint& rHint )
597 //! update of references ?
599 if ( rHint.GetId() == SfxHintId::Dying )
601 pDocShell = nullptr; // became invalid
605 // XDataPilotDescriptor
607 CellRangeAddress SAL_CALL ScDataPilotDescriptorBase::getSourceRange()
609 SolarMutexGuard aGuard;
611 ScDPObject* pDPObject(GetDPObject());
612 if (!pDPObject)
613 throw RuntimeException(u"Failed to get DPObject"_ustr, getXWeak());
615 CellRangeAddress aRet;
616 if (pDPObject->IsSheetData())
617 ScUnoConversion::FillApiRange( aRet, pDPObject->GetSheetDesc()->GetSourceRange() );
618 return aRet;
621 void SAL_CALL ScDataPilotDescriptorBase::setSourceRange( const CellRangeAddress& aSourceRange )
623 SolarMutexGuard aGuard;
625 ScDPObject* pDPObject = GetDPObject();
626 if (!pDPObject)
627 throw RuntimeException(u"Failed to get DPObject"_ustr, getXWeak());
629 ScSheetSourceDesc aSheetDesc(&pDocShell->GetDocument());
630 if (pDPObject->IsSheetData())
631 aSheetDesc = *pDPObject->GetSheetDesc();
633 ScRange aRange;
634 ScUnoConversion::FillScRange(aRange, aSourceRange);
635 aSheetDesc.SetSourceRange(aRange);
636 pDPObject->SetSheetDesc( aSheetDesc );
637 SetDPObject( pDPObject );
640 Reference<XSheetFilterDescriptor> SAL_CALL ScDataPilotDescriptorBase::getFilterDescriptor()
642 SolarMutexGuard aGuard;
643 return new ScDataPilotFilterDescriptor( pDocShell, this );
646 Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getDataPilotFields()
648 SolarMutexGuard aGuard;
649 return new ScDataPilotFieldsObj( *this );
652 Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getColumnFields()
654 SolarMutexGuard aGuard;
655 return new ScDataPilotFieldsObj( *this, DataPilotFieldOrientation_COLUMN );
658 Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getRowFields()
660 SolarMutexGuard aGuard;
661 return new ScDataPilotFieldsObj( *this, DataPilotFieldOrientation_ROW );
664 Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getPageFields()
666 SolarMutexGuard aGuard;
667 return new ScDataPilotFieldsObj( *this, DataPilotFieldOrientation_PAGE );
670 Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getDataFields()
672 SolarMutexGuard aGuard;
673 return new ScDataPilotFieldsObj( *this, DataPilotFieldOrientation_DATA );
676 Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getHiddenFields()
678 SolarMutexGuard aGuard;
679 return new ScDataPilotFieldsObj( *this, DataPilotFieldOrientation_HIDDEN );
682 // XPropertySet
683 Reference< XPropertySetInfo > SAL_CALL ScDataPilotDescriptorBase::getPropertySetInfo( )
685 SolarMutexGuard aGuard;
686 static Reference<XPropertySetInfo> aRef =
687 new SfxItemPropertySetInfo( maPropSet.getPropertyMap() );
688 return aRef;
691 void SAL_CALL ScDataPilotDescriptorBase::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
693 SolarMutexGuard aGuard;
694 ScDPObject* pDPObject = GetDPObject();
695 if (!pDPObject)
696 return;
698 ScDPSaveData* pOldData = pDPObject->GetSaveData();
699 OSL_ENSURE(pOldData, "Here should be a SaveData");
700 if ( pOldData )
702 ScDPSaveData aNewData( *pOldData );
704 if ( aPropertyName == SC_UNO_DP_COLGRAND )
706 aNewData.SetColumnGrand(::cppu::any2bool( aValue ));
708 else if ( aPropertyName == SC_UNO_DP_IGNORE_EMPTYROWS )
710 aNewData.SetIgnoreEmptyRows(::cppu::any2bool( aValue ));
712 else if ( aPropertyName == SC_UNO_DP_REPEATEMPTY )
714 aNewData.SetRepeatIfEmpty(::cppu::any2bool( aValue ));
716 else if ( aPropertyName == SC_UNO_DP_ROWGRAND )
718 aNewData.SetRowGrand(::cppu::any2bool( aValue ));
720 else if ( aPropertyName == SC_UNO_DP_SHOWFILTER )
722 aNewData.SetFilterButton(::cppu::any2bool( aValue ));
724 else if ( aPropertyName == SC_UNO_DP_DRILLDOWN )
726 aNewData.SetDrillDown(::cppu::any2bool( aValue ));
728 else if ( aPropertyName == SC_UNO_DP_GRANDTOTAL_NAME )
730 OUString aStrVal;
731 if ( aValue >>= aStrVal )
732 aNewData.SetGrandTotalName(aStrVal);
734 else if ( aPropertyName == SC_UNO_DP_IMPORTDESC )
736 uno::Sequence<beans::PropertyValue> aArgSeq;
737 if ( aValue >>= aArgSeq )
739 ScImportSourceDesc aImportDesc(&pDocShell->GetDocument());
741 const ScImportSourceDesc* pOldDesc = pDPObject->GetImportSourceDesc();
742 if (pOldDesc)
743 aImportDesc = *pOldDesc;
745 ScImportParam aParam;
746 ScImportDescriptor::FillImportParam( aParam, aArgSeq );
748 sheet::DataImportMode nNewType = sheet::DataImportMode_NONE;
749 if ( aParam.bImport )
751 if ( aParam.bSql )
752 nNewType = sheet::DataImportMode_SQL;
753 else if ( aParam.nType == ScDbQuery )
754 nNewType = sheet::DataImportMode_QUERY;
755 else
756 nNewType = sheet::DataImportMode_TABLE;
758 aImportDesc.nType = nNewType;
759 aImportDesc.aDBName = aParam.aDBName;
760 aImportDesc.aObject = aParam.aStatement;
761 aImportDesc.bNative = aParam.bNative;
763 pDPObject->SetImportDesc( aImportDesc );
766 else if ( aPropertyName == SC_UNO_DP_SOURCESERVICE )
768 OUString aStrVal;
769 if ( aValue >>= aStrVal )
771 ScDPServiceDesc aServiceDesc(u""_ustr, u""_ustr, u""_ustr, u""_ustr, u""_ustr);
773 const ScDPServiceDesc* pOldDesc = pDPObject->GetDPServiceDesc();
774 if (pOldDesc)
775 aServiceDesc = *pOldDesc;
777 aServiceDesc.aServiceName = aStrVal;
779 pDPObject->SetServiceData( aServiceDesc );
782 else if ( aPropertyName == SC_UNO_DP_SERVICEARG )
784 uno::Sequence<beans::PropertyValue> aArgSeq;
785 if ( aValue >>= aArgSeq )
787 ScDPServiceDesc aServiceDesc(u""_ustr, u""_ustr, u""_ustr, u""_ustr, u""_ustr);
789 const ScDPServiceDesc* pOldDesc = pDPObject->GetDPServiceDesc();
790 if (pOldDesc)
791 aServiceDesc = *pOldDesc;
793 OUString aStrVal;
794 for (const beans::PropertyValue& rProp : aArgSeq)
796 OUString aPropName(rProp.Name);
798 if (aPropName == SC_UNO_DP_SOURCENAME)
800 if ( rProp.Value >>= aStrVal )
801 aServiceDesc.aParSource = aStrVal;
803 else if (aPropName == SC_UNO_DP_OBJECTNAME)
805 if ( rProp.Value >>= aStrVal )
806 aServiceDesc.aParName = aStrVal;
808 else if (aPropName == SC_UNO_DP_USERNAME)
810 if ( rProp.Value >>= aStrVal )
811 aServiceDesc.aParUser = aStrVal;
813 else if (aPropName == SC_UNO_DP_PASSWORD)
815 if ( rProp.Value >>= aStrVal )
816 aServiceDesc.aParPass = aStrVal;
820 pDPObject->SetServiceData( aServiceDesc );
823 else
824 throw UnknownPropertyException(aPropertyName);
826 pDPObject->SetSaveData( aNewData );
829 SetDPObject(pDPObject);
832 Any SAL_CALL ScDataPilotDescriptorBase::getPropertyValue( const OUString& aPropertyName )
834 SolarMutexGuard aGuard;
835 Any aRet;
837 ScDPObject* pDPObject(GetDPObject());
838 if (pDPObject)
840 ScDPSaveData* pOldData = pDPObject->GetSaveData();
841 OSL_ENSURE(pOldData, "Here should be a SaveData");
842 if ( pOldData )
844 ScDPSaveData aNewData( *pOldData );
846 if ( aPropertyName == SC_UNO_DP_COLGRAND )
848 aRet <<= aNewData.GetColumnGrand();
850 else if ( aPropertyName == SC_UNO_DP_IGNORE_EMPTYROWS )
852 aRet <<= aNewData.GetIgnoreEmptyRows();
854 else if ( aPropertyName == SC_UNO_DP_REPEATEMPTY )
856 aRet <<= aNewData.GetRepeatIfEmpty();
858 else if ( aPropertyName == SC_UNO_DP_ROWGRAND )
860 aRet <<= aNewData.GetRowGrand();
862 else if ( aPropertyName == SC_UNO_DP_SHOWFILTER )
864 aRet <<= aNewData.GetFilterButton();
866 else if ( aPropertyName == SC_UNO_DP_DRILLDOWN )
868 aRet <<= aNewData.GetDrillDown();
870 else if ( aPropertyName == SC_UNO_DP_GRANDTOTAL_NAME )
872 const std::optional<OUString> & pGrandTotalName = aNewData.GetGrandTotalName();
873 if (pGrandTotalName)
874 aRet <<= *pGrandTotalName; // same behavior as in ScDPSource
876 else if ( aPropertyName == SC_UNO_DP_IMPORTDESC )
878 const ScImportSourceDesc* pImportDesc = pDPObject->GetImportSourceDesc();
879 if ( pImportDesc )
881 // fill ScImportParam so ScImportDescriptor::FillProperties can be used
882 ScImportParam aParam;
883 aParam.bImport = ( pImportDesc->nType != sheet::DataImportMode_NONE );
884 aParam.aDBName = pImportDesc->aDBName;
885 aParam.aStatement = pImportDesc->aObject;
886 aParam.bNative = pImportDesc->bNative;
887 aParam.bSql = ( pImportDesc->nType == sheet::DataImportMode_SQL );
888 aParam.nType = static_cast<sal_uInt8>(( pImportDesc->nType == sheet::DataImportMode_QUERY ) ? ScDbQuery : ScDbTable);
890 uno::Sequence<beans::PropertyValue> aSeq( ScImportDescriptor::GetPropertyCount() );
891 ScImportDescriptor::FillProperties( aSeq, aParam );
892 aRet <<= aSeq;
894 else
896 // empty sequence
897 uno::Sequence<beans::PropertyValue> aEmpty(0);
898 aRet <<= aEmpty;
901 else if ( aPropertyName == SC_UNO_DP_SOURCESERVICE )
903 OUString aServiceName;
904 const ScDPServiceDesc* pServiceDesc = pDPObject->GetDPServiceDesc();
905 if (pServiceDesc)
906 aServiceName = pServiceDesc->aServiceName;
907 aRet <<= aServiceName; // empty string if no ServiceDesc set
909 else if ( aPropertyName == SC_UNO_DP_SERVICEARG )
911 const ScDPServiceDesc* pServiceDesc = pDPObject->GetDPServiceDesc();
912 if (pServiceDesc)
914 uno::Sequence<beans::PropertyValue> aSeq( comphelper::InitPropertySequence({
915 { SC_UNO_DP_SOURCENAME, Any(pServiceDesc->aParSource) },
916 { SC_UNO_DP_OBJECTNAME, Any(pServiceDesc->aParName) },
917 { SC_UNO_DP_USERNAME, Any(pServiceDesc->aParUser) },
918 { SC_UNO_DP_PASSWORD, Any(pServiceDesc->aParPass) }
919 }));
920 aRet <<= aSeq;
922 else
924 // empty sequence
925 uno::Sequence<beans::PropertyValue> aEmpty;
926 aRet <<= aEmpty;
929 else
930 throw UnknownPropertyException(aPropertyName);
934 return aRet;
937 void SAL_CALL ScDataPilotDescriptorBase::addPropertyChangeListener(
938 const OUString& /* aPropertyName */, const Reference<XPropertyChangeListener >& /* xListener */ )
942 void SAL_CALL ScDataPilotDescriptorBase::removePropertyChangeListener(
943 const OUString& /* aPropertyName */, const Reference<XPropertyChangeListener >& /* aListener */ )
947 void SAL_CALL ScDataPilotDescriptorBase::addVetoableChangeListener(
948 const OUString& /* PropertyName */, const Reference<XVetoableChangeListener >& /* aListener */ )
952 void SAL_CALL ScDataPilotDescriptorBase::removeVetoableChangeListener(
953 const OUString& /* PropertyName */, const Reference<XVetoableChangeListener >& /* aListener */ )
957 // XDataPilotDataLayoutFieldSupplier
959 Reference< XDataPilotField > SAL_CALL ScDataPilotDescriptorBase::getDataLayoutField()
961 SolarMutexGuard aGuard;
962 if( ScDPObject* pDPObject = GetDPObject() )
964 if( ScDPSaveData* pSaveData = pDPObject->GetSaveData() )
966 if( pSaveData->GetDataLayoutDimension() )
968 ScFieldIdentifier aFieldId( SC_DATALAYOUT_NAME, true );
969 return new ScDataPilotFieldObj( *this, aFieldId );
973 return nullptr;
976 ScDataPilotTableObj::ScDataPilotTableObj(ScDocShell& rDocSh, SCTAB nT, OUString aN) :
977 ScDataPilotDescriptorBase( rDocSh ),
978 nTab( nT ),
979 aName(std::move( aN )),
980 aModifyListeners( 0 )
984 ScDataPilotTableObj::~ScDataPilotTableObj()
988 Any SAL_CALL ScDataPilotTableObj::queryInterface( const uno::Type& rType )
990 // since we manually do resolve the query for XDataPilotTable2
991 // we also need to do the same for XDataPilotTable
992 uno::Any aReturn = ::cppu::queryInterface(rType,
993 static_cast<XDataPilotTable*>(this),
994 static_cast<XDataPilotTable2*>(this),
995 static_cast<XModifyBroadcaster*>(this));
996 if ( aReturn.hasValue() )
997 return aReturn;
999 return ScDataPilotDescriptorBase::queryInterface( rType );
1002 void SAL_CALL ScDataPilotTableObj::acquire() noexcept
1004 ScDataPilotDescriptorBase::acquire();
1007 void SAL_CALL ScDataPilotTableObj::release() noexcept
1009 ScDataPilotDescriptorBase::release();
1012 Sequence< uno::Type > SAL_CALL ScDataPilotTableObj::getTypes()
1014 return comphelper::concatSequences(
1015 ScDataPilotDescriptorBase::getTypes(),
1016 Sequence< uno::Type >
1018 cppu::UnoType<XDataPilotTable2>::get(),
1019 cppu::UnoType<XModifyBroadcaster>::get()
1020 } );
1023 Sequence<sal_Int8> SAL_CALL ScDataPilotTableObj::getImplementationId()
1025 return css::uno::Sequence<sal_Int8>();
1028 ScDPObject* ScDataPilotTableObj::GetDPObject() const
1030 return lcl_GetDPObject(GetDocShell(), nTab, aName);
1033 void ScDataPilotTableObj::SetDPObject( ScDPObject* pDPObject )
1035 ScDocShell* pDocSh = GetDocShell();
1036 ScDPObject* pDPObj = lcl_GetDPObject(pDocSh, nTab, aName);
1037 if ( pDPObj && pDocSh )
1039 ScDBDocFunc aFunc(*pDocSh);
1040 aFunc.DataPilotUpdate( pDPObj, pDPObject, true, true );
1044 // "rest of XDataPilotDescriptor"
1046 OUString SAL_CALL ScDataPilotTableObj::getName()
1048 SolarMutexGuard aGuard;
1049 ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
1050 if (pDPObj)
1051 return pDPObj->GetName();
1052 return OUString();
1055 void SAL_CALL ScDataPilotTableObj::setName( const OUString& aNewName )
1057 SolarMutexGuard aGuard;
1058 ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
1059 if (pDPObj)
1061 //! test for existing names !!!
1063 pDPObj->SetName( aNewName ); //! Undo - DBDocFunc ???
1064 aName = aNewName;
1066 // DataPilotUpdate would do too much (output table is not changed)
1067 GetDocShell()->SetDocumentModified();
1071 OUString SAL_CALL ScDataPilotTableObj::getTag()
1073 SolarMutexGuard aGuard;
1074 ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
1075 if (pDPObj)
1076 return pDPObj->GetTag();
1077 return OUString();
1080 void SAL_CALL ScDataPilotTableObj::setTag( const OUString& aNewTag )
1082 SolarMutexGuard aGuard;
1083 ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
1084 if (pDPObj)
1086 pDPObj->SetTag( aNewTag ); //! Undo - DBDocFunc ???
1088 // DataPilotUpdate would do too much (output table is not changed)
1089 GetDocShell()->SetDocumentModified();
1093 // XDataPilotTable
1095 CellRangeAddress SAL_CALL ScDataPilotTableObj::getOutputRange()
1097 SolarMutexGuard aGuard;
1098 CellRangeAddress aRet;
1099 ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
1100 if (pDPObj)
1102 ScRange aRange(pDPObj->GetOutRange());
1103 aRet.Sheet = aRange.aStart.Tab();
1104 aRet.StartColumn = aRange.aStart.Col();
1105 aRet.StartRow = aRange.aStart.Row();
1106 aRet.EndColumn = aRange.aEnd.Col();
1107 aRet.EndRow = aRange.aEnd.Row();
1109 return aRet;
1112 void SAL_CALL ScDataPilotTableObj::refresh()
1114 SolarMutexGuard aGuard;
1115 ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
1116 if (pDPObj)
1118 ScDBDocFunc aFunc(*GetDocShell());
1119 aFunc.RefreshPivotTables(pDPObj, true);
1123 Sequence< Sequence<Any> > SAL_CALL ScDataPilotTableObj::getDrillDownData(const CellAddress& aAddr)
1125 SolarMutexGuard aGuard;
1126 Sequence< Sequence<Any> > aTabData;
1127 ScAddress aAddr2(static_cast<SCCOL>(aAddr.Column), static_cast<SCROW>(aAddr.Row), aAddr.Sheet);
1128 ScDPObject* pObj = GetDPObject();
1129 if (!pObj)
1130 throw RuntimeException(u"Failed to get DPObject"_ustr, getXWeak());
1132 pObj->GetDrillDownData(aAddr2, aTabData);
1133 return aTabData;
1136 DataPilotTablePositionData SAL_CALL ScDataPilotTableObj::getPositionData(const CellAddress& aAddr)
1138 SolarMutexGuard aGuard;
1139 DataPilotTablePositionData aPosData;
1140 ScAddress aAddr2(static_cast<SCCOL>(aAddr.Column), static_cast<SCROW>(aAddr.Row), aAddr.Sheet);
1141 ScDPObject* pObj = GetDPObject();
1142 if (!pObj)
1143 throw RuntimeException(u"Failed to get DPObject"_ustr, getXWeak());
1145 pObj->GetPositionData(aAddr2, aPosData);
1146 return aPosData;
1149 void SAL_CALL ScDataPilotTableObj::insertDrillDownSheet(const CellAddress& aAddr)
1151 SolarMutexGuard aGuard;
1152 ScDPObject* pDPObj = GetDPObject();
1153 if (!pDPObj)
1154 throw RuntimeException(u"Failed to get DPObject"_ustr, getXWeak());
1155 ScTabViewShell* pViewSh = GetDocShell()->GetBestViewShell();
1156 if (!pViewSh)
1157 throw RuntimeException(u"Failed to get ViewShell"_ustr, getXWeak());
1159 Sequence<DataPilotFieldFilter> aFilters;
1160 pDPObj->GetDataFieldPositionData(
1161 ScAddress(static_cast<SCCOL>(aAddr.Column), static_cast<SCROW>(aAddr.Row), aAddr.Sheet), aFilters);
1162 pViewSh->ShowDataPilotSourceData(*pDPObj, aFilters);
1165 CellRangeAddress SAL_CALL ScDataPilotTableObj::getOutputRangeByType( sal_Int32 nType )
1167 SolarMutexGuard aGuard;
1168 if (nType < 0 || nType > DataPilotOutputRangeType::RESULT)
1169 throw IllegalArgumentException("nType must be between 0 and " +
1170 OUString::number(DataPilotOutputRangeType::RESULT) + ", got " + OUString::number(nType),
1171 getXWeak(), 0);
1173 CellRangeAddress aRet;
1174 if (ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName))
1175 ScUnoConversion::FillApiRange( aRet, pDPObj->GetOutputRangeByType( nType ) );
1176 return aRet;
1179 void SAL_CALL ScDataPilotTableObj::addModifyListener( const uno::Reference<util::XModifyListener>& aListener )
1181 SolarMutexGuard aGuard;
1183 aModifyListeners.emplace_back( aListener );
1185 if ( aModifyListeners.size() == 1 )
1187 acquire(); // don't lose this object (one ref for all listeners)
1191 void SAL_CALL ScDataPilotTableObj::removeModifyListener( const uno::Reference<util::XModifyListener>& aListener )
1193 SolarMutexGuard aGuard;
1195 rtl::Reference<ScDataPilotTableObj> xSelfHold(this); // in case the listeners have the last ref
1197 sal_uInt16 nCount = aModifyListeners.size();
1198 for ( sal_uInt16 n=nCount; n--; )
1200 uno::Reference<util::XModifyListener>& rObj = aModifyListeners[n];
1201 if ( rObj == aListener )
1203 aModifyListeners.erase( aModifyListeners.begin() + n );
1205 if ( aModifyListeners.empty() )
1207 release(); // release the ref for the listeners
1210 break;
1215 void ScDataPilotTableObj::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
1217 if ( rHint.GetId() == SfxHintId::ScDataPilotModified )
1219 auto pDataPilotHint = static_cast<const ScDataPilotModifiedHint*>(&rHint);
1220 if (pDataPilotHint->GetName() == aName)
1221 Refreshed_Impl();
1223 else if ( rHint.GetId() == SfxHintId::ScUpdateRef )
1225 auto pRefHint = static_cast<const ScUpdateRefHint*>(&rHint);
1226 ScRange aRange( 0, 0, nTab );
1227 ScRangeList aRanges( aRange );
1228 if ( aRanges.UpdateReference( pRefHint->GetMode(), &GetDocShell()->GetDocument(), pRefHint->GetRange(),
1229 pRefHint->GetDx(), pRefHint->GetDy(), pRefHint->GetDz() ) &&
1230 aRanges.size() == 1 )
1232 nTab = aRanges.front().aStart.Tab();
1236 ScDataPilotDescriptorBase::Notify( rBC, rHint );
1239 void ScDataPilotTableObj::Refreshed_Impl()
1241 lang::EventObject aEvent;
1242 aEvent.Source = getXWeak();
1244 // the EventObject holds a Ref to this object until after the listener calls
1246 ScDocument& rDoc = GetDocShell()->GetDocument();
1247 for (const uno::Reference<util::XModifyListener> & xModifyListener : aModifyListeners)
1248 rDoc.AddUnoListenerCall( xModifyListener, aEvent );
1251 ScDataPilotDescriptor::ScDataPilotDescriptor(ScDocShell& rDocSh) :
1252 ScDataPilotDescriptorBase( rDocSh ),
1253 mpDPObject(new ScDPObject(&rDocSh.GetDocument()))
1255 ScDPSaveData aSaveData;
1256 // set defaults like in ScPivotParam constructor
1257 aSaveData.SetColumnGrand( true );
1258 aSaveData.SetRowGrand( true );
1259 aSaveData.SetIgnoreEmptyRows( false );
1260 aSaveData.SetRepeatIfEmpty( false );
1261 mpDPObject->SetSaveData(aSaveData);
1262 ScSheetSourceDesc aSheetDesc(&rDocSh.GetDocument());
1263 mpDPObject->SetSheetDesc(aSheetDesc);
1266 ScDataPilotDescriptor::~ScDataPilotDescriptor()
1270 ScDPObject* ScDataPilotDescriptor::GetDPObject() const
1272 return mpDPObject.get();
1275 void ScDataPilotDescriptor::SetDPObject( ScDPObject* pDPObject )
1277 if (mpDPObject.get() != pDPObject)
1279 mpDPObject.reset( pDPObject );
1280 OSL_FAIL("replace DPObject should not happen");
1284 // "rest of XDataPilotDescriptor"
1286 OUString SAL_CALL ScDataPilotDescriptor::getName()
1288 SolarMutexGuard aGuard;
1289 return mpDPObject->GetName();
1292 void SAL_CALL ScDataPilotDescriptor::setName( const OUString& aNewName )
1294 SolarMutexGuard aGuard;
1295 mpDPObject->SetName( aNewName );
1298 OUString SAL_CALL ScDataPilotDescriptor::getTag()
1300 SolarMutexGuard aGuard;
1301 return mpDPObject->GetTag();
1304 void SAL_CALL ScDataPilotDescriptor::setTag( const OUString& aNewTag )
1306 SolarMutexGuard aGuard;
1307 mpDPObject->SetTag( aNewTag );
1310 ScDataPilotChildObjBase::ScDataPilotChildObjBase( ScDataPilotDescriptorBase& rParent ) :
1311 mxParent( &rParent )
1315 ScDataPilotChildObjBase::ScDataPilotChildObjBase( ScDataPilotDescriptorBase& rParent, ScFieldIdentifier aFieldId ) :
1316 mxParent( &rParent ),
1317 maFieldId(std::move( aFieldId ))
1321 ScDataPilotChildObjBase::~ScDataPilotChildObjBase()
1325 ScDPObject* ScDataPilotChildObjBase::GetDPObject() const
1327 return mxParent->GetDPObject();
1330 void ScDataPilotChildObjBase::SetDPObject( ScDPObject* pDPObject )
1332 mxParent->SetDPObject( pDPObject );
1335 ScDPSaveDimension* ScDataPilotChildObjBase::GetDPDimension( ScDPObject** ppDPObject ) const
1337 if( ScDPObject* pDPObj = GetDPObject() )
1339 if( ppDPObject ) *ppDPObject = pDPObj;
1340 if( ScDPSaveData* pSaveData = pDPObj->GetSaveData() )
1342 if( maFieldId.mbDataLayout )
1343 return pSaveData->GetDataLayoutDimension();
1345 if( maFieldId.mnFieldIdx == 0 )
1346 return pSaveData->GetDimensionByName( maFieldId.maFieldName );
1348 // find dimension with specified index (search in duplicated dimensions)
1349 const ScDPSaveData::DimsType& rDims = pSaveData->GetDimensions();
1351 sal_Int32 nFoundIdx = 0;
1352 for (auto const& it : rDims)
1354 if (it->IsDataLayout())
1355 continue;
1357 OUString aSrcName = ScDPUtil::getSourceDimensionName(it->GetName());
1358 if (aSrcName == maFieldId.maFieldName)
1360 if( nFoundIdx == maFieldId.mnFieldIdx )
1361 return it.get();
1362 ++nFoundIdx;
1367 return nullptr;
1370 sal_Int32 ScDataPilotChildObjBase::GetMemberCount() const
1372 sal_Int32 nRet = 0;
1373 Reference<XNameAccess> xMembersNA = GetMembers();
1374 if (xMembersNA.is())
1376 Reference< XIndexAccess > xMembersIA( new ScNameToIndexAccess( xMembersNA ) );
1377 nRet = xMembersIA->getCount();
1379 return nRet;
1382 Reference< XMembersAccess > ScDataPilotChildObjBase::GetMembers() const
1384 Reference< XMembersAccess > xMembersNA;
1385 if( ScDPObject* pDPObj = GetDPObject() )
1386 pDPObj->GetMembersNA( lcl_GetObjectIndex( pDPObj, maFieldId ), xMembersNA );
1387 return xMembersNA;
1390 ScDocShell* ScDataPilotChildObjBase::GetDocShell() const
1392 return mxParent->GetDocShell();
1395 ScDataPilotFieldsObj::ScDataPilotFieldsObj( ScDataPilotDescriptorBase& rParent ) :
1396 ScDataPilotChildObjBase( rParent )
1400 ScDataPilotFieldsObj::ScDataPilotFieldsObj( ScDataPilotDescriptorBase& rParent, DataPilotFieldOrientation eOrient ) :
1401 ScDataPilotChildObjBase( rParent ),
1402 maOrient( eOrient )
1406 ScDataPilotFieldsObj::~ScDataPilotFieldsObj()
1410 static sal_Int32 lcl_GetFieldCount( const Reference<XDimensionsSupplier>& rSource, const Any& rOrient )
1412 if (!rSource.is())
1413 throw NullPointerException();
1415 sal_Int32 nRet = 0;
1417 Reference<XNameAccess> xDimsName(rSource->getDimensions());
1418 Reference<XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
1419 sal_Int32 nIntCount = xIntDims->getCount();
1420 for (sal_Int32 i = 0; i < nIntCount; ++i)
1422 Reference<XPropertySet> xDim(xIntDims->getByIndex(i), UNO_QUERY);
1423 const bool bMatch = xDim
1424 && (rOrient.hasValue()
1425 // all fields of the specified orientation, including duplicated
1426 ? (xDim->getPropertyValue(SC_UNO_DP_ORIENTATION) == rOrient)
1427 // count all non-duplicated fields
1428 : !lcl_IsDuplicated(xDim));
1429 if (bMatch)
1430 ++nRet;
1433 return nRet;
1436 static bool lcl_GetFieldDataByIndex( const Reference<XDimensionsSupplier>& rSource,
1437 const Any& rOrient, SCSIZE nIndex, ScFieldIdentifier& rFieldId )
1439 if (!rSource.is())
1440 throw NullPointerException();
1442 bool bOk = false;
1443 SCSIZE nPos = 0;
1444 sal_Int32 nDimIndex = 0;
1446 Reference<XNameAccess> xDimsName(rSource->getDimensions());
1447 Reference<XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
1448 sal_Int32 nIntCount = xIntDims->getCount();
1449 Reference<XPropertySet> xDim;
1450 for (sal_Int32 i = 0; i < nIntCount; ++i)
1452 xDim.set(xIntDims->getByIndex(i), UNO_QUERY);
1453 const bool bMatch = xDim
1454 && (rOrient.hasValue()
1455 ? (xDim->getPropertyValue(SC_UNO_DP_ORIENTATION) == rOrient)
1456 : !lcl_IsDuplicated(xDim));
1457 if (bMatch)
1459 if (nPos == nIndex)
1461 bOk = true;
1462 nDimIndex = i;
1463 break;
1465 else
1466 ++nPos;
1470 if ( bOk )
1472 xDim.set( xIntDims->getByIndex(nDimIndex), UNO_QUERY );
1473 Reference<XNamed> xDimName( xDim, UNO_QUERY );
1474 if ( xDimName.is() )
1476 OUString sOriginalName( lcl_GetOriginalName( xDimName ) );
1477 rFieldId.maFieldName = sOriginalName;
1478 rFieldId.mbDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDim,
1479 SC_UNO_DP_ISDATALAYOUT );
1481 sal_Int32 nRepeat = 0;
1482 if ( rOrient.hasValue() && lcl_IsDuplicated( xDim ) )
1484 // find the repeat count
1485 // (this relies on the original dimension always being before the duplicates)
1487 Reference<XNamed> xPrevName;
1488 for (sal_Int32 i = 0; i < nDimIndex; ++i)
1490 xPrevName.set( xIntDims->getByIndex(i), UNO_QUERY );
1491 if ( xPrevName.is() && lcl_GetOriginalName( xPrevName ) == sOriginalName )
1492 ++nRepeat;
1495 rFieldId.mnFieldIdx = nRepeat;
1497 else
1498 bOk = false;
1501 return bOk;
1504 static bool lcl_GetFieldDataByName( ScDPObject* pDPObj, const OUString& rFieldName, ScFieldIdentifier& rFieldId )
1506 // "By name" is always the first match.
1507 // The name "Data" always refers to the data layout field.
1508 rFieldId.maFieldName = rFieldName;
1509 rFieldId.mnFieldIdx = 0;
1510 rFieldId.mbDataLayout = rFieldName == SC_DATALAYOUT_NAME;
1512 pDPObj->GetSource(); // IsDimNameInUse doesn't update source data
1514 // check if the named field exists (not for data layout)
1515 return rFieldId.mbDataLayout || pDPObj->IsDimNameInUse( rFieldName );
1518 // XDataPilotFields
1520 rtl::Reference<ScDataPilotFieldObj> ScDataPilotFieldsObj::GetObjectByIndex_Impl( sal_Int32 nIndex ) const
1522 if (ScDPObject* pObj = GetDPObject())
1524 ScFieldIdentifier aFieldId;
1525 if (lcl_GetFieldDataByIndex( pObj->GetSource(), maOrient, nIndex, aFieldId ))
1526 return new ScDataPilotFieldObj( *mxParent, aFieldId, maOrient );
1528 return nullptr;
1531 rtl::Reference<ScDataPilotFieldObj> ScDataPilotFieldsObj::GetObjectByName_Impl(const OUString& aName) const
1533 if (ScDPObject* pDPObj = GetDPObject())
1535 ScFieldIdentifier aFieldId;
1536 if (lcl_GetFieldDataByName( pDPObj, aName, aFieldId ))
1537 return new ScDataPilotFieldObj( *mxParent, aFieldId, maOrient );
1539 return nullptr;
1542 // XEnumerationAccess
1544 Reference<XEnumeration> SAL_CALL ScDataPilotFieldsObj::createEnumeration()
1546 SolarMutexGuard aGuard;
1547 return new ScIndexEnumeration(this, u"com.sun.star.sheet.DataPilotFieldsEnumeration"_ustr);
1550 // XIndexAccess
1552 sal_Int32 SAL_CALL ScDataPilotFieldsObj::getCount()
1554 SolarMutexGuard aGuard;
1555 ScDPObject* pDPObj = GetDPObject();
1556 return pDPObj ? lcl_GetFieldCount( pDPObj->GetSource(), maOrient ) : 0;
1559 Any SAL_CALL ScDataPilotFieldsObj::getByIndex( sal_Int32 nIndex )
1561 SolarMutexGuard aGuard;
1562 Reference< XPropertySet > xField( GetObjectByIndex_Impl( nIndex ) );
1563 if (!xField.is())
1564 throw IndexOutOfBoundsException();
1565 return Any( xField );
1568 // XElementAccess
1570 uno::Type SAL_CALL ScDataPilotFieldsObj::getElementType()
1572 return cppu::UnoType<XPropertySet>::get();
1575 sal_Bool SAL_CALL ScDataPilotFieldsObj::hasElements()
1577 SolarMutexGuard aGuard;
1578 return ( getCount() != 0 );
1581 // XNameAccess
1583 Any SAL_CALL ScDataPilotFieldsObj::getByName( const OUString& aName )
1585 SolarMutexGuard aGuard;
1586 Reference<XPropertySet> xField(GetObjectByName_Impl(aName));
1587 if (!xField.is())
1588 throw NoSuchElementException();
1589 return Any( xField );
1592 Sequence<OUString> SAL_CALL ScDataPilotFieldsObj::getElementNames()
1594 SolarMutexGuard aGuard;
1595 if (ScDPObject* pDPObj = GetDPObject())
1597 Sequence< OUString > aSeq( lcl_GetFieldCount( pDPObj->GetSource(), maOrient ) );
1598 OUString* pAry = aSeq.getArray();
1600 const ScDPSaveData::DimsType& rDimensions = pDPObj->GetSaveData()->GetDimensions();
1601 for (auto const& it : rDimensions)
1603 if(maOrient.hasValue() && (it->GetOrientation() == maOrient.get< DataPilotFieldOrientation >()))
1605 *pAry = it->GetName();
1606 ++pAry;
1609 return aSeq;
1611 return Sequence<OUString>();
1614 sal_Bool SAL_CALL ScDataPilotFieldsObj::hasByName( const OUString& aName )
1616 SolarMutexGuard aGuard;
1618 return GetObjectByName_Impl(aName) != nullptr;
1621 ScDataPilotFieldObj::ScDataPilotFieldObj(
1622 ScDataPilotDescriptorBase& rParent, const ScFieldIdentifier& rFieldId ) :
1623 ScDataPilotChildObjBase( rParent, rFieldId ),
1624 maPropSet( lcl_GetDataPilotFieldMap() )
1628 ScDataPilotFieldObj::ScDataPilotFieldObj( ScDataPilotDescriptorBase& rParent,
1629 const ScFieldIdentifier& rFieldId, Any aOrient ) :
1630 ScDataPilotChildObjBase( rParent, rFieldId ),
1631 maPropSet( lcl_GetDataPilotFieldMap() ),
1632 maOrient(std::move( aOrient ))
1636 ScDataPilotFieldObj::~ScDataPilotFieldObj()
1640 // XNamed
1642 OUString SAL_CALL ScDataPilotFieldObj::getName()
1644 SolarMutexGuard aGuard;
1645 OUString aName;
1646 if( ScDPSaveDimension* pDim = GetDPDimension() )
1648 if( pDim->IsDataLayout() )
1649 aName = SC_DATALAYOUT_NAME;
1650 else
1652 const std::optional<OUString> & pLayoutName = pDim->GetLayoutName();
1653 if (pLayoutName)
1654 aName = *pLayoutName;
1655 else
1656 aName = pDim->GetName();
1659 return aName;
1662 void SAL_CALL ScDataPilotFieldObj::setName(const OUString& rName)
1664 SolarMutexGuard aGuard;
1665 ScDPObject* pDPObj = nullptr;
1666 ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
1667 if( pDim && !pDim->IsDataLayout() )
1669 pDim->SetLayoutName(rName);
1670 SetDPObject( pDPObj );
1674 // XPropertySet
1676 Reference<XPropertySetInfo> SAL_CALL ScDataPilotFieldObj::getPropertySetInfo()
1678 SolarMutexGuard aGuard;
1679 static Reference<XPropertySetInfo> aRef(
1680 new SfxItemPropertySetInfo( maPropSet.getPropertyMap() ));
1681 return aRef;
1684 void SAL_CALL ScDataPilotFieldObj::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
1686 SolarMutexGuard aGuard;
1687 if ( aPropertyName == SC_UNONAME_FUNCTION )
1689 // #i109350# use GetEnumFromAny because it also allows sal_Int32
1690 ScGeneralFunction eFunction = static_cast<ScGeneralFunction>(ScUnoHelpFunctions::GetEnumFromAny( aValue ));
1691 setFunction( eFunction );
1693 else if ( aPropertyName == SC_UNONAME_FUNCTION2 )
1695 ScGeneralFunction eFunction = static_cast<ScGeneralFunction>(ScUnoHelpFunctions::GetInt16FromAny( aValue ));
1696 setFunction( eFunction );
1698 else if ( aPropertyName == SC_UNONAME_SUBTOTALS )
1700 uno::Sequence<sheet::GeneralFunction> aSeq;
1701 if( aValue >>= aSeq)
1703 std::vector< ScGeneralFunction > aSubTotals(aSeq.getLength());
1704 std::transform(std::cbegin(aSeq), std::cend(aSeq), aSubTotals.begin(),
1705 [](const sheet::GeneralFunction& rValue) -> ScGeneralFunction {
1706 const int nValAsInt = static_cast<int>(rValue);
1707 return static_cast<ScGeneralFunction>(nValAsInt);
1709 setSubtotals( aSubTotals );
1712 else if ( aPropertyName == SC_UNONAME_SUBTOTALS2 )
1714 Sequence< sal_Int16 > aSeq;
1715 if( aValue >>= aSeq )
1717 std::vector< ScGeneralFunction > aSubTotals(aSeq.getLength());
1718 std::transform(std::cbegin(aSeq), std::cend(aSeq), aSubTotals.begin(),
1719 [](sal_Int16 nValue) -> ScGeneralFunction { return static_cast<ScGeneralFunction>(nValue); });
1720 setSubtotals( aSubTotals );
1723 else if ( aPropertyName == SC_UNONAME_ORIENT )
1725 //! test for correct enum type?
1726 DataPilotFieldOrientation eOrient = static_cast<DataPilotFieldOrientation>(ScUnoHelpFunctions::GetEnumFromAny( aValue ));
1727 setOrientation( eOrient );
1729 else if ( aPropertyName == SC_UNONAME_SELPAGE )
1731 OUString sCurrentPage;
1732 if (aValue >>= sCurrentPage)
1733 setCurrentPage(sCurrentPage);
1735 else if ( aPropertyName == SC_UNONAME_USESELPAGE )
1737 setUseCurrentPage(cppu::any2bool(aValue));
1739 else if ( aPropertyName == SC_UNONAME_HASAUTOSHOW )
1741 if (!cppu::any2bool(aValue))
1742 setAutoShowInfo(nullptr);
1744 else if ( aPropertyName == SC_UNONAME_AUTOSHOW )
1746 DataPilotFieldAutoShowInfo aInfo;
1747 if (aValue >>= aInfo)
1748 setAutoShowInfo(&aInfo);
1750 else if ( aPropertyName == SC_UNONAME_HASLAYOUTINFO )
1752 if (!cppu::any2bool(aValue))
1753 setLayoutInfo(nullptr);
1755 else if ( aPropertyName == SC_UNONAME_LAYOUTINFO )
1757 DataPilotFieldLayoutInfo aInfo;
1758 if (aValue >>= aInfo)
1759 setLayoutInfo(&aInfo);
1761 else if ( aPropertyName == SC_UNONAME_HASREFERENCE )
1763 if (!cppu::any2bool(aValue))
1764 setReference(nullptr);
1766 else if ( aPropertyName == SC_UNONAME_REFERENCE )
1768 DataPilotFieldReference aRef;
1769 if (aValue >>= aRef)
1770 setReference(&aRef);
1772 else if ( aPropertyName == SC_UNONAME_HASSORTINFO )
1774 if (!cppu::any2bool(aValue))
1775 setSortInfo(nullptr);
1777 else if ( aPropertyName == SC_UNONAME_SORTINFO )
1779 DataPilotFieldSortInfo aInfo;
1780 if (aValue >>= aInfo)
1781 setSortInfo(&aInfo);
1783 else if ( aPropertyName == SC_UNONAME_ISGROUP )
1785 if (!cppu::any2bool(aValue))
1786 setGroupInfo(nullptr);
1788 else if ( aPropertyName == SC_UNONAME_GROUPINFO )
1790 DataPilotFieldGroupInfo aInfo;
1791 if (aValue >>= aInfo)
1792 setGroupInfo(&aInfo);
1794 else if ( aPropertyName == SC_UNONAME_SHOWEMPTY )
1796 setShowEmpty(cppu::any2bool(aValue));
1798 else if ( aPropertyName == SC_UNONAME_REPEATITEMLABELS )
1800 setRepeatItemLabels(cppu::any2bool(aValue));
1802 else if (aPropertyName == SC_UNONAME_NAME)
1804 OUString sName;
1805 if (aValue >>= sName)
1806 setName(sName);
1810 Any SAL_CALL ScDataPilotFieldObj::getPropertyValue( const OUString& aPropertyName )
1812 SolarMutexGuard aGuard;
1813 Any aRet;
1815 if ( aPropertyName == SC_UNONAME_FUNCTION )
1817 sheet::GeneralFunction eVal;
1818 sal_Int16 nFunction = getFunction();
1819 if (nFunction == sheet::GeneralFunction2::MEDIAN)
1821 eVal = sheet::GeneralFunction_NONE;
1823 else
1825 eVal = static_cast<sheet::GeneralFunction>(nFunction);
1827 aRet <<= eVal;
1829 else if ( aPropertyName == SC_UNONAME_FUNCTION2 )
1830 aRet <<= getFunction();
1831 else if ( aPropertyName == SC_UNONAME_SUBTOTALS )
1833 const uno::Sequence<sal_Int16> aSeq = getSubtotals();
1834 uno::Sequence<sheet::GeneralFunction> aNewSeq(aSeq.getLength());
1835 std::transform(aSeq.begin(), aSeq.end(), aNewSeq.getArray(),
1836 [](sal_Int16 nFunc) -> sheet::GeneralFunction {
1837 if (nFunc == sheet::GeneralFunction2::MEDIAN)
1838 return sheet::GeneralFunction_NONE;
1839 return static_cast<sheet::GeneralFunction>(nFunc);
1841 aRet <<= aNewSeq;
1843 else if ( aPropertyName == SC_UNONAME_SUBTOTALS2 )
1845 aRet <<= getSubtotals();
1847 else if ( aPropertyName == SC_UNONAME_ORIENT )
1848 aRet <<= getOrientation();
1849 else if ( aPropertyName == SC_UNONAME_SELPAGE )
1850 aRet <<= OUString();
1851 else if ( aPropertyName == SC_UNONAME_USESELPAGE )
1852 aRet <<= false;
1853 else if ( aPropertyName == SC_UNONAME_HASAUTOSHOW )
1854 aRet <<= (getAutoShowInfo() != nullptr);
1855 else if ( aPropertyName == SC_UNONAME_AUTOSHOW )
1857 const DataPilotFieldAutoShowInfo* pInfo = getAutoShowInfo();
1858 if (pInfo)
1859 aRet <<= *pInfo;
1861 else if ( aPropertyName == SC_UNONAME_HASLAYOUTINFO )
1862 aRet <<= (getLayoutInfo() != nullptr);
1863 else if ( aPropertyName == SC_UNONAME_LAYOUTINFO )
1865 const DataPilotFieldLayoutInfo* pInfo = getLayoutInfo();
1866 if (pInfo)
1867 aRet <<= *pInfo;
1869 else if ( aPropertyName == SC_UNONAME_HASREFERENCE )
1870 aRet <<= (getReference() != nullptr);
1871 else if ( aPropertyName == SC_UNONAME_REFERENCE )
1873 const DataPilotFieldReference* pRef = getReference();
1874 if (pRef)
1875 aRet <<= *pRef;
1877 else if ( aPropertyName == SC_UNONAME_HASSORTINFO )
1878 aRet <<= (getSortInfo() != nullptr);
1879 else if ( aPropertyName == SC_UNONAME_SORTINFO )
1881 const DataPilotFieldSortInfo* pInfo = getSortInfo();
1882 if (pInfo)
1883 aRet <<= *pInfo;
1885 else if ( aPropertyName == SC_UNONAME_ISGROUP )
1886 aRet <<= hasGroupInfo();
1887 else if ( aPropertyName == SC_UNONAME_GROUPINFO )
1889 aRet <<= getGroupInfo();
1891 else if ( aPropertyName == SC_UNONAME_SHOWEMPTY )
1892 aRet <<= getShowEmpty();
1893 else if ( aPropertyName == SC_UNONAME_REPEATITEMLABELS )
1894 aRet <<= getRepeatItemLabels();
1895 else if (aPropertyName == SC_UNONAME_NAME)
1896 aRet <<= getName();
1898 return aRet;
1901 // XDatePilotField
1903 Reference<XIndexAccess> SAL_CALL ScDataPilotFieldObj::getItems()
1905 SolarMutexGuard aGuard;
1906 if (!mxItems.is())
1907 mxItems.set( new ScDataPilotItemsObj( *mxParent, maFieldId ) );
1908 return mxItems;
1911 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDataPilotFieldObj )
1913 DataPilotFieldOrientation ScDataPilotFieldObj::getOrientation() const
1915 SolarMutexGuard aGuard;
1916 ScDPSaveDimension* pDim = GetDPDimension();
1917 return pDim ? pDim->GetOrientation() : DataPilotFieldOrientation_HIDDEN;
1920 void ScDataPilotFieldObj::setOrientation(DataPilotFieldOrientation eNew)
1922 SolarMutexGuard aGuard;
1923 if (maOrient.hasValue() && (eNew == maOrient.get< DataPilotFieldOrientation >()))
1924 return;
1926 ScDPObject* pDPObj = nullptr;
1927 ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
1928 if(!pDim)
1929 return;
1931 ScDPSaveData* pSaveData = pDPObj->GetSaveData();
1933 /* If the field was taken from getDataPilotFields(), don't reset the
1934 orientation for an existing use, but create a duplicated field
1935 instead (for "Data" orientation only). */
1936 if ( !maOrient.hasValue() && !maFieldId.mbDataLayout &&
1937 (pDim->GetOrientation() != DataPilotFieldOrientation_HIDDEN) &&
1938 (eNew == DataPilotFieldOrientation_DATA) )
1941 ScDPSaveDimension* pNewDim = nullptr;
1943 // look for existing duplicate with orientation "hidden"
1945 sal_Int32 nFound = 0;
1946 const ScDPSaveData::DimsType& rDimensions = pSaveData->GetDimensions();
1947 for (auto const& it : rDimensions)
1949 if ( !it->IsDataLayout() && (it->GetName() == maFieldId.maFieldName) )
1951 if ( it->GetOrientation() == DataPilotFieldOrientation_HIDDEN )
1953 pNewDim = it.get(); // use this one
1954 break;
1956 else
1957 ++nFound; // count existing non-hidden occurrences
1961 if ( !pNewDim ) // if none found, create a new duplicated dimension
1962 pNewDim = &pSaveData->DuplicateDimension( *pDim );
1964 maFieldId.mnFieldIdx = nFound; // keep accessing the new one
1965 pDim = pNewDim;
1968 pDim->SetOrientation(eNew);
1970 // move changed field behind all other fields (make it the last field in dimension)
1971 pSaveData->SetPosition( pDim, pSaveData->GetDimensions().size() );
1973 SetDPObject( pDPObj );
1975 maOrient <<= eNew; // modifying the same object's orientation again doesn't create another duplicate
1978 sal_Int16 ScDataPilotFieldObj::getFunction() const
1980 SolarMutexGuard aGuard;
1981 sal_Int16 eRet = GeneralFunction2::NONE;
1982 if( ScDPSaveDimension* pDim = GetDPDimension() )
1984 if( pDim->GetOrientation() != DataPilotFieldOrientation_DATA )
1986 // for non-data fields, property Function is the subtotals
1987 tools::Long nSubCount = pDim->GetSubTotalsCount();
1988 if ( nSubCount > 0 )
1989 eRet = static_cast<sal_Int16>(pDim->GetSubTotalFunc(0)); // always use the first one
1990 // else keep NONE
1992 else
1993 eRet = static_cast<sal_Int16>(pDim->GetFunction());
1995 return eRet;
1998 void ScDataPilotFieldObj::setFunction(ScGeneralFunction eNewFunc)
2000 SolarMutexGuard aGuard;
2001 ScDPObject* pDPObj = nullptr;
2002 ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
2003 if(!pDim)
2004 return;
2006 if( pDim->GetOrientation() != DataPilotFieldOrientation_DATA )
2008 // for non-data fields, property Function is the subtotals
2009 std::vector<ScGeneralFunction> nSubTotalFuncs;
2010 if ( eNewFunc != ScGeneralFunction::NONE )
2012 nSubTotalFuncs.push_back( eNewFunc );
2014 pDim->SetSubTotals( std::move(nSubTotalFuncs) );
2016 else
2017 pDim->SetFunction( eNewFunc );
2018 SetDPObject( pDPObj );
2021 Sequence< sal_Int16 > ScDataPilotFieldObj::getSubtotals() const
2023 SolarMutexGuard aGuard;
2024 Sequence< sal_Int16 > aRet;
2025 if( ScDPSaveDimension* pDim = GetDPDimension() )
2027 if( pDim->GetOrientation() != DataPilotFieldOrientation_DATA )
2029 // for non-data fields, property Functions is the sequence of subtotals
2030 sal_Int32 nCount = static_cast< sal_Int32 >( pDim->GetSubTotalsCount() );
2031 if ( nCount > 0 )
2033 aRet.realloc( nCount );
2034 auto pRet = aRet.getArray();
2035 for( sal_Int32 nIdx = 0; nIdx < nCount; ++nIdx )
2036 pRet[ nIdx ] = static_cast<sal_Int16>(pDim->GetSubTotalFunc( nIdx ));
2040 return aRet;
2043 void ScDataPilotFieldObj::setSubtotals( const std::vector< ScGeneralFunction >& rSubtotals )
2045 SolarMutexGuard aGuard;
2046 ScDPObject* pDPObj = nullptr;
2047 ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
2048 if(!pDim)
2049 return;
2051 if( pDim->GetOrientation() != DataPilotFieldOrientation_DATA )
2053 sal_Int32 nCount = rSubtotals.size();
2054 if( nCount == 1 )
2056 // count 1: all values are allowed (including NONE and AUTO)
2057 std::vector<ScGeneralFunction> nTmpFuncs;
2058 if( rSubtotals[ 0 ] != ScGeneralFunction::NONE )
2060 nTmpFuncs.push_back( rSubtotals[ 0 ] );
2062 pDim->SetSubTotals( std::move(nTmpFuncs) );
2064 else if( nCount > 1 )
2066 // set multiple functions, ignore NONE and AUTO in this case
2067 ::std::vector< ScGeneralFunction > aSubt;
2068 for( sal_Int32 nIdx = 0; nIdx < nCount; ++nIdx )
2070 ScGeneralFunction eFunc = rSubtotals[ nIdx ];
2071 if( (eFunc != ScGeneralFunction::NONE) && (eFunc != ScGeneralFunction::AUTO) )
2073 // do not insert functions twice
2074 if( ::std::find( aSubt.begin(), aSubt.end(), eFunc ) == aSubt.end() )
2075 aSubt.push_back( eFunc );
2078 // set values from vector to ScDPSaveDimension
2079 pDim->SetSubTotals( std::move(aSubt) );
2082 SetDPObject( pDPObj );
2085 void ScDataPilotFieldObj::setCurrentPage( const OUString& rPage )
2087 SolarMutexGuard aGuard;
2088 ScDPObject* pDPObj = nullptr;
2089 if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
2091 pDim->SetCurrentPage( &rPage );
2092 SetDPObject( pDPObj );
2096 void ScDataPilotFieldObj::setUseCurrentPage( bool bUse )
2098 SolarMutexGuard aGuard;
2099 ScDPObject* pDPObj = nullptr;
2100 ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
2101 if(!pDim)
2102 return;
2104 if( bUse )
2106 /* It is somehow useless to set the property "HasSelectedPage" to
2107 true, because it is still needed to set an explicit page name. */
2108 const OUString aPage;
2109 pDim->SetCurrentPage( &aPage );
2111 else
2112 pDim->SetCurrentPage( nullptr );
2113 SetDPObject( pDPObj );
2116 const DataPilotFieldAutoShowInfo* ScDataPilotFieldObj::getAutoShowInfo() const
2118 SolarMutexGuard aGuard;
2119 ScDPSaveDimension* pDim = GetDPDimension();
2120 return pDim ? pDim->GetAutoShowInfo() : nullptr;
2123 void ScDataPilotFieldObj::setAutoShowInfo( const DataPilotFieldAutoShowInfo* pInfo )
2125 SolarMutexGuard aGuard;
2126 ScDPObject* pDPObj = nullptr;
2127 if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
2129 pDim->SetAutoShowInfo( pInfo );
2130 SetDPObject( pDPObj );
2134 const DataPilotFieldLayoutInfo* ScDataPilotFieldObj::getLayoutInfo() const
2136 SolarMutexGuard aGuard;
2137 ScDPSaveDimension* pDim = GetDPDimension();
2138 return pDim ? pDim->GetLayoutInfo() : nullptr;
2141 void ScDataPilotFieldObj::setLayoutInfo( const DataPilotFieldLayoutInfo* pInfo )
2143 SolarMutexGuard aGuard;
2144 ScDPObject* pDPObj = nullptr;
2145 if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
2147 pDim->SetLayoutInfo( pInfo );
2148 SetDPObject( pDPObj );
2152 const DataPilotFieldReference* ScDataPilotFieldObj::getReference() const
2154 SolarMutexGuard aGuard;
2155 ScDPSaveDimension* pDim = GetDPDimension();
2156 return pDim ? pDim->GetReferenceValue() : nullptr;
2159 void ScDataPilotFieldObj::setReference( const DataPilotFieldReference* pInfo )
2161 SolarMutexGuard aGuard;
2162 ScDPObject* pDPObj = nullptr;
2163 if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
2165 pDim->SetReferenceValue( pInfo );
2166 SetDPObject( pDPObj );
2170 const DataPilotFieldSortInfo* ScDataPilotFieldObj::getSortInfo() const
2172 SolarMutexGuard aGuard;
2173 ScDPSaveDimension* pDim = GetDPDimension();
2174 return pDim ? pDim->GetSortInfo() : nullptr;
2177 void ScDataPilotFieldObj::setSortInfo( const DataPilotFieldSortInfo* pInfo )
2179 SolarMutexGuard aGuard;
2180 ScDPObject* pDPObj = nullptr;
2181 if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
2183 pDim->SetSortInfo( pInfo );
2184 SetDPObject( pDPObj );
2188 bool ScDataPilotFieldObj::getShowEmpty() const
2190 SolarMutexGuard aGuard;
2191 ScDPSaveDimension* pDim = GetDPDimension();
2192 return pDim && pDim->GetShowEmpty();
2195 void ScDataPilotFieldObj::setShowEmpty( bool bShow )
2197 SolarMutexGuard aGuard;
2198 ScDPObject* pDPObj = nullptr;
2199 if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
2201 pDim->SetShowEmpty( bShow );
2202 SetDPObject( pDPObj );
2206 bool ScDataPilotFieldObj::getRepeatItemLabels() const
2208 SolarMutexGuard aGuard;
2209 ScDPSaveDimension* pDim = GetDPDimension();
2210 return pDim && pDim->GetRepeatItemLabels();
2213 void ScDataPilotFieldObj::setRepeatItemLabels( bool bShow )
2215 SolarMutexGuard aGuard;
2216 ScDPObject* pDPObj = nullptr;
2217 if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
2219 pDim->SetRepeatItemLabels( bShow );
2220 SetDPObject( pDPObj );
2224 bool ScDataPilotFieldObj::hasGroupInfo() const
2226 SolarMutexGuard aGuard;
2227 ScDPObject* pDPObj = nullptr;
2228 if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
2229 if( const ScDPDimensionSaveData* pDimData = pDPObj->GetSaveData()->GetExistingDimensionData() )
2230 return pDimData->GetNamedGroupDim( pDim->GetName() ) || pDimData->GetNumGroupDim( pDim->GetName() );
2231 return false;
2234 DataPilotFieldGroupInfo ScDataPilotFieldObj::getGroupInfo()
2236 SolarMutexGuard aGuard;
2237 DataPilotFieldGroupInfo aInfo;
2238 ScDPObject* pDPObj = nullptr;
2239 if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
2241 if( const ScDPDimensionSaveData* pDimData = pDPObj->GetSaveData()->GetExistingDimensionData() )
2243 if( const ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDim( pDim->GetName() ) )
2245 // grouped by ...
2246 aInfo.GroupBy = pGroupDim->GetDatePart();
2248 // find source field
2251 Reference< XNameAccess > xFields( mxParent->getDataPilotFields(), UNO_QUERY_THROW );
2252 aInfo.SourceField.set( xFields->getByName( pGroupDim->GetSourceDimName() ), UNO_QUERY );
2254 catch( Exception& )
2258 ScDataPilotConversion::FillGroupInfo( aInfo, pGroupDim->GetDateInfo() );
2259 if( pGroupDim->GetDatePart() == 0 )
2261 // fill vector of group and group member information
2262 ScFieldGroups aGroups;
2263 for( sal_Int32 nIdx = 0, nCount = pGroupDim->GetGroupCount(); nIdx < nCount; ++nIdx )
2265 const ScDPSaveGroupItem& rGroup = pGroupDim->GetGroupByIndex( nIdx );
2266 ScFieldGroup aGroup;
2267 aGroup.maName = rGroup.GetGroupName();
2268 for( sal_Int32 nMemIdx = 0, nMemCount = rGroup.GetElementCount(); nMemIdx < nMemCount; ++nMemIdx )
2269 if (const OUString* pMem = rGroup.GetElementByIndex(nMemIdx))
2270 aGroup.maMembers.push_back( *pMem );
2271 aGroups.push_back( aGroup );
2273 aInfo.Groups = new ScDataPilotFieldGroupsObj( std::move(aGroups) );
2276 else if( const ScDPSaveNumGroupDimension* pNumGroupDim = pDimData->GetNumGroupDim( pDim->GetName() ) )
2278 if (pNumGroupDim->GetDatePart())
2280 ScDataPilotConversion::FillGroupInfo( aInfo, pNumGroupDim->GetDateInfo() );
2281 aInfo.GroupBy = pNumGroupDim->GetDatePart();
2283 else
2285 ScDataPilotConversion::FillGroupInfo( aInfo, pNumGroupDim->GetInfo() );
2290 return aInfo;
2293 void ScDataPilotFieldObj::setGroupInfo( const DataPilotFieldGroupInfo* pInfo )
2295 SolarMutexGuard aGuard;
2296 ScDPObject* pDPObj = nullptr;
2297 if( /*ScDPSaveDimension* pDim =*/ !GetDPDimension( &pDPObj ) )
2298 return;
2300 ScDPSaveData* pSaveData = pDPObj->GetSaveData();
2301 if( pInfo && lclCheckMinMaxStep( *pInfo ) )
2303 ScDPNumGroupInfo aInfo;
2304 aInfo.mbEnable = true;
2305 aInfo.mbDateValues = pInfo->HasDateValues;
2306 aInfo.mbAutoStart = pInfo->HasAutoStart;
2307 aInfo.mbAutoEnd = pInfo->HasAutoEnd;
2308 aInfo.mfStart = pInfo->Start;
2309 aInfo.mfEnd = pInfo->End;
2310 aInfo.mfStep = pInfo->Step;
2311 Reference< XNamed > xNamed( pInfo->SourceField, UNO_QUERY );
2312 if( xNamed.is() )
2314 ScDPSaveGroupDimension aGroupDim( xNamed->getName(), getName() );
2315 if( pInfo->GroupBy )
2316 aGroupDim.SetDateInfo(aInfo, pInfo->GroupBy);
2317 else
2319 Reference<XIndexAccess> xIndex(pInfo->Groups, UNO_QUERY);
2320 if (xIndex.is())
2322 sal_Int32 nCount(xIndex->getCount());
2323 for(sal_Int32 i = 0; i < nCount; i++)
2325 Reference<XNamed> xGroupNamed(xIndex->getByIndex(i), UNO_QUERY);
2326 if (xGroupNamed.is())
2328 ScDPSaveGroupItem aItem(xGroupNamed->getName());
2329 Reference<XIndexAccess> xGroupIndex(xGroupNamed, UNO_QUERY);
2330 if (xGroupIndex.is())
2332 sal_Int32 nItemCount(xGroupIndex->getCount());
2333 for (sal_Int32 j = 0; j < nItemCount; ++j)
2335 Reference<XNamed> xItemNamed(xGroupIndex->getByIndex(j), UNO_QUERY);
2336 if (xItemNamed.is())
2337 aItem.AddElement(xItemNamed->getName());
2340 aGroupDim.AddGroupItem(aItem);
2346 // get dimension savedata or create new if none
2347 ScDPDimensionSaveData& rDimSaveData = *pSaveData->GetDimensionData();
2348 rDimSaveData.ReplaceGroupDimension( aGroupDim );
2350 else // no source field in group info -> numeric group
2352 ScDPDimensionSaveData* pDimData = pSaveData->GetDimensionData(); // created if not there
2354 ScDPSaveNumGroupDimension* pExisting = pDimData->GetNumGroupDimAcc( getName() );
2355 if ( pExisting )
2357 if (pInfo->GroupBy)
2358 pExisting->SetDateInfo(aInfo, pInfo->GroupBy);
2359 // modify existing group dimension
2360 pExisting->SetGroupInfo( aInfo );
2362 else if (pInfo->GroupBy)
2364 // create new group dimension
2365 ScDPSaveNumGroupDimension aNumGroupDim( getName(), aInfo, pInfo->GroupBy );
2366 pDimData->AddNumGroupDimension( aNumGroupDim );
2368 else
2370 // create new group dimension
2371 ScDPSaveNumGroupDimension aNumGroupDim( getName(), aInfo );
2372 pDimData->AddNumGroupDimension( aNumGroupDim );
2376 else // null passed as argument
2378 pSaveData->SetDimensionData( nullptr );
2381 pDPObj->SetSaveData( *pSaveData );
2382 SetDPObject( pDPObj );
2385 // XDataPilotFieldGrouping
2386 Reference< XDataPilotField > SAL_CALL ScDataPilotFieldObj::createNameGroup( const Sequence< OUString >& rItems )
2388 SolarMutexGuard aGuard;
2390 if( !rItems.hasElements() )
2391 throw IllegalArgumentException(u"rItems is empty"_ustr, getXWeak(), 0);
2393 Reference< XMembersAccess > xMembers = GetMembers();
2394 if (!xMembers.is())
2396 SAL_WARN("sc.ui", "Cannot access members of the field object.");
2397 throw RuntimeException(u"Cannot access members of the field object"_ustr, getXWeak());
2400 for (const OUString& aEntryName : rItems)
2402 if (!xMembers->hasByName(aEntryName))
2404 SAL_WARN("sc.ui", "There is no member with that name: " + aEntryName + ".");
2405 throw IllegalArgumentException("There is no member with name \"" + aEntryName + "\"", getXWeak(), 0);
2409 Reference< XDataPilotField > xRet;
2410 OUString sNewDim;
2411 ScDPObject* pDPObj = nullptr;
2412 if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
2414 const OUString& aDimName = pDim->GetName();
2416 ScDPSaveData aSaveData = *pDPObj->GetSaveData();
2417 ScDPDimensionSaveData* pDimData = aSaveData.GetDimensionData(); // created if not there
2419 // find original base
2420 OUString aBaseDimName( aDimName );
2421 const ScDPSaveGroupDimension* pBaseGroupDim = pDimData->GetNamedGroupDim( aDimName );
2422 if ( pBaseGroupDim )
2424 // any entry's SourceDimName is the original base
2425 aBaseDimName = pBaseGroupDim->GetSourceDimName();
2428 // find existing group dimension
2429 // (using the selected dim, can be intermediate group dim)
2430 ScDPSaveGroupDimension* pGroupDimension = pDimData->GetGroupDimAccForBase( aDimName );
2432 // remove the selected items from their groups
2433 // (empty groups are removed, too)
2434 if ( pGroupDimension )
2436 for (const OUString& aEntryName : rItems)
2438 if ( pBaseGroupDim )
2440 // for each selected (intermediate) group, remove all its items
2441 // (same logic as for adding, below)
2442 const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetNamedGroup( aEntryName );
2443 if ( pBaseGroup )
2444 pBaseGroup->RemoveElementsFromGroups( *pGroupDimension ); // remove all elements
2445 else
2446 pGroupDimension->RemoveFromGroups( aEntryName );
2448 else
2449 pGroupDimension->RemoveFromGroups( aEntryName );
2453 std::unique_ptr<ScDPSaveGroupDimension> pNewGroupDim;
2454 if ( !pGroupDimension )
2456 // create a new group dimension
2457 sNewDim = pDimData->CreateGroupDimName( aBaseDimName, *pDPObj, false, nullptr );
2458 pNewGroupDim.reset(new ScDPSaveGroupDimension( aBaseDimName, sNewDim ));
2460 pGroupDimension = pNewGroupDim.get(); // make changes to the new dim if none existed
2462 if ( pBaseGroupDim )
2464 // If it's a higher-order group dimension, pre-allocate groups for all
2465 // non-selected original groups, so the individual base members aren't
2466 // used for automatic groups (this would make the original groups hard
2467 // to find).
2468 //! Also do this when removing groups?
2469 //! Handle this case dynamically with automatic groups?
2471 tools::Long nGroupCount = pBaseGroupDim->GetGroupCount();
2472 for ( tools::Long nGroup = 0; nGroup < nGroupCount; nGroup++ )
2474 const ScDPSaveGroupItem& rBaseGroup = pBaseGroupDim->GetGroupByIndex( nGroup );
2476 if (comphelper::findValue(rItems, rBaseGroup.GetGroupName()) == -1) //! ignore case?
2478 // add an additional group for each item that is not in the selection
2479 ScDPSaveGroupItem aGroup( rBaseGroup.GetGroupName() );
2480 aGroup.AddElementsFromGroup( rBaseGroup );
2481 pGroupDimension->AddGroupItem( aGroup );
2486 OUString aGroupDimName = pGroupDimension->GetGroupDimName();
2488 ScDPSaveGroupItem aGroup(pGroupDimension->CreateGroupName(ScResId(STR_PIVOT_GROUP)));
2489 for (const OUString& aEntryName : rItems)
2491 if ( pBaseGroupDim )
2493 // for each selected (intermediate) group, add all its items
2494 const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetNamedGroup( aEntryName );
2495 if ( pBaseGroup )
2496 aGroup.AddElementsFromGroup( *pBaseGroup );
2497 else
2498 aGroup.AddElement( aEntryName ); // no group found -> automatic group, add the item itself
2500 else
2501 aGroup.AddElement( aEntryName ); // no group dimension, add all items directly
2504 pGroupDimension->AddGroupItem( aGroup );
2506 if ( pNewGroupDim )
2508 pDimData->AddGroupDimension( *pNewGroupDim );
2509 pNewGroupDim.reset(); // AddGroupDimension copies the object
2510 // don't access pGroupDimension after here
2512 pGroupDimension = nullptr;
2514 // set orientation
2515 ScDPSaveDimension* pSaveDimension = aSaveData.GetDimensionByName( aGroupDimName );
2516 if ( pSaveDimension->GetOrientation() == DataPilotFieldOrientation_HIDDEN )
2518 ScDPSaveDimension* pOldDimension = aSaveData.GetDimensionByName( aDimName );
2519 pSaveDimension->SetOrientation( pOldDimension->GetOrientation() );
2520 aSaveData.SetPosition( pSaveDimension, 0 ); //! before (immediate) base
2523 // apply changes
2524 pDPObj->SetSaveData( aSaveData );
2525 ScDBDocFunc(*GetDocShell()).RefreshPivotTableGroups(pDPObj);
2528 // if new grouping field has been created (on first group), return it
2529 if( !sNewDim.isEmpty() )
2531 Reference< XNameAccess > xFields(mxParent->getDataPilotFields(), UNO_QUERY);
2532 if (xFields.is())
2536 xRet.set(xFields->getByName(sNewDim), UNO_QUERY);
2537 SAL_WARN_IF(!xRet.is(), "sc.ui", "there is a name, so there should be also a field");
2539 catch (const container::NoSuchElementException&)
2541 css::uno::Any anyEx = cppu::getCaughtException();
2542 SAL_WARN("sc.ui", "Cannot find field with that name: " + sNewDim + ".");
2543 // Avoid throwing exception that's not specified in the method signature.
2544 throw css::lang::WrappedTargetRuntimeException(
2545 "Cannot find field with name \"" + sNewDim + "\"",
2546 getXWeak(), anyEx );
2550 return xRet;
2553 Reference < XDataPilotField > SAL_CALL ScDataPilotFieldObj::createDateGroup( const DataPilotFieldGroupInfo& rInfo )
2555 SolarMutexGuard aGuard;
2556 using namespace ::com::sun::star::sheet::DataPilotFieldGroupBy;
2558 if( !rInfo.HasDateValues )
2559 throw IllegalArgumentException(u"HasDateValues is not set"_ustr, getXWeak(), 0);
2560 if( !lclCheckMinMaxStep( rInfo ) )
2561 throw IllegalArgumentException(u"min/max/step"_ustr, getXWeak(), 0);
2563 // only a single date flag is allowed
2564 if( (rInfo.GroupBy == 0) || (rInfo.GroupBy > YEARS) || ((rInfo.GroupBy & (rInfo.GroupBy - 1)) != 0) )
2565 throw IllegalArgumentException("Invalid GroupBy value: " + OUString::number(rInfo.GroupBy), getXWeak(), 0);
2567 // step must be zero, if something else than DAYS is specified
2568 if( rInfo.Step >= ((rInfo.GroupBy == DAYS) ? 32768.0 : 1.0) )
2569 throw IllegalArgumentException("Invalid step value: " + OUString::number(rInfo.Step), getXWeak(), 0);
2571 OUString aGroupDimName;
2572 ScDPObject* pDPObj = nullptr;
2573 if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
2575 ScDPNumGroupInfo aInfo;
2576 aInfo.mbEnable = true;
2577 aInfo.mbDateValues = (rInfo.GroupBy == DAYS) && (rInfo.Step >= 1.0);
2578 aInfo.mbAutoStart = rInfo.HasAutoStart;
2579 aInfo.mbAutoEnd = rInfo.HasAutoEnd;
2580 aInfo.mfStart = rInfo.Start;
2581 aInfo.mfEnd = rInfo.End;
2582 aInfo.mfStep = std::trunc( rInfo.Step );
2584 // create a local copy of the entire save data (will be written back below)
2585 ScDPSaveData aSaveData = *pDPObj->GetSaveData();
2586 // get or create dimension save data
2587 ScDPDimensionSaveData& rDimData = *aSaveData.GetDimensionData();
2589 // find source dimension name
2590 const OUString& rDimName = pDim->GetName();
2591 const ScDPSaveGroupDimension* pGroupDim = rDimData.GetNamedGroupDim( rDimName );
2592 OUString aSrcDimName = pGroupDim ? pGroupDim->GetSourceDimName() : rDimName;
2594 // find a group dimension for the base field, or get numeric grouping
2595 pGroupDim = rDimData.GetFirstNamedGroupDim( aSrcDimName );
2596 const ScDPSaveNumGroupDimension* pNumGroupDim = rDimData.GetNumGroupDim( aSrcDimName );
2598 // do not group by dates, if named groups or numeric grouping is present
2599 bool bHasNamedGrouping = pGroupDim && !pGroupDim->GetDateInfo().mbEnable;
2600 bool bHasNumGrouping = pNumGroupDim && pNumGroupDim->GetInfo().mbEnable && !pNumGroupDim->GetInfo().mbDateValues && !pNumGroupDim->GetDateInfo().mbEnable;
2601 if( bHasNamedGrouping || bHasNumGrouping )
2602 throw IllegalArgumentException();
2604 if( aInfo.mbDateValues ) // create day ranges grouping
2606 // first remove all named group dimensions
2607 while( pGroupDim )
2609 OUString aGroupDimName2 = pGroupDim->GetGroupDimName();
2610 // find next group dimension before deleting this group
2611 pGroupDim = rDimData.GetNextNamedGroupDim( aGroupDimName2 );
2612 // remove from dimension save data
2613 rDimData.RemoveGroupDimension( aGroupDimName2 );
2614 // also remove save data settings for the dimension that no longer exists
2615 aSaveData.RemoveDimensionByName( aGroupDimName2 );
2617 // create or replace the number grouping dimension
2618 ScDPSaveNumGroupDimension aNumGroupDim( aSrcDimName, aInfo );
2619 rDimData.ReplaceNumGroupDimension( aNumGroupDim );
2621 else // create date grouping
2623 // collect all existing date flags
2624 sal_Int32 nDateParts = rDimData.CollectDateParts( aSrcDimName );
2625 if( nDateParts == 0 )
2627 // insert numeric group dimension, if no date groups exist yet (or replace day range grouping)
2628 ScDPSaveNumGroupDimension aNumGroupDim( aSrcDimName, aInfo, rInfo.GroupBy );
2629 rDimData.ReplaceNumGroupDimension( aNumGroupDim );
2631 else if( (nDateParts & rInfo.GroupBy) == 0 ) // do nothing if date field exists already
2633 // create new named group dimension for additional date groups
2634 aGroupDimName = rDimData.CreateDateGroupDimName( rInfo.GroupBy, *pDPObj, true, nullptr );
2635 ScDPSaveGroupDimension aGroupDim( aSrcDimName, aGroupDimName, aInfo, rInfo.GroupBy );
2636 rDimData.AddGroupDimension( aGroupDim );
2638 // set orientation of new named group dimension
2639 ScDPSaveDimension& rSaveDim = *aSaveData.GetDimensionByName( aGroupDimName );
2640 if( rSaveDim.GetOrientation() == DataPilotFieldOrientation_HIDDEN )
2642 ScDPSaveDimension& rOldDim = *aSaveData.GetDimensionByName( aSrcDimName );
2643 rSaveDim.SetOrientation( rOldDim.GetOrientation() );
2644 aSaveData.SetPosition( &rSaveDim, 0 ); //! before (immediate) base
2649 // apply changes
2650 pDPObj->SetSaveData( aSaveData );
2651 ScDBDocFunc(*GetDocShell()).RefreshPivotTableGroups(pDPObj);
2654 // return the UNO object of the new dimension, after writing back saved data
2655 Reference< XDataPilotField > xRet;
2656 if( !aGroupDimName.isEmpty() )
2659 Reference< XNameAccess > xFields( mxParent->getDataPilotFields(), UNO_QUERY_THROW );
2660 xRet.set( xFields->getByName( aGroupDimName ), UNO_QUERY );
2662 catch( Exception& )
2665 return xRet;
2668 namespace {
2670 bool lclExtractGroupMembers( ScFieldGroupMembers& rMembers, const Any& rElement )
2672 // allow empty value to create a new group
2673 if( !rElement.hasValue() )
2674 return true;
2676 // try to extract a simple sequence of strings
2677 Sequence< OUString > aSeq;
2678 if( rElement >>= aSeq )
2680 if( aSeq.hasElements() )
2681 rMembers.insert( rMembers.end(), std::cbegin(aSeq), std::cend(aSeq) );
2682 return true;
2685 // try to use XIndexAccess providing objects that support XNamed
2686 Reference< XIndexAccess > xItemsIA( rElement, UNO_QUERY );
2687 if( xItemsIA.is() )
2689 for( sal_Int32 nIdx = 0, nCount = xItemsIA->getCount(); nIdx < nCount; ++nIdx )
2691 try // getByIndex() should not throw, but we cannot be sure
2693 Reference< XNamed > xItemName( xItemsIA->getByIndex( nIdx ), UNO_QUERY_THROW );
2694 rMembers.push_back( xItemName->getName() );
2696 catch( Exception& )
2698 // ignore exceptions, go ahead with next element in the array
2701 return true;
2704 // nothing valid inside the Any -> return false
2705 return false;
2708 } // namespace
2710 ScDataPilotFieldGroupsObj::ScDataPilotFieldGroupsObj( ScFieldGroups&& rGroups ) :
2711 maGroups( std::move(rGroups) )
2715 ScDataPilotFieldGroupsObj::~ScDataPilotFieldGroupsObj()
2719 // XNameAccess
2721 Any SAL_CALL ScDataPilotFieldGroupsObj::getByName( const OUString& rName )
2723 SolarMutexGuard aGuard;
2724 if( implFindByName( rName ) == maGroups.end() )
2725 throw NoSuchElementException();
2726 return Any( Reference< XNameAccess >( new ScDataPilotFieldGroupObj( *this, rName ) ) );
2729 Sequence< OUString > SAL_CALL ScDataPilotFieldGroupsObj::getElementNames()
2731 SolarMutexGuard aGuard;
2732 Sequence< OUString > aSeq;
2733 if( !maGroups.empty() )
2735 aSeq.realloc( static_cast< sal_Int32 >( maGroups.size() ) );
2736 OUString* pName = aSeq.getArray();
2737 for( const auto& rGroup : maGroups )
2739 *pName = rGroup.maName;
2740 ++pName;
2743 return aSeq;
2746 sal_Bool SAL_CALL ScDataPilotFieldGroupsObj::hasByName( const OUString& rName )
2748 SolarMutexGuard aGuard;
2749 return implFindByName( rName ) != maGroups.end();
2752 // XNameReplace
2754 void SAL_CALL ScDataPilotFieldGroupsObj::replaceByName( const OUString& rName, const Any& rElement )
2756 SolarMutexGuard aGuard;
2758 if( rName.isEmpty() )
2759 throw IllegalArgumentException(u"Name is empty"_ustr, getXWeak(), 0);
2761 ScFieldGroups::iterator aIt = implFindByName( rName );
2762 if( aIt == maGroups.end() )
2763 throw NoSuchElementException("Name \"" + rName + "\" not found", getXWeak());
2765 // read all item names provided by the passed object
2766 ScFieldGroupMembers aMembers;
2767 if( !lclExtractGroupMembers( aMembers, rElement ) )
2768 throw IllegalArgumentException(u"Invalid element object"_ustr, getXWeak(), 0);
2770 // copy and forget, faster than vector assignment
2771 aIt->maMembers.swap( aMembers );
2774 // XNameContainer
2776 void SAL_CALL ScDataPilotFieldGroupsObj::insertByName( const OUString& rName, const Any& rElement )
2778 SolarMutexGuard aGuard;
2780 if( rName.isEmpty() )
2781 throw IllegalArgumentException(u"Name is empty"_ustr, getXWeak(), 0);
2783 ScFieldGroups::iterator aIt = implFindByName( rName );
2784 if( aIt != maGroups.end() )
2785 throw ElementExistException("Name \"" + rName + "\" already exists", getXWeak());
2787 // read all item names provided by the passed object
2788 ScFieldGroupMembers aMembers;
2789 if( !lclExtractGroupMembers( aMembers, rElement ) )
2790 throw IllegalArgumentException(u"Invalid element object"_ustr, getXWeak(), 0);
2792 // create the new entry if no error has been occurred
2793 maGroups.emplace_back();
2794 ScFieldGroup& rGroup = maGroups.back();
2795 rGroup.maName = rName;
2796 rGroup.maMembers.swap( aMembers );
2799 void SAL_CALL ScDataPilotFieldGroupsObj::removeByName( const OUString& rName )
2801 SolarMutexGuard aGuard;
2803 if( rName.isEmpty() )
2804 throw IllegalArgumentException(u"Name is empty"_ustr, getXWeak(), 0);
2806 ScFieldGroups::iterator aIt = implFindByName( rName );
2807 if( aIt == maGroups.end() )
2808 throw NoSuchElementException("Name \"" + rName + "\" not found", getXWeak());
2810 maGroups.erase( aIt );
2813 // XIndexAccess
2815 sal_Int32 SAL_CALL ScDataPilotFieldGroupsObj::getCount()
2817 SolarMutexGuard aGuard;
2818 return static_cast< sal_Int32 >( maGroups.size() );
2821 Any SAL_CALL ScDataPilotFieldGroupsObj::getByIndex( sal_Int32 nIndex )
2823 SolarMutexGuard aGuard;
2824 if ((nIndex < 0) || (o3tl::make_unsigned(nIndex) >= maGroups.size()))
2825 throw IndexOutOfBoundsException();
2826 return Any( Reference< XNameAccess >( new ScDataPilotFieldGroupObj( *this, maGroups[ nIndex ].maName ) ) );
2829 // XEnumerationAccess
2831 Reference<XEnumeration> SAL_CALL ScDataPilotFieldGroupsObj::createEnumeration()
2833 SolarMutexGuard aGuard;
2834 return new ScIndexEnumeration( this, u"com.sun.star.sheet.DataPilotFieldGroupsEnumeration"_ustr );
2837 // XElementAccess
2839 uno::Type SAL_CALL ScDataPilotFieldGroupsObj::getElementType()
2841 return cppu::UnoType<XNameAccess>::get();
2844 sal_Bool SAL_CALL ScDataPilotFieldGroupsObj::hasElements()
2846 SolarMutexGuard aGuard;
2847 return !maGroups.empty();
2850 // implementation
2852 ScFieldGroup& ScDataPilotFieldGroupsObj::getFieldGroup( const OUString& rName )
2854 SolarMutexGuard aGuard;
2855 ScFieldGroups::iterator aIt = implFindByName( rName );
2856 if( aIt == maGroups.end() )
2857 throw RuntimeException("Field Group with name \"" + rName + "\" not found", getXWeak());
2858 return *aIt;
2861 void ScDataPilotFieldGroupsObj::renameFieldGroup( const OUString& rOldName, const OUString& rNewName )
2863 SolarMutexGuard aGuard;
2864 ScFieldGroups::iterator aOldIt = implFindByName( rOldName );
2865 ScFieldGroups::iterator aNewIt = implFindByName( rNewName );
2866 if( aOldIt == maGroups.end() )
2867 throw RuntimeException("Field Group with name \"" + rOldName + "\" not found", getXWeak());
2868 // new name must not exist yet
2869 if( (aNewIt != maGroups.end()) && (aNewIt != aOldIt) )
2870 throw RuntimeException("Field Group with name \"" + rOldName + "\" already exists", getXWeak());
2871 aOldIt->maName = rNewName;
2874 ScFieldGroups::iterator ScDataPilotFieldGroupsObj::implFindByName( const OUString& rName )
2876 return std::find_if(maGroups.begin(), maGroups.end(),
2877 [&rName](const ScFieldGroup& rGroup) { return rGroup.maName == rName; });
2880 namespace {
2882 OUString lclExtractMember( const Any& rElement )
2884 if( rElement.has< OUString >() )
2885 return rElement.get< OUString >();
2887 Reference< XNamed > xNamed( rElement, UNO_QUERY );
2888 if( xNamed.is() )
2889 return xNamed->getName();
2891 return OUString();
2894 } // namespace
2896 ScDataPilotFieldGroupObj::ScDataPilotFieldGroupObj( ScDataPilotFieldGroupsObj& rParent, OUString aGroupName ) :
2897 mxParent( &rParent ),
2898 maGroupName(std::move( aGroupName ))
2902 ScDataPilotFieldGroupObj::~ScDataPilotFieldGroupObj()
2906 // XNameAccess
2908 Any SAL_CALL ScDataPilotFieldGroupObj::getByName( const OUString& rName )
2910 SolarMutexGuard aGuard;
2911 ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
2912 ScFieldGroupMembers::iterator aIt = ::std::find( rMembers.begin(), rMembers.end(), rName );
2913 if( aIt == rMembers.end() )
2914 throw NoSuchElementException("Name \"" + rName + "\" not found", getXWeak());
2915 return Any( Reference< XNamed >( new ScDataPilotFieldGroupItemObj( *this, *aIt ) ) );
2918 Sequence< OUString > SAL_CALL ScDataPilotFieldGroupObj::getElementNames()
2920 SolarMutexGuard aGuard;
2921 return ::comphelper::containerToSequence( mxParent->getFieldGroup( maGroupName ).maMembers );
2924 sal_Bool SAL_CALL ScDataPilotFieldGroupObj::hasByName( const OUString& rName )
2926 SolarMutexGuard aGuard;
2927 ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
2928 return ::std::find( rMembers.begin(), rMembers.end(), rName ) != rMembers.end();
2931 // XNameReplace
2933 void SAL_CALL ScDataPilotFieldGroupObj::replaceByName( const OUString& rName, const Any& rElement )
2935 SolarMutexGuard aGuard;
2937 // it should be possible to quickly rename an item -> accept string or XNamed
2938 OUString aNewName = lclExtractMember( rElement );
2939 if( rName.isEmpty() || aNewName.isEmpty() )
2940 throw IllegalArgumentException(u"Name is empty"_ustr, getXWeak(), 0);
2941 if( rName == aNewName )
2942 return;
2944 ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
2945 ScFieldGroupMembers::iterator aOldIt = ::std::find( rMembers.begin(), rMembers.end(), rName );
2946 ScFieldGroupMembers::iterator aNewIt = ::std::find( rMembers.begin(), rMembers.end(), aNewName );
2947 if( aOldIt == rMembers.end() )
2948 throw NoSuchElementException("Name \"" + rName + "\" not found", getXWeak());
2949 if( aNewIt != rMembers.end() )
2950 throw IllegalArgumentException("Name \"" + rName + "\" already exists", getXWeak(), 0);
2951 *aOldIt = aNewName;
2954 // XNameContainer
2956 void SAL_CALL ScDataPilotFieldGroupObj::insertByName( const OUString& rName, const Any& /*rElement*/ )
2958 SolarMutexGuard aGuard;
2960 // we will ignore the passed element and just try to insert the name
2961 if( rName.isEmpty() )
2962 throw IllegalArgumentException(u"Name is empty"_ustr, getXWeak(), 0);
2964 ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
2965 ScFieldGroupMembers::iterator aIt = ::std::find( rMembers.begin(), rMembers.end(), rName );
2966 if( aIt != rMembers.end() )
2967 throw IllegalArgumentException("Name \"" + rName + "\" already exists", getXWeak(), 0);
2968 rMembers.push_back( rName );
2971 void SAL_CALL ScDataPilotFieldGroupObj::removeByName( const OUString& rName )
2973 SolarMutexGuard aGuard;
2975 if( rName.isEmpty() )
2976 throw IllegalArgumentException(u"Name is empty"_ustr, getXWeak(), 0);
2977 ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
2978 ScFieldGroupMembers::iterator aIt = ::std::find( rMembers.begin(), rMembers.end(), rName );
2979 if( aIt == rMembers.end() )
2980 throw NoSuchElementException("Name \"" + rName + "\" not found", getXWeak());
2981 rMembers.erase( aIt );
2984 // XIndexAccess
2986 sal_Int32 SAL_CALL ScDataPilotFieldGroupObj::getCount()
2988 SolarMutexGuard aGuard;
2989 return static_cast< sal_Int32 >( mxParent->getFieldGroup( maGroupName ).maMembers.size() );
2992 Any SAL_CALL ScDataPilotFieldGroupObj::getByIndex( sal_Int32 nIndex )
2994 SolarMutexGuard aGuard;
2995 ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
2996 if ((nIndex < 0) || (o3tl::make_unsigned(nIndex) >= rMembers.size()))
2997 throw IndexOutOfBoundsException();
2998 return Any( Reference< XNamed >( new ScDataPilotFieldGroupItemObj( *this, rMembers[ nIndex ] ) ) );
3001 // XEnumerationAccess
3003 Reference< XEnumeration > SAL_CALL ScDataPilotFieldGroupObj::createEnumeration()
3005 SolarMutexGuard aGuard;
3006 return new ScIndexEnumeration( this, u"com.sun.star.sheet.DataPilotFieldGroupEnumeration"_ustr );
3009 // XElementAccess
3011 uno::Type SAL_CALL ScDataPilotFieldGroupObj::getElementType()
3013 return cppu::UnoType<XNamed>::get();
3016 sal_Bool SAL_CALL ScDataPilotFieldGroupObj::hasElements()
3018 SolarMutexGuard aGuard;
3019 return !mxParent->getFieldGroup( maGroupName ).maMembers.empty();
3022 // XNamed
3024 OUString SAL_CALL ScDataPilotFieldGroupObj::getName()
3026 SolarMutexGuard aGuard;
3027 return maGroupName;
3030 void SAL_CALL ScDataPilotFieldGroupObj::setName( const OUString& rName )
3032 SolarMutexGuard aGuard;
3033 mxParent->renameFieldGroup( maGroupName, rName );
3034 // if call to renameFieldGroup() did not throw, remember the new name
3035 maGroupName = rName;
3038 ScDataPilotFieldGroupItemObj::ScDataPilotFieldGroupItemObj( ScDataPilotFieldGroupObj& rParent, OUString aName ) :
3039 mxParent( &rParent ),
3040 maName(std::move( aName ))
3044 ScDataPilotFieldGroupItemObj::~ScDataPilotFieldGroupItemObj()
3048 // XNamed
3050 OUString SAL_CALL ScDataPilotFieldGroupItemObj::getName()
3052 SolarMutexGuard aGuard;
3053 return maName;
3056 void SAL_CALL ScDataPilotFieldGroupItemObj::setName( const OUString& rName )
3058 SolarMutexGuard aGuard;
3059 mxParent->replaceByName( maName, Any( rName ) );
3060 // if call to replaceByName() did not throw, remember the new name
3061 maName = rName;
3064 ScDataPilotItemsObj::ScDataPilotItemsObj( ScDataPilotDescriptorBase& rParent, const ScFieldIdentifier& rFieldId ) :
3065 ScDataPilotChildObjBase( rParent, rFieldId )
3069 ScDataPilotItemsObj::~ScDataPilotItemsObj()
3073 // XDataPilotItems
3075 ScDataPilotItemObj* ScDataPilotItemsObj::GetObjectByIndex_Impl( sal_Int32 nIndex ) const
3077 return ((0 <= nIndex) && (nIndex < GetMemberCount())) ?
3078 new ScDataPilotItemObj( *mxParent, maFieldId, nIndex ) : nullptr;
3081 // XNameAccess
3083 Any SAL_CALL ScDataPilotItemsObj::getByName( const OUString& aName )
3085 SolarMutexGuard aGuard;
3086 Reference<XNameAccess> xMembers = GetMembers();
3087 if (xMembers.is())
3089 Reference<XIndexAccess> xMembersIndex(new ScNameToIndexAccess( xMembers ));
3090 sal_Int32 nCount = xMembersIndex->getCount();
3091 sal_Int32 nItem = 0;
3092 while (nItem < nCount)
3094 Reference<XNamed> xMember(xMembersIndex->getByIndex(nItem), UNO_QUERY);
3095 if (xMember.is() && (aName == xMember->getName()))
3097 return Any( Reference< XPropertySet >( GetObjectByIndex_Impl( nItem ) ) );
3099 ++nItem;
3101 throw NoSuchElementException("Name \"" + aName + "\" not found", getXWeak());
3103 return Any();
3106 Sequence<OUString> SAL_CALL ScDataPilotItemsObj::getElementNames()
3108 SolarMutexGuard aGuard;
3109 Sequence< OUString > aSeq;
3110 if( ScDPObject* pDPObj = GetDPObject() )
3111 pDPObj->GetMemberNames( lcl_GetObjectIndex( pDPObj, maFieldId ), aSeq );
3112 return aSeq;
3115 sal_Bool SAL_CALL ScDataPilotItemsObj::hasByName( const OUString& aName )
3117 SolarMutexGuard aGuard;
3118 bool bFound = false;
3119 Reference<XNameAccess> xMembers = GetMembers();
3120 if (xMembers.is())
3122 Reference<XIndexAccess> xMembersIndex(new ScNameToIndexAccess( xMembers ));
3123 sal_Int32 nCount = xMembersIndex->getCount();
3124 sal_Int32 nItem = 0;
3125 while (nItem < nCount && !bFound )
3127 Reference<XNamed> xMember(xMembersIndex->getByIndex(nItem), UNO_QUERY);
3128 if (xMember.is() && aName == xMember->getName())
3129 bFound = true;
3130 else
3131 nItem++;
3134 return bFound;
3137 // XEnumerationAccess
3139 Reference<XEnumeration> SAL_CALL ScDataPilotItemsObj::createEnumeration()
3141 SolarMutexGuard aGuard;
3142 return new ScIndexEnumeration(this, u"com.sun.star.sheet.DataPilotItemsEnumeration"_ustr);
3145 // XIndexAccess
3147 sal_Int32 SAL_CALL ScDataPilotItemsObj::getCount()
3149 SolarMutexGuard aGuard;
3150 return GetMemberCount();
3153 Any SAL_CALL ScDataPilotItemsObj::getByIndex( sal_Int32 nIndex )
3155 SolarMutexGuard aGuard;
3156 Reference< XPropertySet > xItem( GetObjectByIndex_Impl( nIndex ) );
3157 if (!xItem.is())
3158 throw IndexOutOfBoundsException();
3159 return Any( xItem );
3162 uno::Type SAL_CALL ScDataPilotItemsObj::getElementType()
3164 return cppu::UnoType<XPropertySet>::get();
3167 sal_Bool SAL_CALL ScDataPilotItemsObj::hasElements()
3169 SolarMutexGuard aGuard;
3170 return ( getCount() != 0 );
3173 ScDataPilotItemObj::ScDataPilotItemObj( ScDataPilotDescriptorBase& rParent, const ScFieldIdentifier& rFieldId, sal_Int32 nIndex ) :
3174 ScDataPilotChildObjBase( rParent, rFieldId ),
3175 maPropSet( lcl_GetDataPilotItemMap() ),
3176 mnIndex( nIndex )
3180 ScDataPilotItemObj::~ScDataPilotItemObj()
3184 // XNamed
3185 OUString SAL_CALL ScDataPilotItemObj::getName()
3187 SolarMutexGuard aGuard;
3188 OUString sRet;
3189 Reference<XNameAccess> xMembers = GetMembers();
3190 if (xMembers.is())
3192 Reference<XIndexAccess> xMembersIndex(new ScNameToIndexAccess( xMembers ));
3193 sal_Int32 nCount = xMembersIndex->getCount();
3194 if (mnIndex < nCount)
3196 Reference<XNamed> xMember(xMembersIndex->getByIndex(mnIndex), UNO_QUERY);
3197 sRet = xMember->getName();
3200 return sRet;
3203 void SAL_CALL ScDataPilotItemObj::setName( const OUString& /* aName */ )
3207 // XPropertySet
3208 Reference< XPropertySetInfo >
3209 SAL_CALL ScDataPilotItemObj::getPropertySetInfo( )
3211 SolarMutexGuard aGuard;
3212 static Reference<XPropertySetInfo> aRef =
3213 new SfxItemPropertySetInfo( maPropSet.getPropertyMap() );
3214 return aRef;
3217 void SAL_CALL ScDataPilotItemObj::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
3219 SolarMutexGuard aGuard;
3220 ScDPObject* pDPObj = nullptr;
3221 ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
3222 if(!pDim)
3223 return;
3225 Reference<XNameAccess> xMembers = GetMembers();
3226 if( !xMembers.is() )
3227 return;
3229 Reference<XIndexAccess> xMembersIndex( new ScNameToIndexAccess( xMembers ) );
3230 sal_Int32 nCount = xMembersIndex->getCount();
3231 if( mnIndex >= nCount )
3232 return;
3234 Reference<XNamed> xMember(xMembersIndex->getByIndex(mnIndex), UNO_QUERY);
3235 OUString sName(xMember->getName());
3236 ScDPSaveMember* pMember = pDim->GetMemberByName(sName);
3237 if (!pMember)
3238 return;
3240 bool bGetNewIndex = false;
3241 if ( aPropertyName == SC_UNONAME_SHOWDETAIL )
3242 pMember->SetShowDetails(cppu::any2bool(aValue));
3243 else if ( aPropertyName == SC_UNONAME_ISHIDDEN )
3244 pMember->SetIsVisible(!cppu::any2bool(aValue));
3245 else if ( aPropertyName == SC_UNONAME_POS )
3247 sal_Int32 nNewPos = 0;
3248 if ( !( aValue >>= nNewPos ) || nNewPos < 0 || nNewPos >= nCount )
3249 throw IllegalArgumentException();
3251 pDim->SetMemberPosition( sName, nNewPos );
3252 // get new effective index (depends on sorting mode, which isn't modified)
3253 bGetNewIndex = true;
3256 SetDPObject( pDPObj );
3258 if ( bGetNewIndex ) // after SetDPObject, get the new index
3260 Sequence< OUString > aItemNames = xMembers->getElementNames();
3261 sal_Int32 nItemCount = aItemNames.getLength();
3262 for (sal_Int32 nItem=0; nItem<nItemCount; ++nItem)
3263 if (aItemNames[nItem] == sName)
3264 mnIndex = nItem;
3268 Any SAL_CALL ScDataPilotItemObj::getPropertyValue( const OUString& aPropertyName )
3270 SolarMutexGuard aGuard;
3271 Any aRet;
3272 if( ScDPSaveDimension* pDim = GetDPDimension() )
3274 Reference< XNameAccess > xMembers = GetMembers();
3275 if( xMembers.is() )
3277 Reference< XIndexAccess > xMembersIndex( new ScNameToIndexAccess( xMembers ) );
3278 sal_Int32 nCount = xMembersIndex->getCount();
3279 if( mnIndex < nCount )
3281 Reference< XNamed > xMember( xMembersIndex->getByIndex( mnIndex ), UNO_QUERY );
3282 OUString sName( xMember->getName() );
3283 ScDPSaveMember* pMember = pDim->GetExistingMemberByName( sName );
3284 if ( aPropertyName == SC_UNONAME_SHOWDETAIL )
3286 if (pMember && pMember->HasShowDetails())
3288 aRet <<= pMember->GetShowDetails();
3290 else
3292 Reference< XPropertySet > xMemberProps( xMember, UNO_QUERY );
3293 if( xMemberProps.is() )
3294 aRet = xMemberProps->getPropertyValue( SC_UNO_DP_SHOWDETAILS );
3295 else
3296 aRet <<= true;
3299 else if ( aPropertyName == SC_UNONAME_ISHIDDEN )
3301 if (pMember && pMember->HasIsVisible())
3303 aRet <<= !pMember->GetIsVisible();
3305 else
3307 Reference< XPropertySet > xMemberProps( xMember, UNO_QUERY );
3308 if( xMemberProps.is() )
3309 aRet <<= !cppu::any2bool( xMemberProps->getPropertyValue( SC_UNO_DP_ISVISIBLE ) );
3310 else
3311 aRet <<= false;
3314 else if ( aPropertyName == SC_UNONAME_POS )
3316 aRet <<= mnIndex;
3321 return aRet;
3324 void SAL_CALL ScDataPilotItemObj::addPropertyChangeListener(
3325 const OUString& /* aPropertyName */, const Reference< XPropertyChangeListener >& /* xListener */ )
3329 void SAL_CALL ScDataPilotItemObj::removePropertyChangeListener(
3330 const OUString& /* aPropertyName */, const Reference< XPropertyChangeListener >& /* aListener */ )
3334 void SAL_CALL ScDataPilotItemObj::addVetoableChangeListener(
3335 const OUString& /* PropertyName */, const Reference< XVetoableChangeListener >& /* aListener */ )
3339 void SAL_CALL ScDataPilotItemObj::removeVetoableChangeListener(
3340 const OUString& /* PropertyName */, const Reference< XVetoableChangeListener >& /* aListener */ )
3344 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */