LibreOffice Module sc (master) 1
dptabres.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <dptabres.hxx>
21
22#include <dptabdat.hxx>
23#include <dptabsrc.hxx>
24#include <global.hxx>
25#include <subtotal.hxx>
26#include <globstr.hrc>
27#include <scresid.hxx>
28#include <dpitemdata.hxx>
29#include <generalfunction.hxx>
30
31#include <document.hxx>
32#include <dpresfilter.hxx>
33#include <dputil.hxx>
34
35#include <o3tl/safeint.hxx>
36#include <osl/diagnose.h>
37#include <rtl/math.hxx>
38#include <sal/log.hxx>
39
40#include <math.h>
41#include <float.h>
42#include <algorithm>
43#include <limits>
44#include <memory>
45#include <unordered_map>
46
47#include <com/sun/star/sheet/DataResultFlags.hpp>
48#include <com/sun/star/sheet/MemberResultFlags.hpp>
49#include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
50#include <com/sun/star/sheet/DataPilotFieldReferenceItemType.hpp>
51#include <com/sun/star/sheet/DataPilotFieldShowItemsMode.hpp>
52#include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
53#include <com/sun/star/sheet/GeneralFunction2.hpp>
54
55using namespace com::sun::star;
56using ::std::vector;
57using ::std::pair;
58using ::com::sun::star::uno::Sequence;
59
60namespace {
61
62const TranslateId aFuncStrIds[] = // matching enum ScSubTotalFunc
63{
64 {}, // SUBTOTAL_FUNC_NONE
65 STR_FUN_TEXT_AVG, // SUBTOTAL_FUNC_AVE
66 STR_FUN_TEXT_COUNT, // SUBTOTAL_FUNC_CNT
67 STR_FUN_TEXT_COUNT, // SUBTOTAL_FUNC_CNT2
68 STR_FUN_TEXT_MAX, // SUBTOTAL_FUNC_MAX
69 STR_FUN_TEXT_MIN, // SUBTOTAL_FUNC_MIN
70 STR_FUN_TEXT_PRODUCT, // SUBTOTAL_FUNC_PROD
71 STR_FUN_TEXT_STDDEV, // SUBTOTAL_FUNC_STD
72 STR_FUN_TEXT_STDDEV, // SUBTOTAL_FUNC_STDP
73 STR_FUN_TEXT_SUM, // SUBTOTAL_FUNC_SUM
74 STR_FUN_TEXT_VAR, // SUBTOTAL_FUNC_VAR
75 STR_FUN_TEXT_VAR, // SUBTOTAL_FUNC_VARP
76 STR_FUN_TEXT_MEDIAN, // SUBTOTAL_FUNC_MED
77 {} // SUBTOTAL_FUNC_SELECTION_COUNT - not used for pivot table
78};
79
80bool lcl_SearchMember( const std::vector<std::unique_ptr<ScDPResultMember>>& list, SCROW nOrder, SCROW& rIndex)
81{
82 bool bFound = false;
83 SCROW nLo = 0;
84 SCROW nHi = list.size() - 1;
86 while (nLo <= nHi)
87 {
88 nIndex = (nLo + nHi) / 2;
89 if ( list[nIndex]->GetOrder() < nOrder )
90 nLo = nIndex + 1;
91 else
92 {
93 nHi = nIndex - 1;
94 if ( list[nIndex]->GetOrder() == nOrder )
95 {
96 bFound = true;
97 nLo = nIndex;
98 }
99 }
100 }
101 rIndex = nLo;
102 return bFound;
103}
104
105class FilterStack
106{
107 std::vector<ScDPResultFilter>& mrFilters;
108public:
109 explicit FilterStack(std::vector<ScDPResultFilter>& rFilters) : mrFilters(rFilters) {}
110
111 void pushDimName(const OUString& rName, bool bDataLayout)
112 {
113 mrFilters.emplace_back(rName, bDataLayout);
114 }
115
116 void pushDimValue(const OUString& rValueName, const OUString& rValue)
117 {
118 ScDPResultFilter& rFilter = mrFilters.back();
119 rFilter.maValueName = rValueName;
120 rFilter.maValue = rValue;
121 rFilter.mbHasValue = true;
122 }
123
124 ~FilterStack()
125 {
126 ScDPResultFilter& rFilter = mrFilters.back();
127 if (rFilter.mbHasValue)
128 rFilter.mbHasValue = false;
129 else
130 mrFilters.pop_back();
131 }
132};
133
134// function objects for sorting of the column and row members:
135
136class ScDPRowMembersOrder
137{
138 ScDPResultDimension& rDimension;
139 tools::Long nMeasure;
140 bool bAscending;
141
142public:
143 ScDPRowMembersOrder( ScDPResultDimension& rDim, tools::Long nM, bool bAsc ) :
144 rDimension(rDim),
145 nMeasure(nM),
146 bAscending(bAsc)
147 {}
148
149 bool operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const;
150};
151
152class ScDPColMembersOrder
153{
154 ScDPDataDimension& rDimension;
155 tools::Long nMeasure;
156 bool bAscending;
157
158public:
159 ScDPColMembersOrder( ScDPDataDimension& rDim, tools::Long nM, bool bAsc ) :
160 rDimension(rDim),
161 nMeasure(nM),
162 bAscending(bAsc)
163 {}
164
165 bool operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const;
166};
167
168}
169
170static bool lcl_IsLess( const ScDPDataMember* pDataMember1, const ScDPDataMember* pDataMember2, tools::Long nMeasure, bool bAscending )
171{
172 // members can be NULL if used for rows
173
174 ScDPSubTotalState aEmptyState;
175 const ScDPAggData* pAgg1 = pDataMember1 ? pDataMember1->GetConstAggData( nMeasure, aEmptyState ) : nullptr;
176 const ScDPAggData* pAgg2 = pDataMember2 ? pDataMember2->GetConstAggData( nMeasure, aEmptyState ) : nullptr;
177
178 bool bError1 = pAgg1 && pAgg1->HasError();
179 bool bError2 = pAgg2 && pAgg2->HasError();
180 if ( bError1 )
181 return false; // errors are always sorted at the end
182 else if ( bError2 )
183 return true; // errors are always sorted at the end
184 else
185 {
186 double fVal1 = ( pAgg1 && pAgg1->HasData() ) ? pAgg1->GetResult() : 0.0; // no data is sorted as 0
187 double fVal2 = ( pAgg2 && pAgg2->HasData() ) ? pAgg2->GetResult() : 0.0;
188
189 // compare values
190 // don't have to check approxEqual, as this is the only sort criterion
191
192 return bAscending ? ( fVal1 < fVal2 ) : ( fVal1 > fVal2 );
193 }
194}
195
196static bool lcl_IsEqual( const ScDPDataMember* pDataMember1, const ScDPDataMember* pDataMember2, tools::Long nMeasure )
197{
198 // members can be NULL if used for rows
199
200 ScDPSubTotalState aEmptyState;
201 const ScDPAggData* pAgg1 = pDataMember1 ? pDataMember1->GetConstAggData( nMeasure, aEmptyState ) : nullptr;
202 const ScDPAggData* pAgg2 = pDataMember2 ? pDataMember2->GetConstAggData( nMeasure, aEmptyState ) : nullptr;
203
204 bool bError1 = pAgg1 && pAgg1->HasError();
205 bool bError2 = pAgg2 && pAgg2->HasError();
206 if ( bError1 )
207 {
208 if ( bError2 )
209 return true; // equal
210 else
211 return false;
212 }
213 else if ( bError2 )
214 return false;
215 else
216 {
217 double fVal1 = ( pAgg1 && pAgg1->HasData() ) ? pAgg1->GetResult() : 0.0; // no data is sorted as 0
218 double fVal2 = ( pAgg2 && pAgg2->HasData() ) ? pAgg2->GetResult() : 0.0;
219
220 // compare values
221 // this is used to find equal data at the end of the AutoShow range, so approxEqual must be used
222
223 return rtl::math::approxEqual( fVal1, fVal2 );
224 }
225}
226
227bool ScDPRowMembersOrder::operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const
228{
229 const ScDPResultMember* pMember1 = rDimension.GetMember(nIndex1);
230 const ScDPResultMember* pMember2 = rDimension.GetMember(nIndex2);
231
232// make the hide item to the largest order.
233 if ( !pMember1->IsVisible() || !pMember2->IsVisible() )
234 return pMember1->IsVisible();
235 const ScDPDataMember* pDataMember1 = pMember1->GetDataRoot() ;
236 const ScDPDataMember* pDataMember2 = pMember2->GetDataRoot();
237 // GetDataRoot can be NULL if there was no data.
238 // IsVisible == false can happen after AutoShow.
239 return lcl_IsLess( pDataMember1, pDataMember2, nMeasure, bAscending );
240}
241
242bool ScDPColMembersOrder::operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const
243{
244 const ScDPDataMember* pDataMember1 = rDimension.GetMember(nIndex1);
245 const ScDPDataMember* pDataMember2 = rDimension.GetMember(nIndex2);
246 bool bHide1 = pDataMember1 && !pDataMember1->IsVisible();
247 bool bHide2 = pDataMember2 && !pDataMember2->IsVisible();
248 if ( bHide1 || bHide2 )
249 return !bHide1;
250 return lcl_IsLess( pDataMember1, pDataMember2, nMeasure, bAscending );
251}
252
254 mnSrcIndex(nSrcIndex), mnNameIndex(nNameIndex) {}
255
256void ScDPInitState::AddMember( tools::Long nSourceIndex, SCROW nMember )
257{
258 maMembers.emplace_back(nSourceIndex, nMember);
259}
260
262{
263 OSL_ENSURE(!maMembers.empty(), "ScDPInitState::RemoveMember: Attempt to remove member while empty.");
264 if (!maMembers.empty())
265 maMembers.pop_back();
266}
267
268namespace {
269
270#if DUMP_PIVOT_TABLE
271void dumpRow(
272 const OUString& rType, const OUString& rName, const ScDPAggData* pAggData,
273 ScDocument* pDoc, ScAddress& rPos )
274{
275 SCCOL nCol = rPos.Col();
276 SCROW nRow = rPos.Row();
277 SCTAB nTab = rPos.Tab();
278 pDoc->SetString( nCol++, nRow, nTab, rType );
279 pDoc->SetString( nCol++, nRow, nTab, rName );
280 while ( pAggData )
281 {
282 pDoc->SetValue( nCol++, nRow, nTab, pAggData->GetResult() );
283 pAggData = pAggData->GetExistingChild();
284 }
285 rPos.SetRow( nRow + 1 );
286}
287
288void indent( ScDocument* pDoc, SCROW nStartRow, const ScAddress& rPos )
289{
290 SCCOL nCol = rPos.Col();
291 SCTAB nTab = rPos.Tab();
292
293 OUString aString;
294 for (SCROW nRow = nStartRow; nRow < rPos.Row(); nRow++)
295 {
296 aString = pDoc->GetString(nCol, nRow, nTab);
297 if (!aString.isEmpty())
298 {
299 aString = " " + aString;
300 pDoc->SetString( nCol, nRow, nTab, aString );
301 }
302 }
303}
304#endif
305
306}
307
309 pColResRoot(pColRoot), pRowResRoot(pRowRoot)
310{
311 // These arrays should never be empty as the terminating value must be present at all times.
312 maColVisible.push_back(-1);
313 maColSorted.push_back(-1);
314 maRowVisible.push_back(-1);
315 maRowSorted.push_back(-1);
316}
317
318void ScDPRunningTotalState::AddColIndex( sal_Int32 nVisible, tools::Long nSorted )
319{
320 maColVisible.back() = nVisible;
321 maColVisible.push_back(-1);
322
323 maColSorted.back() = nSorted;
324 maColSorted.push_back(-1);
325}
326
327void ScDPRunningTotalState::AddRowIndex( sal_Int32 nVisible, tools::Long nSorted )
328{
329 maRowVisible.back() = nVisible;
330 maRowVisible.push_back(-1);
331
332 maRowSorted.back() = nSorted;
333 maRowSorted.push_back(-1);
334}
335
337{
338 OSL_ENSURE(!maColVisible.empty() && !maColSorted.empty(), "ScDPRunningTotalState::RemoveColIndex: array is already empty!");
339 if (maColVisible.size() >= 2)
340 {
341 maColVisible.pop_back();
342 maColVisible.back() = -1;
343 }
344
345 if (maColSorted.size() >= 2)
346 {
347 maColSorted.pop_back();
348 maColSorted.back() = -1;
349 }
350}
351
353{
354 OSL_ENSURE(!maRowVisible.empty() && !maRowSorted.empty(), "ScDPRunningTotalState::RemoveRowIndex: array is already empty!");
355 if (maRowVisible.size() >= 2)
356 {
357 maRowVisible.pop_back();
358 maRowVisible.back() = -1;
359 }
360
361 if (maRowSorted.size() >= 2)
362 {
363 maRowSorted.pop_back();
364 maRowSorted.back() = -1;
365 }
366}
367
369 nBasePos( nBase ),
370 nDirection( nDir )
371{
372}
373
374void ScDPAggData::Update( const ScDPValue& rNext, ScSubTotalFunc eFunc, const ScDPSubTotalState& rSubState )
375{
376 if (nCount<0) // error?
377 return; // nothing more...
378
379 if (rNext.meType == ScDPValue::Empty)
380 return;
381
382 if ( rSubState.eColForce != SUBTOTAL_FUNC_NONE && rSubState.eRowForce != SUBTOTAL_FUNC_NONE &&
383 rSubState.eColForce != rSubState.eRowForce )
384 return;
385 if ( rSubState.eColForce != SUBTOTAL_FUNC_NONE ) eFunc = rSubState.eColForce;
386 if ( rSubState.eRowForce != SUBTOTAL_FUNC_NONE ) eFunc = rSubState.eRowForce;
387
388 if ( eFunc == SUBTOTAL_FUNC_NONE )
389 return;
390
391 if ( eFunc != SUBTOTAL_FUNC_CNT2 ) // CNT2 counts everything, incl. strings and errors
392 {
393 if (rNext.meType == ScDPValue::Error)
394 {
395 nCount = -1; // -1 for error (not for CNT2)
396 return;
397 }
398 if (rNext.meType == ScDPValue::String)
399 return; // ignore
400 }
401
402 ++nCount; // for all functions
403
404 switch (eFunc)
405 {
408 if ( !SubTotal::SafePlus( fVal, rNext.mfValue ) )
409 nCount = -1; // -1 for error
410 break;
412 if ( nCount == 1 ) // copy first value (fVal is initialized to 0)
413 fVal = rNext.mfValue;
414 else if ( !SubTotal::SafeMult( fVal, rNext.mfValue ) )
415 nCount = -1; // -1 for error
416 break;
419 // nothing more than incrementing nCount
420 break;
422 if ( nCount == 1 || rNext.mfValue > fVal )
423 fVal = rNext.mfValue;
424 break;
426 if ( nCount == 1 || rNext.mfValue < fVal )
427 fVal = rNext.mfValue;
428 break;
433 maWelford.update( rNext.mfValue);
434 break;
436 {
437 auto aIter = std::upper_bound(mSortedValues.begin(), mSortedValues.end(), rNext.mfValue);
438 if (aIter == mSortedValues.end())
439 mSortedValues.push_back(rNext.mfValue);
440 else
441 mSortedValues.insert(aIter, rNext.mfValue);
442 }
443 break;
444 default:
445 OSL_FAIL("invalid function");
446 }
447}
448
450{
451 // calculate the original result
452 // (without reference value, used as the basis for reference value calculation)
453
454 // called several times at the cross-section of several subtotals - don't calculate twice then
455 if ( IsCalculated() )
456 return;
457
458 if ( rSubState.eColForce != SUBTOTAL_FUNC_NONE ) eFunc = rSubState.eColForce;
459 if ( rSubState.eRowForce != SUBTOTAL_FUNC_NONE ) eFunc = rSubState.eRowForce;
460
461 if ( eFunc == SUBTOTAL_FUNC_NONE ) // this happens when there is no data dimension
462 {
463 nCount = SC_DPAGG_RESULT_EMPTY; // make sure there's a valid state for HasData etc.
464 return;
465 }
466
467 // check the error conditions for the selected function
468
469 bool bError = false;
470 switch (eFunc)
471 {
476 bError = ( nCount < 0 ); // only real errors
477 break;
478
483 bError = ( nCount <= 0 ); // no data is an error
484 break;
485
488 bError = ( nCount <= 0 ); // no data is an error
489 assert(bError || nCount == static_cast<sal_Int64>(maWelford.getCount()));
490 break;
491
494 bError = ( nCount < 2 ); // need at least 2 values
495 assert(bError || nCount == static_cast<sal_Int64>(maWelford.getCount()));
496 break;
497
498 default:
499 OSL_FAIL("invalid function");
500 }
501
502 // calculate the selected function
503
504 double fResult = 0.0;
505 if ( !bError )
506 {
507 switch (eFunc)
508 {
513 // different error conditions are handled above
514 fResult = fVal;
515 break;
516
519 fResult = nCount;
520 break;
521
523 if ( nCount > 0 )
524 fResult = fVal / static_cast<double>(nCount);
525 break;
526
528 if ( nCount >= 2 )
529 {
530 fResult = maWelford.getVarianceSample();
531 if (fResult < 0.0)
532 bError = true;
533 else
534 fResult = sqrt( fResult);
535 }
536 break;
538 if ( nCount >= 2 )
539 fResult = maWelford.getVarianceSample();
540 break;
542 if ( nCount > 0 )
543 {
545 if (fResult < 0.0)
546 bError = true;
547 else
548 fResult = sqrt( fResult);
549 }
550 break;
552 if ( nCount > 0 )
554 break;
556 {
557 size_t nSize = mSortedValues.size();
558 if (nSize > 0)
559 {
560 assert(nSize == static_cast<size_t>(nCount));
561 if ((nSize % 2) == 1)
562 fResult = mSortedValues[nSize / 2];
563 else
564 fResult = (mSortedValues[nSize / 2 - 1] + mSortedValues[nSize / 2]) / 2.0;
565 }
566 }
567 break;
568 default:
569 OSL_FAIL("invalid function");
570 }
571 }
572
573 bool bEmpty = ( nCount == 0 ); // no data
574
575 // store the result
576 // Empty is checked first, so empty results are shown empty even for "average" etc.
577 // If these results should be treated as errors in reference value calculations,
578 // a separate state value (EMPTY_ERROR) is needed.
579 // Now, for compatibility, empty "average" results are counted as 0.
580
581 if ( bEmpty )
583 else if ( bError )
585 else
587
588 if ( bEmpty || bError )
589 fResult = 0.0; // default, in case the state is later modified
590
591 fVal = fResult; // used directly from now on
592 fAux = 0.0; // used for running total or original result of reference value
593}
594
596{
597 return ( nCount <= SC_DPAGG_RESULT_EMPTY );
598}
599
601{
602 assert( IsCalculated() && "ScDPAggData not calculated" );
603
604 return fVal; // use calculated value
605}
606
608{
609 assert( IsCalculated() && "ScDPAggData not calculated" );
610
611 return ( nCount == SC_DPAGG_RESULT_ERROR );
612}
613
615{
616 assert( IsCalculated() && "ScDPAggData not calculated" );
617
618 return ( nCount != SC_DPAGG_RESULT_EMPTY ); // values or error
619}
620
621void ScDPAggData::SetResult( double fNew )
622{
623 assert( IsCalculated() && "ScDPAggData not calculated" );
624
625 fVal = fNew; // don't reset error flag
626}
627
629{
630 assert( IsCalculated() && "ScDPAggData not calculated" );
631
633}
634
635void ScDPAggData::SetEmpty( bool bSet )
636{
637 assert( IsCalculated() && "ScDPAggData not calculated" );
638
639 if ( bSet )
641 else
643}
644
646{
647 // after Calculate, fAux is used as auxiliary value for running totals and reference values
648 assert( IsCalculated() && "ScDPAggData not calculated" );
649
650 return fAux;
651}
652
653void ScDPAggData::SetAuxiliary( double fNew )
654{
655 // after Calculate, fAux is used as auxiliary value for running totals and reference values
656 assert( IsCalculated() && "ScDPAggData not calculated" );
657
658 fAux = fNew;
659}
660
662{
663 if (!pChild)
664 pChild.reset( new ScDPAggData );
665 return pChild.get();
666}
667
669{
671 fVal = 0.0;
672 fAux = 0.0;
674 pChild.reset();
675}
676
677#if DUMP_PIVOT_TABLE
678void ScDPAggData::Dump(int nIndent) const
679{
680 std::string aIndent(nIndent*2, ' ');
681 std::cout << aIndent << "* ";
682 if (IsCalculated())
683 std::cout << GetResult();
684 else
685 std::cout << "not calculated";
686
687 std::cout << " [val=" << fVal << "; aux=" << fAux << "; count=" << nCount << "]" << std::endl;
688}
689#endif
690
692 bIsInColRoot( false )
693{
694}
695
697{
698}
699
701{
702 OSL_ENSURE( nMeasure >= 0, "GetColTotal: no measure" );
703
704 ScDPAggData* pAgg = pFirst;
705 tools::Long nSkip = nMeasure;
706
707 // subtotal settings are ignored - column/row totals exist once per measure
708
709 for ( tools::Long nPos=0; nPos<nSkip; nPos++ )
710 pAgg = pAgg->GetChild(); // column total is constructed empty - children need to be created
711
712 if ( !pAgg->IsCalculated() )
713 {
714 // for first use, simulate an empty calculation
715 ScDPSubTotalState aEmptyState;
716 pAgg->Calculate( SUBTOTAL_FUNC_SUM, aEmptyState );
717 }
718
719 return pAgg;
720}
721
723{
724 return lcl_GetChildTotal( &aRowTotal, nMeasure );
725}
726
728{
729 return lcl_GetChildTotal( &aGrandTotal, nMeasure );
730}
731
732static ScSubTotalFunc lcl_GetForceFunc( const ScDPLevel* pLevel, tools::Long nFuncNo )
733{
735 if ( pLevel )
736 {
737 //TODO: direct access via ScDPLevel
738
739 uno::Sequence<sal_Int16> aSeq = pLevel->getSubTotals();
740 tools::Long nSequence = aSeq.getLength();
741 if ( nSequence && aSeq[0] != sheet::GeneralFunction2::AUTO )
742 {
743 // For manual subtotals, "automatic" is added as first function.
744 // ScDPResultMember::GetSubTotalCount adds to the count, here NONE has to be
745 // returned as the first function then.
746
747 --nFuncNo; // keep NONE for first (check below), move the other entries
748 }
749
750 if ( nFuncNo >= 0 && nFuncNo < nSequence )
751 {
752 ScGeneralFunction eUser = static_cast<ScGeneralFunction>(aSeq.getConstArray()[nFuncNo]);
753 if (eUser != ScGeneralFunction::AUTO)
754 eRet = ScDPUtil::toSubTotalFunc(eUser);
755 }
756 }
757 return eRet;
758}
759
761 mrSource(rSrc),
762 bLateInit( false ),
763 bDataAtCol( false ),
764 bDataAtRow( false )
765{
766}
767
769{
770}
771
773 std::vector<ScSubTotalFunc>& rFunctions, std::vector<sheet::DataPilotFieldReference>& rRefs,
774 std::vector<sheet::DataPilotFieldOrientation>& rRefOrient, std::vector<OUString>& rNames )
775{
776 // We need to have at least one measure data at all times.
777
778 maMeasureFuncs.swap(rFunctions);
779 if (maMeasureFuncs.empty())
781
782 maMeasureRefs.swap(rRefs);
783 if (maMeasureRefs.empty())
784 maMeasureRefs.emplace_back(); // default ctor is ok.
785
786 maMeasureRefOrients.swap(rRefOrient);
787 if (maMeasureRefOrients.empty())
788 maMeasureRefOrients.push_back(sheet::DataPilotFieldOrientation_HIDDEN);
789
790 maMeasureNames.swap(rNames);
791 if (maMeasureNames.empty())
792 maMeasureNames.push_back(ScResId(STR_EMPTYDATA));
793}
794
795void ScDPResultData::SetDataLayoutOrientation( sheet::DataPilotFieldOrientation nOrient )
796{
797 bDataAtCol = ( nOrient == sheet::DataPilotFieldOrientation_COLUMN );
798 bDataAtRow = ( nOrient == sheet::DataPilotFieldOrientation_ROW );
799}
800
802{
803 bLateInit = bSet;
804}
805
807{
808 if (maMeasureFuncs.size() == 1)
809 return 0;
810
812}
813
815{
816 if (maMeasureFuncs.size() == 1)
817 return 0;
818
820}
821
823{
824 OSL_ENSURE(o3tl::make_unsigned(nMeasure) < maMeasureFuncs.size(), "bumm");
825 return maMeasureFuncs[nMeasure];
826}
827
828const sheet::DataPilotFieldReference& ScDPResultData::GetMeasureRefVal(tools::Long nMeasure) const
829{
830 OSL_ENSURE(o3tl::make_unsigned(nMeasure) < maMeasureRefs.size(), "bumm");
831 return maMeasureRefs[nMeasure];
832}
833
834sheet::DataPilotFieldOrientation ScDPResultData::GetMeasureRefOrient(tools::Long nMeasure) const
835{
836 OSL_ENSURE(o3tl::make_unsigned(nMeasure) < maMeasureRefOrients.size(), "bumm");
837 return maMeasureRefOrients[nMeasure];
838}
839
840OUString ScDPResultData::GetMeasureString(tools::Long nMeasure, bool bForce, ScSubTotalFunc eForceFunc, bool& rbTotalResult) const
841{
842 // with bForce==true, return function instead of "result" for single measure
843 // with eForceFunc != SUBTOTAL_FUNC_NONE, always use eForceFunc
844 rbTotalResult = false;
845 if ( nMeasure < 0 || (maMeasureFuncs.size() == 1 && !bForce && eForceFunc == SUBTOTAL_FUNC_NONE) )
846 {
847 // for user-specified subtotal function with all measures,
848 // display only function name
849 assert(unsigned(eForceFunc) < SAL_N_ELEMENTS(aFuncStrIds));
850 if ( eForceFunc != SUBTOTAL_FUNC_NONE )
851 return ScResId(aFuncStrIds[eForceFunc]);
852
853 rbTotalResult = true;
854 return ScResId(STR_TABLE_ERGEBNIS);
855 }
856 else
857 {
858 OSL_ENSURE(o3tl::make_unsigned(nMeasure) < maMeasureFuncs.size(), "bumm");
859 const ScDPDimension* pDataDim = mrSource.GetDataDimension(nMeasure);
860 if (pDataDim)
861 {
862 const std::optional<OUString> & pLayoutName = pDataDim->GetLayoutName();
863 if (pLayoutName)
864 return *pLayoutName;
865 }
866
867 ScSubTotalFunc eFunc = ( eForceFunc == SUBTOTAL_FUNC_NONE ) ?
868 GetMeasureFunction(nMeasure) : eForceFunc;
869
870 return ScDPUtil::getDisplayedMeasureName(maMeasureNames[nMeasure], eFunc);
871 }
872}
873
875{
876 if ( nMeasure < 0 )
877 {
878 OSL_FAIL("GetMeasureDimensionName: negative");
879 return "***";
880 }
881
882 return mrSource.GetDataDimName(nMeasure);
883}
884
886{
887 return mrSource.GetData()->IsBaseForGroup(nDim);
888}
889
891{
892 return mrSource.GetData()->GetGroupBase(nGroupDim);
893}
894
896{
897 return mrSource.GetData()->IsNumOrDateGroup(nDim);
898}
899
900bool ScDPResultData::IsInGroup( SCROW nGroupDataId, tools::Long nGroupIndex,
901 const ScDPItemData& rBaseData, tools::Long nBaseIndex ) const
902{
903 const ScDPItemData* pGroupData = mrSource.GetItemDataById(nGroupIndex , nGroupDataId);
904 if ( pGroupData )
905 return mrSource.GetData()->IsInGroup(*pGroupData, nGroupIndex, rBaseData, nBaseIndex);
906 else
907 return false;
908}
909
910bool ScDPResultData::HasCommonElement( SCROW nFirstDataId, tools::Long nFirstIndex,
911 const ScDPItemData& rSecondData, tools::Long nSecondIndex ) const
912{
913 const ScDPItemData* pFirstData = mrSource.GetItemDataById(nFirstIndex , nFirstDataId);
914 if ( pFirstData )
915 return mrSource.GetData()->HasCommonElement(*pFirstData, nFirstIndex, rSecondData, nSecondIndex);
916 else
917 return false;
918}
919
921{
922 if (nDim < static_cast<tools::Long>(maDimMembers.size()) && maDimMembers[nDim])
923 return *maDimMembers[nDim];
924
925 if (nDim >= static_cast<tools::Long>(maDimMembers.size()))
926 maDimMembers.resize(nDim+1);
927
928 std::unique_ptr<ResultMembers> pResultMembers(new ResultMembers());
929 // global order is used to initialize aMembers, so it doesn't have to be looked at later
930 const ScMemberSortOrder& rGlobalOrder = pLevel->GetGlobalOrder();
931
932 ScDPMembers* pMembers = pLevel->GetMembersObject();
933 tools::Long nMembCount = pMembers->getCount();
934 for (tools::Long i = 0; i < nMembCount; ++i)
935 {
936 tools::Long nSorted = rGlobalOrder.empty() ? i : rGlobalOrder[i];
937 ScDPMember* pMember = pMembers->getByIndex(nSorted);
938 if (!pResultMembers->FindMember(pMember->GetItemDataId()))
939 {
940 ScDPParentDimData aNew(i, pDim, pLevel, pMember);
941 pResultMembers->InsertMember(aNew);
942 }
943 }
944
945 maDimMembers[nDim] = std::move(pResultMembers);
946 return *maDimMembers[nDim];
947}
948
950 const ScDPResultData* pData, const ScDPParentDimData& rParentDimData ) :
951 pResultData( pData ),
952 aParentDimData( rParentDimData ),
953 bHasElements( false ),
954 bForceSubTotal( false ),
955 bHasHiddenDetails( false ),
956 bInitialized( false ),
957 bAutoHidden( false ),
958 nMemberStep( 1 )
959{
960 // pParentLevel/pMemberDesc is 0 for root members
961}
962
964 const ScDPResultData* pData, bool bForceSub ) :
965 pResultData( pData ),
966 bHasElements( false ),
967 bForceSubTotal( bForceSub ),
968 bHasHiddenDetails( false ),
969 bInitialized( false ),
970 bAutoHidden( false ),
971 nMemberStep( 1 )
972{
973}
975{
976}
977
979{
980 const ScDPMember* pMemberDesc = GetDPMember();
981 if (pMemberDesc)
982 return pMemberDesc->GetNameStr( false );
983 else
984 return ScResId(STR_PIVOT_TOTAL); // root member
985}
986
987OUString ScDPResultMember::GetDisplayName( bool bLocaleIndependent ) const
988{
989 const ScDPMember* pDPMember = GetDPMember();
990 if (!pDPMember)
991 return OUString();
992
993 ScDPItemData aItem(pDPMember->FillItemData());
995 {
997 return pResultData->GetSource().GetData()->GetFormattedString(nDim, aItem, bLocaleIndependent);
998 }
999
1000 return aItem.GetString();
1001}
1002
1004{
1005 const ScDPMember* pMemberDesc = GetDPMember();
1006 if (pMemberDesc)
1007 return pMemberDesc->FillItemData();
1008 return ScDPItemData(ScResId(STR_PIVOT_TOTAL)); // root member
1009}
1010
1012{
1013 //TODO: store ScDPMember pointer instead of ScDPMember ???
1014 const ScDPMember* pMemberDesc = GetDPMember();
1015 if (pMemberDesc)
1016 return pMemberDesc->IsNamedItem(nIndex);
1017 return false;
1018}
1019
1020bool ScDPResultMember::IsValidEntry( const vector< SCROW >& aMembers ) const
1021{
1022 if ( !IsValid() )
1023 return false;
1024
1025 const ScDPResultDimension* pChildDim = GetChildDimension();
1026 if (pChildDim)
1027 {
1028 if (aMembers.size() < 2)
1029 return false;
1030
1031 vector<SCROW>::const_iterator itr = aMembers.begin();
1032 vector<SCROW> aChildMembers(++itr, aMembers.end());
1033 return pChildDim->IsValidEntry(aChildMembers);
1034 }
1035 else
1036 return true;
1037}
1038
1039void ScDPResultMember::InitFrom( const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLev,
1040 size_t nPos, ScDPInitState& rInitState ,
1041 bool bInitChild )
1042{
1043 // with LateInit, initialize only those members that have data
1044 if ( pResultData->IsLateInit() )
1045 return;
1046
1047 bInitialized = true;
1048
1049 if (nPos >= ppDim.size())
1050 return;
1051
1052 // skip child dimension if details are not shown
1053 if ( GetDPMember() && !GetDPMember()->getShowDetails() )
1054 {
1055 // Show DataLayout dimension
1056 nMemberStep = 1;
1057 while ( nPos < ppDim.size() )
1058 {
1059 if ( ppDim[nPos]->getIsDataLayoutDimension() )
1060 {
1061 if ( !pChildDimension )
1063 pChildDimension->InitFrom( ppDim, ppLev, nPos, rInitState , false );
1064 return;
1065 }
1066 else
1067 { //find next dim
1068 nPos ++;
1069 nMemberStep ++;
1070 }
1071 }
1072 bHasHiddenDetails = true; // only if there is a next dimension
1073 return;
1074 }
1075
1076 if ( bInitChild )
1077 {
1079 pChildDimension->InitFrom(ppDim, ppLev, nPos, rInitState);
1080 }
1081}
1082
1084 LateInitParams& rParams, const vector<SCROW>& pItemData, size_t nPos, ScDPInitState& rInitState)
1085{
1086 // without LateInit, everything has already been initialized
1087 if ( !pResultData->IsLateInit() )
1088 return;
1089
1090 bInitialized = true;
1091
1092 if ( rParams.IsEnd( nPos ) /*nPos >= ppDim.size()*/)
1093 // No next dimension. Bail out.
1094 return;
1095
1096 // skip child dimension if details are not shown
1097 if ( GetDPMember() && !GetDPMember()->getShowDetails() )
1098 {
1099 // Show DataLayout dimension
1100 nMemberStep = 1;
1101 while ( !rParams.IsEnd( nPos ) )
1102 {
1103 if ( rParams.GetDim( nPos )->getIsDataLayoutDimension() )
1104 {
1105 if ( !pChildDimension )
1107
1108 // #i111462# reset InitChild flag only for this child dimension's LateInitFrom call,
1109 // not for following members of parent dimensions
1110 bool bWasInitChild = rParams.GetInitChild();
1111 rParams.SetInitChild( false );
1112 pChildDimension->LateInitFrom( rParams, pItemData, nPos, rInitState );
1113 rParams.SetInitChild( bWasInitChild );
1114 return;
1115 }
1116 else
1117 { //find next dim
1118 nPos ++;
1119 nMemberStep ++;
1120 }
1121 }
1122 bHasHiddenDetails = true; // only if there is a next dimension
1123 return;
1124 }
1125
1126 // LateInitFrom is called several times...
1127 if ( rParams.GetInitChild() )
1128 {
1129 if ( !pChildDimension )
1131 pChildDimension->LateInitFrom( rParams, pItemData, nPos, rInitState );
1132 }
1133}
1134
1136{
1137 bool bRet = false;
1138 if ( pChildDimension && /*pParentLevel*/GetParentLevel() &&
1139 /*pParentLevel*/GetParentLevel()->IsOutlineLayout() && /*pParentLevel*/GetParentLevel()->IsSubtotalsAtTop() )
1140 {
1141 tools::Long nUserSubStart;
1142 tools::Long nSubTotals = GetSubTotalCount( &nUserSubStart );
1143 nSubTotals -= nUserSubStart; // visible count
1144 if ( nSubTotals )
1145 {
1146 if ( nMeasure == SC_DPMEASURE_ALL )
1147 nSubTotals *= pResultData->GetMeasureCount(); // number of subtotals that will be inserted
1148
1149 // only a single subtotal row will be shown in the outline title row
1150 if ( nSubTotals == 1 )
1151 bRet = true;
1152 }
1153 }
1154 return bRet;
1155}
1156
1158{
1159 if ( !IsVisible() )
1160 return 0;
1161 const ScDPLevel* pParentLevel = GetParentLevel();
1162 tools::Long nExtraSpace = 0;
1163 if ( pParentLevel && pParentLevel->IsAddEmpty() )
1164 ++nExtraSpace;
1165
1166 if ( pChildDimension )
1167 {
1168 // outline layout takes up an extra row for the title only if subtotals aren't shown in that row
1169 if ( pParentLevel && pParentLevel->IsOutlineLayout() && !IsSubTotalInTitle( nMeasure ) )
1170 ++nExtraSpace;
1171
1172 tools::Long nSize = pChildDimension->GetSize(nMeasure);
1173 tools::Long nUserSubStart;
1174 tools::Long nUserSubCount = GetSubTotalCount( &nUserSubStart );
1175 nUserSubCount -= nUserSubStart; // for output size, use visible count
1176 if ( nUserSubCount )
1177 {
1178 if ( nMeasure == SC_DPMEASURE_ALL )
1179 nSize += pResultData->GetMeasureCount() * nUserSubCount;
1180 else
1181 nSize += nUserSubCount;
1182 }
1183 return nSize + nExtraSpace;
1184 }
1185 else
1186 {
1187 if ( nMeasure == SC_DPMEASURE_ALL )
1188 return pResultData->GetMeasureCount() + nExtraSpace;
1189 else
1190 return 1 + nExtraSpace;
1191 }
1192}
1193
1195{
1196 if (!bInitialized)
1197 return false;
1198
1199 if (!IsValid())
1200 return false;
1201
1202 if (bHasElements)
1203 return true;
1204
1205 // not initialized -> shouldn't be there at all
1206 // (allocated only to preserve ordering)
1207 const ScDPLevel* pParentLevel = GetParentLevel();
1208
1209 return (pParentLevel && pParentLevel->getShowEmpty());
1210}
1211
1213{
1214 // non-Valid members are left out of calculation
1215
1216 // was member set no invisible at the DataPilotSource?
1217 const ScDPMember* pMemberDesc = GetDPMember();
1218 if ( pMemberDesc && !pMemberDesc->isVisible() )
1219 return false;
1220
1221 if ( bAutoHidden )
1222 return false;
1223
1224 return true;
1225}
1226
1228{
1229 if ( pUserSubStart )
1230 *pUserSubStart = 0; // default
1231
1232 const ScDPLevel* pParentLevel = GetParentLevel();
1233
1234 if ( bForceSubTotal ) // set if needed for root members
1235 return 1; // grand total is always "automatic"
1236 else if ( pParentLevel )
1237 {
1238 //TODO: direct access via ScDPLevel
1239
1240 uno::Sequence<sal_Int16> aSeq = pParentLevel->getSubTotals();
1241 tools::Long nSequence = aSeq.getLength();
1242 if ( nSequence && aSeq[0] != sheet::GeneralFunction2::AUTO )
1243 {
1244 // For manual subtotals, always add "automatic" as first function
1245 // (used for calculation, but not for display, needed for sorting, see lcl_GetForceFunc)
1246
1247 ++nSequence;
1248 if ( pUserSubStart )
1249 *pUserSubStart = 1; // visible subtotals start at 1
1250 }
1251 return nSequence;
1252 }
1253 else
1254 return 0;
1255}
1256
1257void ScDPResultMember::ProcessData( const vector< SCROW >& aChildMembers, const ScDPResultDimension* pDataDim,
1258 const vector< SCROW >& aDataMembers, const vector<ScDPValue>& aValues )
1259{
1261
1262 if (pChildDimension)
1263 pChildDimension->ProcessData( aChildMembers, pDataDim, aDataMembers, aValues );
1264
1265 if ( !pDataRoot )
1266 {
1267 pDataRoot.reset( new ScDPDataMember( pResultData, nullptr ) );
1268 if ( pDataDim )
1269 pDataRoot->InitFrom( pDataDim ); // recursive
1270 }
1271
1272 ScDPSubTotalState aSubState; // initial state
1273
1274 tools::Long nUserSubCount = GetSubTotalCount();
1275
1276 // Calculate at least automatic if no subtotals are selected,
1277 // show only own values if there's no child dimension (innermost).
1278 if ( !nUserSubCount || !pChildDimension )
1279 nUserSubCount = 1;
1280
1281 const ScDPLevel* pParentLevel = GetParentLevel();
1282
1283 for (tools::Long nUserPos=0; nUserPos<nUserSubCount; nUserPos++) // including hidden "automatic"
1284 {
1285 // #i68338# if nUserSubCount is 1 (automatic only), don't set nRowSubTotalFunc
1286 if ( pChildDimension && nUserSubCount > 1 )
1287 {
1288 aSubState.nRowSubTotalFunc = nUserPos;
1289 aSubState.eRowForce = lcl_GetForceFunc( pParentLevel, nUserPos );
1290 }
1291
1292 pDataRoot->ProcessData( aDataMembers, aValues, aSubState );
1293 }
1294}
1295
1300static OUString lcl_parseSubtotalName(std::u16string_view rSubStr, std::u16string_view rCaption)
1301{
1302 OUStringBuffer aNewStr;
1303 sal_Int32 n = rSubStr.size();
1304 bool bEscaped = false;
1305 for (sal_Int32 i = 0; i < n; ++i)
1306 {
1307 sal_Unicode c = rSubStr[i];
1308 if (!bEscaped && c == '\\')
1309 {
1310 bEscaped = true;
1311 continue;
1312 }
1313
1314 if (!bEscaped && c == '?')
1315 aNewStr.append(rCaption);
1316 else
1317 aNewStr.append(c);
1318 bEscaped = false;
1319 }
1320 return aNewStr.makeStringAndClear();
1321}
1322
1324 uno::Sequence<sheet::MemberResult>* pSequences, tools::Long& rPos, tools::Long nMeasure, bool bRoot,
1325 const OUString* pMemberName, const OUString* pMemberCaption )
1326{
1327 // IsVisible() test is in ScDPResultDimension::FillMemberResults
1328 // (not on data layout dimension)
1329
1330 if (!pSequences->hasElements())
1331 // empty sequence. Bail out.
1332 return;
1333
1334 tools::Long nSize = GetSize(nMeasure);
1335 sheet::MemberResult* pArray = pSequences->getArray();
1336 OSL_ENSURE( rPos+nSize <= pSequences->getLength(), "bumm" );
1337
1338 bool bIsNumeric = false;
1339 double fValue = std::numeric_limits<double>::quiet_NaN();
1340 OUString aName;
1341 if ( pMemberName ) // if pMemberName != NULL, use instead of real member name
1342 {
1343 aName = *pMemberName;
1344 }
1345 else
1346 {
1347 ScDPItemData aItemData(FillItemData());
1349 {
1351 aName = pResultData->GetSource().GetData()->GetFormattedString(nDim, aItemData, false);
1352 }
1353 else
1354 {
1355 tools::Long nDim = -1;
1356 const ScDPMember* pMem = GetDPMember();
1357 if (pMem)
1358 nDim = pMem->GetDim();
1359 aName = pResultData->GetSource().GetData()->GetFormattedString(nDim, aItemData, false);
1360 }
1361
1362 ScDPItemData::Type eType = aItemData.GetType();
1364 // IsValue() is not identical to bIsNumeric, i.e.
1365 // ScDPItemData::GroupValue is excluded and not stored in the double,
1366 // so even if the item is numeric the Value may be NaN.
1367 if (aItemData.IsValue())
1368 fValue = aItemData.GetValue();
1369 }
1370
1371 const ScDPDimension* pParentDim = GetParentDim();
1372 if ( bIsNumeric && pParentDim && pResultData->IsNumOrDateGroup( pParentDim->GetDimension() ) )
1373 {
1374 // Numeric group dimensions use numeric entries for proper sorting,
1375 // but the group titles must be output as text.
1376 bIsNumeric = false;
1377 }
1378
1379 OUString aCaption = aName;
1380 const ScDPMember* pMemberDesc = GetDPMember();
1381 if (pMemberDesc)
1382 {
1383 const std::optional<OUString> & pLayoutName = pMemberDesc->GetLayoutName();
1384 if (pLayoutName)
1385 {
1386 aCaption = *pLayoutName;
1387 bIsNumeric = false; // layout name is always non-numeric.
1388 }
1389 }
1390
1391 if ( pMemberCaption ) // use pMemberCaption if != NULL
1392 aCaption = *pMemberCaption;
1393 if (aCaption.isEmpty())
1394 aCaption = ScResId(STR_EMPTYDATA);
1395
1396 if (bIsNumeric)
1397 pArray[rPos].Flags |= sheet::MemberResultFlags::NUMERIC;
1398 else
1399 pArray[rPos].Flags &= ~sheet::MemberResultFlags::NUMERIC;
1400
1401 const ScDPLevel* pParentLevel = GetParentLevel();
1402 if ( nSize && !bRoot ) // root is overwritten by first dimension
1403 {
1404 pArray[rPos].Name = aName;
1405 pArray[rPos].Caption = aCaption;
1406 pArray[rPos].Flags |= sheet::MemberResultFlags::HASMEMBER;
1407 pArray[rPos].Value = fValue;
1408
1409 // set "continue" flag (removed for subtotals later)
1410 for (tools::Long i=1; i<nSize; i++)
1411 {
1412 pArray[rPos+i].Flags |= sheet::MemberResultFlags::CONTINUE;
1413 // tdf#113002 - add numeric flag to recurring data fields
1414 if (bIsNumeric)
1415 pArray[rPos + i].Flags |= sheet::MemberResultFlags::NUMERIC;
1416 }
1417
1418 if ( pParentLevel && pParentLevel->getRepeatItemLabels() )
1419 {
1420 tools::Long nSizeNonEmpty = nSize;
1421 if ( pParentLevel->IsAddEmpty() )
1422 --nSizeNonEmpty;
1423 for (tools::Long i=1; i<nSizeNonEmpty; i++)
1424 {
1425 pArray[rPos+i].Name = aName;
1426 pArray[rPos+i].Caption = aCaption;
1427 pArray[rPos+i].Flags |= sheet::MemberResultFlags::HASMEMBER;
1428 pArray[rPos+i].Value = fValue;
1429 }
1430 }
1431 }
1432
1433 tools::Long nExtraSpace = 0;
1434 if ( pParentLevel && pParentLevel->IsAddEmpty() )
1435 ++nExtraSpace;
1436
1437 bool bTitleLine = false;
1438 if ( pParentLevel && pParentLevel->IsOutlineLayout() )
1439 bTitleLine = true;
1440
1441 // if the subtotals are shown at the top (title row) in outline layout,
1442 // no extra row for the subtotals is needed
1443 bool bSubTotalInTitle = IsSubTotalInTitle( nMeasure );
1444
1445 bool bHasChild = ( pChildDimension != nullptr );
1446 if (bHasChild)
1447 {
1448 if ( bTitleLine ) // in tabular layout the title is on a separate row
1449 ++rPos; // -> fill child dimension one row below
1450
1451 if (bRoot) // same sequence for root member
1452 pChildDimension->FillMemberResults( pSequences, rPos, nMeasure );
1453 else
1454 pChildDimension->FillMemberResults( pSequences + nMemberStep/*1*/, rPos, nMeasure );
1455
1456 if ( bTitleLine ) // title row is included in GetSize, so the following
1457 --rPos; // positions are calculated with the normal values
1458 }
1459
1460 rPos += nSize;
1461
1462 tools::Long nUserSubStart;
1463 tools::Long nUserSubCount = GetSubTotalCount(&nUserSubStart);
1464 if ( !nUserSubCount || !pChildDimension || bSubTotalInTitle )
1465 return;
1466
1467 tools::Long nMemberMeasure = nMeasure;
1468 tools::Long nSubSize = pResultData->GetCountForMeasure(nMeasure);
1469
1470 rPos -= nSubSize * (nUserSubCount - nUserSubStart); // GetSize includes space for SubTotal
1471 rPos -= nExtraSpace; // GetSize includes the empty line
1472
1473 for (tools::Long nUserPos=nUserSubStart; nUserPos<nUserSubCount; nUserPos++)
1474 {
1475 for ( tools::Long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
1476 {
1477 if ( nMeasure == SC_DPMEASURE_ALL )
1478 nMemberMeasure = nSubCount;
1479
1481 if (bHasChild)
1482 eForce = lcl_GetForceFunc( pParentLevel, nUserPos );
1483
1484 bool bTotalResult = false;
1485 OUString aSubStr = aCaption + " " + pResultData->GetMeasureString(nMemberMeasure, false, eForce, bTotalResult);
1486
1487 if (bTotalResult)
1488 {
1489 if (pMemberDesc)
1490 {
1491 // single data field layout.
1492 const std::optional<OUString> & pSubtotalName = pParentDim->GetSubtotalName();
1493 if (pSubtotalName)
1494 aSubStr = lcl_parseSubtotalName(*pSubtotalName, aCaption);
1495 pArray[rPos].Flags &= ~sheet::MemberResultFlags::GRANDTOTAL;
1496 }
1497 else
1498 {
1499 // root member - subtotal (grand total?) for multi-data field layout.
1500 const std::optional<OUString> & pGrandTotalName = pResultData->GetSource().GetGrandTotalName();
1501 if (pGrandTotalName)
1502 aSubStr = *pGrandTotalName;
1503 pArray[rPos].Flags |= sheet::MemberResultFlags::GRANDTOTAL;
1504 }
1505 }
1506
1507 fValue = std::numeric_limits<double>::quiet_NaN(); /* TODO: any numeric value to obtain? */
1508 pArray[rPos].Name = aName;
1509 pArray[rPos].Caption = aSubStr;
1510 pArray[rPos].Flags = ( pArray[rPos].Flags |
1511 ( sheet::MemberResultFlags::HASMEMBER | sheet::MemberResultFlags::SUBTOTAL) ) &
1512 ~sheet::MemberResultFlags::CONTINUE;
1513 pArray[rPos].Value = fValue;
1514
1515 if ( nMeasure == SC_DPMEASURE_ALL )
1516 {
1517 // data layout dimension is (direct/indirect) child of this.
1518 // data layout dimension must have name for all entries.
1519
1520 uno::Sequence<sheet::MemberResult>* pLayoutSeq = pSequences;
1521 if (!bRoot)
1522 ++pLayoutSeq;
1523 ScDPResultDimension* pLayoutDim = pChildDimension.get();
1524 while ( pLayoutDim && !pLayoutDim->IsDataLayout() )
1525 {
1526 pLayoutDim = pLayoutDim->GetFirstChildDimension();
1527 ++pLayoutSeq;
1528 }
1529 if ( pLayoutDim )
1530 {
1531 sheet::MemberResult* pLayoutArray = pLayoutSeq->getArray();
1532 pLayoutArray[rPos].Name = pResultData->GetMeasureDimensionName(nMemberMeasure);
1533 }
1534 }
1535
1536 rPos += 1;
1537 }
1538 }
1539
1540 rPos += nExtraSpace; // add again (subtracted above)
1541}
1542
1544 const ScDPResultMember* pRefMember,
1545 ScDPResultFilterContext& rFilterCxt, uno::Sequence<uno::Sequence<sheet::DataResult> >& rSequence,
1546 tools::Long nMeasure) const
1547{
1548 std::unique_ptr<FilterStack> pFilterStack;
1549 const ScDPMember* pDPMember = GetDPMember();
1550 if (pDPMember)
1551 {
1552 // Root result has no corresponding DP member. Only take the non-root results.
1553 pFilterStack.reset(new FilterStack(rFilterCxt.maFilters));
1554 pFilterStack->pushDimValue( GetDisplayName( false), GetDisplayName( true));
1555 }
1556
1557 // IsVisible() test is in ScDPResultDimension::FillDataResults
1558 // (not on data layout dimension)
1559 const ScDPLevel* pParentLevel = GetParentLevel();
1560 sal_Int32 nStartRow = rFilterCxt.mnRow;
1561
1562 tools::Long nExtraSpace = 0;
1563 if ( pParentLevel && pParentLevel->IsAddEmpty() )
1564 ++nExtraSpace;
1565
1566 bool bTitleLine = false;
1567 if ( pParentLevel && pParentLevel->IsOutlineLayout() )
1568 bTitleLine = true;
1569
1570 bool bSubTotalInTitle = IsSubTotalInTitle( nMeasure );
1571
1572 bool bHasChild = ( pChildDimension != nullptr );
1573 if (bHasChild)
1574 {
1575 if ( bTitleLine ) // in tabular layout the title is on a separate row
1576 ++rFilterCxt.mnRow; // -> fill child dimension one row below
1577
1578 sal_Int32 nOldRow = rFilterCxt.mnRow;
1579 pChildDimension->FillDataResults(pRefMember, rFilterCxt, rSequence, nMeasure);
1580 rFilterCxt.mnRow = nOldRow; // Revert to the original row before the call.
1581
1582 rFilterCxt.mnRow += GetSize( nMeasure );
1583
1584 if ( bTitleLine ) // title row is included in GetSize, so the following
1585 --rFilterCxt.mnRow; // positions are calculated with the normal values
1586 }
1587
1588 tools::Long nUserSubStart;
1589 tools::Long nUserSubCount = GetSubTotalCount(&nUserSubStart);
1590 if ( !nUserSubCount && bHasChild )
1591 return;
1592
1593 // Calculate at least automatic if no subtotals are selected,
1594 // show only own values if there's no child dimension (innermost).
1595 if ( !nUserSubCount || !bHasChild )
1596 {
1597 nUserSubCount = 1;
1598 nUserSubStart = 0;
1599 }
1600
1601 tools::Long nMemberMeasure = nMeasure;
1602 tools::Long nSubSize = pResultData->GetCountForMeasure(nMeasure);
1603 if (bHasChild)
1604 {
1605 rFilterCxt.mnRow -= nSubSize * ( nUserSubCount - nUserSubStart ); // GetSize includes space for SubTotal
1606 rFilterCxt.mnRow -= nExtraSpace; // GetSize includes the empty line
1607 }
1608
1609 tools::Long nMoveSubTotal = 0;
1610 if ( bSubTotalInTitle )
1611 {
1612 nMoveSubTotal = rFilterCxt.mnRow - nStartRow; // force to first (title) row
1613 rFilterCxt.mnRow = nStartRow;
1614 }
1615
1616 if ( pDataRoot )
1617 {
1618 ScDPSubTotalState aSubState; // initial state
1619
1620 for (tools::Long nUserPos=nUserSubStart; nUserPos<nUserSubCount; nUserPos++)
1621 {
1622 if ( bHasChild && nUserSubCount > 1 )
1623 {
1624 aSubState.nRowSubTotalFunc = nUserPos;
1625 aSubState.eRowForce = lcl_GetForceFunc( /*pParentLevel*/GetParentLevel() , nUserPos );
1626 }
1627
1628 for ( tools::Long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
1629 {
1630 if ( nMeasure == SC_DPMEASURE_ALL )
1631 nMemberMeasure = nSubCount;
1633 nMemberMeasure = SC_DPMEASURE_ALL;
1634
1635 OSL_ENSURE( rFilterCxt.mnRow < rSequence.getLength(), "bumm" );
1636 rFilterCxt.mnCol = 0;
1637 if (pRefMember->IsVisible())
1638 {
1639 uno::Sequence<sheet::DataResult>& rSubSeq = rSequence.getArray()[rFilterCxt.mnRow];
1640 pDataRoot->FillDataRow(pRefMember, rFilterCxt, rSubSeq, nMemberMeasure, bHasChild, aSubState);
1641 }
1642 rFilterCxt.mnRow += 1;
1643 }
1644 }
1645 }
1646 else
1647 rFilterCxt.mnRow += nSubSize * ( nUserSubCount - nUserSubStart ); // empty rows occur when ShowEmpty is true
1648
1649 // add extra space again if subtracted from GetSize above,
1650 // add to own size if no children
1651 rFilterCxt.mnRow += nExtraSpace;
1652 rFilterCxt.mnRow += nMoveSubTotal;
1653}
1654
1656{
1657 // IsVisible() test is in ScDPResultDimension::FillDataResults
1658 // (not on data layout dimension)
1659
1660 bool bHasChild = ( pChildDimension != nullptr );
1661
1662 tools::Long nUserSubCount = GetSubTotalCount();
1663
1664 // process subtotals even if not shown
1665
1666 // Calculate at least automatic if no subtotals are selected,
1667 // show only own values if there's no child dimension (innermost).
1668 if (!nUserSubCount || !bHasChild)
1669 nUserSubCount = 1;
1670
1671 tools::Long nMemberMeasure = nMeasure;
1672 tools::Long nSubSize = pResultData->GetCountForMeasure(nMeasure);
1673
1674 if (pDataRoot)
1675 {
1676 ScDPSubTotalState aSubState; // initial state
1677
1678 for (tools::Long nUserPos = 0; nUserPos < nUserSubCount; ++nUserPos) // including hidden "automatic"
1679 {
1680 if (bHasChild && nUserSubCount > 1)
1681 {
1682 aSubState.nRowSubTotalFunc = nUserPos;
1683 aSubState.eRowForce = lcl_GetForceFunc(GetParentLevel(), nUserPos);
1684 }
1685
1686 for (tools::Long nSubCount = 0; nSubCount < nSubSize; ++nSubCount)
1687 {
1688 if (nMeasure == SC_DPMEASURE_ALL)
1689 nMemberMeasure = nSubCount;
1691 nMemberMeasure = SC_DPMEASURE_ALL;
1692
1693 pDataRoot->UpdateDataRow(pRefMember, nMemberMeasure, bHasChild, aSubState);
1694 }
1695 }
1696 }
1697
1698 if (bHasChild) // child dimension must be processed last, so the column total is known
1699 {
1700 pChildDimension->UpdateDataResults( pRefMember, nMeasure );
1701 }
1702}
1703
1705{
1706 bool bHasChild = ( pChildDimension != nullptr );
1707 if (bHasChild)
1708 pChildDimension->SortMembers( pRefMember ); // sorting is done at the dimension
1709
1710 if ( IsRoot() && pDataRoot )
1711 {
1712 // use the row root member to sort columns
1713 // sub total count is always 1
1714
1715 pDataRoot->SortMembers( pRefMember );
1716 }
1717}
1718
1720{
1721 bool bHasChild = ( pChildDimension != nullptr );
1722 if (bHasChild)
1723 pChildDimension->DoAutoShow( pRefMember ); // sorting is done at the dimension
1724
1725 if ( IsRoot()&& pDataRoot )
1726 {
1727 // use the row root member to sort columns
1728 // sub total count is always 1
1729
1730 pDataRoot->DoAutoShow( pRefMember );
1731 }
1732}
1733
1735{
1736 if (pDataRoot)
1737 pDataRoot->ResetResults();
1738
1739 if (pChildDimension)
1740 pChildDimension->ResetResults();
1741}
1742
1744 ScDPRunningTotalState& rRunning, ScDPRowTotals& rTotals ) const
1745{
1746 // IsVisible() test is in ScDPResultDimension::FillDataResults
1747 // (not on data layout dimension)
1748
1749 rTotals.SetInColRoot( IsRoot() );
1750
1751 bool bHasChild = ( pChildDimension != nullptr );
1752
1753 tools::Long nUserSubCount = GetSubTotalCount();
1754 //if ( nUserSubCount || !bHasChild )
1755 {
1756 // Calculate at least automatic if no subtotals are selected,
1757 // show only own values if there's no child dimension (innermost).
1758 if ( !nUserSubCount || !bHasChild )
1759 nUserSubCount = 1;
1760
1761 tools::Long nMemberMeasure = nMeasure;
1762 tools::Long nSubSize = pResultData->GetCountForMeasure(nMeasure);
1763
1764 if ( pDataRoot )
1765 {
1766 ScDPSubTotalState aSubState; // initial state
1767
1768 for (tools::Long nUserPos=0; nUserPos<nUserSubCount; nUserPos++) // including hidden "automatic"
1769 {
1770 if ( bHasChild && nUserSubCount > 1 )
1771 {
1772 aSubState.nRowSubTotalFunc = nUserPos;
1773 aSubState.eRowForce = lcl_GetForceFunc(GetParentLevel(), nUserPos);
1774 }
1775
1776 for ( tools::Long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
1777 {
1778 if ( nMeasure == SC_DPMEASURE_ALL )
1779 nMemberMeasure = nSubCount;
1781 nMemberMeasure = SC_DPMEASURE_ALL;
1782
1783 if (pRefMember->IsVisible())
1784 pDataRoot->UpdateRunningTotals(
1785 pRefMember, nMemberMeasure, bHasChild, aSubState, rRunning, rTotals, *this);
1786 }
1787 }
1788 }
1789 }
1790
1791 if (bHasChild) // child dimension must be processed last, so the column total is known
1792 {
1793 pChildDimension->UpdateRunningTotals( pRefMember, nMeasure, rRunning, rTotals );
1794 }
1795}
1796
1797#if DUMP_PIVOT_TABLE
1798void ScDPResultMember::DumpState( const ScDPResultMember* pRefMember, ScDocument* pDoc, ScAddress& rPos ) const
1799{
1800 dumpRow("ScDPResultMember", GetName(), nullptr, pDoc, rPos);
1801 SCROW nStartRow = rPos.Row();
1802
1803 if (pDataRoot)
1804 pDataRoot->DumpState( pRefMember, pDoc, rPos );
1805
1806 if (pChildDimension)
1807 pChildDimension->DumpState( pRefMember, pDoc, rPos );
1808
1809 indent(pDoc, nStartRow, rPos);
1810}
1811
1812void ScDPResultMember::Dump(int nIndent) const
1813{
1814 std::string aIndent(nIndent*2, ' ');
1815 std::cout << aIndent << "-- result member '" << GetName() << "'" << std::endl;
1816
1817 std::cout << aIndent << " column totals" << std::endl;
1818 for (const ScDPAggData* p = &aColTotal; p; p = p->GetExistingChild())
1819 p->Dump(nIndent+1);
1820
1821 if (pChildDimension)
1822 pChildDimension->Dump(nIndent+1);
1823
1824 if (pDataRoot)
1825 {
1826 std::cout << aIndent << " data root" << std::endl;
1827 pDataRoot->Dump(nIndent+1);
1828 }
1829}
1830#endif
1831
1833{
1834 return lcl_GetChildTotal( const_cast<ScDPAggData*>(&aColTotal), nMeasure );
1835}
1836
1838{
1839 if (pChildDimension)
1840 pChildDimension->FillVisibilityData(rData);
1841}
1842
1844 pResultData( pData ),
1845 pResultMember( pRes )
1846{
1847 // pResultMember is 0 for root members
1848}
1849
1851{
1852}
1853
1855{
1856 if (pResultMember)
1857 return pResultMember->GetName();
1858 else
1859 return OUString();
1860}
1861
1863{
1864 if (pResultMember)
1865 return pResultMember->IsVisible();
1866 else
1867 return false;
1868}
1869
1871{
1872 if (pResultMember)
1873 return pResultMember->IsNamedItem(nRow);
1874 else
1875 return false;
1876}
1877
1879{
1880 if (pResultMember)
1882 else
1883 return false;
1884}
1885
1887{
1888 if ( !pChildDimension )
1890 pChildDimension->InitFrom(pDim);
1891}
1892
1893const tools::Long SC_SUBTOTALPOS_AUTO = -1; // default
1894const tools::Long SC_SUBTOTALPOS_SKIP = -2; // don't use
1895
1897{
1898 if ( rSubState.nColSubTotalFunc >= 0 && rSubState.nRowSubTotalFunc >= 0 &&
1899 rSubState.nColSubTotalFunc != rSubState.nRowSubTotalFunc )
1900 {
1901 // #i68338# don't return the same index for different combinations (leading to repeated updates),
1902 // return a "don't use" value instead
1903
1904 return SC_SUBTOTALPOS_SKIP;
1905 }
1906
1908 if ( rSubState.nColSubTotalFunc >= 0 ) nRet = rSubState.nColSubTotalFunc;
1909 if ( rSubState.nRowSubTotalFunc >= 0 ) nRet = rSubState.nRowSubTotalFunc;
1910 return nRet;
1911}
1912
1913void ScDPDataMember::UpdateValues( const vector<ScDPValue>& aValues, const ScDPSubTotalState& rSubState )
1914{
1915 //TODO: find out how many and which subtotals are used
1916
1917 ScDPAggData* pAgg = &aAggregate;
1918
1919 tools::Long nSubPos = lcl_GetSubTotalPos(rSubState);
1920 if (nSubPos == SC_SUBTOTALPOS_SKIP)
1921 return;
1922 if (nSubPos > 0)
1923 {
1924 tools::Long nSkip = nSubPos * pResultData->GetMeasureCount();
1925 for (tools::Long i=0; i<nSkip; i++)
1926 pAgg = pAgg->GetChild(); // created if not there
1927 }
1928
1929 size_t nCount = aValues.size();
1930 for (size_t nPos = 0; nPos < nCount; ++nPos)
1931 {
1932 pAgg->Update(aValues[nPos], pResultData->GetMeasureFunction(nPos), rSubState);
1933 pAgg = pAgg->GetChild();
1934 }
1935}
1936
1937void ScDPDataMember::ProcessData( const vector< SCROW >& aChildMembers, const vector<ScDPValue>& aValues,
1938 const ScDPSubTotalState& rSubState )
1939{
1941 {
1942 // if this DataMember doesn't have a child dimension because the ResultMember's
1943 // child dimension wasn't there yet during this DataMembers's creation,
1944 // create the child dimension now
1946 }
1947
1949
1950 // Calculate at least automatic if no subtotals are selected,
1951 // show only own values if there's no child dimension (innermost).
1952 if ( !nUserSubCount || !pChildDimension )
1953 nUserSubCount = 1;
1954
1955 ScDPSubTotalState aLocalSubState = rSubState; // keep row state, modify column
1956 for (tools::Long nUserPos=0; nUserPos<nUserSubCount; nUserPos++) // including hidden "automatic"
1957 {
1958 if ( pChildDimension && nUserSubCount > 1 )
1959 {
1960 const ScDPLevel* pForceLevel = pResultMember ? pResultMember->GetParentLevel() : nullptr;
1961 aLocalSubState.nColSubTotalFunc = nUserPos;
1962 aLocalSubState.eColForce = lcl_GetForceFunc( pForceLevel, nUserPos );
1963 }
1964
1965 UpdateValues( aValues, aLocalSubState );
1966 }
1967
1968 if (pChildDimension)
1969 pChildDimension->ProcessData( aChildMembers, aValues, rSubState ); // with unmodified subtotal state
1970}
1971
1972bool ScDPDataMember::HasData( tools::Long nMeasure, const ScDPSubTotalState& rSubState ) const
1973{
1974 if ( rSubState.eColForce != SUBTOTAL_FUNC_NONE && rSubState.eRowForce != SUBTOTAL_FUNC_NONE &&
1975 rSubState.eColForce != rSubState.eRowForce )
1976 return false;
1977
1978 // HasData can be different between measures!
1979
1980 const ScDPAggData* pAgg = GetConstAggData( nMeasure, rSubState );
1981 if (!pAgg)
1982 return false; //TODO: error?
1983
1984 return pAgg->HasData();
1985}
1986
1987bool ScDPDataMember::HasError( tools::Long nMeasure, const ScDPSubTotalState& rSubState ) const
1988{
1989 const ScDPAggData* pAgg = GetConstAggData( nMeasure, rSubState );
1990 if (!pAgg)
1991 return true;
1992
1993 return pAgg->HasError();
1994}
1995
1996double ScDPDataMember::GetAggregate( tools::Long nMeasure, const ScDPSubTotalState& rSubState ) const
1997{
1998 const ScDPAggData* pAgg = GetConstAggData( nMeasure, rSubState );
1999 if (!pAgg)
2000 return DBL_MAX; //TODO: error?
2001
2002 return pAgg->GetResult();
2003}
2004
2006{
2007 OSL_ENSURE( nMeasure >= 0, "GetAggData: no measure" );
2008
2009 ScDPAggData* pAgg = &aAggregate;
2010 tools::Long nSkip = nMeasure;
2011 tools::Long nSubPos = lcl_GetSubTotalPos(rSubState);
2012 if (nSubPos == SC_SUBTOTALPOS_SKIP)
2013 return nullptr;
2014 if (nSubPos > 0)
2015 nSkip += nSubPos * pResultData->GetMeasureCount();
2016
2017 for ( tools::Long nPos=0; nPos<nSkip; nPos++ )
2018 pAgg = pAgg->GetChild(); //TODO: need to create children here?
2019
2020 return pAgg;
2021}
2022
2024{
2025 OSL_ENSURE( nMeasure >= 0, "GetConstAggData: no measure" );
2026
2027 const ScDPAggData* pAgg = &aAggregate;
2028 tools::Long nSkip = nMeasure;
2029 tools::Long nSubPos = lcl_GetSubTotalPos(rSubState);
2030 if (nSubPos == SC_SUBTOTALPOS_SKIP)
2031 return nullptr;
2032 if (nSubPos > 0)
2033 nSkip += nSubPos * pResultData->GetMeasureCount();
2034
2035 for ( tools::Long nPos=0; nPos<nSkip; nPos++ )
2036 {
2037 pAgg = pAgg->GetExistingChild();
2038 if (!pAgg)
2039 return nullptr;
2040 }
2041
2042 return pAgg;
2043}
2044
2046 const ScDPResultMember* pRefMember, ScDPResultFilterContext& rFilterCxt,
2047 uno::Sequence<sheet::DataResult>& rSequence, tools::Long nMeasure, bool bIsSubTotalRow,
2048 const ScDPSubTotalState& rSubState) const
2049{
2050 std::unique_ptr<FilterStack> pFilterStack;
2051 if (pResultMember)
2052 {
2053 // Topmost data member (pResultMember=NULL) doesn't need to be handled
2054 // since its immediate parent result member is linked to the same
2055 // dimension member.
2056 pFilterStack.reset(new FilterStack(rFilterCxt.maFilters));
2057 pFilterStack->pushDimValue( pResultMember->GetDisplayName( false), pResultMember->GetDisplayName( true));
2058 }
2059
2060 OSL_ENSURE( pRefMember == pResultMember || !pResultMember, "bla" );
2061
2062 tools::Long nStartCol = rFilterCxt.mnCol;
2063
2064 const ScDPDataDimension* pDataChild = GetChildDimension();
2065 const ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();
2066
2067 const ScDPLevel* pRefParentLevel = pRefMember->GetParentLevel();
2068
2069 tools::Long nExtraSpace = 0;
2070 if ( pRefParentLevel && pRefParentLevel->IsAddEmpty() )
2071 ++nExtraSpace;
2072
2073 bool bTitleLine = false;
2074 if ( pRefParentLevel && pRefParentLevel->IsOutlineLayout() )
2075 bTitleLine = true;
2076
2077 bool bSubTotalInTitle = pRefMember->IsSubTotalInTitle( nMeasure );
2078
2079 // leave space for children even if the DataMember hasn't been initialized
2080 // (pDataChild is null then, this happens when no values for it are in this row)
2081 bool bHasChild = ( pRefChild != nullptr );
2082
2083 if ( bHasChild )
2084 {
2085 if ( bTitleLine ) // in tabular layout the title is on a separate column
2086 ++rFilterCxt.mnCol; // -> fill child dimension one column below
2087
2088 if ( pDataChild )
2089 {
2090 tools::Long nOldCol = rFilterCxt.mnCol;
2091 pDataChild->FillDataRow(pRefChild, rFilterCxt, rSequence, nMeasure, bIsSubTotalRow, rSubState);
2092 rFilterCxt.mnCol = nOldCol; // Revert to the old column value before the call.
2093 }
2094 rFilterCxt.mnCol += static_cast<sal_uInt16>(pRefMember->GetSize( nMeasure ));
2095
2096 if ( bTitleLine ) // title column is included in GetSize, so the following
2097 --rFilterCxt.mnCol; // positions are calculated with the normal values
2098 }
2099
2100 tools::Long nUserSubStart;
2101 tools::Long nUserSubCount = pRefMember->GetSubTotalCount(&nUserSubStart);
2102 if ( !nUserSubCount && bHasChild )
2103 return;
2104
2105 // Calculate at least automatic if no subtotals are selected,
2106 // show only own values if there's no child dimension (innermost).
2107 if ( !nUserSubCount || !bHasChild )
2108 {
2109 nUserSubCount = 1;
2110 nUserSubStart = 0;
2111 }
2112
2113 ScDPSubTotalState aLocalSubState(rSubState); // keep row state, modify column
2114
2115 tools::Long nMemberMeasure = nMeasure;
2116 tools::Long nSubSize = pResultData->GetCountForMeasure(nMeasure);
2117 if (bHasChild)
2118 {
2119 rFilterCxt.mnCol -= nSubSize * ( nUserSubCount - nUserSubStart ); // GetSize includes space for SubTotal
2120 rFilterCxt.mnCol -= nExtraSpace; // GetSize includes the empty line
2121 }
2122
2123 tools::Long nMoveSubTotal = 0;
2124 if ( bSubTotalInTitle )
2125 {
2126 nMoveSubTotal = rFilterCxt.mnCol - nStartCol; // force to first (title) column
2127 rFilterCxt.mnCol = nStartCol;
2128 }
2129
2130 for (tools::Long nUserPos=nUserSubStart; nUserPos<nUserSubCount; nUserPos++)
2131 {
2132 if ( pChildDimension && nUserSubCount > 1 )
2133 {
2134 const ScDPLevel* pForceLevel = pResultMember ? pResultMember->GetParentLevel() : nullptr;
2135 aLocalSubState.nColSubTotalFunc = nUserPos;
2136 aLocalSubState.eColForce = lcl_GetForceFunc( pForceLevel, nUserPos );
2137 }
2138
2139 for ( tools::Long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
2140 {
2141 if ( nMeasure == SC_DPMEASURE_ALL )
2142 nMemberMeasure = nSubCount;
2143
2144 OSL_ENSURE( rFilterCxt.mnCol < rSequence.getLength(), "bumm" );
2145 sheet::DataResult& rRes = rSequence.getArray()[rFilterCxt.mnCol];
2146
2147 if ( HasData( nMemberMeasure, aLocalSubState ) )
2148 {
2149 if ( HasError( nMemberMeasure, aLocalSubState ) )
2150 {
2151 rRes.Value = 0;
2152 rRes.Flags |= sheet::DataResultFlags::ERROR;
2153 }
2154 else
2155 {
2156 rRes.Value = GetAggregate( nMemberMeasure, aLocalSubState );
2157 rRes.Flags |= sheet::DataResultFlags::HASDATA;
2158 }
2159 }
2160
2161 if ( bHasChild || bIsSubTotalRow )
2162 rRes.Flags |= sheet::DataResultFlags::SUBTOTAL;
2163
2164 rFilterCxt.maFilterSet.add(rFilterCxt.maFilters, rRes.Value);
2165 rFilterCxt.mnCol += 1;
2166 }
2167 }
2168
2169 // add extra space again if subtracted from GetSize above,
2170 // add to own size if no children
2171 rFilterCxt.mnCol += nExtraSpace;
2172 rFilterCxt.mnCol += nMoveSubTotal;
2173}
2174
2176 const ScDPResultMember* pRefMember, tools::Long nMeasure, bool bIsSubTotalRow,
2177 const ScDPSubTotalState& rSubState )
2178{
2179 OSL_ENSURE( pRefMember == pResultMember || !pResultMember, "bla" );
2180
2181 // Calculate must be called even if not visible (for use as reference value)
2182 const ScDPDataDimension* pDataChild = GetChildDimension();
2183 const ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();
2184
2185 // leave space for children even if the DataMember hasn't been initialized
2186 // (pDataChild is null then, this happens when no values for it are in this row)
2187 bool bHasChild = ( pRefChild != nullptr );
2188
2189 // process subtotals even if not shown
2190 tools::Long nUserSubCount = pRefMember->GetSubTotalCount();
2191
2192 // Calculate at least automatic if no subtotals are selected,
2193 // show only own values if there's no child dimension (innermost).
2194 if ( !nUserSubCount || !bHasChild )
2195 nUserSubCount = 1;
2196
2197 ScDPSubTotalState aLocalSubState(rSubState); // keep row state, modify column
2198
2199 tools::Long nMemberMeasure = nMeasure;
2200 tools::Long nSubSize = pResultData->GetCountForMeasure(nMeasure);
2201
2202 for (tools::Long nUserPos=0; nUserPos<nUserSubCount; nUserPos++) // including hidden "automatic"
2203 {
2204 if ( pChildDimension && nUserSubCount > 1 )
2205 {
2206 const ScDPLevel* pForceLevel = pResultMember ? pResultMember->GetParentLevel() : nullptr;
2207 aLocalSubState.nColSubTotalFunc = nUserPos;
2208 aLocalSubState.eColForce = lcl_GetForceFunc( pForceLevel, nUserPos );
2209 }
2210
2211 for ( tools::Long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
2212 {
2213 if ( nMeasure == SC_DPMEASURE_ALL )
2214 nMemberMeasure = nSubCount;
2215
2216 // update data...
2217 ScDPAggData* pAggData = GetAggData( nMemberMeasure, aLocalSubState );
2218 if (pAggData)
2219 {
2220 //TODO: aLocalSubState?
2221 ScSubTotalFunc eFunc = pResultData->GetMeasureFunction( nMemberMeasure );
2222 sheet::DataPilotFieldReference aReferenceValue = pResultData->GetMeasureRefVal( nMemberMeasure );
2223 sal_Int32 eRefType = aReferenceValue.ReferenceType;
2224
2225 // calculate the result first - for all members, regardless of reference value
2226 pAggData->Calculate( eFunc, aLocalSubState );
2227
2228 if ( eRefType == sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE ||
2229 eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE ||
2230 eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE )
2231 {
2232 // copy the result into auxiliary value, so differences can be
2233 // calculated in any order
2234 pAggData->SetAuxiliary( pAggData->GetResult() );
2235 }
2236 // column/row percentage/index is now in UpdateRunningTotals, so it doesn't disturb sorting
2237 }
2238 }
2239 }
2240
2241 if ( bHasChild ) // child dimension must be processed last, so the row total is known
2242 {
2243 if ( pDataChild )
2244 pDataChild->UpdateDataRow( pRefChild, nMeasure, bIsSubTotalRow, rSubState );
2245 }
2246}
2247
2249{
2250 OSL_ENSURE( pRefMember == pResultMember || !pResultMember, "bla" );
2251
2252 if ( pRefMember->IsVisible() ) //TODO: here or in ScDPDataDimension ???
2253 {
2254 ScDPDataDimension* pDataChild = GetChildDimension();
2255 ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();
2256 if ( pRefChild && pDataChild )
2257 pDataChild->SortMembers( pRefChild ); // sorting is done at the dimension
2258 }
2259}
2260
2262{
2263 OSL_ENSURE( pRefMember == pResultMember || !pResultMember, "bla" );
2264
2265 if ( pRefMember->IsVisible() ) //TODO: here or in ScDPDataDimension ???
2266 {
2267 ScDPDataDimension* pDataChild = GetChildDimension();
2268 ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();
2269 if ( pRefChild && pDataChild )
2270 pDataChild->DoAutoShow( pRefChild ); // sorting is done at the dimension
2271 }
2272}
2273
2275{
2276 aAggregate.Reset();
2277
2278 ScDPDataDimension* pDataChild = GetChildDimension();
2279 if ( pDataChild )
2280 pDataChild->ResetResults();
2281}
2282
2284 const ScDPResultMember* pRefMember, tools::Long nMeasure, bool bIsSubTotalRow,
2285 const ScDPSubTotalState& rSubState, ScDPRunningTotalState& rRunning,
2286 ScDPRowTotals& rTotals, const ScDPResultMember& rRowParent )
2287{
2288 OSL_ENSURE( pRefMember == pResultMember || !pResultMember, "bla" );
2289
2290 const ScDPDataDimension* pDataChild = GetChildDimension();
2291 const ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();
2292
2293 bool bIsRoot = ( pResultMember == nullptr || pResultMember->GetParentLevel() == nullptr );
2294
2295 // leave space for children even if the DataMember hasn't been initialized
2296 // (pDataChild is null then, this happens when no values for it are in this row)
2297 bool bHasChild = ( pRefChild != nullptr );
2298
2299 tools::Long nUserSubCount = pRefMember->GetSubTotalCount();
2300 {
2301 // Calculate at least automatic if no subtotals are selected,
2302 // show only own values if there's no child dimension (innermost).
2303 if ( !nUserSubCount || !bHasChild )
2304 nUserSubCount = 1;
2305
2306 ScDPSubTotalState aLocalSubState(rSubState); // keep row state, modify column
2307
2308 tools::Long nMemberMeasure = nMeasure;
2309 tools::Long nSubSize = pResultData->GetCountForMeasure(nMeasure);
2310
2311 for (tools::Long nUserPos=0; nUserPos<nUserSubCount; nUserPos++) // including hidden "automatic"
2312 {
2313 if ( pChildDimension && nUserSubCount > 1 )
2314 {
2315 const ScDPLevel* pForceLevel = pResultMember ? pResultMember->GetParentLevel() : nullptr;
2316 aLocalSubState.nColSubTotalFunc = nUserPos;
2317 aLocalSubState.eColForce = lcl_GetForceFunc( pForceLevel, nUserPos );
2318 }
2319
2320 for ( tools::Long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
2321 {
2322 if ( nMeasure == SC_DPMEASURE_ALL )
2323 nMemberMeasure = nSubCount;
2324
2325 // update data...
2326 ScDPAggData* pAggData = GetAggData( nMemberMeasure, aLocalSubState );
2327 if (pAggData)
2328 {
2329 //TODO: aLocalSubState?
2330 sheet::DataPilotFieldReference aReferenceValue = pResultData->GetMeasureRefVal( nMemberMeasure );
2331 sal_Int32 eRefType = aReferenceValue.ReferenceType;
2332
2333 if ( eRefType == sheet::DataPilotFieldReferenceType::RUNNING_TOTAL ||
2334 eRefType == sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE ||
2335 eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE ||
2336 eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE )
2337 {
2338 bool bRunningTotal = ( eRefType == sheet::DataPilotFieldReferenceType::RUNNING_TOTAL );
2339 bool bRelative =
2340 ( aReferenceValue.ReferenceItemType != sheet::DataPilotFieldReferenceItemType::NAMED && !bRunningTotal );
2341 tools::Long nRelativeDir = bRelative ?
2342 ( ( aReferenceValue.ReferenceItemType == sheet::DataPilotFieldReferenceItemType::PREVIOUS ) ? -1 : 1 ) : 0;
2343
2344 const ScDPRunningTotalState::IndexArray& rColVisible = rRunning.GetColVisible();
2345 const ScDPRunningTotalState::IndexArray& rColSorted = rRunning.GetColSorted();
2346 const ScDPRunningTotalState::IndexArray& rRowVisible = rRunning.GetRowVisible();
2347 const ScDPRunningTotalState::IndexArray& rRowSorted = rRunning.GetRowSorted();
2348
2349 OUString aRefFieldName = aReferenceValue.ReferenceField;
2350
2351 //TODO: aLocalSubState?
2352 sheet::DataPilotFieldOrientation nRefOrient = pResultData->GetMeasureRefOrient( nMemberMeasure );
2353 bool bRefDimInCol = ( nRefOrient == sheet::DataPilotFieldOrientation_COLUMN );
2354 bool bRefDimInRow = ( nRefOrient == sheet::DataPilotFieldOrientation_ROW );
2355
2356 ScDPResultDimension* pSelectDim = nullptr;
2357 sal_Int32 nRowPos = 0;
2358 sal_Int32 nColPos = 0;
2359
2360 // find the reference field in column or row dimensions
2361
2362 if ( bRefDimInRow ) // look in row dimensions
2363 {
2364 pSelectDim = rRunning.GetRowResRoot()->GetChildDimension();
2365 while ( pSelectDim && pSelectDim->GetName() != aRefFieldName )
2366 {
2367 tools::Long nIndex = rRowSorted[nRowPos];
2368 if ( nIndex >= 0 && nIndex < pSelectDim->GetMemberCount() )
2369 pSelectDim = pSelectDim->GetMember(nIndex)->GetChildDimension();
2370 else
2371 pSelectDim = nullptr;
2372 ++nRowPos;
2373 }
2374 // child dimension of innermost member?
2375 if ( pSelectDim && rRowSorted[nRowPos] < 0 )
2376 pSelectDim = nullptr;
2377 }
2378
2379 if ( bRefDimInCol ) // look in column dimensions
2380 {
2381 pSelectDim = rRunning.GetColResRoot()->GetChildDimension();
2382 while ( pSelectDim && pSelectDim->GetName() != aRefFieldName )
2383 {
2384 tools::Long nIndex = rColSorted[nColPos];
2385 if ( nIndex >= 0 && nIndex < pSelectDim->GetMemberCount() )
2386 pSelectDim = pSelectDim->GetMember(nIndex)->GetChildDimension();
2387 else
2388 pSelectDim = nullptr;
2389 ++nColPos;
2390 }
2391 // child dimension of innermost member?
2392 if ( pSelectDim && rColSorted[nColPos] < 0 )
2393 pSelectDim = nullptr;
2394 }
2395
2396 bool bNoDetailsInRef = false;
2397 if ( pSelectDim && bRunningTotal )
2398 {
2399 // Running totals:
2400 // If details are hidden for this member in the reference dimension,
2401 // don't show or sum up the value. Otherwise, for following members,
2402 // the running totals of details and subtotals wouldn't match.
2403
2404 tools::Long nMyIndex = bRefDimInCol ? rColSorted[nColPos] : rRowSorted[nRowPos];
2405 if ( nMyIndex >= 0 && nMyIndex < pSelectDim->GetMemberCount() )
2406 {
2407 const ScDPResultMember* pMyRefMember = pSelectDim->GetMember(nMyIndex);
2408 if ( pMyRefMember && pMyRefMember->HasHiddenDetails() )
2409 {
2410 pSelectDim = nullptr; // don't calculate
2411 bNoDetailsInRef = true; // show error, not empty
2412 }
2413 }
2414 }
2415
2416 if ( bRelative )
2417 {
2418 // Difference/Percentage from previous/next:
2419 // If details are hidden for this member in the innermost column/row
2420 // dimension (the orientation of the reference dimension), show an
2421 // error value.
2422 // - If the no-details dimension is the reference dimension, its
2423 // members will be skipped when finding the previous/next member,
2424 // so there must be no results for its members.
2425 // - If the no-details dimension is outside of the reference dimension,
2426 // no calculation in the reference dimension is possible.
2427 // - Otherwise, the error isn't strictly necessary, but shown for
2428 // consistency.
2429
2430 bool bInnerNoDetails = bRefDimInCol ? HasHiddenDetails() :
2431 ( !bRefDimInRow || rRowParent.HasHiddenDetails() );
2432 if ( bInnerNoDetails )
2433 {
2434 pSelectDim = nullptr;
2435 bNoDetailsInRef = true; // show error, not empty
2436 }
2437 }
2438
2439 if ( !bRefDimInCol && !bRefDimInRow ) // invalid dimension specified
2440 bNoDetailsInRef = true; // pSelectDim is then already NULL
2441
2442 // get the member for the reference item and do the calculation
2443
2444 if ( bRunningTotal )
2445 {
2446 // running total in (dimension) -> find first existing member
2447
2448 if ( pSelectDim )
2449 {
2450 ScDPDataMember* pSelectMember;
2451 if ( bRefDimInCol )
2452 pSelectMember = ScDPResultDimension::GetColReferenceMember( nullptr, nullptr,
2453 nColPos, rRunning );
2454 else
2455 {
2456 const sal_Int32* pRowSorted = rRowSorted.data();
2457 const sal_Int32* pColSorted = rColSorted.data();
2458 pRowSorted += nRowPos + 1; // including the reference dimension
2459 pSelectMember = pSelectDim->GetRowReferenceMember(
2460 nullptr, nullptr, pRowSorted, pColSorted);
2461 }
2462
2463 if ( pSelectMember )
2464 {
2465 // The running total is kept as the auxiliary value in
2466 // the first available member for the reference dimension.
2467 // Members are visited in final order, so each one's result
2468 // can be used and then modified.
2469
2470 ScDPAggData* pSelectData = pSelectMember->
2471 GetAggData( nMemberMeasure, aLocalSubState );
2472 if ( pSelectData )
2473 {
2474 double fTotal = pSelectData->GetAuxiliary();
2475 fTotal += pAggData->GetResult();
2476 pSelectData->SetAuxiliary( fTotal );
2477 pAggData->SetResult( fTotal );
2478 pAggData->SetEmpty(false); // always display
2479 }
2480 }
2481 else
2482 pAggData->SetError();
2483 }
2484 else if (bNoDetailsInRef)
2485 pAggData->SetError();
2486 else
2487 pAggData->SetEmpty(true); // empty (dim set to 0 above)
2488 }
2489 else
2490 {
2491 // difference/percentage -> find specified member
2492
2493 if ( pSelectDim )
2494 {
2495 OUString aRefItemName = aReferenceValue.ReferenceItemName;
2496 ScDPRelativePos aRefItemPos( 0, nRelativeDir ); // nBasePos is modified later
2497
2498 const OUString* pRefName = nullptr;
2499 const ScDPRelativePos* pRefPos = nullptr;
2500 if ( bRelative )
2501 pRefPos = &aRefItemPos;
2502 else
2503 pRefName = &aRefItemName;
2504
2505 ScDPDataMember* pSelectMember;
2506 if ( bRefDimInCol )
2507 {
2508 aRefItemPos.nBasePos = rColVisible[nColPos]; // without sort order applied
2509 pSelectMember = ScDPResultDimension::GetColReferenceMember( pRefPos, pRefName,
2510 nColPos, rRunning );
2511 }
2512 else
2513 {
2514 aRefItemPos.nBasePos = rRowVisible[nRowPos]; // without sort order applied
2515 const sal_Int32* pRowSorted = rRowSorted.data();
2516 const sal_Int32* pColSorted = rColSorted.data();
2517 pRowSorted += nRowPos + 1; // including the reference dimension
2518 pSelectMember = pSelectDim->GetRowReferenceMember(
2519 pRefPos, pRefName, pRowSorted, pColSorted);
2520 }
2521
2522 // difference or perc.difference is empty for the reference item itself
2523 if ( pSelectMember == this &&
2524 eRefType != sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE )
2525 {
2526 pAggData->SetEmpty(true);
2527 }
2528 else if ( pSelectMember )
2529 {
2530 const ScDPAggData* pOtherAggData = pSelectMember->
2531 GetConstAggData( nMemberMeasure, aLocalSubState );
2532 OSL_ENSURE( pOtherAggData, "no agg data" );
2533 if ( pOtherAggData )
2534 {
2535 // Reference member may be visited before or after this one,
2536 // so the auxiliary value is used for the original result.
2537
2538 double fOtherResult = pOtherAggData->GetAuxiliary();
2539 double fThisResult = pAggData->GetResult();
2540 bool bError = false;
2541 switch ( eRefType )
2542 {
2543 case sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE:
2544 fThisResult = fThisResult - fOtherResult;
2545 break;
2546 case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE:
2547 if ( fOtherResult == 0.0 )
2548 bError = true;
2549 else
2550 fThisResult = fThisResult / fOtherResult;
2551 break;
2552 case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE:
2553 if ( fOtherResult == 0.0 )
2554 bError = true;
2555 else
2556 fThisResult = ( fThisResult - fOtherResult ) / fOtherResult;
2557 break;
2558 default:
2559 OSL_FAIL("invalid calculation type");
2560 }
2561 if ( bError )
2562 {
2563 pAggData->SetError();
2564 }
2565 else
2566 {
2567 pAggData->SetResult(fThisResult);
2568 pAggData->SetEmpty(false); // always display
2569 }
2570 //TODO: errors in data?
2571 }
2572 }
2573 else if (bRelative && !bNoDetailsInRef)
2574 pAggData->SetEmpty(true); // empty
2575 else
2576 pAggData->SetError(); // error
2577 }
2578 else if (bNoDetailsInRef)
2579 pAggData->SetError(); // error
2580 else
2581 pAggData->SetEmpty(true); // empty
2582 }
2583 }
2584 else if ( eRefType == sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE ||
2585 eRefType == sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE ||
2586 eRefType == sheet::DataPilotFieldReferenceType::TOTAL_PERCENTAGE ||
2587 eRefType == sheet::DataPilotFieldReferenceType::INDEX )
2588 {
2589
2590 // set total values when they are encountered (always before their use)
2591
2592 ScDPAggData* pColTotalData = pRefMember->GetColTotal( nMemberMeasure );
2593 ScDPAggData* pRowTotalData = rTotals.GetRowTotal( nMemberMeasure );
2594 ScDPAggData* pGrandTotalData = rTotals.GetGrandTotal( nMemberMeasure );
2595
2596 double fTotalValue = pAggData->HasError() ? 0 : pAggData->GetResult();
2597
2598 if ( bIsRoot && rTotals.IsInColRoot() && pGrandTotalData )
2599 pGrandTotalData->SetAuxiliary( fTotalValue );
2600
2601 if ( bIsRoot && pRowTotalData )
2602 pRowTotalData->SetAuxiliary( fTotalValue );
2603
2604 if ( rTotals.IsInColRoot() && pColTotalData )
2605 pColTotalData->SetAuxiliary( fTotalValue );
2606
2607 // find relation to total values
2608
2609 switch ( eRefType )
2610 {
2611 case sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE:
2612 case sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE:
2613 case sheet::DataPilotFieldReferenceType::TOTAL_PERCENTAGE:
2614 {
2615 double nTotal;
2616 if ( eRefType == sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE )
2617 nTotal = pRowTotalData ? pRowTotalData->GetAuxiliary() : 0.0;
2618 else if ( eRefType == sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE )
2619 nTotal = pColTotalData ? pColTotalData->GetAuxiliary() : 0.0;
2620 else
2621 nTotal = pGrandTotalData ? pGrandTotalData->GetAuxiliary() : 0.0;
2622
2623 if ( nTotal == 0.0 )
2624 pAggData->SetError();
2625 else
2626 pAggData->SetResult( pAggData->GetResult() / nTotal );
2627 }
2628 break;
2629 case sheet::DataPilotFieldReferenceType::INDEX:
2630 {
2631 double nColTotal = pColTotalData ? pColTotalData->GetAuxiliary() : 0.0;
2632 double nRowTotal = pRowTotalData ? pRowTotalData->GetAuxiliary() : 0.0;
2633 double nGrandTotal = pGrandTotalData ? pGrandTotalData->GetAuxiliary() : 0.0;
2634 if ( nRowTotal == 0.0 || nColTotal == 0.0 )
2635 pAggData->SetError();
2636 else
2637 pAggData->SetResult(
2638 ( pAggData->GetResult() * nGrandTotal ) /
2639 ( nRowTotal * nColTotal ) );
2640 }
2641 break;
2642 }
2643 }
2644 }
2645 }
2646 }
2647 }
2648
2649 if ( bHasChild ) // child dimension must be processed last, so the row total is known
2650 {
2651 if ( pDataChild )
2652 pDataChild->UpdateRunningTotals( pRefChild, nMeasure,
2653 bIsSubTotalRow, rSubState, rRunning, rTotals, rRowParent );
2654 }
2655}
2656
2657#if DUMP_PIVOT_TABLE
2658void ScDPDataMember::DumpState( const ScDPResultMember* pRefMember, ScDocument* pDoc, ScAddress& rPos ) const
2659{
2660 dumpRow("ScDPDataMember", GetName(), &aAggregate, pDoc, rPos);
2661 SCROW nStartRow = rPos.Row();
2662
2663 const ScDPDataDimension* pDataChild = GetChildDimension();
2664 const ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();
2665 if ( pDataChild && pRefChild )
2666 pDataChild->DumpState( pRefChild, pDoc, rPos );
2667
2668 indent(pDoc, nStartRow, rPos);
2669}
2670
2671void ScDPDataMember::Dump(int nIndent) const
2672{
2673 std::string aIndent(nIndent*2, ' ');
2674 std::cout << aIndent << "-- data member '"
2675 << (pResultMember ? pResultMember->GetName() : OUString()) << "'" << std::endl;
2676 for (const ScDPAggData* pAgg = &aAggregate; pAgg; pAgg = pAgg->GetExistingChild())
2677 pAgg->Dump(nIndent+1);
2678
2679 if (pChildDimension)
2680 pChildDimension->Dump(nIndent+1);
2681}
2682#endif
2683
2684// Helper class to select the members to include in
2685// ScDPResultDimension::InitFrom or LateInitFrom if groups are used
2686
2687namespace {
2688
2689class ScDPGroupCompare
2690{
2691private:
2692 const ScDPResultData* pResultData;
2693 const ScDPInitState& rInitState;
2694 tools::Long nDimSource;
2695 bool bIncludeAll;
2696 bool bIsBase;
2697 tools::Long nGroupBase;
2698public:
2699 ScDPGroupCompare( const ScDPResultData* pData, const ScDPInitState& rState, tools::Long nDimension );
2700
2701 bool IsIncluded( const ScDPMember& rMember ) { return bIncludeAll || TestIncluded( rMember ); }
2702 bool TestIncluded( const ScDPMember& rMember );
2703};
2704
2705}
2706
2707ScDPGroupCompare::ScDPGroupCompare( const ScDPResultData* pData, const ScDPInitState& rState, tools::Long nDimension ) :
2708 pResultData( pData ),
2709 rInitState( rState ),
2710 nDimSource( nDimension )
2711{
2712 bIsBase = pResultData->IsBaseForGroup( nDimSource );
2713 nGroupBase = pResultData->GetGroupBase( nDimSource ); //TODO: get together in one call?
2714
2715 // if bIncludeAll is set, TestIncluded doesn't need to be called
2716 bIncludeAll = !( bIsBase || nGroupBase >= 0 );
2717}
2718
2719bool ScDPGroupCompare::TestIncluded( const ScDPMember& rMember )
2720{
2721 bool bInclude = true;
2722 if ( bIsBase )
2723 {
2724 // need to check all previous groups
2725 //TODO: get array of groups (or indexes) before loop?
2726 ScDPItemData aMemberData(rMember.FillItemData());
2727
2728 const std::vector<ScDPInitState::Member>& rMemStates = rInitState.GetMembers();
2729 bInclude = std::all_of(rMemStates.begin(), rMemStates.end(),
2730 [this, &aMemberData](const ScDPInitState::Member& rMem) {
2731 return (pResultData->GetGroupBase(rMem.mnSrcIndex) != nDimSource)
2732 || pResultData->IsInGroup(rMem.mnNameIndex, rMem.mnSrcIndex, aMemberData, nDimSource);
2733 });
2734 }
2735 else if ( nGroupBase >= 0 )
2736 {
2737 // base isn't used in preceding fields
2738 // -> look for other groups using the same base
2739
2740 //TODO: get array of groups (or indexes) before loop?
2741 ScDPItemData aMemberData(rMember.FillItemData());
2742 const std::vector<ScDPInitState::Member>& rMemStates = rInitState.GetMembers();
2743 bInclude = std::all_of(rMemStates.begin(), rMemStates.end(),
2744 [this, &aMemberData](const ScDPInitState::Member& rMem) {
2745 // coverity[copy_paste_error : FALSE] - same base (hierarchy between
2746 // the two groups is irrelevant)
2747 return (pResultData->GetGroupBase(rMem.mnSrcIndex) != nGroupBase)
2748 || pResultData->HasCommonElement(rMem.mnNameIndex, rMem.mnSrcIndex, aMemberData, nDimSource);
2749 });
2750 }
2751
2752 return bInclude;
2753}
2754
2756 pResultData( pData ),
2757 nSortMeasure( 0 ),
2758 bIsDataLayout( false ),
2759 bSortByData( false ),
2760 bSortAscending( false ),
2761 bAutoShow( false ),
2762 bAutoTopItems( false ),
2763 bInitialized( false ),
2764 nAutoMeasure( 0 ),
2765 nAutoCount( 0 )
2766{
2767}
2768
2770{
2771}
2772
2774{
2775 if( bIsDataLayout )
2776 {
2777 SAL_WARN_IF(maMemberArray.empty(), "sc.core", "MemberArray is empty");
2778 return !maMemberArray.empty() ? maMemberArray[0].get() : nullptr;
2779 }
2780
2781 MemberHash::const_iterator aRes = maMemberHash.find( iData );
2782 if( aRes != maMemberHash.end()) {
2783 if ( aRes->second->IsNamedItem( iData ) )
2784 return aRes->second;
2785 OSL_FAIL("problem! hash result is not the same as IsNamedItem");
2786 }
2787
2788 unsigned int i;
2789 unsigned int nCount = maMemberArray.size();
2790 for( i = 0; i < nCount ; i++ )
2791 {
2792 ScDPResultMember* pResultMember = maMemberArray[i].get();
2793 if ( pResultMember->IsNamedItem( iData ) )
2794 return pResultMember;
2795 }
2796 return nullptr;
2797}
2798
2800 const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLev,
2801 size_t nPos, ScDPInitState& rInitState, bool bInitChild )
2802{
2803 if (nPos >= ppDim.size() || nPos >= ppLev.size())
2804 {
2805 bInitialized = true;
2806 return;
2807 }
2808
2809 ScDPDimension* pThisDim = ppDim[nPos];
2810 ScDPLevel* pThisLevel = ppLev[nPos];
2811
2812 if (!pThisDim || !pThisLevel)
2813 {
2814 bInitialized = true;
2815 return;
2816 }
2817
2818 bIsDataLayout = pThisDim->getIsDataLayoutDimension(); // member
2819 aDimensionName = pThisDim->getName(); // member
2820
2821 // Check the autoshow setting. If it's enabled, store the settings.
2822 const sheet::DataPilotFieldAutoShowInfo& rAutoInfo = pThisLevel->GetAutoShow();
2823 if ( rAutoInfo.IsEnabled )
2824 {
2825 bAutoShow = true;
2826 bAutoTopItems = ( rAutoInfo.ShowItemsMode == sheet::DataPilotFieldShowItemsMode::FROM_TOP );
2827 nAutoMeasure = pThisLevel->GetAutoMeasure();
2828 nAutoCount = rAutoInfo.ItemCount;
2829 }
2830
2831 // Check the sort info, and store the settings if appropriate.
2832 const sheet::DataPilotFieldSortInfo& rSortInfo = pThisLevel->GetSortInfo();
2833 if ( rSortInfo.Mode == sheet::DataPilotFieldSortMode::DATA )
2834 {
2835 bSortByData = true;
2836 bSortAscending = rSortInfo.IsAscending;
2837 nSortMeasure = pThisLevel->GetSortMeasure();
2838 }
2839
2840 // global order is used to initialize aMembers, so it doesn't have to be looked at later
2841 const ScMemberSortOrder& rGlobalOrder = pThisLevel->GetGlobalOrder();
2842
2843 tools::Long nDimSource = pThisDim->GetDimension(); //TODO: check GetSourceDim?
2844 ScDPGroupCompare aCompare( pResultData, rInitState, nDimSource );
2845
2846 // Now, go through all members and initialize them.
2847 ScDPMembers* pMembers = pThisLevel->GetMembersObject();
2848 tools::Long nMembCount = pMembers->getCount();
2849 for ( tools::Long i=0; i<nMembCount; i++ )
2850 {
2851 tools::Long nSorted = rGlobalOrder.empty() ? i : rGlobalOrder[i];
2852
2853 ScDPMember* pMember = pMembers->getByIndex(nSorted);
2854 if ( aCompare.IsIncluded( *pMember ) )
2855 {
2856 ScDPParentDimData aData( i, pThisDim, pThisLevel, pMember);
2857 ScDPResultMember* pNew = AddMember( aData );
2858
2859 rInitState.AddMember(nDimSource, pNew->GetDataId());
2860 pNew->InitFrom( ppDim, ppLev, nPos+1, rInitState, bInitChild );
2861 rInitState.RemoveMember();
2862 }
2863 }
2864 bInitialized = true;
2865}
2866
2868 LateInitParams& rParams, const vector<SCROW>& pItemData, size_t nPos, ScDPInitState& rInitState)
2869{
2870 if ( rParams.IsEnd( nPos ) )
2871 return;
2872 if (nPos >= pItemData.size())
2873 {
2874 SAL_WARN("sc.core", "pos " << nPos << ", but vector size is " << pItemData.size());
2875 return;
2876 }
2877 SCROW rThisData = pItemData[nPos];
2878 ScDPDimension* pThisDim = rParams.GetDim( nPos );
2879 ScDPLevel* pThisLevel = rParams.GetLevel( nPos );
2880
2881 if (!pThisDim || !pThisLevel)
2882 return;
2883
2884 tools::Long nDimSource = pThisDim->GetDimension(); //TODO: check GetSourceDim?
2885
2886 bool bShowEmpty = pThisLevel->getShowEmpty();
2887
2888 if ( !bInitialized )
2889 { // init some values
2890 // create all members at the first call (preserve order)
2892 aDimensionName = pThisDim->getName();
2893
2894 const sheet::DataPilotFieldAutoShowInfo& rAutoInfo = pThisLevel->GetAutoShow();
2895 if ( rAutoInfo.IsEnabled )
2896 {
2897 bAutoShow = true;
2898 bAutoTopItems = ( rAutoInfo.ShowItemsMode == sheet::DataPilotFieldShowItemsMode::FROM_TOP );
2899 nAutoMeasure = pThisLevel->GetAutoMeasure();
2900 nAutoCount = rAutoInfo.ItemCount;
2901 }
2902
2903 const sheet::DataPilotFieldSortInfo& rSortInfo = pThisLevel->GetSortInfo();
2904 if ( rSortInfo.Mode == sheet::DataPilotFieldSortMode::DATA )
2905 {
2906 bSortByData = true;
2907 bSortAscending = rSortInfo.IsAscending;
2908 nSortMeasure = pThisLevel->GetSortMeasure();
2909 }
2910 }
2911
2912 bool bLateInitAllMembers= bIsDataLayout || rParams.GetInitAllChild() || bShowEmpty;
2913
2914 if ( !bLateInitAllMembers )
2915 {
2916 ResultMembers& rMembers = pResultData->GetDimResultMembers(nDimSource, pThisDim, pThisLevel);
2917 bLateInitAllMembers = rMembers.IsHasHideDetailsMembers();
2918
2919 SAL_INFO("sc.core", aDimensionName << (rMembers.IsHasHideDetailsMembers() ? " HasHideDetailsMembers" : ""));
2920
2921 rMembers.SetHasHideDetailsMembers( false );
2922 }
2923
2924 bool bNewAllMembers = (!rParams.IsRow()) || nPos == 0 || bLateInitAllMembers;
2925
2926 if (bNewAllMembers )
2927 {
2928 // global order is used to initialize aMembers, so it doesn't have to be looked at later
2929 if ( !bInitialized )
2930 { //init all members
2931 const ScMemberSortOrder& rGlobalOrder = pThisLevel->GetGlobalOrder();
2932
2933 ScDPGroupCompare aCompare( pResultData, rInitState, nDimSource );
2934 ScDPMembers* pMembers = pThisLevel->GetMembersObject();
2935 tools::Long nMembCount = pMembers->getCount();
2936 for ( tools::Long i=0; i<nMembCount; i++ )
2937 {
2938 tools::Long nSorted = rGlobalOrder.empty() ? i : rGlobalOrder[i];
2939
2940 ScDPMember* pMember = pMembers->getByIndex(nSorted);
2941 if ( aCompare.IsIncluded( *pMember ) )
2942 { // add all members
2943 ScDPParentDimData aData( i, pThisDim, pThisLevel, pMember );
2944 AddMember( aData );
2945 }
2946 }
2947 bInitialized = true; // don't call again, even if no members were included
2948 }
2949 // initialize only specific member (or all if "show empty" flag is set)
2950 if ( bLateInitAllMembers )
2951 {
2953 for (tools::Long i=0; i<nCount; i++)
2954 {
2955 ScDPResultMember* pResultMember = maMemberArray[i].get();
2956
2957 // check show empty
2958 bool bAllChildren = false;
2959 if( bShowEmpty )
2960 {
2961 bAllChildren = !pResultMember->IsNamedItem( rThisData );
2962 }
2963 rParams.SetInitAllChildren( bAllChildren );
2964 rInitState.AddMember( nDimSource, pResultMember->GetDataId() );
2965 pResultMember->LateInitFrom( rParams, pItemData, nPos+1, rInitState );
2966 rInitState.RemoveMember();
2967 }
2968 }
2969 else
2970 {
2971 ScDPResultMember* pResultMember = FindMember( rThisData );
2972 if( nullptr != pResultMember )
2973 {
2974 rInitState.AddMember( nDimSource, pResultMember->GetDataId() );
2975 pResultMember->LateInitFrom( rParams, pItemData, nPos+1, rInitState );
2976 rInitState.RemoveMember();
2977 }
2978 }
2979 }
2980 else
2981 InitWithMembers( rParams, pItemData, nPos, rInitState );
2982}
2983
2985{
2986 tools::Long nMemberCount = maMemberArray.size();
2987 if (!nMemberCount)
2988 return 0;
2989
2990 tools::Long nTotal = 0;
2991 if (bIsDataLayout)
2992 {
2993 OSL_ENSURE(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
2994 "DataLayout dimension twice?");
2995 // repeat first member...
2996 nTotal = nMemberCount * maMemberArray[0]->GetSize(0); // all measures have equal size
2997 }
2998 else
2999 {
3000 // add all members
3001 for (tools::Long nMem=0; nMem<nMemberCount; nMem++)
3002 nTotal += maMemberArray[nMem]->GetSize(nMeasure);
3003 }
3004 return nTotal;
3005}
3006
3007bool ScDPResultDimension::IsValidEntry( const vector< SCROW >& aMembers ) const
3008{
3009 if (aMembers.empty())
3010 return false;
3011
3012 const ScDPResultMember* pMember = FindMember( aMembers[0] );
3013 if ( nullptr != pMember )
3014 return pMember->IsValidEntry( aMembers );
3015#if OSL_DEBUG_LEVEL > 0
3016 SAL_INFO("sc.core", "IsValidEntry: Member not found, DimNam = " << GetName());
3017#endif
3018 return false;
3019}
3020
3021void ScDPResultDimension::ProcessData( const vector< SCROW >& aMembers,
3022 const ScDPResultDimension* pDataDim,
3023 const vector< SCROW >& aDataMembers,
3024 const vector<ScDPValue>& aValues ) const
3025{
3026 if (aMembers.empty())
3027 return;
3028
3029 ScDPResultMember* pMember = FindMember( aMembers[0] );
3030 if ( nullptr != pMember )
3031 {
3032 vector<SCROW> aChildMembers;
3033 if (aMembers.size() > 1)
3034 {
3035 vector<SCROW>::const_iterator itr = aMembers.begin();
3036 aChildMembers.insert(aChildMembers.begin(), ++itr, aMembers.end());
3037 }
3038 pMember->ProcessData( aChildMembers, pDataDim, aDataMembers, aValues );
3039 return;
3040 }
3041
3042 OSL_FAIL("ProcessData: Member not found");
3043}
3044
3045void ScDPResultDimension::FillMemberResults( uno::Sequence<sheet::MemberResult>* pSequences,
3046 tools::Long nStart, tools::Long nMeasure )
3047{
3048 tools::Long nPos = nStart;
3050
3051 for (tools::Long i=0; i<nCount; i++)
3052 {
3053 tools::Long nSorted = aMemberOrder.empty() ? i : aMemberOrder[i];
3054
3055 ScDPResultMember* pMember = maMemberArray[nSorted].get();
3056 // in data layout dimension, use first member with different measures/names
3057 if ( bIsDataLayout )
3058 {
3059 bool bTotalResult = false;
3060 OUString aMbrName = pResultData->GetMeasureDimensionName( nSorted );
3061 OUString aMbrCapt = pResultData->GetMeasureString( nSorted, false, SUBTOTAL_FUNC_NONE, bTotalResult );
3062 maMemberArray[0]->FillMemberResults( pSequences, nPos, nSorted, false, &aMbrName, &aMbrCapt );
3063 }
3064 else if ( pMember->IsVisible() )
3065 {
3066 pMember->FillMemberResults( pSequences, nPos, nMeasure, false, nullptr, nullptr );
3067 }
3068 // nPos is modified
3069 }
3070}
3071
3073 const ScDPResultMember* pRefMember, ScDPResultFilterContext& rFilterCxt,
3074 uno::Sequence< uno::Sequence<sheet::DataResult> >& rSequence, tools::Long nMeasure) const
3075{
3076 FilterStack aFilterStack(rFilterCxt.maFilters);
3077 aFilterStack.pushDimName(GetName(), bIsDataLayout);
3078
3079 tools::Long nMemberMeasure = nMeasure;
3081 for (tools::Long i=0; i<nCount; i++)
3082 {
3083 tools::Long nSorted = aMemberOrder.empty() ? i : aMemberOrder[i];
3084
3085 const ScDPResultMember* pMember;
3086 if (bIsDataLayout)
3087 {
3088 OSL_ENSURE(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
3089 "DataLayout dimension twice?");
3090 pMember = maMemberArray[0].get();
3091 nMemberMeasure = nSorted;
3092 }
3093 else
3094 pMember = maMemberArray[nSorted].get();
3095
3096 if ( pMember->IsVisible() )
3097 pMember->FillDataResults(pRefMember, rFilterCxt, rSequence, nMemberMeasure);
3098 }
3099}
3100
3102{
3103 tools::Long nMemberMeasure = nMeasure;
3105 for (tools::Long i=0; i<nCount; i++)
3106 {
3107 const ScDPResultMember* pMember;
3108 if (bIsDataLayout)
3109 {
3110 OSL_ENSURE(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
3111 "DataLayout dimension twice?");
3112 pMember = maMemberArray[0].get();
3113 nMemberMeasure = i;
3114 }
3115 else
3116 pMember = maMemberArray[i].get();
3117
3118 if ( pMember->IsVisible() )
3119 pMember->UpdateDataResults( pRefMember, nMemberMeasure );
3120 }
3121}
3122
3124{
3126
3127 if ( bSortByData )
3128 {
3129 // sort members
3130
3131 OSL_ENSURE( aMemberOrder.empty(), "sort twice?" );
3132 aMemberOrder.resize( nCount );
3133 for (tools::Long nPos=0; nPos<nCount; nPos++)
3135
3136 ScDPRowMembersOrder aComp( *this, nSortMeasure, bSortAscending );
3137 ::std::sort( aMemberOrder.begin(), aMemberOrder.end(), aComp );
3138 }
3139
3140 // handle children
3141
3142 // for data layout, call only once - sorting measure is always taken from settings
3143 tools::Long nLoopCount = bIsDataLayout ? std::min<tools::Long>(1, nCount) : nCount;
3144 for (tools::Long i=0; i<nLoopCount; i++)
3145 {
3146 ScDPResultMember* pMember = maMemberArray[i].get();
3147 if ( pMember->IsVisible() )
3148 pMember->SortMembers( pRefMember );
3149 }
3150}
3151
3153{
3155
3156 // handle children first, before changing the visible state
3157
3158 // for data layout, call only once - sorting measure is always taken from settings
3159 tools::Long nLoopCount = bIsDataLayout ? 1 : nCount;
3160 for (tools::Long i=0; i<nLoopCount; i++)
3161 {
3162 ScDPResultMember* pMember = maMemberArray[i].get();
3163 if ( pMember->IsVisible() )
3164 pMember->DoAutoShow( pRefMember );
3165 }
3166
3167 if ( !(bAutoShow && nAutoCount > 0 && nAutoCount < nCount) )
3168 return;
3169
3170 // establish temporary order, hide remaining members
3171
3172 ScMemberSortOrder aAutoOrder;
3173 aAutoOrder.resize( nCount );
3175 for (nPos=0; nPos<nCount; nPos++)
3176 aAutoOrder[nPos] = nPos;
3177
3178 ScDPRowMembersOrder aComp( *this, nAutoMeasure, !bAutoTopItems );
3179 ::std::sort( aAutoOrder.begin(), aAutoOrder.end(), aComp );
3180
3181 // look for equal values to the last included one
3182
3183 tools::Long nIncluded = nAutoCount;
3184 const ScDPResultMember* pMember1 = maMemberArray[aAutoOrder[nIncluded - 1]].get();
3185 const ScDPDataMember* pDataMember1 = pMember1->IsVisible() ? pMember1->GetDataRoot() : nullptr;
3186 bool bContinue = true;
3187 while ( bContinue )
3188 {
3189 bContinue = false;
3190 if ( nIncluded < nCount )
3191 {
3192 const ScDPResultMember* pMember2 = maMemberArray[aAutoOrder[nIncluded]].get();
3193 const ScDPDataMember* pDataMember2 = pMember2->IsVisible() ? pMember2->GetDataRoot() : nullptr;
3194
3195 if ( lcl_IsEqual( pDataMember1, pDataMember2, nAutoMeasure ) )
3196 {
3197 ++nIncluded; // include more members if values are equal
3198 bContinue = true;
3199 }
3200 }
3201 }
3202
3203 // hide the remaining members
3204
3205 for (nPos = nIncluded; nPos < nCount; nPos++)
3206 {
3207 ScDPResultMember* pMember = maMemberArray[aAutoOrder[nPos]].get();
3208 pMember->SetAutoHidden();
3209 }
3210}
3211
3213{
3215 for (tools::Long i=0; i<nCount; i++)
3216 {
3217 // sort order doesn't matter
3218 ScDPResultMember* pMember = maMemberArray[bIsDataLayout ? 0 : i].get();
3219 pMember->ResetResults();
3220 }
3221}
3222
3224{
3225 return aMemberOrder.empty() ? nUnsorted : aMemberOrder[nUnsorted];
3226}
3227
3229 ScDPRunningTotalState& rRunning, ScDPRowTotals& rTotals ) const
3230{
3231 const ScDPResultMember* pMember;
3232 tools::Long nMemberMeasure = nMeasure;
3234 for (tools::Long i=0; i<nCount; i++)
3235 {
3236 tools::Long nSorted = aMemberOrder.empty() ? i : aMemberOrder[i];
3237
3238 if (bIsDataLayout)
3239 {
3240 OSL_ENSURE(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
3241 "DataLayout dimension twice?");
3242 pMember = maMemberArray[0].get();
3243 nMemberMeasure = nSorted;
3244 }
3245 else
3246 pMember = maMemberArray[nSorted].get();
3247
3248 if ( pMember->IsVisible() )
3249 {
3250 if ( bIsDataLayout )
3251 rRunning.AddRowIndex( 0, 0 );
3252 else
3253 rRunning.AddRowIndex( i, nSorted );
3254 pMember->UpdateRunningTotals( pRefMember, nMemberMeasure, rRunning, rTotals );
3255 rRunning.RemoveRowIndex();
3256 }
3257 }
3258}
3259
3261 const ScDPRelativePos* pRelativePos, const OUString* pName,
3262 const sal_Int32* pRowIndexes, const sal_Int32* pColIndexes ) const
3263{
3264 // get named, previous/next, or first member of this dimension (first existing if pRelativePos and pName are NULL)
3265
3266 OSL_ENSURE( pRelativePos == nullptr || pName == nullptr, "can't use position and name" );
3267
3268 ScDPDataMember* pColMember = nullptr;
3269
3270 bool bFirstExisting = ( pRelativePos == nullptr && pName == nullptr );
3271 tools::Long nMemberCount = maMemberArray.size();
3272 tools::Long nMemberIndex = 0; // unsorted
3273 tools::Long nDirection = 1; // forward if no relative position is used
3274 if ( pRelativePos )
3275 {
3276 nDirection = pRelativePos->nDirection;
3277 nMemberIndex = pRelativePos->nBasePos + nDirection; // bounds are handled below
3278
3279 OSL_ENSURE( nDirection == 1 || nDirection == -1, "Direction must be 1 or -1" );
3280 }
3281 else if ( pName )
3282 {
3283 // search for named member
3284
3285 const ScDPResultMember* pRowMember = maMemberArray[GetSortedIndex(nMemberIndex)].get();
3286
3287 //TODO: use ScDPItemData, as in ScDPDimension::IsValidPage?
3288 while ( pRowMember && pRowMember->GetName() != *pName )
3289 {
3290 ++nMemberIndex;
3291 if ( nMemberIndex < nMemberCount )
3292 pRowMember = maMemberArray[GetSortedIndex(nMemberIndex)].get();
3293 else
3294 pRowMember = nullptr;
3295 }
3296 }
3297
3298 bool bContinue = true;
3299 while ( bContinue && nMemberIndex >= 0 && nMemberIndex < nMemberCount )
3300 {
3301 const ScDPResultMember* pRowMember = maMemberArray[GetSortedIndex(nMemberIndex)].get();
3302
3303 // get child members by given indexes
3304
3305 const sal_Int32* pNextRowIndex = pRowIndexes;
3306 while ( *pNextRowIndex >= 0 && pRowMember )
3307 {
3308 const ScDPResultDimension* pRowChild = pRowMember->GetChildDimension();
3309 if ( pRowChild && *pNextRowIndex < pRowChild->GetMemberCount() )
3310 pRowMember = pRowChild->GetMember( *pNextRowIndex );
3311 else
3312 pRowMember = nullptr;
3313 ++pNextRowIndex;
3314 }
3315
3316 if ( pRowMember && pRelativePos )
3317 {
3318 // Skip the member if it has hidden details
3319 // (because when looking for the details, it is skipped, too).
3320 // Also skip if the member is invisible because it has no data,
3321 // for consistent ordering.
3322 if ( pRowMember->HasHiddenDetails() || !pRowMember->IsVisible() )
3323 pRowMember = nullptr;
3324 }
3325
3326 if ( pRowMember )
3327 {
3328 pColMember = pRowMember->GetDataRoot();
3329
3330 const sal_Int32* pNextColIndex = pColIndexes;
3331 while ( *pNextColIndex >= 0 && pColMember )
3332 {
3333 ScDPDataDimension* pColChild = pColMember->GetChildDimension();
3334 if ( pColChild && *pNextColIndex < pColChild->GetMemberCount() )
3335 pColMember = pColChild->GetMember( *pNextColIndex );
3336 else
3337 pColMember = nullptr;
3338 ++pNextColIndex;
3339 }
3340 }
3341
3342 // continue searching only if looking for first existing or relative position
3343 bContinue = ( pColMember == nullptr && ( bFirstExisting || pRelativePos ) );
3344 nMemberIndex += nDirection;
3345 }
3346
3347 return pColMember;
3348}
3349
3351 const ScDPRelativePos* pRelativePos, const OUString* pName,
3352 sal_Int32 nRefDimPos, const ScDPRunningTotalState& rRunning )
3353{
3354 OSL_ENSURE( pRelativePos == nullptr || pName == nullptr, "can't use position and name" );
3355
3356 const sal_Int32* pColIndexes = rRunning.GetColSorted().data();
3357 const sal_Int32* pRowIndexes = rRunning.GetRowSorted().data();
3358
3359 // get own row member using all indexes
3360
3361 const ScDPResultMember* pRowMember = rRunning.GetRowResRoot();
3362 ScDPDataMember* pColMember = nullptr;
3363
3364 const sal_Int32* pNextRowIndex = pRowIndexes;
3365 while ( *pNextRowIndex >= 0 && pRowMember )
3366 {
3367 const ScDPResultDimension* pRowChild = pRowMember->GetChildDimension();
3368 if ( pRowChild && *pNextRowIndex < pRowChild->GetMemberCount() )
3369 pRowMember = pRowChild->GetMember( *pNextRowIndex );
3370 else
3371 pRowMember = nullptr;
3372 ++pNextRowIndex;
3373 }
3374
3375 // get column (data) members before the reference field
3376 //TODO: pass rRowParent from ScDPDataMember::UpdateRunningTotals instead
3377
3378 if ( pRowMember )
3379 {
3380 pColMember = pRowMember->GetDataRoot();
3381
3382 const sal_Int32* pNextColIndex = pColIndexes;
3383 sal_Int32 nColSkipped = 0;
3384 while ( *pNextColIndex >= 0 && pColMember && nColSkipped < nRefDimPos )
3385 {
3386 ScDPDataDimension* pColChild = pColMember->GetChildDimension();
3387 if ( pColChild && *pNextColIndex < pColChild->GetMemberCount() )
3388 pColMember = pColChild->GetMember( *pNextColIndex );
3389 else
3390 pColMember = nullptr;
3391 ++pNextColIndex;
3392 ++nColSkipped;
3393 }
3394 }
3395
3396 // get column member for the reference field
3397
3398 if ( pColMember )
3399 {
3400 ScDPDataDimension* pReferenceDim = pColMember->GetChildDimension();
3401 if ( pReferenceDim )
3402 {
3403 tools::Long nReferenceCount = pReferenceDim->GetMemberCount();
3404
3405 bool bFirstExisting = ( pRelativePos == nullptr && pName == nullptr );
3406 tools::Long nMemberIndex = 0; // unsorted
3407 tools::Long nDirection = 1; // forward if no relative position is used
3408 pColMember = nullptr; // don't use parent dimension's member if none found
3409 if ( pRelativePos )
3410 {
3411 nDirection = pRelativePos->nDirection;
3412 nMemberIndex = pRelativePos->nBasePos + nDirection; // bounds are handled below
3413 }
3414 else if ( pName )
3415 {
3416 // search for named member
3417
3418 pColMember = pReferenceDim->GetMember( pReferenceDim->GetSortedIndex( nMemberIndex ) );
3419
3420 //TODO: use ScDPItemData, as in ScDPDimension::IsValidPage?
3421 while ( pColMember && pColMember->GetName() != *pName )
3422 {
3423 ++nMemberIndex;
3424 if ( nMemberIndex < nReferenceCount )
3425 pColMember = pReferenceDim->GetMember( pReferenceDim->GetSortedIndex( nMemberIndex ) );
3426 else
3427 pColMember = nullptr;
3428 }
3429 }
3430
3431 bool bContinue = true;
3432 while ( bContinue && nMemberIndex >= 0 && nMemberIndex < nReferenceCount )
3433 {
3434 pColMember = pReferenceDim->GetMember( pReferenceDim->GetSortedIndex( nMemberIndex ) );
3435
3436 // get column members below the reference field
3437
3438 const sal_Int32* pNextColIndex = pColIndexes + nRefDimPos + 1;
3439 while ( *pNextColIndex >= 0 && pColMember )
3440 {
3441 ScDPDataDimension* pColChild = pColMember->GetChildDimension();
3442 if ( pColChild && *pNextColIndex < pColChild->GetMemberCount() )
3443 pColMember = pColChild->GetMember( *pNextColIndex );
3444 else
3445 pColMember = nullptr;
3446 ++pNextColIndex;
3447 }
3448
3449 if ( pColMember && pRelativePos )
3450 {
3451 // Skip the member if it has hidden details
3452 // (because when looking for the details, it is skipped, too).
3453 // Also skip if the member is invisible because it has no data,
3454 // for consistent ordering.
3455 if ( pColMember->HasHiddenDetails() || !pColMember->IsVisible() )
3456 pColMember = nullptr;
3457 }
3458
3459 // continue searching only if looking for first existing or relative position
3460 bContinue = ( pColMember == nullptr && ( bFirstExisting || pRelativePos ) );
3461 nMemberIndex += nDirection;
3462 }
3463 }
3464 else
3465 pColMember = nullptr;
3466 }
3467
3468 return pColMember;
3469}
3470
3471#if DUMP_PIVOT_TABLE
3472void ScDPResultDimension::DumpState( const ScDPResultMember* pRefMember, ScDocument* pDoc, ScAddress& rPos ) const
3473{
3474 OUString aDimName = bIsDataLayout ? OUString("(data layout)") : GetName();
3475 dumpRow("ScDPResultDimension", aDimName, nullptr, pDoc, rPos);
3476
3477 SCROW nStartRow = rPos.Row();
3478
3480 for (tools::Long i=0; i<nCount; i++)
3481 {
3482 const ScDPResultMember* pMember = maMemberArray[i].get();
3483 pMember->DumpState( pRefMember, pDoc, rPos );
3484 }
3485
3486 indent(pDoc, nStartRow, rPos);
3487}
3488
3489void ScDPResultDimension::Dump(int nIndent) const
3490{
3491 std::string aIndent(nIndent*2, ' ');
3492 std::cout << aIndent << "-- dimension '" << GetName() << "'" << std::endl;
3493 for (const auto& rxMember : maMemberArray)
3494 {
3495 const ScDPResultMember* p = rxMember.get();
3496 p->Dump(nIndent+1);
3497 }
3498}
3499#endif
3500
3502{
3503 return maMemberArray.size();
3504}
3505
3507{
3508 return maMemberArray[n].get();
3509}
3511{
3512 return maMemberArray[n].get();
3513}
3514
3516{
3517 if ( !maMemberArray.empty() )
3518 return maMemberArray[0]->GetChildDimension();
3519 else
3520 return nullptr;
3521}
3522
3524{
3525 if (IsDataLayout())
3526 return;
3527
3528 for (const auto& rxMember : maMemberArray)
3529 {
3530 ScDPResultMember* pMember = rxMember.get();
3531 if (pMember->IsValid())
3532 {
3533 ScDPItemData aItem(pMember->FillItemData());
3534 rData.addVisibleMember(GetName(), aItem);
3535 pMember->FillVisibilityData(rData);
3536 }
3537 }
3538}
3539
3541 pResultData( pData ),
3542 pResultDimension( nullptr ),
3543 bIsDataLayout( false )
3544{
3545}
3546
3548{
3549}
3550
3552{
3553 if (!pDim)
3554 return;
3555
3556 pResultDimension = pDim;
3557 bIsDataLayout = pDim->IsDataLayout();
3558
3559 // Go through all result members under the given result dimension, and
3560 // create a new data member instance for each result member.
3562 for (tools::Long i=0; i<nCount; i++)
3563 {
3564 const ScDPResultMember* pResMem = pDim->GetMember(i);
3565
3566 ScDPDataMember* pNew = new ScDPDataMember( pResultData, pResMem );
3567 maMembers.emplace_back( pNew);
3568
3569 if ( !pResultData->IsLateInit() )
3570 {
3571 // with LateInit, pResMem hasn't necessarily been initialized yet,
3572 // so InitFrom for the new result member is called from its ProcessData method
3573
3574 const ScDPResultDimension* pChildDim = pResMem->GetChildDimension();
3575 if ( pChildDim )
3576 pNew->InitFrom( pChildDim );
3577 }
3578 }
3579}
3580
3581void ScDPDataDimension::ProcessData( const vector< SCROW >& aDataMembers, const vector<ScDPValue>& aValues,
3582 const ScDPSubTotalState& rSubState )
3583{
3584 // the ScDPItemData array must contain enough entries for all dimensions - this isn't checked
3585
3586 tools::Long nCount = maMembers.size();
3587 for (tools::Long i=0; i<nCount; i++)
3588 {
3589 ScDPDataMember* pMember = maMembers[static_cast<sal_uInt16>(i)].get();
3590
3591 // always first member for data layout dim
3592 if ( bIsDataLayout || ( !aDataMembers.empty() && pMember->IsNamedItem(aDataMembers[0]) ) )
3593 {
3594 vector<SCROW> aChildDataMembers;
3595 if (aDataMembers.size() > 1)
3596 {
3597 vector<SCROW>::const_iterator itr = aDataMembers.begin();
3598 aChildDataMembers.insert(aChildDataMembers.begin(), ++itr, aDataMembers.end());
3599 }
3600 pMember->ProcessData( aChildDataMembers, aValues, rSubState );
3601 return;
3602 }
3603 }
3604
3605 OSL_FAIL("ProcessData: Member not found");
3606}
3607
3609 const ScDPResultDimension* pRefDim, ScDPResultFilterContext& rFilterCxt,
3610 uno::Sequence<sheet::DataResult>& rSequence, tools::Long nMeasure, bool bIsSubTotalRow,
3611 const ScDPSubTotalState& rSubState) const
3612{
3613 OUString aDimName;
3614 bool bDataLayout = false;
3615 if (pResultDimension)
3616 {
3617 aDimName = pResultDimension->GetName();
3618 bDataLayout = pResultDimension->IsDataLayout();
3619 }
3620
3621 FilterStack aFilterStack(rFilterCxt.maFilters);
3622 aFilterStack.pushDimName(aDimName, bDataLayout);
3623
3624 OSL_ENSURE( pRefDim && static_cast<size_t>(pRefDim->GetMemberCount()) == maMembers.size(), "dimensions don't match" );
3625 OSL_ENSURE( pRefDim == pResultDimension, "wrong dim" );
3626
3627 const ScMemberSortOrder& rMemberOrder = pRefDim->GetMemberOrder();
3628
3629 tools::Long nMemberMeasure = nMeasure;
3630 tools::Long nCount = maMembers.size();
3631 for (tools::Long i=0; i<nCount; i++)
3632 {
3633 tools::Long nSorted = rMemberOrder.empty() ? i : rMemberOrder[i];
3634
3635 tools::Long nMemberPos = nSorted;
3636 if (bIsDataLayout)
3637 {
3638 OSL_ENSURE(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
3639 "DataLayout dimension twice?");
3640 nMemberPos = 0;
3641 nMemberMeasure = nSorted;
3642 }
3643
3644 const ScDPResultMember* pRefMember = pRefDim->GetMember(nMemberPos);
3645 if ( pRefMember->IsVisible() ) //TODO: here or in ScDPDataMember::FillDataRow ???
3646 {
3647 const ScDPDataMember* pDataMember = maMembers[static_cast<sal_uInt16>(nMemberPos)].get();
3648 pDataMember->FillDataRow(pRefMember, rFilterCxt, rSequence, nMemberMeasure, bIsSubTotalRow, rSubState);
3649 }
3650 }
3651}
3652
3654 tools::Long nMeasure, bool bIsSubTotalRow,
3655 const ScDPSubTotalState& rSubState ) const
3656{
3657 OSL_ENSURE( pRefDim && static_cast<size_t>(pRefDim->GetMemberCount()) == maMembers.size(), "dimensions don't match" );
3658 OSL_ENSURE( pRefDim == pResultDimension, "wrong dim" );
3659
3660 tools::Long nMemberMeasure = nMeasure;
3661 tools::Long nCount = maMembers.size();
3662 for (tools::Long i=0; i<nCount; i++)
3663 {
3664 tools::Long nMemberPos = i;
3665 if (bIsDataLayout)
3666 {
3667 OSL_ENSURE(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
3668 "DataLayout dimension twice?");
3669 nMemberPos = 0;
3670 nMemberMeasure = i;
3671 }
3672
3673 // Calculate must be called even if the member is not visible (for use as reference value)
3674 const ScDPResultMember* pRefMember = pRefDim->GetMember(nMemberPos);
3675 ScDPDataMember* pDataMember = maMembers[static_cast<sal_uInt16>(nMemberPos)].get();
3676 pDataMember->UpdateDataRow( pRefMember, nMemberMeasure, bIsSubTotalRow, rSubState );
3677 }
3678}
3679
3681{
3682 tools::Long nCount = maMembers.size();
3683
3684 if ( pRefDim->IsSortByData() )
3685 {
3686 // sort members
3687
3688 ScMemberSortOrder& rMemberOrder = pRefDim->GetMemberOrder();
3689 OSL_ENSURE( rMemberOrder.empty(), "sort twice?" );
3690 rMemberOrder.resize( nCount );
3691 for (tools::Long nPos=0; nPos<nCount; nPos++)
3692 rMemberOrder[nPos] = nPos;
3693
3694 ScDPColMembersOrder aComp( *this, pRefDim->GetSortMeasure(), pRefDim->IsSortAscending() );
3695 ::std::sort( rMemberOrder.begin(), rMemberOrder.end(), aComp );
3696 }
3697
3698 // handle children
3699
3700 OSL_ENSURE( pRefDim && static_cast<size_t>(pRefDim->GetMemberCount()) == maMembers.size(), "dimensions don't match" );
3701 OSL_ENSURE( pRefDim == pResultDimension, "wrong dim" );
3702
3703 // for data layout, call only once - sorting measure is always taken from settings
3704 tools::Long nLoopCount = bIsDataLayout ? 1 : nCount;
3705 for (tools::Long i=0; i<nLoopCount; i++)
3706 {
3707 ScDPResultMember* pRefMember = pRefDim->GetMember(i);
3708 if ( pRefMember->IsVisible() ) //TODO: here or in ScDPDataMember ???
3709 {
3710 ScDPDataMember* pDataMember = maMembers[static_cast<sal_uInt16>(i)].get();
3711 pDataMember->SortMembers( pRefMember );
3712 }
3713 }
3714}
3715
3717{
3718 tools::Long nCount = maMembers.size();
3719
3720 // handle children first, before changing the visible state
3721
3722 OSL_ENSURE( pRefDim && static_cast<size_t>(pRefDim->GetMemberCount()) == maMembers.size(), "dimensions don't match" );
3723 OSL_ENSURE( pRefDim == pResultDimension, "wrong dim" );
3724
3725 // for data layout, call only once - sorting measure is always taken from settings
3726 tools::Long nLoopCount = bIsDataLayout ? 1 : nCount;
3727 for (tools::Long i=0; i<nLoopCount; i++)
3728 {
3729 ScDPResultMember* pRefMember = pRefDim->GetMember(i);
3730 if ( pRefMember->IsVisible() ) //TODO: here or in ScDPDataMember ???
3731 {
3732 ScDPDataMember* pDataMember = maMembers[i].get();
3733 pDataMember->DoAutoShow( pRefMember );
3734 }
3735 }
3736
3737 if ( !(pRefDim->IsAutoShow() && pRefDim->GetAutoCount() > 0 && pRefDim->GetAutoCount() < nCount) )
3738 return;
3739
3740 // establish temporary order, hide remaining members
3741
3742 ScMemberSortOrder aAutoOrder;
3743 aAutoOrder.resize( nCount );
3745 for (nPos=0; nPos<nCount; nPos++)
3746 aAutoOrder[nPos] = nPos;
3747
3748 ScDPColMembersOrder aComp( *this, pRefDim->GetAutoMeasure(), !pRefDim->IsAutoTopItems() );
3749 ::std::sort( aAutoOrder.begin(), aAutoOrder.end(), aComp );
3750
3751 // look for equal values to the last included one
3752
3753 tools::Long nIncluded = pRefDim->GetAutoCount();
3754 ScDPDataMember* pDataMember1 = maMembers[aAutoOrder[nIncluded - 1]].get();
3755 if ( !pDataMember1->IsVisible() )
3756 pDataMember1 = nullptr;
3757 bool bContinue = true;
3758 while ( bContinue )
3759 {
3760 bContinue = false;
3761 if ( nIncluded < nCount )
3762 {
3763 ScDPDataMember* pDataMember2 = maMembers[aAutoOrder[nIncluded]].get();
3764 if ( !pDataMember2->IsVisible() )
3765 pDataMember2 = nullptr;
3766
3767 if ( lcl_IsEqual( pDataMember1, pDataMember2, pRefDim->GetAutoMeasure() ) )
3768 {
3769 ++nIncluded; // include more members if values are equal
3770 bContinue = true;
3771 }
3772 }
3773 }
3774
3775 // hide the remaining members
3776
3777 for (nPos = nIncluded; nPos < nCount; nPos++)
3778 {
3779 ScDPResultMember* pMember = pRefDim->GetMember(aAutoOrder[nPos]);
3780 pMember->SetAutoHidden();
3781 }
3782}
3783
3785{
3786 tools::Long nCount = maMembers.size();
3787 for (tools::Long i=0; i<nCount; i++)
3788 {
3789 // sort order doesn't matter
3790
3791 tools::Long nMemberPos = bIsDataLayout ? 0 : i;
3792 ScDPDataMember* pDataMember = maMembers[nMemberPos].get();
3793 pDataMember->ResetResults();
3794 }
3795}
3796
3798{
3799 if (!pResultDimension)
3800 return nUnsorted;
3801
3802 const ScMemberSortOrder& rMemberOrder = pResultDimension->GetMemberOrder();
3803 return rMemberOrder.empty() ? nUnsorted : rMemberOrder[nUnsorted];
3804}
3805
3807 tools::Long nMeasure, bool bIsSubTotalRow,
3808 const ScDPSubTotalState& rSubState, ScDPRunningTotalState& rRunning,
3809 ScDPRowTotals& rTotals, const ScDPResultMember& rRowParent ) const
3810{
3811 OSL_ENSURE( pRefDim && static_cast<size_t>(pRefDim->GetMemberCount()) == maMembers.size(), "dimensions don't match" );
3812 OSL_ENSURE( pRefDim == pResultDimension, "wrong dim" );
3813
3814 tools::Long nMemberMeasure = nMeasure;
3815 tools::Long nCount = maMembers.size();
3816 for (tools::Long i=0; i<nCount; i++)
3817 {
3818 const ScMemberSortOrder& rMemberOrder = pRefDim->GetMemberOrder();
3819 tools::Long nSorted = rMemberOrder.empty() ? i : rMemberOrder[i];
3820
3821 tools::Long nMemberPos = nSorted;
3822 if (bIsDataLayout)
3823 {
3824 OSL_ENSURE(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
3825 "DataLayout dimension twice?");
3826 nMemberPos = 0;
3827 nMemberMeasure = nSorted;
3828 }
3829
3830 const ScDPResultMember* pRefMember = pRefDim->GetMember(nMemberPos);
3831 if ( pRefMember->IsVisible() )
3832 {
3833 if ( bIsDataLayout )
3834 rRunning.AddColIndex( 0, 0 );
3835 else
3836 rRunning.AddColIndex( i, nSorted );
3837
3838 ScDPDataMember* pDataMember = maMembers[nMemberPos].get();
3839 pDataMember->UpdateRunningTotals(
3840 pRefMember, nMemberMeasure, bIsSubTotalRow, rSubState, rRunning, rTotals, rRowParent);
3841
3842 rRunning.RemoveColIndex();
3843 }
3844 }
3845}
3846
3847#if DUMP_PIVOT_TABLE
3848void ScDPDataDimension::DumpState( const ScDPResultDimension* pRefDim, ScDocument* pDoc, ScAddress& rPos ) const
3849{
3850 OUString aDimName = bIsDataLayout ? OUString("(data layout)") : OUString("(unknown)");
3851 dumpRow("ScDPDataDimension", aDimName, nullptr, pDoc, rPos);
3852
3853 SCROW nStartRow = rPos.Row();
3854
3856 for (tools::Long i=0; i<nCount; i++)
3857 {
3858 const ScDPResultMember* pRefMember = pRefDim->GetMember(i);
3859 const ScDPDataMember* pDataMember = maMembers[i].get();
3860 pDataMember->DumpState( pRefMember, pDoc, rPos );
3861 }
3862
3863 indent(pDoc, nStartRow, rPos);
3864}
3865
3866void ScDPDataDimension::Dump(int nIndent) const
3867{
3868 std::string aIndent(nIndent*2, ' ');
3869 std::cout << aIndent << "-- data dimension '"
3870 << (pResultDimension ? pResultDimension->GetName() : OUString()) << "'" << std::endl;
3871 for (auto& rxMember : maMembers)
3872 rxMember->Dump(nIndent+1);
3873}
3874#endif
3875
3877{
3878 return maMembers.size();
3879}
3880
3882{
3883 return maMembers[n].get();
3884}
3885
3887{
3888 return maMembers[n].get();
3889}
3890
3892 ScDPSource* pSource) :
3893 mpSource(pSource)
3894{
3895}
3896
3898{
3899}
3900
3901void ScDPResultVisibilityData::addVisibleMember(const OUString& rDimName, const ScDPItemData& rMemberItem)
3902{
3903 DimMemberType::iterator itr = maDimensions.find(rDimName);
3904 if (itr == maDimensions.end())
3905 {
3906 pair<DimMemberType::iterator, bool> r = maDimensions.emplace(
3907 rDimName, VisibleMemberType());
3908
3909 if (!r.second)
3910 // insertion failed.
3911 return;
3912
3913 itr = r.first;
3914 }
3915 VisibleMemberType& rMem = itr->second;
3916 rMem.insert(rMemberItem);
3917}
3918
3919void ScDPResultVisibilityData::fillFieldFilters(vector<ScDPFilteredCache::Criterion>& rFilters) const
3920{
3921 typedef std::unordered_map<OUString, tools::Long> FieldNameMapType;
3922 FieldNameMapType aFieldNames;
3924 sal_Int32 nColumnCount = pData->GetColumnCount();
3925 for (sal_Int32 i = 0; i < nColumnCount; ++i)
3926 {
3927 aFieldNames.emplace(pData->getDimensionName(i), i);
3928 }
3929
3931 for (const auto& [rDimName, rMem] : maDimensions)
3932 {
3934 FieldNameMapType::const_iterator itrField = aFieldNames.find(rDimName);
3935 if (itrField == aFieldNames.end())
3936 // This should never happen!
3937 continue;
3938
3939 tools::Long nDimIndex = itrField->second;
3940 aCri.mnFieldIndex = static_cast<sal_Int32>(nDimIndex);
3941 aCri.mpFilter = std::make_shared<ScDPFilteredCache::GroupFilter>();
3942
3943 ScDPFilteredCache::GroupFilter* pGrpFilter =
3944 static_cast<ScDPFilteredCache::GroupFilter*>(aCri.mpFilter.get());
3945
3946 for (const ScDPItemData& rMemItem : rMem)
3947 {
3948 pGrpFilter->addMatchItem(rMemItem);
3949 }
3950
3951 ScDPDimension* pDim = pDims->getByIndex(nDimIndex);
3952 ScDPMembers* pMembers = pDim->GetHierarchiesObject()->getByIndex(0)->
3953 GetLevelsObject()->getByIndex(0)->GetMembersObject();
3954 if (pGrpFilter->getMatchItemCount() < o3tl::make_unsigned(pMembers->getCount()))
3955 rFilters.push_back(aCri);
3956 }
3957}
3958
3960{
3961 if (r.IsValue())
3962 return static_cast<size_t>(::rtl::math::approxFloor(r.GetValue()));
3963 else
3964 return r.GetString().hashCode();
3965}
3967{
3968 const ScDPMember* pMemberDesc = GetDPMember();
3969 if (pMemberDesc)
3970 return pMemberDesc->GetItemDataId();
3971 return -1;
3972}
3973
3975{
3976 ScDPResultMember* pMember = new ScDPResultMember( pResultData, aData );
3977 SCROW nDataIndex = pMember->GetDataId();
3978 maMemberArray.emplace_back( pMember );
3979
3980 maMemberHash.emplace( nDataIndex, pMember );
3981 return pMember;
3982}
3983
3985{
3986 SCROW nInsert = 0;
3987 if ( !lcl_SearchMember( maMemberArray, pMemberData->mnOrder , nInsert ) )
3988 {
3989 ScDPResultMember* pNew = new ScDPResultMember( pResultData, *pMemberData );
3990 maMemberArray.emplace( maMemberArray.begin()+nInsert, pNew );
3991
3992 SCROW nDataIndex = pMemberData->mpMemberDesc->GetItemDataId();
3993 maMemberHash.emplace( nDataIndex, pNew );
3994 return pNew;
3995 }
3996 return maMemberArray[ nInsert ].get();
3997}
3998
4000 LateInitParams& rParams, const std::vector<SCROW>& pItemData, size_t nPos,
4001 ScDPInitState& rInitState)
4002{
4003 if ( rParams.IsEnd( nPos ) )
4004 return;
4005 ScDPDimension* pThisDim = rParams.GetDim( nPos );
4006 ScDPLevel* pThisLevel = rParams.GetLevel( nPos );
4007 SCROW nDataID = pItemData[nPos];
4008
4009 if (!(pThisDim && pThisLevel))
4010 return;
4011
4012 tools::Long nDimSource = pThisDim->GetDimension(); //TODO: check GetSourceDim?
4013
4014 // create all members at the first call (preserve order)
4015 ResultMembers& rMembers = pResultData->GetDimResultMembers(nDimSource, pThisDim, pThisLevel);
4016 ScDPGroupCompare aCompare( pResultData, rInitState, nDimSource );
4017 // initialize only specific member (or all if "show empty" flag is set)
4018 ScDPResultMember* pResultMember = nullptr;
4019 if ( bInitialized )
4020 pResultMember = FindMember( nDataID );
4021 else
4022 bInitialized = true;
4023
4024 if ( pResultMember == nullptr )
4025 { //only insert found item
4026 const ScDPParentDimData* pMemberData = rMembers.FindMember( nDataID );
4027 if ( pMemberData && aCompare.IsIncluded( *( pMemberData->mpMemberDesc ) ) )
4028 pResultMember = InsertMember( pMemberData );
4029 }
4030 if ( pResultMember )
4031 {
4032 rInitState.AddMember( nDimSource, pResultMember->GetDataId() );
4033 pResultMember->LateInitFrom(rParams, pItemData, nPos+1, rInitState);
4034 rInitState.RemoveMember();
4035 }
4036}
4037
4039 mnOrder(-1), mpParentDim(nullptr), mpParentLevel(nullptr), mpMemberDesc(nullptr) {}
4040
4042 SCROW nIndex, const ScDPDimension* pDim, const ScDPLevel* pLev, const ScDPMember* pMember) :
4043 mnOrder(nIndex), mpParentDim(pDim), mpParentLevel(pLev), mpMemberDesc(pMember) {}
4044
4046{
4047 auto aRes = maMemberHash.find( nIndex );
4048 if( aRes != maMemberHash.end()) {
4049 if ( aRes->second.mpMemberDesc && aRes->second.mpMemberDesc->GetItemDataId()==nIndex )
4050 return &aRes->second;
4051 }
4052 return nullptr;
4053}
4055{
4056 if ( !rNew.mpMemberDesc->getShowDetails() )
4058 maMemberHash.emplace( rNew.mpMemberDesc->GetItemDataId(), rNew );
4059}
4060
4062 mbHasHideDetailsMember( false )
4063{
4064}
4066{
4067}
4068
4070 const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLev, bool bRow ) :
4071 mppDim( ppDim ),
4072 mppLev( ppLev ),
4073 mbRow( bRow ),
4074 mbInitChild( true ),
4075 mbAllChildren( false )
4076{
4077}
4078
4079bool LateInitParams::IsEnd( size_t nPos ) const
4080{
4081 return nPos >= mppDim.size();
4082}
4083
4085{
4087
4088 for (tools::Long i=0; i<nCount; i++)
4089 {
4090 ScDPResultMember* pMember = maMemberArray.at(i).get();
4091 pMember->CheckShowEmpty(bShow);
4092 }
4093
4094}
4095
4097{
4098 if (bHasElements)
4099 {
4101 if (pChildDim)
4102 pChildDim->CheckShowEmpty();
4103 }
4104 else if (IsValid() && bInitialized)
4105 {
4106 bShow = bShow || (GetParentLevel() && GetParentLevel()->getShowEmpty());
4107 if (bShow)
4108 {
4111 if (pChildDim)
4112 pChildDim->CheckShowEmpty(true);
4113 }
4114 }
4115}
4116
4117/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const char * pName
const char *const aFieldNames[]
bool IsEnd(size_t nPos) const
Definition: dptabres.cxx:4079
void SetInitChild(bool b)
Definition: dptabres.hxx:256
LateInitParams(const ::std::vector< ScDPDimension * > &ppDim, const ::std::vector< ScDPLevel * > &ppLev, bool bRow)
Definition: dptabres.cxx:4069
bool IsRow() const
Definition: dptabres.hxx:264
bool GetInitChild() const
Definition: dptabres.hxx:262
const ::std::vector< ScDPDimension * > & mppDim
Definition: dptabres.hxx:246
ScDPDimension * GetDim(size_t nPos) const
Definition: dptabres.hxx:259
void SetInitAllChildren(bool b)
Definition: dptabres.hxx:257
ScDPLevel * GetLevel(size_t nPos) const
Definition: dptabres.hxx:260
bool GetInitAllChild() const
Definition: dptabres.hxx:263
bool mbHasHideDetailsMember
Definition: dptabres.hxx:233
std::unordered_map< SCROW, ScDPParentDimData > maMemberHash
Definition: dptabres.hxx:232
void SetHasHideDetailsMembers(bool b)
Definition: dptabres.hxx:238
const ScDPParentDimData * FindMember(SCROW nIndex) const
Definition: dptabres.cxx:4045
bool IsHasHideDetailsMembers() const
Definition: dptabres.hxx:237
void InsertMember(ScDPParentDimData const &rNew)
Definition: dptabres.cxx:4054
SCTAB Tab() const
Definition: address.hxx:283
SCROW Row() const
Definition: address.hxx:274
void SetRow(SCROW nRowP)
Definition: address.hxx:287
SCCOL Col() const
Definition: address.hxx:279
ScDPAggData * GetChild()
Definition: dptabres.cxx:661
sal_Int64 nCount
Definition: dptabres.hxx:159
bool IsCalculated() const
Definition: dptabres.cxx:595
bool HasData() const
Definition: dptabres.cxx:614
std::vector< double > mSortedValues
Definition: dptabres.hxx:161
void Update(const ScDPValue &rNext, ScSubTotalFunc eFunc, const ScDPSubTotalState &rSubState)
Definition: dptabres.cxx:374
double fVal
Definition: dptabres.hxx:157
const ScDPAggData * GetExistingChild() const
Definition: dptabres.hxx:183
void Dump(int nIndent) const
bool HasError() const
Definition: dptabres.cxx:607
WelfordRunner maWelford
Definition: dptabres.hxx:156
void SetError()
Definition: dptabres.cxx:628
void SetEmpty(bool bSet)
Definition: dptabres.cxx:635
void Reset()
Definition: dptabres.cxx:668
std::unique_ptr< ScDPAggData > pChild
Definition: dptabres.hxx:160
double fAux
Definition: dptabres.hxx:158
void Calculate(ScSubTotalFunc eFunc, const ScDPSubTotalState &rSubState)
Definition: dptabres.cxx:449
double GetAuxiliary() const
Definition: dptabres.cxx:645
void SetAuxiliary(double fNew)
Definition: dptabres.cxx:653
void SetResult(double fNew)
Definition: dptabres.cxx:621
double GetResult() const
Definition: dptabres.cxx:600
void UpdateDataRow(const ScDPResultDimension *pRefDim, tools::Long nMeasure, bool bIsSubTotalRow, const ScDPSubTotalState &rSubState) const
Definition: dptabres.cxx:3653
const ScDPResultData * pResultData
Definition: dptabres.hxx:603
void DoAutoShow(ScDPResultDimension *pRefDim)
Definition: dptabres.cxx:3716
tools::Long GetSortedIndex(tools::Long nUnsorted) const
Definition: dptabres.cxx:3797
ScDPDataDimension(const ScDPResultData *pData)
or ptr to IntDimension?
Definition: dptabres.cxx:3540
void UpdateRunningTotals(const ScDPResultDimension *pRefDim, tools::Long nMeasure, bool bIsSubTotalRow, const ScDPSubTotalState &rSubState, ScDPRunningTotalState &rRunning, ScDPRowTotals &rTotals, const ScDPResultMember &rRowParent) const
Definition: dptabres.cxx:3806
const ScDPResultDimension * pResultDimension
Definition: dptabres.hxx:604
std::vector< std::unique_ptr< ScDPDataMember > > maMembers
Definition: dptabres.hxx:605
void SortMembers(ScDPResultDimension *pRefDim)
Definition: dptabres.cxx:3680
void ProcessData(const ::std::vector< SCROW > &aDataMembers, const ::std::vector< ScDPValue > &aValues, const ScDPSubTotalState &rSubState)
Definition: dptabres.cxx:3581
void DumpState(const ScDPResultDimension *pRefDim, ScDocument *pDoc, ScAddress &rPos) const
void Dump(int nIndent) const
tools::Long GetMemberCount() const
Definition: dptabres.cxx:3876
const ScDPDataMember * GetMember(tools::Long n) const
Definition: dptabres.cxx:3881
void FillDataRow(const ScDPResultDimension *pRefDim, ScDPResultFilterContext &rFilterCxt, css::uno::Sequence< css::sheet::DataResult > &rSequence, tools::Long nMeasure, bool bIsSubTotalRow, const ScDPSubTotalState &rSubState) const
Definition: dptabres.cxx:3608
void InitFrom(const ScDPResultDimension *pDim)
Definition: dptabres.cxx:3551
void UpdateValues(const ::std::vector< ScDPValue > &aValues, const ScDPSubTotalState &rSubState)
Definition: dptabres.cxx:1913
void Dump(int nIndent) const
OUString GetName() const
Definition: dptabres.cxx:1854
const ScDPResultMember * pResultMember
Definition: dptabres.hxx:429
ScDPAggData * GetAggData(tools::Long nMeasure, const ScDPSubTotalState &rSubState)
Definition: dptabres.cxx:2005
void SortMembers(ScDPResultMember *pRefMember)
Definition: dptabres.cxx:2248
bool HasHiddenDetails() const
Definition: dptabres.cxx:1878
void InitFrom(const ScDPResultDimension *pDim)
Definition: dptabres.cxx:1886
void ResetResults()
Definition: dptabres.cxx:2274
ScDPDataMember(const ScDPResultData *pData, const ScDPResultMember *pRes)
Definition: dptabres.cxx:1843
void UpdateRunningTotals(const ScDPResultMember *pRefMember, tools::Long nMeasure, bool bIsSubTotalRow, const ScDPSubTotalState &rSubState, ScDPRunningTotalState &rRunning, ScDPRowTotals &rTotals, const ScDPResultMember &rRowParent)
Definition: dptabres.cxx:2283
bool HasError(tools::Long nMeasure, const ScDPSubTotalState &rSubState) const
Definition: dptabres.cxx:1987
void UpdateDataRow(const ScDPResultMember *pRefMember, tools::Long nMeasure, bool bIsSubTotalRow, const ScDPSubTotalState &rSubState)
Definition: dptabres.cxx:2175
void ProcessData(const ::std::vector< SCROW > &aChildMembers, const ::std::vector< ScDPValue > &aValues, const ScDPSubTotalState &rSubState)
Definition: dptabres.cxx:1937
bool IsVisible() const
Definition: dptabres.cxx:1862
void DumpState(const ScDPResultMember *pRefMember, ScDocument *pDoc, ScAddress &rPos) const
void DoAutoShow(ScDPResultMember *pRefMember)
Definition: dptabres.cxx:2261
double GetAggregate(tools::Long nMeasure, const ScDPSubTotalState &rSubState) const
Definition: dptabres.cxx:1996
const ScDPDataDimension * GetChildDimension() const
this will be removed!
Definition: dptabres.hxx:480
bool IsNamedItem(SCROW nRow) const
Definition: dptabres.cxx:1870
const ScDPResultData * pResultData
Definition: dptabres.hxx:428
bool HasData(tools::Long nMeasure, const ScDPSubTotalState &rSubState) const
Definition: dptabres.cxx:1972
ScDPAggData aAggregate
Definition: dptabres.hxx:432
std::unique_ptr< ScDPDataDimension > pChildDimension
Ref?
Definition: dptabres.hxx:431
const ScDPAggData * GetConstAggData(tools::Long nMeasure, const ScDPSubTotalState &rSubState) const
Definition: dptabres.cxx:2023
void FillDataRow(const ScDPResultMember *pRefMember, ScDPResultFilterContext &rFilterCxt, css::uno::Sequence< css::sheet::DataResult > &rSequence, tools::Long nMeasure, bool bIsSubTotalRow, const ScDPSubTotalState &rSubState) const
Definition: dptabres.cxx:2045
ScDPHierarchies * GetHierarchiesObject()
Definition: dptabsrc.cxx:1279
const std::optional< OUString > & GetLayoutName() const
Definition: dptabsrc.cxx:1288
virtual OUString SAL_CALL getName() override
Definition: dptabsrc.cxx:1303
bool getIsDataLayoutDimension() const
Definition: dptabsrc.cxx:1322
sal_Int32 GetDimension() const
Definition: dptabsrc.hxx:287
const std::optional< OUString > & GetSubtotalName() const
Definition: dptabsrc.cxx:1293
ScDPDimension * getByIndex(tools::Long nIndex) const
Definition: dptabsrc.cxx:1242
multi-item (group) filter.
void addMatchItem(const ScDPItemData &rItem)
ScDPHierarchy * getByIndex(tools::Long nIndex) const
Definition: dptabsrc.cxx:1662
Member names that are being processed for InitFrom/LateInitFrom (needed for initialization of grouped...
Definition: dptabres.hxx:56
void RemoveMember()
Definition: dptabres.cxx:261
void AddMember(tools::Long nSourceIndex, SCROW nMember)
Definition: dptabres.cxx:256
std::vector< Member > maMembers
Definition: dptabres.hxx:72
When assigning a string value, you can also assign an interned string whose life-cycle is managed by ...
Definition: dpitemdata.hxx:29
double GetValue() const
Definition: dpitemdata.cxx:347
bool IsValue() const
Definition: dpitemdata.cxx:322
Type GetType() const
Definition: dpitemdata.hxx:67
OUString GetString() const
Definition: dpitemdata.cxx:327
ScDPMembers * GetMembersObject()
Definition: dptabsrc.cxx:1959
const css::sheet::DataPilotFieldAutoShowInfo & GetAutoShow() const
Definition: dptabsrc.hxx:511
sal_Int32 GetAutoMeasure() const
Definition: dptabsrc.hxx:519
bool IsAddEmpty() const
Definition: dptabsrc.hxx:537
const css::sheet::DataPilotFieldSortInfo & GetSortInfo() const
Definition: dptabsrc.hxx:510
sal_Int32 GetSortMeasure() const
Definition: dptabsrc.hxx:518
const ::std::vector< sal_Int32 > & GetGlobalOrder() const
Definition: dptabsrc.hxx:516
bool getShowEmpty() const
Definition: dptabsrc.hxx:507
css::uno::Sequence< sal_Int16 > getSubTotals() const
Definition: dptabsrc.cxx:2044
bool IsOutlineLayout() const
Definition: dptabsrc.hxx:521
bool getRepeatItemLabels() const
Definition: dptabsrc.hxx:508
bool isVisible() const
Definition: dptabsrc.hxx:656
bool getShowDetails() const
Definition: dptabsrc.hxx:657
SCROW GetItemDataId() const
Definition: dptabsrc.hxx:623
bool IsNamedItem(SCROW nIndex) const
Definition: dptabsrc.cxx:2450
tools::Long GetDim() const
Definition: dptabsrc.hxx:627
ScDPItemData FillItemData() const
Definition: dptabsrc.cxx:2495
OUString GetNameStr(bool bLocaleIndependent) const
Definition: dptabsrc.cxx:2508
const std::optional< OUString > & GetLayoutName() const
Definition: dptabsrc.cxx:2503
sal_Int32 getCount() const
Definition: dptabsrc.hxx:583
ScDPMember * getByIndex(sal_Int32 nIndex) const
Definition: dptabsrc.cxx:2338
The term 'measure' here roughly equals "data dimension" ?
Definition: dptabres.hxx:272
void SetDataLayoutOrientation(css::sheet::DataPilotFieldOrientation nOrient)
Definition: dptabres.cxx:795
bool IsNumOrDateGroup(tools::Long nDim) const
Definition: dptabres.cxx:895
tools::Long GetGroupBase(tools::Long nGroupDim) const
Definition: dptabres.cxx:890
css::sheet::DataPilotFieldOrientation GetMeasureRefOrient(tools::Long nMeasure) const
Definition: dptabres.cxx:834
void SetMeasureData(std::vector< ScSubTotalFunc > &rFunctions, std::vector< css::sheet::DataPilotFieldReference > &rRefs, std::vector< css::sheet::DataPilotFieldOrientation > &rRefOrient, std::vector< OUString > &rNames)
Definition: dptabres.cxx:772
ScDPSource & mrSource
Definition: dptabres.hxx:273
bool IsLateInit() const
Definition: dptabres.hxx:307
ScSubTotalFunc GetMeasureFunction(tools::Long nMeasure) const
Definition: dptabres.cxx:822
std::vector< css::sheet::DataPilotFieldReference > maMeasureRefs
Definition: dptabres.hxx:277
ScDPResultData(ScDPSource &rSrc)
Definition: dptabres.cxx:760
const css::sheet::DataPilotFieldReference & GetMeasureRefVal(tools::Long nMeasure) const
Definition: dptabres.cxx:828
tools::Long GetCountForMeasure(tools::Long nMeas) const
Definition: dptabres.hxx:312
void SetLateInit(bool bSet)
Definition: dptabres.cxx:801
OUString GetMeasureString(tools::Long nMeasure, bool bForce, ScSubTotalFunc eForceFunc, bool &rbTotalResult) const
Definition: dptabres.cxx:840
tools::Long GetRowStartMeasure() const
Definition: dptabres.cxx:814
OUString GetMeasureDimensionName(tools::Long nMeasure) const
Definition: dptabres.cxx:874
std::vector< ScSubTotalFunc > maMeasureFuncs
keep things like measure lists here
Definition: dptabres.hxx:276
tools::Long GetMeasureCount() const
Definition: dptabres.hxx:300
std::vector< std::unique_ptr< ResultMembers > > maDimMembers
add "displayed values" settings
Definition: dptabres.hxx:286
bool HasCommonElement(SCROW nFirstDataId, tools::Long nFirstIndex, const ScDPItemData &rSecondData, tools::Long nSecondIndex) const
Definition: dptabres.cxx:910
std::vector< OUString > maMeasureNames
Definition: dptabres.hxx:279
tools::Long GetColStartMeasure() const
Definition: dptabres.cxx:806
std::vector< css::sheet::DataPilotFieldOrientation > maMeasureRefOrients
Definition: dptabres.hxx:278
bool IsInGroup(SCROW nGroupDataId, tools::Long nGroupIndex, const ScDPItemData &rBaseData, tools::Long nBaseIndex) const
Definition: dptabres.cxx:900
const ScDPSource & GetSource() const
Definition: dptabres.hxx:324
bool IsBaseForGroup(tools::Long nDim) const
Definition: dptabres.cxx:885
ResultMembers & GetDimResultMembers(tools::Long nDim, const ScDPDimension *pDim, ScDPLevel *pLevel) const
Definition: dptabres.cxx:920
tools::Long GetMemberCount() const
Definition: dptabres.cxx:3501
void FillVisibilityData(ScDPResultVisibilityData &rData) const
Definition: dptabres.cxx:3523
void InitWithMembers(LateInitParams &rParams, const ::std::vector< SCROW > &pItemData, size_t nPos, ScDPInitState &rInitState)
Definition: dptabres.cxx:3999
void SortMembers(ScDPResultMember *pRefMember)
Definition: dptabres.cxx:3123
void LateInitFrom(LateInitParams &rParams, const ::std::vector< SCROW > &pItemData, size_t nPos, ScDPInitState &rInitState)
Definition: dptabres.cxx:2867
bool IsValidEntry(const ::std::vector< SCROW > &aMembers) const
Definition: dptabres.cxx:3007
tools::Long GetSortMeasure() const
Definition: dptabres.hxx:588
void DoAutoShow(ScDPResultMember *pRefMember)
Definition: dptabres.cxx:3152
bool IsSortAscending() const
Definition: dptabres.hxx:587
void UpdateRunningTotals(const ScDPResultMember *pRefMember, tools::Long nMeasure, ScDPRunningTotalState &rRunning, ScDPRowTotals &rTotals) const
Definition: dptabres.cxx:3228
void UpdateDataResults(const ScDPResultMember *pRefMember, tools::Long nMeasure) const
Definition: dptabres.cxx:3101
ScDPDataMember * GetRowReferenceMember(const ScDPRelativePos *pMemberPos, const OUString *pName, const sal_Int32 *pRowIndexes, const sal_Int32 *pColIndexes) const
Definition: dptabres.cxx:3260
void Dump(int nIndent) const
OUString aDimensionName
Definition: dptabres.hxx:495
ScDPResultDimension * GetFirstChildDimension() const
Definition: dptabres.cxx:3515
ScDPResultMember * InsertMember(const ScDPParentDimData *pMemberData)
Definition: dptabres.cxx:3984
const ScMemberSortOrder & GetMemberOrder() const
Definition: dptabres.hxx:580
MemberArray maMemberArray
Definition: dptabres.hxx:493
ScDPResultMember * FindMember(SCROW iData) const
Definition: dptabres.cxx:2773
ScDPResultDimension(const ScDPResultData *pData)
Definition: dptabres.cxx:2755
void CheckShowEmpty(bool bShow=false)
Definition: dptabres.cxx:4084
void DumpState(const ScDPResultMember *pRefMember, ScDocument *pDoc, ScAddress &rPos) const
bool IsDataLayout() const
Definition: dptabres.hxx:583
bool IsAutoTopItems() const
Definition: dptabres.hxx:591
void FillMemberResults(css::uno::Sequence< css::sheet::MemberResult > *pSequences, tools::Long nStart, tools::Long nMeasure)
Test.
Definition: dptabres.cxx:3045
tools::Long GetAutoCount() const
Definition: dptabres.hxx:593
tools::Long nSortMeasure
or ptr to IntDimension?
Definition: dptabres.hxx:496
ScDPResultMember * AddMember(const ScDPParentDimData &aData)
Definition: dptabres.cxx:3974
tools::Long nAutoCount
Definition: dptabres.hxx:505
tools::Long GetAutoMeasure() const
Definition: dptabres.hxx:592
tools::Long nAutoMeasure
Definition: dptabres.hxx:504
bool bSortByData
or ptr to IntDimension?
Definition: dptabres.hxx:499
MemberHash maMemberHash
Definition: dptabres.hxx:494
static ScDPDataMember * GetColReferenceMember(const ScDPRelativePos *pMemberPos, const OUString *pName, sal_Int32 nRefDimPos, const ScDPRunningTotalState &rRunning)
Definition: dptabres.cxx:3350
tools::Long GetSortedIndex(tools::Long nUnsorted) const
Definition: dptabres.cxx:3223
bool IsAutoShow() const
Definition: dptabres.hxx:590
void ProcessData(const ::std::vector< SCROW > &aMembers, const ScDPResultDimension *pDataDim, const ::std::vector< SCROW > &aDataMembers, const ::std::vector< ScDPValue > &aValues) const
Definition: dptabres.cxx:3021
const ScDPResultMember * GetMember(tools::Long n) const
Definition: dptabres.cxx:3506
const ScDPResultData * pResultData
Definition: dptabres.hxx:492
tools::Long GetSize(tools::Long nMeasure) const
Definition: dptabres.cxx:2984
void InitFrom(const ::std::vector< ScDPDimension * > &ppDim, const ::std::vector< ScDPLevel * > &ppLev, size_t nPos, ScDPInitState &rInitState, bool bInitChild=true)
Definition: dptabres.cxx:2799
bool IsSortByData() const
Definition: dptabres.hxx:586
const OUString & GetName() const
Definition: dptabres.hxx:584
void FillDataResults(const ScDPResultMember *pRefMember, ScDPResultFilterContext &rFilterCxt, css::uno::Sequence< css::uno::Sequence< css::sheet::DataResult > > &rSequence, tools::Long nMeasure) const
Definition: dptabres.cxx:3072
ScMemberSortOrder aMemberOrder
Definition: dptabres.hxx:497
void ProcessData(const ::std::vector< SCROW > &aChildMembers, const ScDPResultDimension *pDataDim, const ::std::vector< SCROW > &aDataMembers, const ::std::vector< ScDPValue > &aValues)
Definition: dptabres.cxx:1257
void LateInitFrom(LateInitParams &rParams, const ::std::vector< SCROW > &pItemData, size_t nPos, ScDPInitState &rInitState)
Definition: dptabres.cxx:1083
const ScDPMember * GetDPMember() const
Ref.
Definition: dptabres.hxx:416
bool IsValid() const
Definition: dptabres.cxx:1212
const ScDPLevel * GetParentLevel() const
Ref.
Definition: dptabres.hxx:415
std::unique_ptr< ScDPResultDimension > pChildDimension
Definition: dptabres.hxx:332
void UpdateDataResults(const ScDPResultMember *pRefMember, tools::Long nMeasure) const
Definition: dptabres.cxx:1655
void SetHasElements()
Definition: dptabres.hxx:376
ScDPResultMember(const ScDPResultData *pData, const ScDPParentDimData &rParentDimData)
Definition: dptabres.cxx:949
const ScDPResultData * pResultData
Definition: dptabres.hxx:330
void FillDataResults(const ScDPResultMember *pRefMember, ScDPResultFilterContext &rFilterCxt, css::uno::Sequence< css::uno::Sequence< css::sheet::DataResult > > &rSequence, tools::Long nMeasure) const
Definition: dptabres.cxx:1543
void InitFrom(const ::std::vector< ScDPDimension * > &ppDim, const ::std::vector< ScDPLevel * > &ppLev, size_t nPos, ScDPInitState &rInitState, bool bInitChild=true)
Definition: dptabres.cxx:1039
bool HasHiddenDetails() const
Definition: dptabres.hxx:368
tools::Long GetSubTotalCount(tools::Long *pUserSubStart=nullptr) const
Definition: dptabres.cxx:1227
bool IsRoot() const
Ref.
Definition: dptabres.hxx:418
void CheckShowEmpty(bool bShow=false)
Definition: dptabres.cxx:4096
const ScDPDimension * GetParentDim() const
Definition: dptabres.hxx:414
void Dump(int nIndent) const
void DoAutoShow(ScDPResultMember *pRefMember)
Definition: dptabres.cxx:1719
bool IsNamedItem(SCROW nIndex) const
Definition: dptabres.cxx:1011
SCROW GetDataId() const
Definition: dptabres.cxx:3966
const ScDPResultDimension * GetChildDimension() const
this will be removed!
Definition: dptabres.hxx:409
void FillVisibilityData(ScDPResultVisibilityData &rData) const
Definition: dptabres.cxx:1837
bool IsSubTotalInTitle(tools::Long nMeasure) const
Definition: dptabres.cxx:1135
OUString GetDisplayName(bool bLocaleIndependent) const
Definition: dptabres.cxx:987
ScDPItemData FillItemData() const
Definition: dptabres.cxx:1003
void FillMemberResults(css::uno::Sequence< css::sheet::MemberResult > *pSequences, tools::Long &rPos, tools::Long nMeasure, bool bRoot, const OUString *pMemberName, const OUString *pMemberCaption)
Definition: dptabres.cxx:1323
ScDPParentDimData aParentDimData
Definition: dptabres.hxx:331
ScDPDataMember * GetDataRoot() const
Definition: dptabres.hxx:412
void UpdateRunningTotals(const ScDPResultMember *pRefMember, tools::Long nMeasure, ScDPRunningTotalState &rRunning, ScDPRowTotals &rTotals) const
Definition: dptabres.cxx:1743
bool IsVisible() const
Definition: dptabres.cxx:1194
tools::Long GetSize(tools::Long nMeasure) const
Definition: dptabres.cxx:1157
ScDPAggData * GetColTotal(tools::Long nMeasure) const
Definition: dptabres.cxx:1832
void SortMembers(ScDPResultMember *pRefMember)
Definition: dptabres.cxx:1704
std::unique_ptr< ScDPDataMember > pDataRoot
Definition: dptabres.hxx:333
void DumpState(const ScDPResultMember *pRefMember, ScDocument *pDoc, ScAddress &rPos) const
sal_uInt16 nMemberStep
Definition: dptabres.hxx:341
void SetAutoHidden()
Definition: dptabres.hxx:377
bool IsValidEntry(const ::std::vector< SCROW > &aMembers) const
Definition: dptabres.cxx:1020
ScDPAggData aColTotal
Definition: dptabres.hxx:339
OUString GetName() const
Definition: dptabres.cxx:978
bool bHasHiddenDetails
Definition: dptabres.hxx:336
void add(const std::vector< ScDPResultFilter > &rFilter, double fVal)
Add a single value filter path.
Definition: dpresfilter.cxx:83
This class collects visible members of each dimension and uses that information to create filtering c...
Definition: dptabres.hxx:649
ScDPResultVisibilityData(ScDPSource *pSource)
Definition: dptabres.cxx:3891
void fillFieldFilters(::std::vector< ScDPFilteredCache::Criterion > &rFilters) const
Definition: dptabres.cxx:3919
void addVisibleMember(const OUString &rDimName, const ScDPItemData &rMemberItem)
Definition: dptabres.cxx:3901
DimMemberType maDimensions
Definition: dptabres.hxx:664
std::unordered_set< ScDPItemData, MemberHash > VisibleMemberType
Definition: dptabres.hxx:662
ScDPAggData * GetGrandTotal(tools::Long nMeasure)
Definition: dptabres.cxx:727
void SetInColRoot(bool bSet)
Definition: dptabres.hxx:207
ScDPAggData * GetRowTotal(tools::Long nMeasure)
Definition: dptabres.cxx:722
bool IsInColRoot() const
Definition: dptabres.hxx:206
ScDPAggData aGrandTotal
Definition: dptabres.hxx:196
ScDPAggData aRowTotal
Definition: dptabres.hxx:195
indexes when calculating running totals
Definition: dptabres.hxx:105
ScDPRunningTotalState(ScDPResultMember *pColRoot, ScDPResultMember *pRowRoot)
array of sal_Int32 terminated by -1.
Definition: dptabres.cxx:308
void AddRowIndex(sal_Int32 nVisible, tools::Long nSorted)
Definition: dptabres.cxx:327
std::vector< sal_Int32 > IndexArray
Definition: dptabres.hxx:107
ScDPResultMember * GetRowResRoot() const
Definition: dptabres.hxx:112
const IndexArray & GetRowVisible() const
Definition: dptabres.hxx:116
IndexArray maRowSorted
Definition: dptabres.hxx:131
const IndexArray & GetRowSorted() const
Definition: dptabres.hxx:117
IndexArray maColVisible
Definition: dptabres.hxx:128
IndexArray maColSorted
Definition: dptabres.hxx:129
const IndexArray & GetColVisible() const
Definition: dptabres.hxx:114
IndexArray maRowVisible
Definition: dptabres.hxx:130
void AddColIndex(sal_Int32 nVisible, tools::Long nSorted)
Definition: dptabres.cxx:318
const IndexArray & GetColSorted() const
Definition: dptabres.hxx:115
ScDPResultMember * GetColResRoot() const
Definition: dptabres.hxx:111
ScDPDimensions * GetDimensionsObject()
Definition: dptabsrc.cxx:292
ScDPTableData * GetData()
Definition: dptabsrc.hxx:143
OUString GetDataDimName(sal_Int32 nIndex)
Definition: dptabsrc.cxx:155
const std::optional< OUString > & GetGrandTotalName() const
Definition: dptabsrc.cxx:119
const ScDPItemData * GetItemDataById(sal_Int32 nDim, sal_Int32 nId)
Definition: dptabsrc.cxx:2595
ScDPDimension * GetDataDimension(sal_Int32 nIndex)
Definition: dptabsrc.cxx:146
Base class that abstracts different data source types of a datapilot table.
Definition: dptabdat.hxx:57
virtual sal_Int32 GetGroupBase(sal_Int32 nGroupDim) const
Definition: dptabdat.cxx:117
virtual bool IsNumOrDateGroup(sal_Int32 nDim) const
Definition: dptabdat.cxx:122
virtual bool HasCommonElement(const ScDPItemData &rFirstData, sal_Int32 nFirstIndex, const ScDPItemData &rSecondData, sal_Int32 nSecondIndex) const
Definition: dptabdat.cxx:134
OUString GetFormattedString(sal_Int32 nDim, const ScDPItemData &rItem, bool bLocaleIndependent) const
Definition: dptabdat.cxx:51
virtual bool IsInGroup(const ScDPItemData &rGroupData, sal_Int32 nGroupIndex, const ScDPItemData &rBaseData, sal_Int32 nBaseIndex) const
Definition: dptabdat.cxx:127
virtual bool IsBaseForGroup(sal_Int32 nDim) const
Definition: dptabdat.cxx:112
static SC_DLLPUBLIC ScSubTotalFunc toSubTotalFunc(ScGeneralFunction eGenFunc)
Definition: dputil.cxx:395
static SC_DLLPUBLIC OUString getDisplayedMeasureName(const OUString &rName, ScSubTotalFunc eFunc)
Definition: dputil.cxx:384
SC_DLLPUBLIC bool SetString(SCCOL nCol, SCROW nRow, SCTAB nTab, const OUString &rString, const ScSetStringParam *pParam=nullptr)
Definition: document.cxx:3391
SC_DLLPUBLIC void SetValue(SCCOL nCol, SCROW nRow, SCTAB nTab, const double &rVal)
Definition: document.cxx:3477
SC_DLLPUBLIC OUString GetString(SCCOL nCol, SCROW nRow, SCTAB nTab, const ScInterpreterContext *pContext=nullptr) const
Definition: document.cxx:3505
static bool SafePlus(double &fVal1, double fVal2)
Definition: subtotal.cxx:24
static bool SafeMult(double &fVal1, double fVal2)
Definition: subtotal.cxx:40
Implements the Welford Online one-pass algorithm.
Definition: subtotal.hxx:39
double getVariancePopulation() const
Definition: subtotal.hxx:45
sal_uInt64 getCount() const
Definition: subtotal.hxx:43
void update(double fVal)
Definition: subtotal.cxx:196
double getVarianceSample() const
Definition: subtotal.hxx:44
int nCount
static tools::Long lcl_GetSubTotalPos(const ScDPSubTotalState &rSubState)
Definition: dptabres.cxx:1896
const tools::Long SC_SUBTOTALPOS_AUTO
Definition: dptabres.cxx:1893
static ScDPAggData * lcl_GetChildTotal(ScDPAggData *pFirst, tools::Long nMeasure)
Definition: dptabres.cxx:700
static bool lcl_IsEqual(const ScDPDataMember *pDataMember1, const ScDPDataMember *pDataMember2, tools::Long nMeasure)
Definition: dptabres.cxx:196
static bool lcl_IsLess(const ScDPDataMember *pDataMember1, const ScDPDataMember *pDataMember2, tools::Long nMeasure, bool bAscending)
Definition: dptabres.cxx:170
static ScSubTotalFunc lcl_GetForceFunc(const ScDPLevel *pLevel, tools::Long nFuncNo)
Definition: dptabres.cxx:732
static OUString lcl_parseSubtotalName(std::u16string_view rSubStr, std::u16string_view rCaption)
Parse subtotal string and replace all occurrences of '?' with the caption string.
Definition: dptabres.cxx:1300
const tools::Long SC_SUBTOTALPOS_SKIP
Definition: dptabres.cxx:1894
::std::vector< sal_Int32 > ScMemberSortOrder
Definition: dptabres.hxx:75
const sal_Int64 SC_DPAGG_RESULT_VALID
Definition: dptabres.hxx:150
#define SC_DPMEASURE_ALL
Definition: dptabres.hxx:216
const sal_Int64 SC_DPAGG_RESULT_EMPTY
Definition: dptabres.hxx:149
const sal_Int64 SC_DPAGG_RESULT_ERROR
Definition: dptabres.hxx:151
const sal_Int64 SC_DPAGG_EMPTY
separate header file?
Definition: dptabres.hxx:147
#define SC_DPMEASURE_ANY
Definition: dptabres.hxx:217
DocumentType eType
ScGeneralFunction
the css::sheet::GeneralFunction enum is extended by constants in GeneralFunction2,...
@ AUTO
function is determined automatically.
ScSubTotalFunc
Definition: global.hxx:860
@ SUBTOTAL_FUNC_STDP
Definition: global.hxx:869
@ SUBTOTAL_FUNC_MAX
Definition: global.hxx:865
@ SUBTOTAL_FUNC_CNT2
Definition: global.hxx:864
@ SUBTOTAL_FUNC_AVE
Definition: global.hxx:862
@ SUBTOTAL_FUNC_VARP
Definition: global.hxx:872
@ SUBTOTAL_FUNC_VAR
Definition: global.hxx:871
@ SUBTOTAL_FUNC_NONE
Definition: global.hxx:861
@ SUBTOTAL_FUNC_SUM
Definition: global.hxx:870
@ SUBTOTAL_FUNC_MED
Definition: global.hxx:873
@ SUBTOTAL_FUNC_STD
Definition: global.hxx:868
@ SUBTOTAL_FUNC_MIN
Definition: global.hxx:866
@ SUBTOTAL_FUNC_CNT
Definition: global.hxx:863
@ SUBTOTAL_FUNC_PROD
Definition: global.hxx:867
sal_Int32 nIndex
OUString aName
void * p
sal_Int64 n
sal_uInt16 nPos
Sequence< sal_Int8 > aSeq
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
#define SAL_N_ELEMENTS(arr)
std::unique_ptr< sal_Int32[]> pData
constexpr OUStringLiteral aData
double getLength(const B2DPolygon &rCandidate)
int i
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
long Long
OUString ScResId(TranslateId aId)
Definition: scdll.cxx:90
single filtering criterion.
std::shared_ptr< FilterBase > mpFilter
Member(tools::Long nSrcIndex, SCROW nNameIndex)
Definition: dptabres.cxx:253
const ScDPDimension * mpParentDim
Ref.
Definition: dptabres.hxx:222
const ScDPMember * mpMemberDesc
Ref.
Definition: dptabres.hxx:224
const SCROW mnOrder
Definition: dptabres.hxx:221
tools::Long nBasePos
Definition: dptabres.hxx:136
tools::Long nDirection
Definition: dptabres.hxx:137
ScDPRelativePos(tools::Long nBase, tools::Long nDir)
Definition: dptabres.cxx:368
std::vector< ScDPResultFilter > maFilters
ScDPResultTree maFilterSet
OUString maValueName
Definition: dpresfilter.hxx:32
size_t operator()(const ScDPItemData &r) const
Definition: dptabres.cxx:3959
Select subtotal information, passed down the dimensions.
Definition: dptabres.hxx:81
ScSubTotalFunc eRowForce
Definition: dptabres.hxx:83
ScSubTotalFunc eColForce
Definition: dptabres.hxx:82
tools::Long nColSubTotalFunc
Definition: dptabres.hxx:84
tools::Long nRowSubTotalFunc
Definition: dptabres.hxx:85
double mfValue
Definition: dpglobal.hxx:48
Type meType
Definition: dpglobal.hxx:49
sal_uInt16 sal_Unicode
sal_Int16 SCTAB
Definition: types.hxx:22
sal_Int16 SCCOL
Definition: types.hxx:21
sal_Int32 SCROW
Definition: types.hxx:17