LibreOffice Module sc (master) 1
PivotTableDataProvider.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
10#include <limits>
11#include <memory>
12#include <sal/config.h>
13
17
18#include <miscuno.hxx>
19#include <document.hxx>
20#include <unonames.hxx>
21#include <scresid.hxx>
22#include <globstr.hrc>
23#include <strings.hrc>
24#include <dpobject.hxx>
25#include <hints.hxx>
26
27#include <o3tl/safeint.hxx>
28#include <vcl/svapp.hxx>
29#include <sfx2/objsh.hxx>
33
34#include <com/sun/star/chart2/data/LabeledDataSequence.hpp>
35#include <com/sun/star/chart/ChartDataRowSource.hpp>
36#include <com/sun/star/frame/XModel.hpp>
37
38#include <com/sun/star/sheet/XDataPilotResults.hpp>
39#include <com/sun/star/sheet/DataResultFlags.hpp>
40
41#include <com/sun/star/sheet/XDimensionsSupplier.hpp>
42#include <com/sun/star/sheet/XHierarchiesSupplier.hpp>
43#include <com/sun/star/sheet/XLevelsSupplier.hpp>
44#include <com/sun/star/sheet/XDataPilotMemberResults.hpp>
45#include <com/sun/star/sheet/MemberResultFlags.hpp>
46#include <com/sun/star/sheet/XMembersSupplier.hpp>
47
48#include <com/sun/star/chart/ChartDataChangeEvent.hpp>
49#include <com/sun/star/container/XNamed.hpp>
50
51#include <unordered_map>
52
53using namespace css;
54
55namespace sc
56{
57namespace
58{
59constexpr OUStringLiteral constIdCategories(u"categories");
60constexpr OUStringLiteral constIdLabel(u"label");
61constexpr OUStringLiteral constIdData(u"data");
62
63o3tl::span<const SfxItemPropertyMapEntry> lcl_GetDataProviderPropertyMap()
64{
65 static const SfxItemPropertyMapEntry aDataProviderPropertyMap_Impl[] =
66 {
69 };
70 return aDataProviderPropertyMap_Impl;
71}
72
73uno::Reference<frame::XModel> lcl_GetXModel(const ScDocument * pDoc)
74{
75 uno::Reference<frame::XModel> xModel;
76 SfxObjectShell* pObjSh(pDoc ? pDoc->GetDocumentShell() : nullptr);
77 if (pObjSh)
78 xModel.set(pObjSh->GetModel());
79 return xModel;
80}
81
82OUString lcl_identifierForData(sal_Int32 index)
83{
84 return "PT@" + constIdData + " " + OUString::number(index);
85}
86
87OUString lcl_identifierForLabel(sal_Int32 index)
88{
89 return "PT@" + constIdLabel + " " + OUString::number(index);
90}
91
92OUString lcl_identifierForCategories()
93{
94 return "PT@" + constIdCategories;
95}
96
97std::vector<OUString> lcl_getVisiblePageMembers(const uno::Reference<uno::XInterface> & xLevel)
98{
99 std::vector<OUString> aResult;
100 if (!xLevel.is())
101 return aResult;
102
103 uno::Reference<sheet::XMembersSupplier> xMembersSupplier(xLevel, uno::UNO_QUERY);
104 if (!xMembersSupplier.is())
105 return aResult;
106
107 uno::Reference<sheet::XMembersAccess> xMembersAccess = xMembersSupplier->getMembers();
108 if (!xMembersAccess.is())
109 return aResult;
110
111 const css::uno::Sequence<OUString> aMembersNames = xMembersAccess->getElementNames();
112 for (OUString const & rMemberNames : aMembersNames)
113 {
114 uno::Reference<beans::XPropertySet> xProperties(xMembersAccess->getByName(rMemberNames), uno::UNO_QUERY);
115 if (!xProperties.is())
116 continue;
117
118 OUString aCaption = ScUnoHelpFunctions::GetStringProperty(xProperties, SC_UNO_DP_LAYOUTNAME, OUString());
119 if (aCaption.isEmpty())
120 aCaption = rMemberNames;
121
123
124 if (bVisible)
125 aResult.push_back(aCaption);
126 }
127
128 return aResult;
129}
130
131} // end anonymous namespace
132
133SC_SIMPLE_SERVICE_INFO(PivotTableDataProvider, "PivotTableDataProvider", SC_SERVICENAME_CHART_PIVOTTABLE_DATAPROVIDER)
134
135// DataProvider ==============================================================
136
138 : m_pDocument(&rDoc)
139 , m_aPropSet(lcl_GetDataProviderPropertyMap())
140 , m_bIncludeHiddenCells(true)
141 , m_bNeedsUpdate(true)
142 , m_xContext(comphelper::getProcessComponentContext())
143{
144 rDoc.AddUnoObject(*this);
145}
146
148{
150
151 if (m_pDocument)
153}
154
155void PivotTableDataProvider::Notify(SfxBroadcaster& /*rBroadcaster*/, const SfxHint& rHint)
156{
157 if (rHint.GetId() == SfxHintId::Dying)
158 {
159 m_pDocument = nullptr;
160 }
161 else if (m_pDocument)
162 {
163 if (auto pDataPilotHint = dynamic_cast<const ScDataPilotModifiedHint*>(&rHint))
164 {
165 if (pDataPilotHint->GetName() == m_sPivotTableName)
166 {
167 m_bNeedsUpdate = true;
168 for (uno::Reference<util::XModifyListener> const & xListener : m_aValueListeners)
169 {
170 css::chart::ChartDataChangeEvent aEvent(getXWeak(),
171 css::chart::ChartDataChangeType_ALL,
172 0, 0, 0, 0);
173 xListener->modified(aEvent);
174 }
175 }
176 }
177 }
178}
179
180sal_Bool SAL_CALL PivotTableDataProvider::createDataSourcePossible(const uno::Sequence<beans::PropertyValue>& /*aArguments*/)
181{
182 SolarMutexGuard aGuard;
183 if (!m_pDocument)
184 return false;
185
186 if (m_sPivotTableName.isEmpty())
187 return false;
188
189 ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
190 return bool(pDPCollection->GetByName(m_sPivotTableName));
191}
192
193uno::Reference<chart2::data::XDataSource> SAL_CALL
194 PivotTableDataProvider::createDataSource(const uno::Sequence<beans::PropertyValue>& aArguments)
195{
196 SolarMutexGuard aGuard;
197
198 if (!m_pDocument)
199 throw uno::RuntimeException();
200
201 bool bOrientCol = true;
202 OUString aRangeRepresentation;
203
204 for (beans::PropertyValue const & rProperty : aArguments)
205 {
206 if (rProperty.Name == "DataRowSource")
207 {
208 chart::ChartDataRowSource eSource = chart::ChartDataRowSource_COLUMNS;
209 if (!(rProperty.Value >>= eSource))
210 {
211 sal_Int32 nSource(0);
212 if (rProperty.Value >>= nSource)
213 eSource = chart::ChartDataRowSource(nSource);
214 }
215 bOrientCol = (eSource == chart::ChartDataRowSource_COLUMNS);
216 }
217 else if (rProperty.Name == "CellRangeRepresentation")
218 rProperty.Value >>= aRangeRepresentation;
219 }
220
221 uno::Reference<chart2::data::XDataSource> xResult;
222
223 if (aRangeRepresentation == lcl_identifierForCategories())
224 xResult = createCategoriesDataSource(bOrientCol);
225 else
226 xResult = createValuesDataSource();
227
228 return xResult;
229}
230
231uno::Reference<chart2::data::XLabeledDataSequence>
233{
234 uno::Reference<chart2::data::XLabeledDataSequence> xResult;
235 if (!m_xContext.is())
236 return xResult;
237 xResult.set(chart2::data::LabeledDataSequence::create(m_xContext), uno::UNO_QUERY_THROW);
238 return xResult;
239}
240
241uno::Reference<chart2::data::XDataSource>
243{
244 if (m_bNeedsUpdate)
246
247 uno::Reference<chart2::data::XDataSource> xDataSource;
248 std::vector<uno::Reference<chart2::data::XLabeledDataSequence>> aLabeledSequences;
249
250 std::vector<std::vector<ValueAndFormat>> const & rCategoriesVector = bOrientationIsColumn ? m_aCategoriesColumnOrientation
252
253 for (std::vector<ValueAndFormat> const & rCategories : rCategoriesVector)
254 {
255 uno::Reference<chart2::data::XLabeledDataSequence> xResult = newLabeledDataSequence();
257 lcl_identifierForCategories(), std::vector(rCategories)));
258 pSequence->setRole("categories");
259 xResult->setValues(uno::Reference<chart2::data::XDataSequence>(pSequence));
260
261 aLabeledSequences.push_back(xResult);
262 }
263
264 xDataSource.set(new PivotTableDataSource(std::move(aLabeledSequences)));
265 return xDataSource;
266}
267
269{
270 ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
271 ScDPObject* pDPObject = pDPCollection->GetByName(m_sPivotTableName);
272 if (!pDPObject)
273 return;
274
277 m_aLabels.clear();
278 m_aDataRowVector.clear();
279 m_aColumnFields.clear();
280 m_aRowFields.clear();
281 m_aPageFields.clear();
282 m_aDataFields.clear();
284
285 uno::Reference<sheet::XDataPilotResults> xDPResults(pDPObject->GetSource(), uno::UNO_QUERY);
286 if (!xDPResults.is())
287 return;
288 const uno::Sequence<uno::Sequence<sheet::DataResult>> xDataResultsSequence = xDPResults->getResults();
289
290 std::unordered_set<size_t> aValidRowIndex;
291
292 size_t nRowIndex = 0;
293 for (uno::Sequence<sheet::DataResult> const & xDataResults : xDataResultsSequence)
294 {
295 std::vector<ValueAndFormat> aRow;
296 bool bRowEmpty = true;
297 // First pass - collect a row of valid data and track if the row is empty
298 for (sheet::DataResult const & rDataResult : xDataResults)
299 {
300 if (rDataResult.Flags & css::sheet::DataResultFlags::SUBTOTAL)
301 continue;
302 if (rDataResult.Flags == 0 || rDataResult.Flags & css::sheet::DataResultFlags::HASDATA)
303 {
304 aRow.emplace_back(rDataResult.Flags ? rDataResult.Value
305 : std::numeric_limits<double>::quiet_NaN(), 0);
306 if (rDataResult.Flags != 0) // set as valid only if we have data
307 {
308 bRowEmpty = false;
309 // We need to remember all valid (non-empty) row indices
310 aValidRowIndex.insert(nRowIndex);
311 }
312 }
313 }
314 // Second pass: add to collection only non-empty rows
315 if (!bRowEmpty)
316 {
317 size_t nColumnIndex = 0;
318 for (ValueAndFormat const & aValue : aRow)
319 {
320 if (nColumnIndex >= m_aDataRowVector.size())
321 m_aDataRowVector.resize(nColumnIndex + 1);
322 m_aDataRowVector[nColumnIndex].push_back(aValue);
323 nColumnIndex++;
324 }
325 }
326 nRowIndex++;
327 }
328
329 uno::Reference<sheet::XDimensionsSupplier> xDimensionsSupplier(pDPObject->GetSource());
330 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess(xDimensionsSupplier->getDimensions());
331
332 std::unordered_map<OUString, sal_Int32> aDataFieldNumberFormatMap;
333 std::vector<OUString> aDataFieldNamesVectors;
334
335 std::unordered_map<OUString, OUString> aDataFieldCaptionNames;
336
337 sheet::DataPilotFieldOrientation eDataFieldOrientation = sheet::DataPilotFieldOrientation_HIDDEN;
338
339 for (sal_Int32 nDim = 0; nDim < xDims->getCount(); nDim++)
340 {
341 uno::Reference<uno::XInterface> xDim(xDims->getByIndex(nDim), uno::UNO_QUERY);
342 uno::Reference<beans::XPropertySet> xDimProp(xDim, uno::UNO_QUERY);
343 uno::Reference<sheet::XHierarchiesSupplier> xDimSupp(xDim, uno::UNO_QUERY);
344
345 if (!xDimProp.is() || !xDimSupp.is())
346 continue;
347
348 sheet::DataPilotFieldOrientation eDimOrient =
350 sheet::DataPilotFieldOrientation_HIDDEN);
351
352 if (eDimOrient == sheet::DataPilotFieldOrientation_HIDDEN)
353 continue;
354
355 uno::Reference<container::XIndexAccess> xHierarchies = new ScNameToIndexAccess(xDimSupp->getHierarchies());
356 sal_Int32 nHierarchy = ScUnoHelpFunctions::GetLongProperty(xDimProp, SC_UNO_DP_USEDHIERARCHY);
357 if (nHierarchy >= xHierarchies->getCount())
358 nHierarchy = 0;
359
360 uno::Reference<sheet::XLevelsSupplier> xLevelsSupplier(xHierarchies->getByIndex(nHierarchy),
361 uno::UNO_QUERY);
362
363 if (!xLevelsSupplier.is())
364 continue;
365
366 uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess(xLevelsSupplier->getLevels());
367
368 for (tools::Long nLevel = 0; nLevel < xLevels->getCount(); nLevel++)
369 {
370 uno::Reference<uno::XInterface> xLevel(xLevels->getByIndex(nLevel), uno::UNO_QUERY);
371 uno::Reference<container::XNamed> xLevelName(xLevel, uno::UNO_QUERY);
372 uno::Reference<sheet::XDataPilotMemberResults> xLevelResult(xLevel, uno::UNO_QUERY );
373
374 if (xLevelName.is() && xLevelResult.is())
375 {
376 bool bIsDataLayout = ScUnoHelpFunctions::GetBoolProperty(xDimProp, SC_UNO_DP_ISDATALAYOUT);
377 sal_Int32 nDimPos = ScUnoHelpFunctions::GetLongProperty(xDimProp, SC_UNO_DP_POSITION);
378 sal_Int32 nNumberFormat = ScUnoHelpFunctions::GetLongProperty(xDimProp, SC_UNO_DP_NUMBERFO);
379 bool bHasHiddenMember = ScUnoHelpFunctions::GetBoolProperty(xDimProp, SC_UNO_DP_HAS_HIDDEN_MEMBER);
380
381 switch (eDimOrient)
382 {
383 case sheet::DataPilotFieldOrientation_COLUMN:
384 {
385 m_aColumnFields.emplace_back(xLevelName->getName(), nDim, nDimPos, bHasHiddenMember);
386
387 const uno::Sequence<sheet::MemberResult> aSequence = xLevelResult->getResults();
388 size_t i = 0;
389 OUString sCaption;
390 OUString sName;
391 for (sheet::MemberResult const & rMember : aSequence)
392 {
393 // Skip grandtotals and subtotals
394 if (rMember.Flags & sheet::MemberResultFlags::SUBTOTAL ||
395 rMember.Flags & sheet::MemberResultFlags::GRANDTOTAL)
396 continue;
397 if (rMember.Flags & sheet::MemberResultFlags::HASMEMBER ||
398 rMember.Flags & sheet::MemberResultFlags::CONTINUE)
399 {
400 if (!(rMember.Flags & sheet::MemberResultFlags::CONTINUE))
401 {
402 sCaption = rMember.Caption;
403 sName = rMember.Name;
404 }
405
406 if (i >= m_aLabels.size())
407 m_aLabels.resize(i + 1);
408
409 if (o3tl::make_unsigned(nDimPos) >= m_aLabels[i].size())
410 m_aLabels[i].resize(nDimPos + 1);
411 m_aLabels[i][nDimPos] = ValueAndFormat(sCaption);
412
413 if (bIsDataLayout)
414 {
415 // Remember data fields to determine the number format of data
416 aDataFieldNamesVectors.push_back(sName);
417 eDataFieldOrientation = sheet::DataPilotFieldOrientation_COLUMN;
418 // Remember the caption name
419 aDataFieldCaptionNames[rMember.Name] = rMember.Caption;
420 }
421 i++;
422 }
423 }
424 }
425 break;
426
427 case sheet::DataPilotFieldOrientation_ROW:
428 {
429 m_aRowFields.emplace_back(xLevelName->getName(), nDim, nDimPos, bHasHiddenMember);
430
431 const uno::Sequence<sheet::MemberResult> aSequence = xLevelResult->getResults();
432
433 size_t i = 0;
434 size_t nEachIndex = 0;
435 std::unique_ptr<ValueAndFormat> pItem;
436
437 for (sheet::MemberResult const & rMember : aSequence)
438 {
439 bool bFound = aValidRowIndex.find(nEachIndex) != aValidRowIndex.end();
440
441 nEachIndex++;
442
443 bool bHasContinueFlag = rMember.Flags & sheet::MemberResultFlags::CONTINUE;
444
445 if (rMember.Flags & sheet::MemberResultFlags::HASMEMBER || bHasContinueFlag)
446 {
447 if (!bHasContinueFlag)
448 {
449 // Chart2 does not use number format for labels, so use the display string.
450 pItem.reset(new ValueAndFormat(rMember.Caption));
451 }
452
453 if (bFound)
454 {
455 assert(pItem && "bHasContinueFlag must be false on this or some preceding element");
456
457 if (i >= m_aCategoriesRowOrientation.size())
458 m_aCategoriesRowOrientation.resize(i + 1);
459
461 m_aCategoriesColumnOrientation.resize(nDimPos + 1);
462 m_aCategoriesColumnOrientation[nDimPos].push_back(*pItem);
463
465 m_aCategoriesRowOrientation[i].resize(nDimPos + 1);
466 m_aCategoriesRowOrientation[i][nDimPos] = *pItem;
467
468 if (bIsDataLayout)
469 {
470 // Remember data fields to determine the number format of data
471 aDataFieldNamesVectors.push_back(rMember.Name);
472 eDataFieldOrientation = sheet::DataPilotFieldOrientation_ROW;
473
474 // Remember the caption name
475 aDataFieldCaptionNames[rMember.Name] = rMember.Caption;
476 }
477
478 // Set to empty so the sub categories are set to empty when they continue
479 pItem.reset(new ValueAndFormat);
480 i++;
481 }
482 }
483 }
484 }
485 break;
486
487 case sheet::DataPilotFieldOrientation_PAGE:
488 {
489 m_aPageFields.emplace_back(xLevelName->getName(), nDim, nDimPos, bHasHiddenMember);
490
491 // Resolve filtering
492 OUString aFieldOutputDescription;
493 if (bHasHiddenMember)
494 {
495 std::vector<OUString> aMembers = lcl_getVisiblePageMembers(xLevel);
496
497 if (aMembers.size() == 1)
498 aFieldOutputDescription = aMembers[0];
499 else
500 aFieldOutputDescription = ScResId(SCSTR_MULTIPLE);
501 }
502 else
503 {
504 aFieldOutputDescription = ScResId(SCSTR_ALL);
505 }
506 m_aFieldOutputDescriptionMap[nDim] = aFieldOutputDescription;
507 }
508 break;
509
510 case sheet::DataPilotFieldOrientation_DATA:
511 {
512 aDataFieldNumberFormatMap[xLevelName->getName()] = nNumberFormat;
513 m_aDataFields.emplace_back(xLevelName->getName(), nDim, nDimPos, bHasHiddenMember);
514 }
515 break;
516
517 default:
518 break;
519 }
520 }
521 }
522 }
523
524 // Transform the name of data fields
525 for (chart2::data::PivotTableFieldEntry& rDataFields : m_aDataFields)
526 {
527 rDataFields.Name = aDataFieldCaptionNames[rDataFields.Name];
528 }
529
530 // Apply number format to the data
531 if (eDataFieldOrientation == sheet::DataPilotFieldOrientation_ROW)
532 {
533 for (std::vector<ValueAndFormat> & rDataRow : m_aDataRowVector)
534 {
535 size_t i = 0;
536 for (ValueAndFormat & rItem : rDataRow)
537 {
538 OUString sName = aDataFieldNamesVectors[i];
539 sal_Int32 nNumberFormat = aDataFieldNumberFormatMap[sName];
540 rItem.m_nNumberFormat = nNumberFormat;
541 i++;
542 }
543 }
544 }
545 else if (eDataFieldOrientation == sheet::DataPilotFieldOrientation_COLUMN)
546 {
547 size_t i = 0;
548 for (std::vector<ValueAndFormat> & rDataRow : m_aDataRowVector)
549 {
550 OUString sName = aDataFieldNamesVectors[i];
551 sal_Int32 nNumberFormat = aDataFieldNumberFormatMap[sName];
552 for (ValueAndFormat & rItem : rDataRow)
553 {
554 rItem.m_nNumberFormat = nNumberFormat;
555 }
556 i++;
557 }
558 }
559
560 // Sort fields so it respects the order of how it is represented in the pivot table
561
562 auto funcDimensionPositionSortCompare = [] (chart2::data::PivotTableFieldEntry const & entry1,
563 chart2::data::PivotTableFieldEntry const & entry2)
564 {
565 return entry1.DimensionPositionIndex < entry2.DimensionPositionIndex;
566 };
567
568 std::sort(m_aColumnFields.begin(), m_aColumnFields.end(), funcDimensionPositionSortCompare);
569 std::sort(m_aRowFields.begin(), m_aRowFields.end(), funcDimensionPositionSortCompare);
570 std::sort(m_aPageFields.begin(), m_aPageFields.end(), funcDimensionPositionSortCompare);
571 std::sort(m_aDataFields.begin(), m_aDataFields.end(), funcDimensionPositionSortCompare);
572
573 // Mark that we updated the data
574 m_bNeedsUpdate = false;
575}
576
577uno::Reference<chart2::data::XDataSequence>
579{
580 uno::Reference<chart2::data::XDataSequence> xDataSequence;
581 if (nIndex >= m_aDataRowVector.size())
582 return xDataSequence;
583
584 OUString sDataID = lcl_identifierForData(nIndex);
585
586 std::vector<ValueAndFormat> const & rRowOfData = m_aDataRowVector[nIndex];
587 rtl::Reference<PivotTableDataSequence> pSequence(new PivotTableDataSequence(m_pDocument, sDataID, std::vector(rRowOfData)));
588 pSequence->setRole("values-y");
589 xDataSequence = pSequence;
590 return xDataSequence;
591}
592
593uno::Reference<chart2::data::XDataSequence>
595{
596 uno::Reference<chart2::data::XDataSequence> xDataSequence;
597
598 OUString sLabelID = lcl_identifierForLabel(nIndex);
599
600 OUStringBuffer aLabel;
601 bool bFirst = true;
602
603 if (m_aLabels.empty())
604 {
605 aLabel = ScResId(STR_PIVOT_TOTAL);
606 }
607 else if (nIndex < m_aLabels.size())
608 {
609 for (ValueAndFormat const & rItem : m_aLabels[nIndex])
610 {
611 if (bFirst)
612 {
613 aLabel.append(rItem.m_aString);
614 bFirst = false;
615 }
616 else
617 {
618 aLabel.append(" - " + rItem.m_aString);
619 }
620 }
621 }
622
623 std::vector<ValueAndFormat> aLabelVector { ValueAndFormat(aLabel.makeStringAndClear()) };
624
626 sLabelID, std::move(aLabelVector)));
627 pSequence->setRole("values-y");
628 xDataSequence = pSequence;
629 return xDataSequence;
630}
631
632css::uno::Reference<css::chart2::data::XDataSequence>
634{
635 uno::Reference<chart2::data::XDataSequence> xDataSequence;
636
638 return xDataSequence;
639
640 std::vector<ValueAndFormat> const & rCategories = m_aCategoriesColumnOrientation.back();
641
643 lcl_identifierForCategories(), std::vector(rCategories)));
644 pSequence->setRole("categories");
645 xDataSequence = pSequence;
646
647 return xDataSequence;
648}
649
650uno::Reference<chart2::data::XDataSource>
652{
653 if (m_bNeedsUpdate)
655
656 uno::Reference<chart2::data::XDataSource> xDataSource;
657 std::vector<uno::Reference<chart2::data::XLabeledDataSequence>> aLabeledSequences;
658
659 // Fill first sequence of categories
660 {
661 uno::Reference<chart2::data::XLabeledDataSequence> xResult = newLabeledDataSequence();
662 xResult->setValues(assignFirstCategoriesToDataSequence());
663 aLabeledSequences.push_back(xResult);
664 }
665
666 // Fill values and labels
667 {
668 for (size_t i = 0; i < m_aDataRowVector.size(); ++i)
669 {
670 uno::Reference<chart2::data::XLabeledDataSequence> xResult = newLabeledDataSequence();
671 xResult->setValues(assignValuesToDataSequence(i));
672 xResult->setLabel(assignLabelsToDataSequence(i));
673 aLabeledSequences.push_back(xResult);
674 }
675 }
676
677 xDataSource.set(new PivotTableDataSource(std::move(aLabeledSequences)));
678 return xDataSource;
679}
680
681
682uno::Sequence<beans::PropertyValue> SAL_CALL PivotTableDataProvider::detectArguments(
683 const uno::Reference<chart2::data::XDataSource> & xDataSource)
684{
685 if (!m_pDocument ||!xDataSource.is())
686 return uno::Sequence<beans::PropertyValue>();
687
689 { "CellRangeRepresentation", uno::Any(OUString("PivotChart")) },
690 { "DataRowSource", uno::Any(chart::ChartDataRowSource_COLUMNS) },
691 { "FirstCellAsLabel", uno::Any(false) },
692 { "HasCategories", uno::Any(true) }
693 });
694}
695
697{
698 return false;
699}
700
701uno::Reference<chart2::data::XDataSequence> SAL_CALL
703{
704 uno::Reference<chart2::data::XDataSequence> xDataSequence;
705 return xDataSequence;
706}
707
708uno::Reference<chart2::data::XDataSequence> SAL_CALL
710 const OUString& /*aRangeRepresentation*/,
711 const OUString& /*aRoleQualifier*/)
712{
713 return uno::Reference<chart2::data::XDataSequence>();
714}
715
716uno::Reference<sheet::XRangeSelection> SAL_CALL PivotTableDataProvider::getRangeSelection()
717{
718 uno::Reference<sheet::XRangeSelection> xResult;
719
720 uno::Reference<frame::XModel> xModel(lcl_GetXModel(m_pDocument));
721 if (xModel.is())
722 xResult.set(xModel->getCurrentController(), uno::UNO_QUERY);
723
724 return xResult;
725}
726
727// XPivotTableDataProvider ========================================================
728
729uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getColumnFields()
730{
732}
733
734uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getRowFields()
735{
737}
738
739uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getPageFields()
740{
742}
743
744uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getDataFields()
745{
747}
748
750{
751 return m_sPivotTableName;
752}
753
754void PivotTableDataProvider::setPivotTableName(const OUString& sPivotTableName)
755{
756 ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
757 ScDPObject* pDPObject = pDPCollection->GetByName(sPivotTableName);
758 if (pDPObject)
759 m_sPivotTableName = sPivotTableName;
760}
761
763{
764 if (m_sPivotTableName.isEmpty())
765 return false;
766
767 ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
768 ScDPObject* pDPObject = pDPCollection->GetByName(m_sPivotTableName);
769
770 if (pDPObject)
771 return true;
772
773 return false;
774}
775
776uno::Reference<chart2::data::XDataSequence>
778{
779 SolarMutexGuard aGuard;
780
781 if (m_bNeedsUpdate)
783
784 return assignValuesToDataSequence(size_t(nIndex));
785}
786
787uno::Reference<css::chart2::data::XDataSequence>
789{
790 SolarMutexGuard aGuard;
791
792 if (m_bNeedsUpdate)
794
795 return assignLabelsToDataSequence(size_t(nIndex));
796}
797
798uno::Reference<css::chart2::data::XDataSequence>
800{
801 SolarMutexGuard aGuard;
802
803 if (m_bNeedsUpdate)
805
807}
808
809OUString PivotTableDataProvider::getFieldOutputDescription(sal_Int32 nDimensionIndex)
810{
811 if (nDimensionIndex < 0)
812 return OUString();
813 return m_aFieldOutputDescriptionMap[size_t(nDimensionIndex)];
814}
815
816// XModifyBroadcaster ========================================================
817
818void SAL_CALL PivotTableDataProvider::addModifyListener(const uno::Reference< util::XModifyListener>& aListener)
819{
820 SolarMutexGuard aGuard;
821
822 m_aValueListeners.emplace_back(aListener);
823}
824
825void SAL_CALL PivotTableDataProvider::removeModifyListener(const uno::Reference<util::XModifyListener>& aListener )
826{
827 SolarMutexGuard aGuard;
828
829 sal_uInt16 nCount = m_aValueListeners.size();
830 for (sal_uInt16 n = nCount; n--;)
831 {
832 uno::Reference<util::XModifyListener>& rObject = m_aValueListeners[n];
833 if (rObject == aListener)
834 {
835 m_aValueListeners.erase(m_aValueListeners.begin() + n);
836 }
837 }
838}
839
840// DataProvider XPropertySet ========================================================
841
842uno::Reference< beans::XPropertySetInfo> SAL_CALL
844{
845 SolarMutexGuard aGuard;
846 static uno::Reference<beans::XPropertySetInfo> aRef =
848 return aRef;
849}
850
851void SAL_CALL PivotTableDataProvider::setPropertyValue(const OUString& rPropertyName, const uno::Any& rValue)
852{
853 if (rPropertyName != SC_UNONAME_INCLUDEHIDDENCELLS)
854 throw beans::UnknownPropertyException(rPropertyName);
855
856 if (!(rValue >>= m_bIncludeHiddenCells))
857 throw lang::IllegalArgumentException();
858}
859
860uno::Any SAL_CALL PivotTableDataProvider::getPropertyValue(const OUString& rPropertyName)
861{
862 uno::Any aRet;
863 if (rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS)
864 aRet <<= m_bIncludeHiddenCells;
865 else if (rPropertyName == SC_UNONAME_USE_INTERNAL_DATA_PROVIDER)
866 {
867 // This is a read-only property.
869 }
870 else
871 throw beans::UnknownPropertyException(rPropertyName);
872 return aRet;
873}
874
876 const OUString& /*rPropertyName*/,
877 const uno::Reference<beans::XPropertyChangeListener>& /*xListener*/)
878{
879 OSL_FAIL("Not yet implemented");
880}
881
883 const OUString& /*rPropertyName*/,
884 const uno::Reference<beans::XPropertyChangeListener>& /*rListener*/)
885{
886 OSL_FAIL("Not yet implemented");
887}
888
890 const OUString& /*rPropertyName*/,
891 const uno::Reference<beans::XVetoableChangeListener>& /*rListener*/)
892{
893 OSL_FAIL("Not yet implemented");
894}
895
897 const OUString& /*rPropertyName*/,
898 const uno::Reference<beans::XVetoableChangeListener>& /*rListener*/ )
899{
900 OSL_FAIL("Not yet implemented");
901}
902
903} // end sc namespace
904
905/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
AnyEventRef aEvent
ScDPObject * GetByName(std::u16string_view rName) const
Definition: dpobject.cxx:3732
css::uno::Reference< css::sheet::XDimensionsSupplier > const & GetSource()
Definition: dpobject.cxx:516
bool PastingDrawFromOtherDoc() const
Definition: document.hxx:2527
SfxObjectShell * GetDocumentShell() const
Definition: document.hxx:1083
void RemoveUnoObject(SfxListener &rObject)
Definition: documen3.cxx:909
SC_DLLPUBLIC ScDPCollection * GetDPCollection()
Definition: documen3.cxx:365
static bool GetBoolProperty(const css::uno::Reference< css::beans::XPropertySet > &xProp, const OUString &rName, bool bDefault=false)
Definition: miscuno.cxx:36
static EnumT GetEnumProperty(const css::uno::Reference< css::beans::XPropertySet > &xProp, const OUString &rName, EnumT nDefault)
Definition: miscuno.hxx:159
static OUString GetStringProperty(const css::uno::Reference< css::beans::XPropertySet > &xProp, const OUString &rName, const OUString &rDefault)
Definition: miscuno.cxx:120
static sal_Int32 GetLongProperty(const css::uno::Reference< css::beans::XPropertySet > &xProp, const OUString &rName)
Definition: miscuno.cxx:72
SfxHintId GetId() const
const SfxItemPropertyMap & getPropertyMap() const
css::uno::Type const & get()
css::uno::Reference< css::uno::XComponentContext > m_xContext
virtual void SAL_CALL addModifyListener(const css::uno::Reference< css::util::XModifyListener > &aListener) override
virtual css::uno::Reference< css::sheet::XRangeSelection > SAL_CALL getRangeSelection() override
virtual void SAL_CALL removePropertyChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > &rListener) override
css::uno::Reference< css::chart2::data::XDataSequence > assignValuesToDataSequence(size_t nIndex)
virtual css::uno::Sequence< css::chart2::data::PivotTableFieldEntry > SAL_CALL getRowFields() override
virtual sal_Bool SAL_CALL hasPivotTable() override
css::uno::Reference< css::chart2::data::XLabeledDataSequence > newLabeledDataSequence()
virtual css::uno::Reference< css::chart2::data::XDataSequence > SAL_CALL createDataSequenceOfCategories() override
virtual css::uno::Sequence< css::chart2::data::PivotTableFieldEntry > SAL_CALL getDataFields() override
std::vector< css::chart2::data::PivotTableFieldEntry > m_aDataFields
std::unordered_map< sal_Int32, OUString > m_aFieldOutputDescriptionMap
virtual void SAL_CALL setPivotTableName(const OUString &sPivotTableName) override
virtual css::uno::Reference< css::chart2::data::XDataSource > SAL_CALL createDataSource(const css::uno::Sequence< css::beans::PropertyValue > &aArguments) override
virtual void SAL_CALL addPropertyChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > &xListener) override
virtual void SAL_CALL setPropertyValue(const OUString &rPropertyName, const css::uno::Any &rValue) override
virtual sal_Bool SAL_CALL createDataSequenceByRangeRepresentationPossible(const OUString &aRangeRepresentation) override
virtual void SAL_CALL removeVetoableChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > &rListener) override
virtual OUString SAL_CALL getFieldOutputDescription(sal_Int32 nPageFieldIndex) override
std::vector< std::vector< ValueAndFormat > > m_aDataRowVector
virtual css::uno::Reference< css::chart2::data::XDataSequence > SAL_CALL createDataSequenceOfValuesByIndex(sal_Int32 nIndex) override
std::vector< std::vector< ValueAndFormat > > m_aLabels
virtual sal_Bool SAL_CALL createDataSourcePossible(const css::uno::Sequence< css::beans::PropertyValue > &aArguments) override
virtual css::uno::Reference< css::chart2::data::XDataSequence > SAL_CALL createDataSequenceOfLabelsByIndex(sal_Int32 nIndex) override
std::vector< css::chart2::data::PivotTableFieldEntry > m_aColumnFields
virtual ~PivotTableDataProvider() override
virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override
virtual css::uno::Reference< css::chart2::data::XDataSequence > SAL_CALL createDataSequenceByRangeRepresentation(const OUString &aRangeRepresentation) override
css::uno::Reference< css::chart2::data::XDataSource > createValuesDataSource()
virtual css::uno::Sequence< css::chart2::data::PivotTableFieldEntry > SAL_CALL getColumnFields() override
css::uno::Reference< css::chart2::data::XDataSequence > assignLabelsToDataSequence(size_t nIndex)
std::vector< css::chart2::data::PivotTableFieldEntry > m_aRowFields
virtual void SAL_CALL addVetoableChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > &rListener) override
std::vector< css::uno::Reference< css::util::XModifyListener > > m_aValueListeners
std::vector< std::vector< ValueAndFormat > > m_aCategoriesRowOrientation
virtual css::uno::Any SAL_CALL getPropertyValue(const OUString &rPropertyName) override
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint) override
virtual css::uno::Sequence< css::chart2::data::PivotTableFieldEntry > SAL_CALL getPageFields() override
std::vector< std::vector< ValueAndFormat > > m_aCategoriesColumnOrientation
virtual void SAL_CALL removeModifyListener(const css::uno::Reference< css::util::XModifyListener > &aListener) override
css::uno::Reference< css::chart2::data::XDataSource > createCategoriesDataSource(bool bOrientationIsColumn)
virtual OUString SAL_CALL getPivotTableName() override
css::uno::Reference< css::chart2::data::XDataSequence > assignFirstCategoriesToDataSequence()
std::vector< css::chart2::data::PivotTableFieldEntry > m_aPageFields
virtual css::uno::Reference< css::chart2::data::XDataSequence > SAL_CALL createDataSequenceByValueArray(const OUString &aRole, const OUString &aRangeRepresentation, const OUString &aRoleQualifier) override
virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL detectArguments(const css::uno::Reference< css::chart2::data::XDataSource > &xDataSource) override
int nCount
OUString sName
Sequence< PropertyValue > aArguments
sal_Int32 nIndex
sal_Int64 n
#define SC_SIMPLE_SERVICE_INFO(ClassName, ClassNameAscii, ServiceAscii)
Definition: miscuno.hxx:63
size
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
css::uno::Sequence< css::beans::PropertyValue > InitPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
int i
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
CAUTION! The following defines must be in the same namespace as the respective type.
Definition: broadcast.cxx:15
long Long
OUString ScResId(TranslateId aId)
Definition: scdll.cxx:90
Reference< XModel > xModel
bool bVisible
unsigned char sal_Bool
OUString aLabel
constexpr OUStringLiteral SC_UNO_DP_HAS_HIDDEN_MEMBER
Definition: unonames.hxx:630
constexpr OUStringLiteral SC_UNO_DP_POSITION
Definition: unonames.hxx:609
constexpr OUStringLiteral SC_UNO_DP_ISDATALAYOUT
Definition: unonames.hxx:607
constexpr OUStringLiteral SC_UNO_DP_LAYOUTNAME
Definition: unonames.hxx:627
constexpr OUStringLiteral SC_SERVICENAME_CHART_PIVOTTABLE_DATAPROVIDER
Definition: unonames.hxx:36
#define SC_UNO_DP_NUMBERFO
Definition: unonames.hxx:623
constexpr OUStringLiteral SC_UNONAME_USE_INTERNAL_DATA_PROVIDER
Definition: unonames.hxx:697
constexpr OUStringLiteral SC_UNO_DP_USEDHIERARCHY
Definition: unonames.hxx:612
constexpr OUStringLiteral SC_UNO_DP_ORIENTATION
Definition: unonames.hxx:608
constexpr OUStringLiteral SC_UNONAME_INCLUDEHIDDENCELLS
Definition: unonames.hxx:696
constexpr OUStringLiteral SC_UNO_DP_ISVISIBLE
Definition: unonames.hxx:618