1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
22 #include <dpdimsave.hxx>
23 #include <miscuno.hxx>
24 #include <unonames.hxx>
26 #include <generalfunction.hxx>
27 #include <dptabdat.hxx>
28 #include <pivot/PivotTableFormats.hxx>
30 #include <sal/types.h>
31 #include <sal/log.hxx>
32 #include <osl/diagnose.h>
33 #include <comphelper/stl_types.hxx>
34 #include <unotools/charclass.hxx>
36 #include <com/sun/star/sheet/XDimensionsSupplier.hpp>
37 #include <com/sun/star/sheet/DataPilotFieldAutoShowInfo.hpp>
38 #include <com/sun/star/sheet/DataPilotFieldLayoutInfo.hpp>
39 #include <com/sun/star/sheet/DataPilotFieldReference.hpp>
40 #include <com/sun/star/sheet/DataPilotFieldSortInfo.hpp>
41 #include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
42 #include <com/sun/star/sheet/XHierarchiesSupplier.hpp>
43 #include <com/sun/star/sheet/XLevelsSupplier.hpp>
44 #include <com/sun/star/sheet/XMembersSupplier.hpp>
45 #include <com/sun/star/container/XNamed.hpp>
46 #include <com/sun/star/util/XCloneable.hpp>
47 #include <comphelper/diagnose_ex.hxx>
49 #include <unordered_map>
53 using namespace com::sun::star
;
54 using namespace com::sun::star::sheet
;
55 using ::std::unique_ptr
;
57 #define SC_DPSAVEMODE_DONTKNOW 2
59 static void lcl_SetBoolProperty( const uno::Reference
<beans::XPropertySet
>& xProp
,
60 const OUString
& rName
, bool bValue
)
62 //TODO: move to ScUnoHelpFunctions?
64 xProp
->setPropertyValue( rName
, uno::Any( bValue
) );
67 ScDPSaveMember::ScDPSaveMember(OUString _aName
) :
68 aName(std::move( _aName
)),
69 nVisibleMode( SC_DPSAVEMODE_DONTKNOW
),
70 nShowDetailsMode( SC_DPSAVEMODE_DONTKNOW
)
74 ScDPSaveMember::ScDPSaveMember(const ScDPSaveMember
& r
) :
76 mpLayoutName( r
.mpLayoutName
),
77 nVisibleMode( r
.nVisibleMode
),
78 nShowDetailsMode( r
.nShowDetailsMode
)
82 ScDPSaveMember::~ScDPSaveMember()
86 bool ScDPSaveMember::operator== ( const ScDPSaveMember
& r
) const
88 return aName
== r
.aName
&&
89 nVisibleMode
== r
.nVisibleMode
&&
90 nShowDetailsMode
== r
.nShowDetailsMode
;
93 bool ScDPSaveMember::HasIsVisible() const
95 return nVisibleMode
!= SC_DPSAVEMODE_DONTKNOW
;
98 void ScDPSaveMember::SetIsVisible(bool bSet
)
100 nVisibleMode
= sal_uInt16(bSet
);
103 bool ScDPSaveMember::HasShowDetails() const
105 return nShowDetailsMode
!= SC_DPSAVEMODE_DONTKNOW
;
108 void ScDPSaveMember::SetShowDetails(bool bSet
)
110 nShowDetailsMode
= sal_uInt16(bSet
);
113 void ScDPSaveMember::SetName( const OUString
& rNew
)
115 // Used only if the source member was renamed (groups).
116 // For UI renaming of members, a layout name must be used.
121 void ScDPSaveMember::SetLayoutName( const OUString
& rName
)
123 mpLayoutName
= rName
;
126 const std::optional
<OUString
> & ScDPSaveMember::GetLayoutName() const
131 void ScDPSaveMember::RemoveLayoutName()
133 mpLayoutName
.reset();
136 void ScDPSaveMember::WriteToSource( const uno::Reference
<uno::XInterface
>& xMember
, sal_Int32 nPosition
)
138 uno::Reference
<beans::XPropertySet
> xMembProp( xMember
, uno::UNO_QUERY
);
139 OSL_ENSURE( xMembProp
.is(), "no properties at member" );
140 if ( !xMembProp
.is() )
143 // exceptions are caught at ScDPSaveData::WriteToSource
145 if ( nVisibleMode
!= SC_DPSAVEMODE_DONTKNOW
)
146 lcl_SetBoolProperty( xMembProp
,
147 SC_UNO_DP_ISVISIBLE
, static_cast<bool>(nVisibleMode
) );
149 if ( nShowDetailsMode
!= SC_DPSAVEMODE_DONTKNOW
)
150 lcl_SetBoolProperty( xMembProp
,
151 SC_UNO_DP_SHOWDETAILS
, static_cast<bool>(nShowDetailsMode
) );
154 ScUnoHelpFunctions::SetOptionalPropertyValue(xMembProp
, SC_UNO_DP_LAYOUTNAME
, *mpLayoutName
);
156 if ( nPosition
>= 0 )
157 ScUnoHelpFunctions::SetOptionalPropertyValue(xMembProp
, SC_UNO_DP_POSITION
, nPosition
);
162 void ScDPSaveMember::Dump(int nIndent
) const
164 std::string
aIndent(nIndent
*4, ' ');
165 cout
<< aIndent
<< "* member name: '" << aName
<< "'" << endl
;
167 cout
<< aIndent
<< " + layout name: ";
169 cout
<< "'" << *mpLayoutName
<< "'";
174 cout
<< aIndent
<< " + visibility: ";
175 if (nVisibleMode
== SC_DPSAVEMODE_DONTKNOW
)
178 cout
<< (nVisibleMode
? "visible" : "hidden");
184 ScDPSaveDimension::ScDPSaveDimension(OUString _aName
, bool bDataLayout
) :
185 aName(std::move( _aName
)),
186 bIsDataLayout( bDataLayout
),
188 nOrientation( sheet::DataPilotFieldOrientation_HIDDEN
),
189 nFunction( ScGeneralFunction::AUTO
),
190 nUsedHierarchy( -1 ),
191 nShowEmptyMode( SC_DPSAVEMODE_DONTKNOW
),
192 bRepeatItemLabels( false ),
193 bSubTotalDefault( true )
197 ScDPSaveDimension::ScDPSaveDimension(const ScDPSaveDimension
& r
) :
199 mpLayoutName( r
.mpLayoutName
),
200 mpSubtotalName( r
.mpSubtotalName
),
201 bIsDataLayout( r
.bIsDataLayout
),
202 bDupFlag( r
.bDupFlag
),
203 nOrientation( r
.nOrientation
),
204 nFunction( r
.nFunction
),
205 nUsedHierarchy( r
.nUsedHierarchy
),
206 nShowEmptyMode( r
.nShowEmptyMode
),
207 bRepeatItemLabels( r
.bRepeatItemLabels
),
208 bSubTotalDefault( r
.bSubTotalDefault
),
209 maSubTotalFuncs( r
.maSubTotalFuncs
)
211 for (const ScDPSaveMember
* pMem
: r
.maMemberList
)
213 const OUString
& rName
= pMem
->GetName();
214 std::unique_ptr
<ScDPSaveMember
> pNew(new ScDPSaveMember( *pMem
));
215 maMemberList
.push_back( pNew
.get() );
216 maMemberHash
[rName
] = std::move(pNew
);
218 if (r
.pReferenceValue
)
219 pReferenceValue
.reset( new sheet::DataPilotFieldReference( *(r
.pReferenceValue
) ) );
221 pSortInfo
.reset( new sheet::DataPilotFieldSortInfo( *(r
.pSortInfo
) ) );
223 pAutoShowInfo
.reset( new sheet::DataPilotFieldAutoShowInfo( *(r
.pAutoShowInfo
) ) );
225 pLayoutInfo
.reset(new sheet::DataPilotFieldLayoutInfo( *(r
.pLayoutInfo
) ));
228 ScDPSaveDimension::~ScDPSaveDimension()
230 maMemberHash
.clear();
231 pReferenceValue
.reset();
233 pAutoShowInfo
.reset();
237 bool ScDPSaveDimension::operator== ( const ScDPSaveDimension
& r
) const
239 if ( aName
!= r
.aName
||
240 bIsDataLayout
!= r
.bIsDataLayout
||
241 bDupFlag
!= r
.bDupFlag
||
242 nOrientation
!= r
.nOrientation
||
243 nFunction
!= r
.nFunction
||
244 nUsedHierarchy
!= r
.nUsedHierarchy
||
245 nShowEmptyMode
!= r
.nShowEmptyMode
||
246 bRepeatItemLabels
!= r
.bRepeatItemLabels
||
247 bSubTotalDefault
!= r
.bSubTotalDefault
||
248 maSubTotalFuncs
!= r
.maSubTotalFuncs
)
251 if (maMemberHash
.size() != r
.maMemberHash
.size() )
254 if (!std::equal(maMemberList
.begin(), maMemberList
.end(), r
.maMemberList
.begin(), r
.maMemberList
.end(),
255 [](const ScDPSaveMember
* a
, const ScDPSaveMember
* b
) { return *a
== *b
; }))
258 if( pReferenceValue
&& r
.pReferenceValue
)
260 if ( *pReferenceValue
!= *r
.pReferenceValue
)
265 else if ( pReferenceValue
|| r
.pReferenceValue
)
269 if( this->pSortInfo
&& r
.pSortInfo
)
271 if ( *this->pSortInfo
!= *r
.pSortInfo
)
276 else if ( this->pSortInfo
|| r
.pSortInfo
)
280 if( this->pAutoShowInfo
&& r
.pAutoShowInfo
)
282 if ( *this->pAutoShowInfo
!= *r
.pAutoShowInfo
)
287 else if ( this->pAutoShowInfo
|| r
.pAutoShowInfo
)
295 void ScDPSaveDimension::AddMember(std::unique_ptr
<ScDPSaveMember
> pMember
)
297 const OUString
& rName
= pMember
->GetName();
298 auto aExisting
= maMemberHash
.find( rName
);
299 auto tmp
= pMember
.get();
300 if ( aExisting
== maMemberHash
.end() )
302 maMemberHash
[rName
] = std::move(pMember
);
306 std::erase(maMemberList
, aExisting
->second
.get());
307 aExisting
->second
= std::move(pMember
);
309 maMemberList
.push_back( tmp
);
312 void ScDPSaveDimension::SetName( const OUString
& rNew
)
314 // Used only if the source dim was renamed (groups).
315 // For UI renaming of dimensions, the layout name must be used.
320 void ScDPSaveDimension::SetOrientation(css::sheet::DataPilotFieldOrientation nNew
)
325 void ScDPSaveDimension::SetSubTotals(std::vector
<ScGeneralFunction
> && rFuncs
)
327 maSubTotalFuncs
= std::move(rFuncs
);
328 bSubTotalDefault
= false;
331 bool ScDPSaveDimension::HasShowEmpty() const
333 return nShowEmptyMode
!= SC_DPSAVEMODE_DONTKNOW
;
336 void ScDPSaveDimension::SetShowEmpty(bool bSet
)
338 nShowEmptyMode
= sal_uInt16(bSet
);
341 void ScDPSaveDimension::SetRepeatItemLabels(bool bSet
)
343 bRepeatItemLabels
= bSet
;
346 void ScDPSaveDimension::SetFunction(ScGeneralFunction nNew
)
351 void ScDPSaveDimension::SetUsedHierarchy(tools::Long nNew
)
353 nUsedHierarchy
= nNew
;
356 void ScDPSaveDimension::SetSubtotalName(const OUString
& rName
)
358 mpSubtotalName
= rName
;
361 const std::optional
<OUString
> & ScDPSaveDimension::GetSubtotalName() const
363 return mpSubtotalName
;
366 void ScDPSaveDimension::RemoveSubtotalName()
368 mpSubtotalName
.reset();
371 bool ScDPSaveDimension::IsMemberNameInUse(const OUString
& rName
) const
373 return std::any_of(maMemberList
.begin(), maMemberList
.end(), [&rName
](const ScDPSaveMember
* pMem
) {
374 if (rName
.equalsIgnoreAsciiCase(pMem
->GetName()))
377 const std::optional
<OUString
> & pLayoutName
= pMem
->GetLayoutName();
378 return pLayoutName
&& rName
.equalsIgnoreAsciiCase(*pLayoutName
);
382 void ScDPSaveDimension::SetLayoutName(const OUString
& rName
)
384 mpLayoutName
= rName
;
387 const std::optional
<OUString
> & ScDPSaveDimension::GetLayoutName() const
392 void ScDPSaveDimension::RemoveLayoutName()
394 mpLayoutName
.reset();
397 void ScDPSaveDimension::SetReferenceValue(const sheet::DataPilotFieldReference
* pNew
)
400 pReferenceValue
.reset( new sheet::DataPilotFieldReference(*pNew
) );
402 pReferenceValue
.reset();
405 void ScDPSaveDimension::SetSortInfo(const sheet::DataPilotFieldSortInfo
* pNew
)
408 pSortInfo
.reset( new sheet::DataPilotFieldSortInfo(*pNew
) );
413 void ScDPSaveDimension::SetAutoShowInfo(const sheet::DataPilotFieldAutoShowInfo
* pNew
)
416 pAutoShowInfo
.reset( new sheet::DataPilotFieldAutoShowInfo(*pNew
) );
418 pAutoShowInfo
.reset();
421 void ScDPSaveDimension::SetLayoutInfo(const sheet::DataPilotFieldLayoutInfo
* pNew
)
424 pLayoutInfo
.reset( new sheet::DataPilotFieldLayoutInfo(*pNew
) );
429 void ScDPSaveDimension::SetCurrentPage( const OUString
* pPage
)
431 // We use member's visibility attribute to filter by page dimension.
433 // pPage == nullptr -> all members visible.
434 for (ScDPSaveMember
* pMem
: maMemberList
)
436 bool bVisible
= !pPage
|| pMem
->GetName() == *pPage
;
437 pMem
->SetIsVisible(bVisible
);
441 OUString
ScDPSaveDimension::GetCurrentPage() const
443 MemberList::const_iterator it
= std::find_if(maMemberList
.begin(), maMemberList
.end(),
444 [](const ScDPSaveMember
* pMem
) { return pMem
->GetIsVisible(); });
445 if (it
!= maMemberList
.end())
446 return (*it
)->GetName();
451 ScDPSaveMember
* ScDPSaveDimension::GetExistingMemberByName(const OUString
& rName
)
453 auto res
= maMemberHash
.find (rName
);
454 if (res
!= maMemberHash
.end())
455 return res
->second
.get();
459 ScDPSaveMember
* ScDPSaveDimension::GetMemberByName(const OUString
& rName
)
461 ScDPSaveMember
* pResult
= GetExistingMemberByName(rName
);
465 pResult
= new ScDPSaveMember(rName
);
466 maMemberHash
[rName
] = std::unique_ptr
<ScDPSaveMember
>(pResult
);
467 maMemberList
.push_back(pResult
);
471 void ScDPSaveDimension::SetMemberPosition( const OUString
& rName
, sal_Int32 nNewPos
)
473 ScDPSaveMember
* pMember
= GetMemberByName( rName
); // make sure it exists and is in the hash
475 std::erase(maMemberList
, pMember
);
477 maMemberList
.insert( maMemberList
.begin() + nNewPos
, pMember
);
480 void ScDPSaveDimension::WriteToSource( const uno::Reference
<uno::XInterface
>& xDim
)
482 uno::Reference
<beans::XPropertySet
> xDimProp( xDim
, uno::UNO_QUERY
);
483 OSL_ENSURE( xDimProp
.is(), "no properties at dimension" );
486 // exceptions are caught at ScDPSaveData::WriteToSource
488 sheet::DataPilotFieldOrientation eOrient
= nOrientation
;
489 xDimProp
->setPropertyValue( SC_UNO_DP_ORIENTATION
, uno::Any(eOrient
) );
491 sal_Int16 eFunc
= static_cast<sal_Int16
>(nFunction
);
492 xDimProp
->setPropertyValue( SC_UNO_DP_FUNCTION2
, uno::Any(eFunc
) );
494 if ( nUsedHierarchy
>= 0 )
496 xDimProp
->setPropertyValue( SC_UNO_DP_USEDHIERARCHY
, uno::Any(static_cast<sal_Int32
>(nUsedHierarchy
)) );
499 if ( pReferenceValue
)
502 xDimProp
->setPropertyValue( SC_UNO_DP_REFVALUE
, uno::Any(*pReferenceValue
) );
506 ScUnoHelpFunctions::SetOptionalPropertyValue(xDimProp
, SC_UNO_DP_LAYOUTNAME
, *mpLayoutName
);
508 const std::optional
<OUString
> & pSubTotalName
= GetSubtotalName();
510 // Custom subtotal name, with '?' being replaced by the visible field name later.
511 ScUnoHelpFunctions::SetOptionalPropertyValue(xDimProp
, SC_UNO_DP_FIELD_SUBTOTALNAME
, *pSubTotalName
);
514 // Level loop outside of maMemberList loop
515 // because SubTotals have to be set independently of known members
517 tools::Long nCount
= maMemberHash
.size();
519 tools::Long nHierCount
= 0;
520 uno::Reference
<container::XIndexAccess
> xHiers
;
521 uno::Reference
<sheet::XHierarchiesSupplier
> xHierSupp( xDim
, uno::UNO_QUERY
);
522 if ( xHierSupp
.is() )
524 xHiers
= new ScNameToIndexAccess(xHierSupp
->getHierarchies());
525 nHierCount
= xHiers
->getCount();
528 bool bHasHiddenMember
= false;
530 for (tools::Long nHier
=0; nHier
<nHierCount
; nHier
++)
532 tools::Long nLevCount
= 0;
533 uno::Reference
<container::XIndexAccess
> xLevels
;
534 uno::Reference
<sheet::XLevelsSupplier
> xLevSupp(xHiers
->getByIndex(nHier
), uno::UNO_QUERY
);
537 xLevels
= new ScNameToIndexAccess(xLevSupp
->getLevels());
538 nLevCount
= xLevels
->getCount();
541 for (tools::Long nLev
=0; nLev
<nLevCount
; nLev
++)
543 uno::Reference
<uno::XInterface
> xLevel(xLevels
->getByIndex(nLev
), uno::UNO_QUERY
);
544 uno::Reference
<beans::XPropertySet
> xLevProp( xLevel
, uno::UNO_QUERY
);
545 OSL_ENSURE( xLevProp
.is(), "no properties at level" );
548 if ( !bSubTotalDefault
)
550 uno::Sequence
<sal_Int16
> aSeq(maSubTotalFuncs
.size());
551 for(size_t i
= 0; i
< maSubTotalFuncs
.size(); ++i
)
552 aSeq
.getArray()[i
] = static_cast<sal_Int16
>(maSubTotalFuncs
[i
]);
553 xLevProp
->setPropertyValue( SC_UNO_DP_SUBTOTAL2
, uno::Any(aSeq
) );
555 if ( nShowEmptyMode
!= SC_DPSAVEMODE_DONTKNOW
)
556 lcl_SetBoolProperty( xLevProp
,
557 SC_UNO_DP_SHOWEMPTY
, static_cast<bool>(nShowEmptyMode
) );
559 lcl_SetBoolProperty( xLevProp
,
560 SC_UNO_DP_REPEATITEMLABELS
, bRepeatItemLabels
);
563 ScUnoHelpFunctions::SetOptionalPropertyValue(xLevProp
, SC_UNO_DP_SORTING
, *pSortInfo
);
566 ScUnoHelpFunctions::SetOptionalPropertyValue(xLevProp
, SC_UNO_DP_AUTOSHOW
, *pAutoShowInfo
);
569 ScUnoHelpFunctions::SetOptionalPropertyValue(xLevProp
, SC_UNO_DP_LAYOUT
, *pLayoutInfo
);
571 // exceptions are caught at ScDPSaveData::WriteToSource
576 uno::Reference
<sheet::XMembersSupplier
> xMembSupp( xLevel
, uno::UNO_QUERY
);
577 if ( xMembSupp
.is() )
579 uno::Reference
<sheet::XMembersAccess
> xMembers
= xMembSupp
->getMembers();
582 sal_Int32 nPosition
= -1; // set position only in manual mode
583 if ( !pSortInfo
|| pSortInfo
->Mode
== sheet::DataPilotFieldSortMode::MANUAL
)
586 for (ScDPSaveMember
* pMember
: maMemberList
)
588 if (!pMember
->GetIsVisible())
589 bHasHiddenMember
= true;
590 OUString aMemberName
= pMember
->GetName();
591 if ( xMembers
->hasByName( aMemberName
) )
593 uno::Reference
<uno::XInterface
> xMemberInt(
594 xMembers
->getByName(aMemberName
), uno::UNO_QUERY
);
595 pMember
->WriteToSource( xMemberInt
, nPosition
);
597 if ( nPosition
>= 0 )
598 ++nPosition
; // increase if initialized
600 // missing member is no error
609 ScUnoHelpFunctions::SetOptionalPropertyValue(xDimProp
, SC_UNO_DP_HAS_HIDDEN_MEMBER
, bHasHiddenMember
);
612 void ScDPSaveDimension::UpdateMemberVisibility(const std::unordered_map
<OUString
, bool>& rData
)
614 for (ScDPSaveMember
* pMem
: maMemberList
)
616 const OUString
& rMemName
= pMem
->GetName();
617 auto itr
= rData
.find(rMemName
);
618 if (itr
!= rData
.end())
619 pMem
->SetIsVisible(itr
->second
);
623 bool ScDPSaveDimension::HasInvisibleMember() const
625 return std::any_of(maMemberList
.begin(), maMemberList
.end(),
626 [](const ScDPSaveMember
* pMem
) { return !pMem
->GetIsVisible(); });
629 void ScDPSaveDimension::RemoveObsoleteMembers(const MemberSetType
& rMembers
)
632 for (ScDPSaveMember
* pMem
: maMemberList
)
634 if (rMembers
.count(pMem
->GetName()))
636 // This member still exists.
637 aNew
.push_back(pMem
);
641 maMemberHash
.erase(pMem
->GetName());
645 maMemberList
.swap(aNew
);
650 void ScDPSaveDimension::Dump(int nIndent
) const
652 static const char* pOrientNames
[] = { "hidden", "column", "row", "page", "data" };
653 std::string
aIndent(nIndent
*4, ' ');
655 cout
<< aIndent
<< "* dimension name: '" << aName
<< "'" << endl
;
657 cout
<< aIndent
<< " + orientation: ";
658 if (nOrientation
<= DataPilotFieldOrientation_DATA
)
659 cout
<< pOrientNames
[static_cast<int>(nOrientation
)];
664 cout
<< aIndent
<< " + layout name: ";
666 cout
<< "'" << *mpLayoutName
<< "'";
671 cout
<< aIndent
<< " + subtotal name: ";
673 cout
<< "'" << *mpSubtotalName
<< "'";
678 cout
<< aIndent
<< " + is data layout: " << (bIsDataLayout
? "yes" : "no") << endl
;
679 cout
<< aIndent
<< " + is duplicate: " << (bDupFlag
? "yes" : "no") << endl
;
681 for (ScDPSaveMember
* pMem
: maMemberList
)
683 pMem
->Dump(nIndent
+1);
686 cout
<< endl
; // blank line
691 ScDPSaveData::ScDPSaveData()
692 : mnColumnGrandMode(SC_DPSAVEMODE_DONTKNOW
)
693 , mnRowGrandMode(SC_DPSAVEMODE_DONTKNOW
)
694 , mnIgnoreEmptyMode(SC_DPSAVEMODE_DONTKNOW
)
695 , mnRepeatEmptyMode(SC_DPSAVEMODE_DONTKNOW
)
696 , mbFilterButton(true)
698 , mbExpandCollapse(false)
699 , mbDimensionMembersBuilt(false)
703 ScDPSaveData::ScDPSaveData(const ScDPSaveData
& rOther
)
704 : mnColumnGrandMode(rOther
.mnColumnGrandMode
)
705 , mnRowGrandMode(rOther
.mnRowGrandMode
)
706 , mnIgnoreEmptyMode(rOther
.mnIgnoreEmptyMode
)
707 , mnRepeatEmptyMode(rOther
.mnRepeatEmptyMode
)
708 , mbFilterButton(rOther
.mbFilterButton
)
709 , mbDrillDown(rOther
.mbDrillDown
)
710 , mbExpandCollapse(rOther
.mbExpandCollapse
)
711 , mbDimensionMembersBuilt(rOther
.mbDimensionMembersBuilt
)
712 , mpGrandTotalName(rOther
.mpGrandTotalName
)
714 if (rOther
.mpDimensionData
)
715 mpDimensionData
.reset(new ScDPDimensionSaveData(*rOther
.mpDimensionData
));
716 if (rOther
.mpFormats
)
717 mpFormats
.reset(new sc::PivotTableFormats(*rOther
.mpFormats
));
719 for (auto const& rOtherSaveDimension
: rOther
.m_DimList
)
721 m_DimList
.push_back(std::make_unique
<ScDPSaveDimension
>(*rOtherSaveDimension
));
725 ScDPSaveData
& ScDPSaveData::operator=(const ScDPSaveData
& rOther
)
729 this->~ScDPSaveData();
730 new(this)ScDPSaveData(rOther
);
735 bool ScDPSaveData::operator== (const ScDPSaveData
& rOther
) const
737 if (mnColumnGrandMode
!= rOther
.mnColumnGrandMode
||
738 mnRowGrandMode
!= rOther
.mnRowGrandMode
||
739 mnIgnoreEmptyMode
!= rOther
.mnIgnoreEmptyMode
||
740 mnRepeatEmptyMode
!= rOther
.mnRepeatEmptyMode
||
741 mbFilterButton
!= rOther
.mbFilterButton
||
742 mbDrillDown
!= rOther
.mbDrillDown
||
743 mbDimensionMembersBuilt
!= rOther
.mbDimensionMembersBuilt
)
746 if (mpDimensionData
|| rOther
.mpDimensionData
)
747 if (!mpDimensionData
|| !rOther
.mpDimensionData
|| !(*mpDimensionData
== *rOther
.mpDimensionData
))
750 if (!(::comphelper::ContainerUniquePtrEquals(m_DimList
, rOther
.m_DimList
)))
753 if (mpGrandTotalName
)
755 if (!rOther
.mpGrandTotalName
)
757 if (*mpGrandTotalName
!= *rOther
.mpGrandTotalName
)
760 else if (rOther
.mpGrandTotalName
)
766 ScDPSaveData::~ScDPSaveData()
770 void ScDPSaveData::setFormats(sc::PivotTableFormats
const& rPivotTableFormats
)
772 mpFormats
.reset(new sc::PivotTableFormats(rPivotTableFormats
));
775 bool ScDPSaveData::hasFormats()
777 return bool(mpFormats
);
780 sc::PivotTableFormats
const& ScDPSaveData::getFormats()
785 void ScDPSaveData::SetGrandTotalName(const OUString
& rName
)
787 mpGrandTotalName
= rName
;
790 const std::optional
<OUString
> & ScDPSaveData::GetGrandTotalName() const
792 return mpGrandTotalName
;
797 class DimOrderInserter
799 ScDPSaveData::DimOrderType
& mrNames
;
801 explicit DimOrderInserter(ScDPSaveData::DimOrderType
& rNames
) : mrNames(rNames
) {}
803 void operator() (const ScDPSaveDimension
* pDim
)
805 size_t nRank
= mrNames
.size();
806 mrNames
.emplace(ScGlobal::getCharClass().uppercase(pDim
->GetName()), nRank
);
812 const ScDPSaveData::DimOrderType
& ScDPSaveData::GetDimensionSortOrder() const
816 mpDimOrder
.reset(new DimOrderType
);
817 std::vector
<const ScDPSaveDimension
*> aRowDims
, aColDims
;
818 GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_ROW
, aRowDims
);
819 GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_COLUMN
, aColDims
);
821 std::for_each(aRowDims
.begin(), aRowDims
.end(), DimOrderInserter(*mpDimOrder
));
822 std::for_each(aColDims
.begin(), aColDims
.end(), DimOrderInserter(*mpDimOrder
));
827 void ScDPSaveData::GetAllDimensionsByOrientation(
828 sheet::DataPilotFieldOrientation eOrientation
, std::vector
<const ScDPSaveDimension
*>& rDims
) const
830 std::vector
<const ScDPSaveDimension
*> aDims
;
831 for (auto const& it
: m_DimList
)
833 const ScDPSaveDimension
& rDim
= *it
;
834 if (rDim
.GetOrientation() != eOrientation
)
837 aDims
.push_back(&rDim
);
843 void ScDPSaveData::AddDimension(ScDPSaveDimension
* pDim
)
848 CheckDuplicateName(*pDim
);
849 m_DimList
.push_back(std::unique_ptr
<ScDPSaveDimension
>(pDim
));
854 ScDPSaveDimension
* ScDPSaveData::GetDimensionByName(const OUString
& rName
)
856 for (auto const& iter
: m_DimList
)
858 if (iter
->GetName() == rName
&& !iter
->IsDataLayout() )
862 return AppendNewDimension(rName
, false);
865 ScDPSaveDimension
* ScDPSaveData::GetExistingDimensionByName(std::u16string_view rName
) const
867 for (auto const& iter
: m_DimList
)
869 if (iter
->GetName() == rName
&& !iter
->IsDataLayout() )
872 return nullptr; // don't create new
875 ScDPSaveDimension
* ScDPSaveData::GetNewDimensionByName(const OUString
& rName
)
877 for (auto const& iter
: m_DimList
)
879 if (iter
->GetName() == rName
&& !iter
->IsDataLayout() )
880 return DuplicateDimension(rName
);
883 return AppendNewDimension(rName
, false);
886 ScDPSaveDimension
* ScDPSaveData::GetDataLayoutDimension()
888 ScDPSaveDimension
* pDim
= GetExistingDataLayoutDimension();
892 return AppendNewDimension(OUString(), true);
895 ScDPSaveDimension
* ScDPSaveData::GetExistingDataLayoutDimension() const
897 for (auto const& iter
: m_DimList
)
899 if ( iter
->IsDataLayout() )
905 ScDPSaveDimension
* ScDPSaveData::DuplicateDimension(std::u16string_view rName
)
909 ScDPSaveDimension
* pOld
= GetExistingDimensionByName(rName
);
913 ScDPSaveDimension
* pNew
= new ScDPSaveDimension( *pOld
);
918 void ScDPSaveData::RemoveDimensionByName(const OUString
& rName
)
920 auto iter
= std::find_if(m_DimList
.begin(), m_DimList
.end(),
921 [&rName
](const std::unique_ptr
<ScDPSaveDimension
>& rxDim
) {
922 return rxDim
->GetName() == rName
&& !rxDim
->IsDataLayout(); });
923 if (iter
!= m_DimList
.end())
925 m_DimList
.erase(iter
);
926 RemoveDuplicateNameCount(rName
);
931 ScDPSaveDimension
& ScDPSaveData::DuplicateDimension( const ScDPSaveDimension
& rDim
)
933 ScDPSaveDimension
* pNew
= new ScDPSaveDimension( rDim
);
938 ScDPSaveDimension
* ScDPSaveData::GetInnermostDimension(DataPilotFieldOrientation nOrientation
)
940 // return the innermost dimension for the given orientation,
941 // excluding data layout dimension
943 auto iter
= std::find_if(m_DimList
.rbegin(), m_DimList
.rend(),
944 [&nOrientation
](const std::unique_ptr
<ScDPSaveDimension
>& rxDim
) {
945 return rxDim
->GetOrientation() == nOrientation
&& !rxDim
->IsDataLayout(); });
946 if (iter
!= m_DimList
.rend())
952 ScDPSaveDimension
* ScDPSaveData::GetFirstDimension(sheet::DataPilotFieldOrientation eOrientation
)
954 for (auto const& iter
: m_DimList
)
956 if (iter
->GetOrientation() == eOrientation
&& !iter
->IsDataLayout())
962 tools::Long
ScDPSaveData::GetDataDimensionCount() const
964 tools::Long nDataCount
= 0;
966 for (auto const& iter
: m_DimList
)
968 if (iter
->GetOrientation() == sheet::DataPilotFieldOrientation_DATA
)
975 void ScDPSaveData::SetPosition( ScDPSaveDimension
* pDim
, tools::Long nNew
)
977 // position (nNew) is counted within dimensions of the same orientation
979 DataPilotFieldOrientation nOrient
= pDim
->GetOrientation();
981 auto it
= std::find_if(m_DimList
.begin(), m_DimList
.end(),
982 [&pDim
](const std::unique_ptr
<ScDPSaveDimension
>& rxDim
) { return pDim
== rxDim
.get(); });
983 if (it
!= m_DimList
.end())
985 // Tell vector<unique_ptr> to give up ownership of this element. Don't
986 // delete this instance as it is re-inserted into the container later.
987 // coverity[leaked_storage] - re-inserted into the container later
992 auto iterInsert
= std::find_if(m_DimList
.begin(), m_DimList
.end(),
993 [&nOrient
, &nNew
](const std::unique_ptr
<ScDPSaveDimension
>& rxDim
) {
994 if (rxDim
->GetOrientation() == nOrient
)
999 m_DimList
.insert(iterInsert
, std::unique_ptr
<ScDPSaveDimension
>(pDim
));
1000 DimensionsChanged();
1003 void ScDPSaveData::SetColumnGrand(bool bSet
)
1005 mnColumnGrandMode
= sal_uInt16(bSet
);
1008 void ScDPSaveData::SetRowGrand(bool bSet
)
1010 mnRowGrandMode
= sal_uInt16(bSet
);
1013 void ScDPSaveData::SetIgnoreEmptyRows(bool bSet
)
1015 mnIgnoreEmptyMode
= sal_uInt16(bSet
);
1018 void ScDPSaveData::SetRepeatIfEmpty(bool bSet
)
1020 mnRepeatEmptyMode
= sal_uInt16(bSet
);
1023 void ScDPSaveData::SetFilterButton(bool bSet
)
1025 mbFilterButton
= bSet
;
1028 void ScDPSaveData::SetDrillDown(bool bSet
)
1033 void ScDPSaveData::SetExpandCollapse(bool bSet
)
1035 mbExpandCollapse
= bSet
;
1038 static void lcl_ResetOrient( const uno::Reference
<sheet::XDimensionsSupplier
>& xSource
)
1040 uno::Reference
<container::XNameAccess
> xDimsName
= xSource
->getDimensions();
1041 uno::Reference
<container::XIndexAccess
> xIntDims
= new ScNameToIndexAccess( xDimsName
);
1042 tools::Long nIntCount
= xIntDims
->getCount();
1043 for (tools::Long nIntDim
=0; nIntDim
<nIntCount
; nIntDim
++)
1045 uno::Reference
<beans::XPropertySet
> xDimProp(xIntDims
->getByIndex(nIntDim
), uno::UNO_QUERY
);
1048 xDimProp
->setPropertyValue( SC_UNO_DP_ORIENTATION
, uno::Any(sheet::DataPilotFieldOrientation_HIDDEN
) );
1053 void ScDPSaveData::WriteToSource( const uno::Reference
<sheet::XDimensionsSupplier
>& xSource
)
1058 // source options must be first!
1060 uno::Reference
<beans::XPropertySet
> xSourceProp( xSource
, uno::UNO_QUERY
);
1061 SAL_WARN_IF( !xSourceProp
.is(), "sc.core", "no properties at source" );
1062 if ( xSourceProp
.is() )
1064 // source options are not available for external sources
1065 //TODO: use XPropertySetInfo to test for availability?
1069 if (mnIgnoreEmptyMode
!= SC_DPSAVEMODE_DONTKNOW
)
1070 lcl_SetBoolProperty(xSourceProp
, SC_UNO_DP_IGNOREEMPTY
, bool(mnIgnoreEmptyMode
));
1071 if (mnRepeatEmptyMode
!= SC_DPSAVEMODE_DONTKNOW
)
1072 lcl_SetBoolProperty(xSourceProp
, SC_UNO_DP_REPEATEMPTY
, bool(mnRepeatEmptyMode
));
1074 catch(uno::Exception
&)
1079 const std::optional
<OUString
> & pGrandTotalName
= GetGrandTotalName();
1080 if (pGrandTotalName
)
1081 ScUnoHelpFunctions::SetOptionalPropertyValue(xSourceProp
, SC_UNO_DP_GRANDTOTAL_NAME
, *pGrandTotalName
);
1084 // exceptions in the other calls are errors
1087 // reset all orientations
1088 //TODO: "forgetSettings" or similar at source ?????
1089 //TODO: reset all duplicated dimensions, or reuse them below !!!
1090 SAL_INFO("sc.core", "ScDPSaveData::WriteToSource");
1092 lcl_ResetOrient( xSource
);
1094 uno::Reference
<container::XNameAccess
> xDimsName
= xSource
->getDimensions();
1095 uno::Reference
<container::XIndexAccess
> xIntDims
= new ScNameToIndexAccess( xDimsName
);
1096 tools::Long nIntCount
= xIntDims
->getCount();
1098 for (const auto& rxDim
: m_DimList
)
1100 OUString aName
= rxDim
->GetName();
1101 OUString aCoreName
= ScDPUtil::getSourceDimensionName(aName
);
1103 SAL_INFO("sc.core", aName
);
1105 bool bData
= rxDim
->IsDataLayout();
1107 //TODO: getByName for ScDPSource, including DataLayoutDimension !!!!!!!!
1109 bool bFound
= false;
1110 for (tools::Long nIntDim
=0; nIntDim
<nIntCount
&& !bFound
; nIntDim
++)
1112 uno::Reference
<uno::XInterface
> xIntDim(xIntDims
->getByIndex(nIntDim
),
1116 uno::Reference
<beans::XPropertySet
> xDimProp( xIntDim
, uno::UNO_QUERY
);
1117 if ( xDimProp
.is() )
1119 bFound
= ScUnoHelpFunctions::GetBoolProperty( xDimProp
,
1120 SC_UNO_DP_ISDATALAYOUT
);
1121 //TODO: error checking -- is "IsDataLayoutDimension" property required??
1126 uno::Reference
<container::XNamed
> xDimName( xIntDim
, uno::UNO_QUERY
);
1127 if (xDimName
.is() && xDimName
->getName() == aCoreName
)
1133 if (rxDim
->GetDupFlag())
1135 uno::Reference
<util::XCloneable
> xCloneable(xIntDim
, uno::UNO_QUERY
);
1136 SAL_WARN_IF(!xCloneable
.is(), "sc.core", "cannot clone dimension");
1137 if (xCloneable
.is())
1139 uno::Reference
<util::XCloneable
> xNew
= xCloneable
->createClone();
1140 uno::Reference
<container::XNamed
> xNewName(xNew
, uno::UNO_QUERY
);
1143 xNewName
->setName(aName
);
1144 rxDim
->WriteToSource(xNew
);
1149 rxDim
->WriteToSource( xIntDim
);
1152 SAL_WARN_IF(!bFound
, "sc.core", "WriteToSource: Dimension not found: " + aName
+ ".");
1155 if ( xSourceProp
.is() )
1157 if (mnColumnGrandMode
!= SC_DPSAVEMODE_DONTKNOW
)
1158 lcl_SetBoolProperty(xSourceProp
, SC_UNO_DP_COLGRAND
, bool(mnColumnGrandMode
));
1159 if (mnRowGrandMode
!= SC_DPSAVEMODE_DONTKNOW
)
1160 lcl_SetBoolProperty(xSourceProp
, SC_UNO_DP_ROWGRAND
, bool(mnRowGrandMode
));
1163 catch(uno::Exception
const &)
1165 TOOLS_WARN_EXCEPTION("sc.core", "WriteToSource");
1169 bool ScDPSaveData::IsEmpty() const
1171 for (auto const& iter
: m_DimList
)
1173 if (iter
->GetOrientation() != sheet::DataPilotFieldOrientation_HIDDEN
&& !iter
->IsDataLayout())
1176 return true; // no entries that are not hidden
1179 void ScDPSaveData::RemoveAllGroupDimensions( const OUString
& rSrcDimName
, std::vector
<OUString
>* pDeletedNames
)
1181 if (!mpDimensionData
)
1182 // No group dimensions exist. Nothing to do.
1185 // Remove numeric group dimension (exists once at most). No need to delete
1186 // anything in save data (grouping was done inplace in an existing base
1188 mpDimensionData
->RemoveNumGroupDimension(rSrcDimName
);
1190 // Remove named group dimension(s). Dimensions have to be removed from
1191 // dimension save data and from save data too.
1192 const ScDPSaveGroupDimension
* pExistingGroup
= mpDimensionData
->GetGroupDimForBase(rSrcDimName
);
1193 while ( pExistingGroup
)
1195 OUString aGroupDimName
= pExistingGroup
->GetGroupDimName();
1196 mpDimensionData
->RemoveGroupDimension(aGroupDimName
); // pExistingGroup is deleted
1198 // also remove SaveData settings for the dimension that no longer exists
1199 RemoveDimensionByName(aGroupDimName
);
1202 pDeletedNames
->push_back(aGroupDimName
);
1204 // see if there are more group dimensions
1205 pExistingGroup
= mpDimensionData
->GetGroupDimForBase(rSrcDimName
);
1207 if ( pExistingGroup
&& pExistingGroup
->GetGroupDimName() == aGroupDimName
)
1209 // still get the same group dimension?
1210 OSL_FAIL("couldn't remove group dimension");
1211 pExistingGroup
= nullptr; // avoid endless loop
1216 ScDPDimensionSaveData
* ScDPSaveData::GetDimensionData()
1218 if (!mpDimensionData
)
1219 mpDimensionData
.reset(new ScDPDimensionSaveData
);
1220 return mpDimensionData
.get();
1223 void ScDPSaveData::SetDimensionData(const ScDPDimensionSaveData
* pNew
)
1226 mpDimensionData
.reset(new ScDPDimensionSaveData(*pNew
));
1228 mpDimensionData
.reset();
1231 void ScDPSaveData::BuildAllDimensionMembers(ScDPTableData
* pData
)
1233 if (mbDimensionMembersBuilt
)
1236 // First, build a dimension name-to-index map.
1237 typedef std::unordered_map
<OUString
, tools::Long
> NameIndexMap
;
1239 tools::Long nColCount
= pData
->GetColumnCount();
1240 for (tools::Long i
= 0; i
< nColCount
; ++i
)
1241 aMap
.emplace(pData
->getDimensionName(i
), i
);
1243 NameIndexMap::const_iterator itrEnd
= aMap
.end();
1245 for (auto const& iter
: m_DimList
)
1247 const OUString
& rDimName
= iter
->GetName();
1248 if (rDimName
.isEmpty())
1249 // empty dimension name. It must be data layout.
1252 NameIndexMap::const_iterator itr
= aMap
.find(rDimName
);
1254 // dimension name not in the data. This should never happen!
1257 tools::Long nDimIndex
= itr
->second
;
1258 const std::vector
<SCROW
>& rMembers
= pData
->GetColumnEntries(nDimIndex
);
1259 size_t nMemberCount
= rMembers
.size();
1260 for (size_t j
= 0; j
< nMemberCount
; ++j
)
1262 const ScDPItemData
* pMemberData
= pData
->GetMemberById( nDimIndex
, rMembers
[j
] );
1263 OUString aMemName
= pData
->GetFormattedString(nDimIndex
, *pMemberData
, false);
1264 if (iter
->GetExistingMemberByName(aMemName
))
1265 // this member instance already exists. nothing to do.
1268 unique_ptr
<ScDPSaveMember
> pNewMember(new ScDPSaveMember(aMemName
));
1269 pNewMember
->SetIsVisible(true);
1270 iter
->AddMember(std::move(pNewMember
));
1274 mbDimensionMembersBuilt
= true;
1277 void ScDPSaveData::SyncAllDimensionMembers(ScDPTableData
* pData
)
1279 typedef std::unordered_map
<OUString
, tools::Long
> NameIndexMap
;
1281 // First, build a dimension name-to-index map.
1283 tools::Long nColCount
= pData
->GetColumnCount();
1284 for (tools::Long i
= 0; i
< nColCount
; ++i
)
1285 aMap
.emplace(pData
->getDimensionName(i
), i
);
1287 NameIndexMap::const_iterator itMapEnd
= aMap
.end();
1289 for (auto const& it
: m_DimList
)
1291 const OUString
& rDimName
= it
->GetName();
1292 if (rDimName
.isEmpty())
1293 // empty dimension name. It must be data layout.
1296 NameIndexMap::const_iterator itMap
= aMap
.find(rDimName
);
1297 if (itMap
== itMapEnd
)
1298 // dimension name not in the data. This should never happen!
1301 ScDPSaveDimension::MemberSetType aMemNames
;
1302 tools::Long nDimIndex
= itMap
->second
;
1303 const std::vector
<SCROW
>& rMembers
= pData
->GetColumnEntries(nDimIndex
);
1304 size_t nMemberCount
= rMembers
.size();
1305 for (size_t j
= 0; j
< nMemberCount
; ++j
)
1307 const ScDPItemData
* pMemberData
= pData
->GetMemberById(nDimIndex
, rMembers
[j
]);
1308 // ScDPCache::GetItemDataById() (via
1309 // ScDPTableData::GetMemberById(),
1310 // ScDPGroupTableData::GetMemberById() through
1311 // GetCacheTable().getCache()) may return nullptr.
1314 OUString aMemName
= pData
->GetFormattedString(nDimIndex
, *pMemberData
, false);
1315 aMemNames
.insert(aMemName
);
1319 SAL_WARN("sc.core", "No pMemberData for nDimIndex " << nDimIndex
<< ", rMembers[j] " << rMembers
[j
]
1324 it
->RemoveObsoleteMembers(aMemNames
);
1328 bool ScDPSaveData::HasInvisibleMember(std::u16string_view rDimName
) const
1330 ScDPSaveDimension
* pDim
= GetExistingDimensionByName(rDimName
);
1334 return pDim
->HasInvisibleMember();
1337 #if DUMP_PIVOT_TABLE
1339 void ScDPSaveData::Dump() const
1341 for (auto const& itDim
: m_DimList
)
1343 const ScDPSaveDimension
& rDim
= *itDim
;
1350 void ScDPSaveData::CheckDuplicateName(ScDPSaveDimension
& rDim
)
1352 const OUString aName
= ScDPUtil::getSourceDimensionName(rDim
.GetName());
1353 DupNameCountType::iterator it
= maDupNameCounts
.find(aName
);
1354 if (it
!= maDupNameCounts
.end())
1356 rDim
.SetName(ScDPUtil::createDuplicateDimensionName(aName
, ++it
->second
));
1357 rDim
.SetDupFlag(true);
1361 maDupNameCounts
.emplace(aName
, 0);
1364 void ScDPSaveData::RemoveDuplicateNameCount(const OUString
& rName
)
1366 OUString aCoreName
= rName
;
1367 if (ScDPUtil::isDuplicateDimension(rName
))
1368 aCoreName
= ScDPUtil::getSourceDimensionName(rName
);
1370 DupNameCountType::iterator it
= maDupNameCounts
.find(aCoreName
);
1371 if (it
== maDupNameCounts
.end())
1376 maDupNameCounts
.erase(it
);
1383 ScDPSaveDimension
* ScDPSaveData::AppendNewDimension(const OUString
& rName
, bool bDataLayout
)
1385 if (ScDPUtil::isDuplicateDimension(rName
))
1386 // This call is for original dimensions only.
1389 ScDPSaveDimension
* pNew
= new ScDPSaveDimension(rName
, bDataLayout
);
1390 m_DimList
.push_back(std::unique_ptr
<ScDPSaveDimension
>(pNew
));
1391 if (!maDupNameCounts
.count(rName
))
1392 maDupNameCounts
.emplace(rName
, 0);
1394 DimensionsChanged();
1398 void ScDPSaveData::DimensionsChanged()
1403 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */