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 <memory>
11 #include <sal/config.h>
12 
14 #include <PivotTableDataSource.hxx>
16 
17 #include <miscuno.hxx>
18 #include <document.hxx>
19 #include <unonames.hxx>
20 #include <scresid.hxx>
21 #include <globstr.hrc>
22 #include <strings.hrc>
23 #include <dpobject.hxx>
24 #include <hints.hxx>
25 
26 #include <o3tl/safeint.hxx>
27 #include <vcl/svapp.hxx>
28 #include <sfx2/objsh.hxx>
30 #include <comphelper/sequence.hxx>
32 
33 #include <com/sun/star/chart2/data/LabeledDataSequence.hpp>
34 #include <com/sun/star/chart/ChartDataRowSource.hpp>
35 #include <com/sun/star/frame/XModel.hpp>
36 
37 #include <com/sun/star/sheet/XDataPilotResults.hpp>
38 #include <com/sun/star/sheet/DataResultFlags.hpp>
39 
40 #include <com/sun/star/sheet/XDimensionsSupplier.hpp>
41 #include <com/sun/star/sheet/XHierarchiesSupplier.hpp>
42 #include <com/sun/star/sheet/XLevelsSupplier.hpp>
43 #include <com/sun/star/sheet/XDataPilotMemberResults.hpp>
44 #include <com/sun/star/sheet/MemberResultFlags.hpp>
45 #include <com/sun/star/sheet/XMembersSupplier.hpp>
46 
47 #include <com/sun/star/chart/ChartDataChangeEvent.hpp>
48 #include <com/sun/star/container/XNamed.hpp>
49 
50 #include <unordered_map>
51 
52 using namespace css;
53 
54 namespace sc
55 {
56 namespace
57 {
58 constexpr OUStringLiteral constIdCategories(u"categories");
59 constexpr OUStringLiteral constIdLabel(u"label");
60 constexpr OUStringLiteral constIdData(u"data");
61 
62 const SfxItemPropertyMapEntry* lcl_GetDataProviderPropertyMap()
63 {
64  static const SfxItemPropertyMapEntry aDataProviderPropertyMap_Impl[] =
65  {
68  { u"", 0, css::uno::Type(), 0, 0 }
69  };
70  return aDataProviderPropertyMap_Impl;
71 }
72 
73 uno::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 
82 OUString lcl_identifierForData(sal_Int32 index)
83 {
84  return "PT@" + constIdData + " " + OUString::number(index);
85 }
86 
87 OUString lcl_identifierForLabel(sal_Int32 index)
88 {
89  return "PT@" + constIdLabel + " " + OUString::number(index);
90 }
91 
92 OUString lcl_identifierForCategories()
93 {
94  return "PT@" + constIdCategories;
95 }
96 
97 std::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 
133 SC_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 
147 PivotTableDataProvider::~PivotTableDataProvider()
148 {
149  SolarMutexGuard g;
150 
151  if (m_pDocument)
152  m_pDocument->RemoveUnoObject( *this);
153 }
154 
155 void 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(static_cast<cppu::OWeakObject*>(this),
171  css::chart::ChartDataChangeType_ALL,
172  0, 0, 0, 0);
173  xListener->modified(aEvent);
174  }
175  }
176  }
177  }
178 }
179 
180 sal_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 
193 uno::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 
231 uno::Reference<chart2::data::XLabeledDataSequence>
232  PivotTableDataProvider::newLabeledDataSequence()
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 
241 uno::Reference<chart2::data::XDataSource>
242 PivotTableDataProvider::createCategoriesDataSource(bool bOrientationIsColumn)
243 {
244  if (m_bNeedsUpdate)
245  collectPivotTableData();
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
251  : m_aCategoriesRowOrientation;
252 
253  for (std::vector<ValueAndFormat> const & rCategories : rCategoriesVector)
254  {
255  uno::Reference<chart2::data::XLabeledDataSequence> xResult = newLabeledDataSequence();
257  lcl_identifierForCategories(), 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(aLabeledSequences));
265  return xDataSource;
266 }
267 
268 void PivotTableDataProvider::collectPivotTableData()
269 {
270  ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
271  ScDPObject* pDPObject = pDPCollection->GetByName(m_sPivotTableName);
272  if (!pDPObject)
273  return;
274 
275  m_aCategoriesColumnOrientation.clear();
276  m_aCategoriesRowOrientation.clear();
277  m_aLabels.clear();
278  m_aDataRowVector.clear();
279  m_aColumnFields.clear();
280  m_aRowFields.clear();
281  m_aPageFields.clear();
282  m_aDataFields.clear();
283  m_aFieldOutputDescriptionMap.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  double fNan;
291  rtl::math::setNan(&fNan);
292 
293  std::unordered_set<size_t> aValidRowIndex;
294 
295  size_t nRowIndex = 0;
296  for (uno::Sequence<sheet::DataResult> const & xDataResults : xDataResultsSequence)
297  {
298  std::vector<ValueAndFormat> aRow;
299  bool bRowEmpty = true;
300  // First pass - collect a row of valid data and track if the row is empty
301  for (sheet::DataResult const & rDataResult : xDataResults)
302  {
303  if (rDataResult.Flags & css::sheet::DataResultFlags::SUBTOTAL)
304  continue;
305  if (rDataResult.Flags == 0 || rDataResult.Flags & css::sheet::DataResultFlags::HASDATA)
306  {
307  aRow.emplace_back(rDataResult.Flags ? rDataResult.Value : fNan, 0);
308  if (rDataResult.Flags != 0) // set as valid only if we have data
309  {
310  bRowEmpty = false;
311  // We need to remember all valid (non-empty) row indices
312  aValidRowIndex.insert(nRowIndex);
313  }
314  }
315  }
316  // Second pass: add to collection only non-empty rows
317  if (!bRowEmpty)
318  {
319  size_t nColumnIndex = 0;
320  for (ValueAndFormat const & aValue : aRow)
321  {
322  if (nColumnIndex >= m_aDataRowVector.size())
323  m_aDataRowVector.resize(nColumnIndex + 1);
324  m_aDataRowVector[nColumnIndex].push_back(aValue);
325  nColumnIndex++;
326  }
327  }
328  nRowIndex++;
329  }
330 
331  uno::Reference<sheet::XDimensionsSupplier> xDimensionsSupplier(pDPObject->GetSource());
332  uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess(xDimensionsSupplier->getDimensions());
333 
334  std::unordered_map<OUString, sal_Int32> aDataFieldNumberFormatMap;
335  std::vector<OUString> aDataFieldNamesVectors;
336 
337  std::unordered_map<OUString, OUString> aDataFieldCaptionNames;
338 
339  sheet::DataPilotFieldOrientation eDataFieldOrientation = sheet::DataPilotFieldOrientation_HIDDEN;
340 
341  for (sal_Int32 nDim = 0; nDim < xDims->getCount(); nDim++)
342  {
343  uno::Reference<uno::XInterface> xDim(xDims->getByIndex(nDim), uno::UNO_QUERY);
344  uno::Reference<beans::XPropertySet> xDimProp(xDim, uno::UNO_QUERY);
345  uno::Reference<sheet::XHierarchiesSupplier> xDimSupp(xDim, uno::UNO_QUERY);
346 
347  if (!xDimProp.is() || !xDimSupp.is())
348  continue;
349 
350  sheet::DataPilotFieldOrientation eDimOrient =
352  sheet::DataPilotFieldOrientation_HIDDEN);
353 
354  if (eDimOrient == sheet::DataPilotFieldOrientation_HIDDEN)
355  continue;
356 
357  uno::Reference<container::XIndexAccess> xHierarchies = new ScNameToIndexAccess(xDimSupp->getHierarchies());
358  sal_Int32 nHierarchy = ScUnoHelpFunctions::GetLongProperty(xDimProp, SC_UNO_DP_USEDHIERARCHY);
359  if (nHierarchy >= xHierarchies->getCount())
360  nHierarchy = 0;
361 
362  uno::Reference<sheet::XLevelsSupplier> xLevelsSupplier(xHierarchies->getByIndex(nHierarchy),
363  uno::UNO_QUERY);
364 
365  if (!xLevelsSupplier.is())
366  continue;
367 
368  uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess(xLevelsSupplier->getLevels());
369 
370  for (tools::Long nLevel = 0; nLevel < xLevels->getCount(); nLevel++)
371  {
372  uno::Reference<uno::XInterface> xLevel(xLevels->getByIndex(nLevel), uno::UNO_QUERY);
373  uno::Reference<container::XNamed> xLevelName(xLevel, uno::UNO_QUERY);
374  uno::Reference<sheet::XDataPilotMemberResults> xLevelResult(xLevel, uno::UNO_QUERY );
375 
376  if (xLevelName.is() && xLevelResult.is())
377  {
378  bool bIsDataLayout = ScUnoHelpFunctions::GetBoolProperty(xDimProp, SC_UNO_DP_ISDATALAYOUT);
379  sal_Int32 nDimPos = ScUnoHelpFunctions::GetLongProperty(xDimProp, SC_UNO_DP_POSITION);
380  sal_Int32 nNumberFormat = ScUnoHelpFunctions::GetLongProperty(xDimProp, SC_UNO_DP_NUMBERFO);
381  bool bHasHiddenMember = ScUnoHelpFunctions::GetBoolProperty(xDimProp, SC_UNO_DP_HAS_HIDDEN_MEMBER);
382 
383  switch (eDimOrient)
384  {
385  case sheet::DataPilotFieldOrientation_COLUMN:
386  {
387  m_aColumnFields.emplace_back(xLevelName->getName(), nDim, nDimPos, bHasHiddenMember);
388 
389  const uno::Sequence<sheet::MemberResult> aSequence = xLevelResult->getResults();
390  size_t i = 0;
391  OUString sCaption;
392  OUString sName;
393  for (sheet::MemberResult const & rMember : aSequence)
394  {
395  // Skip grandtotals and subtotals
396  if (rMember.Flags & sheet::MemberResultFlags::SUBTOTAL ||
397  rMember.Flags & sheet::MemberResultFlags::GRANDTOTAL)
398  continue;
399  if (rMember.Flags & sheet::MemberResultFlags::HASMEMBER ||
400  rMember.Flags & sheet::MemberResultFlags::CONTINUE)
401  {
402  if (!(rMember.Flags & sheet::MemberResultFlags::CONTINUE))
403  {
404  sCaption = rMember.Caption;
405  sName = rMember.Name;
406  }
407 
408  if (i >= m_aLabels.size())
409  m_aLabels.resize(i + 1);
410 
411  if (o3tl::make_unsigned(nDimPos) >= m_aLabels[i].size())
412  m_aLabels[i].resize(nDimPos + 1);
413  m_aLabels[i][nDimPos] = ValueAndFormat(sCaption);
414 
415  if (bIsDataLayout)
416  {
417  // Remember data fields to determine the number format of data
418  aDataFieldNamesVectors.push_back(sName);
419  eDataFieldOrientation = sheet::DataPilotFieldOrientation_COLUMN;
420  // Remember the caption name
421  aDataFieldCaptionNames[rMember.Name] = rMember.Caption;
422  }
423  i++;
424  }
425  }
426  }
427  break;
428 
429  case sheet::DataPilotFieldOrientation_ROW:
430  {
431  m_aRowFields.emplace_back(xLevelName->getName(), nDim, nDimPos, bHasHiddenMember);
432 
433  const uno::Sequence<sheet::MemberResult> aSequence = xLevelResult->getResults();
434 
435  size_t i = 0;
436  size_t nEachIndex = 0;
437  std::unique_ptr<ValueAndFormat> pItem;
438 
439  for (sheet::MemberResult const & rMember : aSequence)
440  {
441  bool bFound = aValidRowIndex.find(nEachIndex) != aValidRowIndex.end();
442 
443  nEachIndex++;
444 
445  bool bHasContinueFlag = rMember.Flags & sheet::MemberResultFlags::CONTINUE;
446 
447  if (rMember.Flags & sheet::MemberResultFlags::HASMEMBER || bHasContinueFlag)
448  {
449  if (!bHasContinueFlag)
450  {
451  // Chart2 does not use number format for labels, so use the display string.
452  pItem.reset(new ValueAndFormat(rMember.Caption));
453  }
454 
455  if (bFound)
456  {
457  if (i >= m_aCategoriesRowOrientation.size())
458  m_aCategoriesRowOrientation.resize(i + 1);
459 
460  if (o3tl::make_unsigned(nDimPos) >= m_aCategoriesColumnOrientation.size())
461  m_aCategoriesColumnOrientation.resize(nDimPos + 1);
462  m_aCategoriesColumnOrientation[nDimPos].push_back(*pItem);
463 
464  if (o3tl::make_unsigned(nDimPos) >= m_aCategoriesRowOrientation[i].size())
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 
577 uno::Reference<chart2::data::XDataSequence>
578 PivotTableDataProvider::assignValuesToDataSequence(size_t nIndex)
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, rRowOfData));
588  pSequence->setRole("values-y");
589  xDataSequence = pSequence;
590  return xDataSequence;
591 }
592 
593 uno::Reference<chart2::data::XDataSequence>
594 PivotTableDataProvider::assignLabelsToDataSequence(size_t nIndex)
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, aLabelVector));
627  pSequence->setRole("values-y");
628  xDataSequence = pSequence;
629  return xDataSequence;
630 }
631 
632 css::uno::Reference<css::chart2::data::XDataSequence>
633  PivotTableDataProvider::assignFirstCategoriesToDataSequence()
634 {
635  uno::Reference<chart2::data::XDataSequence> xDataSequence;
636 
637  if (m_aCategoriesColumnOrientation.empty())
638  return xDataSequence;
639 
640  std::vector<ValueAndFormat> const & rCategories = m_aCategoriesColumnOrientation.back();
641 
643  lcl_identifierForCategories(), rCategories));
644  pSequence->setRole("categories");
645  xDataSequence = pSequence;
646 
647  return xDataSequence;
648 }
649 
650 uno::Reference<chart2::data::XDataSource>
651  PivotTableDataProvider::createValuesDataSource()
652 {
653  if (m_bNeedsUpdate)
654  collectPivotTableData();
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(aLabeledSequences));
678  return xDataSource;
679 }
680 
681 
682 uno::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 
696 sal_Bool SAL_CALL PivotTableDataProvider::createDataSequenceByRangeRepresentationPossible(const OUString& /*aRangeRepresentation*/)
697 {
698  return false;
699 }
700 
701 uno::Reference<chart2::data::XDataSequence> SAL_CALL
702  PivotTableDataProvider::createDataSequenceByRangeRepresentation(const OUString& /*rRangeRepresentation*/)
703 {
704  uno::Reference<chart2::data::XDataSequence> xDataSequence;
705  return xDataSequence;
706 }
707 
708 uno::Reference<chart2::data::XDataSequence> SAL_CALL
709  PivotTableDataProvider::createDataSequenceByValueArray(const OUString& /*aRole*/,
710  const OUString& /*aRangeRepresentation*/)
711 {
712  return uno::Reference<chart2::data::XDataSequence>();
713 }
714 
715 uno::Reference<sheet::XRangeSelection> SAL_CALL PivotTableDataProvider::getRangeSelection()
716 {
717  uno::Reference<sheet::XRangeSelection> xResult;
718 
719  uno::Reference<frame::XModel> xModel(lcl_GetXModel(m_pDocument));
720  if (xModel.is())
721  xResult.set(xModel->getCurrentController(), uno::UNO_QUERY);
722 
723  return xResult;
724 }
725 
726 // XPivotTableDataProvider ========================================================
727 
728 uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getColumnFields()
729 {
730  return comphelper::containerToSequence(m_aColumnFields);
731 }
732 
733 uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getRowFields()
734 {
735  return comphelper::containerToSequence(m_aRowFields);
736 }
737 
738 uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getPageFields()
739 {
740  return comphelper::containerToSequence(m_aPageFields);
741 }
742 
743 uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getDataFields()
744 {
745  return comphelper::containerToSequence(m_aDataFields);
746 }
747 
748 OUString PivotTableDataProvider::getPivotTableName()
749 {
750  return m_sPivotTableName;
751 }
752 
753 void PivotTableDataProvider::setPivotTableName(const OUString& sPivotTableName)
754 {
755  ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
756  ScDPObject* pDPObject = pDPCollection->GetByName(sPivotTableName);
757  if (pDPObject)
758  m_sPivotTableName = sPivotTableName;
759 }
760 
761 sal_Bool PivotTableDataProvider::hasPivotTable()
762 {
763  if (m_sPivotTableName.isEmpty())
764  return false;
765 
766  ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
767  ScDPObject* pDPObject = pDPCollection->GetByName(m_sPivotTableName);
768 
769  if (pDPObject)
770  return true;
771 
772  return false;
773 }
774 
775 uno::Reference<chart2::data::XDataSequence>
776  PivotTableDataProvider::createDataSequenceOfValuesByIndex(sal_Int32 nIndex)
777 {
778  SolarMutexGuard aGuard;
779 
780  if (m_bNeedsUpdate)
781  collectPivotTableData();
782 
783  return assignValuesToDataSequence(size_t(nIndex));
784 }
785 
786 uno::Reference<css::chart2::data::XDataSequence>
787  PivotTableDataProvider::createDataSequenceOfLabelsByIndex(sal_Int32 nIndex)
788 {
789  SolarMutexGuard aGuard;
790 
791  if (m_bNeedsUpdate)
792  collectPivotTableData();
793 
794  return assignLabelsToDataSequence(size_t(nIndex));
795 }
796 
797 uno::Reference<css::chart2::data::XDataSequence>
798  PivotTableDataProvider::createDataSequenceOfCategories()
799 {
800  SolarMutexGuard aGuard;
801 
802  if (m_bNeedsUpdate)
803  collectPivotTableData();
804 
805  return assignFirstCategoriesToDataSequence();
806 }
807 
808 OUString PivotTableDataProvider::getFieldOutputDescription(sal_Int32 nDimensionIndex)
809 {
810  if (nDimensionIndex < 0)
811  return OUString();
812  return m_aFieldOutputDescriptionMap[size_t(nDimensionIndex)];
813 }
814 
815 // XModifyBroadcaster ========================================================
816 
817 void SAL_CALL PivotTableDataProvider::addModifyListener(const uno::Reference< util::XModifyListener>& aListener)
818 {
819  SolarMutexGuard aGuard;
820 
821  m_aValueListeners.emplace_back(aListener);
822 }
823 
824 void SAL_CALL PivotTableDataProvider::removeModifyListener(const uno::Reference<util::XModifyListener>& aListener )
825 {
826  SolarMutexGuard aGuard;
827 
828  sal_uInt16 nCount = m_aValueListeners.size();
829  for (sal_uInt16 n = nCount; n--;)
830  {
831  uno::Reference<util::XModifyListener>& rObject = m_aValueListeners[n];
832  if (rObject == aListener)
833  {
834  m_aValueListeners.erase(m_aValueListeners.begin() + n);
835  }
836  }
837 }
838 
839 // DataProvider XPropertySet ========================================================
840 
841 uno::Reference< beans::XPropertySetInfo> SAL_CALL
842  PivotTableDataProvider::getPropertySetInfo()
843 {
844  SolarMutexGuard aGuard;
845  static uno::Reference<beans::XPropertySetInfo> aRef =
846  new SfxItemPropertySetInfo( m_aPropSet.getPropertyMap() );
847  return aRef;
848 }
849 
850 void SAL_CALL PivotTableDataProvider::setPropertyValue(const OUString& rPropertyName, const uno::Any& rValue)
851 {
852  if (rPropertyName != SC_UNONAME_INCLUDEHIDDENCELLS)
853  throw beans::UnknownPropertyException(rPropertyName);
854 
855  if (!(rValue >>= m_bIncludeHiddenCells))
856  throw lang::IllegalArgumentException();
857 }
858 
859 uno::Any SAL_CALL PivotTableDataProvider::getPropertyValue(const OUString& rPropertyName)
860 {
861  uno::Any aRet;
862  if (rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS)
863  aRet <<= m_bIncludeHiddenCells;
864  else if (rPropertyName == SC_UNONAME_USE_INTERNAL_DATA_PROVIDER)
865  {
866  // This is a read-only property.
867  aRet <<= m_pDocument->PastingDrawFromOtherDoc();
868  }
869  else
870  throw beans::UnknownPropertyException(rPropertyName);
871  return aRet;
872 }
873 
874 void SAL_CALL PivotTableDataProvider::addPropertyChangeListener(
875  const OUString& /*rPropertyName*/,
876  const uno::Reference<beans::XPropertyChangeListener>& /*xListener*/)
877 {
878  OSL_FAIL("Not yet implemented");
879 }
880 
881 void SAL_CALL PivotTableDataProvider::removePropertyChangeListener(
882  const OUString& /*rPropertyName*/,
883  const uno::Reference<beans::XPropertyChangeListener>& /*rListener*/)
884 {
885  OSL_FAIL("Not yet implemented");
886 }
887 
888 void SAL_CALL PivotTableDataProvider::addVetoableChangeListener(
889  const OUString& /*rPropertyName*/,
890  const uno::Reference<beans::XVetoableChangeListener>& /*rListener*/)
891 {
892  OSL_FAIL("Not yet implemented");
893 }
894 
895 void SAL_CALL PivotTableDataProvider::removeVetoableChangeListener(
896  const OUString& /*rPropertyName*/,
897  const uno::Reference<beans::XVetoableChangeListener>& /*rListener*/ )
898 {
899  OSL_FAIL("Not yet implemented");
900 }
901 
902 } // end sc namespace
903 
904 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
#define SC_UNONAME_INCLUDEHIDDENCELLS
Definition: unonames.hxx:677
bool bVisible
static sal_Int32 GetLongProperty(const css::uno::Reference< css::beans::XPropertySet > &xProp, const OUString &rName)
Definition: miscuno.cxx:71
#define SC_UNONAME_USE_INTERNAL_DATA_PROVIDER
Definition: unonames.hxx:678
long Long
sal_Int64 n
static EnumT GetEnumProperty(const css::uno::Reference< css::beans::XPropertySet > &xProp, const OUString &rName, EnumT nDefault)
Definition: miscuno.hxx:159
#define SC_UNO_DP_POSITION
Definition: unonames.hxx:592
static OUString GetStringProperty(const css::uno::Reference< css::beans::XPropertySet > &xProp, const OUString &rName, const OUString &rDefault)
Definition: miscuno.cxx:119
ScDPObject * GetByName(std::u16string_view rName) const
Definition: dpobject.cxx:3691
SfxHintId GetId() const
#define SC_UNO_DP_LAYOUTNAME
Definition: unonames.hxx:610
int nCount
css::uno::Sequence< css::beans::PropertyValue > InitPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
const char * sName
int i
css::uno::Reference< css::sheet::XDimensionsSupplier > const & GetSource()
Definition: dpobject.cxx:515
void Notify(ScModelObj &rModelObj, const ScRangeList &rChangeRanges, const OUString &rType=OUString("cell-change"), const css::uno::Sequence< css::beans::PropertyValue > &rProperties=css::uno::Sequence< css::beans::PropertyValue >())
Definition: docsh.hxx:478
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
static bool GetBoolProperty(const css::uno::Reference< css::beans::XPropertySet > &xProp, const OUString &rName, bool bDefault=false)
Definition: miscuno.cxx:35
float u
unsigned char sal_Bool
OUString ScResId(const char *pId)
Definition: scdll.cxx:89
size
css::uno::Type const & get()
#define SC_SIMPLE_SERVICE_INFO(ClassName, ClassNameAscii, ServiceAscii)
Definition: miscuno.hxx:63
#define SC_UNO_DP_HAS_HIDDEN_MEMBER
Definition: unonames.hxx:613
#define SC_UNO_DP_ORIENTATION
Definition: unonames.hxx:591
#define SC_UNO_DP_USEDHIERARCHY
Definition: unonames.hxx:595
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
#define SC_UNO_DP_ISVISIBLE
Definition: unonames.hxx:601
OUString aLabel
SfxObjectShell * GetDocumentShell() const
Definition: document.hxx:1056
Reference< XModel > xModel
#define SC_UNO_DP_ISDATALAYOUT
Definition: unonames.hxx:590
Reference< XComponentContext > m_xContext
#define SC_SERVICENAME_CHART_PIVOTTABLE_DATAPROVIDER
Definition: unonames.hxx:34
#define SC_UNO_DP_NUMBERFO
Definition: unonames.hxx:606
AnyEventRef aEvent