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();
256  std::unique_ptr<PivotTableDataSequence> pSequence;
257  pSequence.reset(new PivotTableDataSequence(m_pDocument,
258  lcl_identifierForCategories(), rCategories));
259  pSequence->setRole("categories");
260  xResult->setValues(uno::Reference<chart2::data::XDataSequence>(pSequence.release()));
261 
262  aLabeledSequences.push_back(xResult);
263  }
264 
265  xDataSource.set(new PivotTableDataSource(aLabeledSequences));
266  return xDataSource;
267 }
268 
269 void PivotTableDataProvider::collectPivotTableData()
270 {
271  ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
272  ScDPObject* pDPObject = pDPCollection->GetByName(m_sPivotTableName);
273  if (!pDPObject)
274  return;
275 
276  m_aCategoriesColumnOrientation.clear();
277  m_aCategoriesRowOrientation.clear();
278  m_aLabels.clear();
279  m_aDataRowVector.clear();
280  m_aColumnFields.clear();
281  m_aRowFields.clear();
282  m_aPageFields.clear();
283  m_aDataFields.clear();
284  m_aFieldOutputDescriptionMap.clear();
285 
286  uno::Reference<sheet::XDataPilotResults> xDPResults(pDPObject->GetSource(), uno::UNO_QUERY);
287  if (!xDPResults.is())
288  return;
289  const uno::Sequence<uno::Sequence<sheet::DataResult>> xDataResultsSequence = xDPResults->getResults();
290 
291  double fNan;
292  rtl::math::setNan(&fNan);
293 
294  std::unordered_set<size_t> aValidRowIndex;
295 
296  size_t nRowIndex = 0;
297  for (uno::Sequence<sheet::DataResult> const & xDataResults : xDataResultsSequence)
298  {
299  std::vector<ValueAndFormat> aRow;
300  bool bRowEmpty = true;
301  // First pass - collect a row of valid data and track if the row is empty
302  for (sheet::DataResult const & rDataResult : xDataResults)
303  {
304  if (rDataResult.Flags & css::sheet::DataResultFlags::SUBTOTAL)
305  continue;
306  if (rDataResult.Flags == 0 || rDataResult.Flags & css::sheet::DataResultFlags::HASDATA)
307  {
308  aRow.emplace_back(rDataResult.Flags ? rDataResult.Value : fNan, 0);
309  if (rDataResult.Flags != 0) // set as valid only if we have data
310  {
311  bRowEmpty = false;
312  // We need to remember all valid (non-empty) row indices
313  aValidRowIndex.insert(nRowIndex);
314  }
315  }
316  }
317  // Second pass: add to collection only non-empty rows
318  if (!bRowEmpty)
319  {
320  size_t nColumnIndex = 0;
321  for (ValueAndFormat const & aValue : aRow)
322  {
323  if (nColumnIndex >= m_aDataRowVector.size())
324  m_aDataRowVector.resize(nColumnIndex + 1);
325  m_aDataRowVector[nColumnIndex].push_back(aValue);
326  nColumnIndex++;
327  }
328  }
329  nRowIndex++;
330  }
331 
332  uno::Reference<sheet::XDimensionsSupplier> xDimensionsSupplier(pDPObject->GetSource());
333  uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess(xDimensionsSupplier->getDimensions());
334 
335  std::unordered_map<OUString, sal_Int32> aDataFieldNumberFormatMap;
336  std::vector<OUString> aDataFieldNamesVectors;
337 
338  std::unordered_map<OUString, OUString> aDataFieldCaptionNames;
339 
340  sheet::DataPilotFieldOrientation eDataFieldOrientation = sheet::DataPilotFieldOrientation_HIDDEN;
341 
342  for (sal_Int32 nDim = 0; nDim < xDims->getCount(); nDim++)
343  {
344  uno::Reference<uno::XInterface> xDim(xDims->getByIndex(nDim), uno::UNO_QUERY);
345  uno::Reference<beans::XPropertySet> xDimProp(xDim, uno::UNO_QUERY);
346  uno::Reference<sheet::XHierarchiesSupplier> xDimSupp(xDim, uno::UNO_QUERY);
347 
348  if (!xDimProp.is() || !xDimSupp.is())
349  continue;
350 
351  sheet::DataPilotFieldOrientation eDimOrient =
353  sheet::DataPilotFieldOrientation_HIDDEN);
354 
355  if (eDimOrient == sheet::DataPilotFieldOrientation_HIDDEN)
356  continue;
357 
358  uno::Reference<container::XIndexAccess> xHierarchies = new ScNameToIndexAccess(xDimSupp->getHierarchies());
359  sal_Int32 nHierarchy = ScUnoHelpFunctions::GetLongProperty(xDimProp, SC_UNO_DP_USEDHIERARCHY);
360  if (nHierarchy >= xHierarchies->getCount())
361  nHierarchy = 0;
362 
363  uno::Reference<sheet::XLevelsSupplier> xLevelsSupplier(xHierarchies->getByIndex(nHierarchy),
364  uno::UNO_QUERY);
365 
366  if (!xLevelsSupplier.is())
367  continue;
368 
369  uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess(xLevelsSupplier->getLevels());
370 
371  for (tools::Long nLevel = 0; nLevel < xLevels->getCount(); nLevel++)
372  {
373  uno::Reference<uno::XInterface> xLevel(xLevels->getByIndex(nLevel), uno::UNO_QUERY);
374  uno::Reference<container::XNamed> xLevelName(xLevel, uno::UNO_QUERY);
375  uno::Reference<sheet::XDataPilotMemberResults> xLevelResult(xLevel, uno::UNO_QUERY );
376 
377  if (xLevelName.is() && xLevelResult.is())
378  {
379  bool bIsDataLayout = ScUnoHelpFunctions::GetBoolProperty(xDimProp, SC_UNO_DP_ISDATALAYOUT);
380  sal_Int32 nDimPos = ScUnoHelpFunctions::GetLongProperty(xDimProp, SC_UNO_DP_POSITION);
381  sal_Int32 nNumberFormat = ScUnoHelpFunctions::GetLongProperty(xDimProp, SC_UNO_DP_NUMBERFO);
382  bool bHasHiddenMember = ScUnoHelpFunctions::GetBoolProperty(xDimProp, SC_UNO_DP_HAS_HIDDEN_MEMBER);
383 
384  switch (eDimOrient)
385  {
386  case sheet::DataPilotFieldOrientation_COLUMN:
387  {
388  m_aColumnFields.emplace_back(xLevelName->getName(), nDim, nDimPos, bHasHiddenMember);
389 
390  const uno::Sequence<sheet::MemberResult> aSequence = xLevelResult->getResults();
391  size_t i = 0;
392  OUString sCaption;
393  OUString sName;
394  for (sheet::MemberResult const & rMember : aSequence)
395  {
396  // Skip grandtotals and subtotals
397  if (rMember.Flags & sheet::MemberResultFlags::SUBTOTAL ||
398  rMember.Flags & sheet::MemberResultFlags::GRANDTOTAL)
399  continue;
400  if (rMember.Flags & sheet::MemberResultFlags::HASMEMBER ||
401  rMember.Flags & sheet::MemberResultFlags::CONTINUE)
402  {
403  if (!(rMember.Flags & sheet::MemberResultFlags::CONTINUE))
404  {
405  sCaption = rMember.Caption;
406  sName = rMember.Name;
407  }
408 
409  if (i >= m_aLabels.size())
410  m_aLabels.resize(i + 1);
411 
412  if (o3tl::make_unsigned(nDimPos) >= m_aLabels[i].size())
413  m_aLabels[i].resize(nDimPos + 1);
414  m_aLabels[i][nDimPos] = ValueAndFormat(sCaption);
415 
416  if (bIsDataLayout)
417  {
418  // Remember data fields to determine the number format of data
419  aDataFieldNamesVectors.push_back(sName);
420  eDataFieldOrientation = sheet::DataPilotFieldOrientation_COLUMN;
421  // Remember the caption name
422  aDataFieldCaptionNames[rMember.Name] = rMember.Caption;
423  }
424  i++;
425  }
426  }
427  }
428  break;
429 
430  case sheet::DataPilotFieldOrientation_ROW:
431  {
432  m_aRowFields.emplace_back(xLevelName->getName(), nDim, nDimPos, bHasHiddenMember);
433 
434  const uno::Sequence<sheet::MemberResult> aSequence = xLevelResult->getResults();
435 
436  size_t i = 0;
437  size_t nEachIndex = 0;
438  std::unique_ptr<ValueAndFormat> pItem;
439 
440  for (sheet::MemberResult const & rMember : aSequence)
441  {
442  bool bFound = aValidRowIndex.find(nEachIndex) != aValidRowIndex.end();
443 
444  nEachIndex++;
445 
446  bool bHasContinueFlag = rMember.Flags & sheet::MemberResultFlags::CONTINUE;
447 
448  if (rMember.Flags & sheet::MemberResultFlags::HASMEMBER || bHasContinueFlag)
449  {
450  if (!bHasContinueFlag)
451  {
452  // Chart2 does not use number format for labels, so use the display string.
453  pItem.reset(new ValueAndFormat(rMember.Caption));
454  }
455 
456  if (bFound)
457  {
458  if (i >= m_aCategoriesRowOrientation.size())
459  m_aCategoriesRowOrientation.resize(i + 1);
460 
461  if (o3tl::make_unsigned(nDimPos) >= m_aCategoriesColumnOrientation.size())
462  m_aCategoriesColumnOrientation.resize(nDimPos + 1);
463  m_aCategoriesColumnOrientation[nDimPos].push_back(*pItem);
464 
465  if (o3tl::make_unsigned(nDimPos) >= m_aCategoriesRowOrientation[i].size())
466  m_aCategoriesRowOrientation[i].resize(nDimPos + 1);
467  m_aCategoriesRowOrientation[i][nDimPos] = *pItem;
468 
469  if (bIsDataLayout)
470  {
471  // Remember data fields to determine the number format of data
472  aDataFieldNamesVectors.push_back(rMember.Name);
473  eDataFieldOrientation = sheet::DataPilotFieldOrientation_ROW;
474 
475  // Remember the caption name
476  aDataFieldCaptionNames[rMember.Name] = rMember.Caption;
477  }
478 
479  // Set to empty so the sub categories are set to empty when they continue
480  pItem.reset(new ValueAndFormat);
481  i++;
482  }
483  }
484  }
485  }
486  break;
487 
488  case sheet::DataPilotFieldOrientation_PAGE:
489  {
490  m_aPageFields.emplace_back(xLevelName->getName(), nDim, nDimPos, bHasHiddenMember);
491 
492  // Resolve filtering
493  OUString aFieldOutputDescription;
494  if (bHasHiddenMember)
495  {
496  std::vector<OUString> aMembers = lcl_getVisiblePageMembers(xLevel);
497 
498  if (aMembers.size() == 1)
499  aFieldOutputDescription = aMembers[0];
500  else
501  aFieldOutputDescription = ScResId(SCSTR_MULTIPLE);
502  }
503  else
504  {
505  aFieldOutputDescription = ScResId(SCSTR_ALL);
506  }
507  m_aFieldOutputDescriptionMap[nDim] = aFieldOutputDescription;
508  }
509  break;
510 
511  case sheet::DataPilotFieldOrientation_DATA:
512  {
513  aDataFieldNumberFormatMap[xLevelName->getName()] = nNumberFormat;
514  m_aDataFields.emplace_back(xLevelName->getName(), nDim, nDimPos, bHasHiddenMember);
515  }
516  break;
517 
518  default:
519  break;
520  }
521  }
522  }
523  }
524 
525  // Transform the name of data fields
526  for (chart2::data::PivotTableFieldEntry& rDataFields : m_aDataFields)
527  {
528  rDataFields.Name = aDataFieldCaptionNames[rDataFields.Name];
529  }
530 
531  // Apply number format to the data
532  if (eDataFieldOrientation == sheet::DataPilotFieldOrientation_ROW)
533  {
534  for (std::vector<ValueAndFormat> & rDataRow : m_aDataRowVector)
535  {
536  size_t i = 0;
537  for (ValueAndFormat & rItem : rDataRow)
538  {
539  OUString sName = aDataFieldNamesVectors[i];
540  sal_Int32 nNumberFormat = aDataFieldNumberFormatMap[sName];
541  rItem.m_nNumberFormat = nNumberFormat;
542  i++;
543  }
544  }
545  }
546  else if (eDataFieldOrientation == sheet::DataPilotFieldOrientation_COLUMN)
547  {
548  size_t i = 0;
549  for (std::vector<ValueAndFormat> & rDataRow : m_aDataRowVector)
550  {
551  OUString sName = aDataFieldNamesVectors[i];
552  sal_Int32 nNumberFormat = aDataFieldNumberFormatMap[sName];
553  for (ValueAndFormat & rItem : rDataRow)
554  {
555  rItem.m_nNumberFormat = nNumberFormat;
556  }
557  i++;
558  }
559  }
560 
561  // Sort fields so it respects the order of how it is represented in the pivot table
562 
563  auto funcDimensionPositionSortCompare = [] (chart2::data::PivotTableFieldEntry const & entry1,
564  chart2::data::PivotTableFieldEntry const & entry2)
565  {
566  return entry1.DimensionPositionIndex < entry2.DimensionPositionIndex;
567  };
568 
569  std::sort(m_aColumnFields.begin(), m_aColumnFields.end(), funcDimensionPositionSortCompare);
570  std::sort(m_aRowFields.begin(), m_aRowFields.end(), funcDimensionPositionSortCompare);
571  std::sort(m_aPageFields.begin(), m_aPageFields.end(), funcDimensionPositionSortCompare);
572  std::sort(m_aDataFields.begin(), m_aDataFields.end(), funcDimensionPositionSortCompare);
573 
574  // Mark that we updated the data
575  m_bNeedsUpdate = false;
576 }
577 
578 uno::Reference<chart2::data::XDataSequence>
579 PivotTableDataProvider::assignValuesToDataSequence(size_t nIndex)
580 {
581  uno::Reference<chart2::data::XDataSequence> xDataSequence;
582  if (nIndex >= m_aDataRowVector.size())
583  return xDataSequence;
584 
585  OUString sDataID = lcl_identifierForData(nIndex);
586 
587  std::vector<ValueAndFormat> const & rRowOfData = m_aDataRowVector[nIndex];
588  std::unique_ptr<PivotTableDataSequence> pSequence;
589  pSequence.reset(new PivotTableDataSequence(m_pDocument, sDataID, rRowOfData));
590  pSequence->setRole("values-y");
591  xDataSequence.set(pSequence.release());
592  return xDataSequence;
593 }
594 
595 uno::Reference<chart2::data::XDataSequence>
596 PivotTableDataProvider::assignLabelsToDataSequence(size_t nIndex)
597 {
598  uno::Reference<chart2::data::XDataSequence> xDataSequence;
599 
600  OUString sLabelID = lcl_identifierForLabel(nIndex);
601 
602  OUStringBuffer aLabel;
603  bool bFirst = true;
604 
605  if (m_aLabels.empty())
606  {
607  aLabel = ScResId(STR_PIVOT_TOTAL);
608  }
609  else if (nIndex < m_aLabels.size())
610  {
611  for (ValueAndFormat const & rItem : m_aLabels[nIndex])
612  {
613  if (bFirst)
614  {
615  aLabel.append(rItem.m_aString);
616  bFirst = false;
617  }
618  else
619  {
620  aLabel.append(" - ").append(rItem.m_aString);
621  }
622  }
623  }
624 
625  std::vector<ValueAndFormat> aLabelVector { ValueAndFormat(aLabel.makeStringAndClear()) };
626 
627  std::unique_ptr<PivotTableDataSequence> pSequence;
628  pSequence.reset(new PivotTableDataSequence(m_pDocument,
629  sLabelID, aLabelVector));
630  pSequence->setRole("values-y");
631  xDataSequence.set(pSequence.release());
632  return xDataSequence;
633 }
634 
635 css::uno::Reference<css::chart2::data::XDataSequence>
636  PivotTableDataProvider::assignFirstCategoriesToDataSequence()
637 {
638  uno::Reference<chart2::data::XDataSequence> xDataSequence;
639 
640  if (m_aCategoriesColumnOrientation.empty())
641  return xDataSequence;
642 
643  std::vector<ValueAndFormat> const & rCategories = m_aCategoriesColumnOrientation.back();
644 
645  std::unique_ptr<PivotTableDataSequence> pSequence;
646  pSequence.reset(new PivotTableDataSequence(m_pDocument,
647  lcl_identifierForCategories(), rCategories));
648  pSequence->setRole("categories");
649  xDataSequence.set(uno::Reference<chart2::data::XDataSequence>(pSequence.release()));
650 
651  return xDataSequence;
652 }
653 
654 uno::Reference<chart2::data::XDataSource>
655  PivotTableDataProvider::createValuesDataSource()
656 {
657  if (m_bNeedsUpdate)
658  collectPivotTableData();
659 
660  uno::Reference<chart2::data::XDataSource> xDataSource;
661  std::vector<uno::Reference<chart2::data::XLabeledDataSequence>> aLabeledSequences;
662 
663  // Fill first sequence of categories
664  {
665  uno::Reference<chart2::data::XLabeledDataSequence> xResult = newLabeledDataSequence();
666  xResult->setValues(assignFirstCategoriesToDataSequence());
667  aLabeledSequences.push_back(xResult);
668  }
669 
670  // Fill values and labels
671  {
672  for (size_t i = 0; i < m_aDataRowVector.size(); ++i)
673  {
674  uno::Reference<chart2::data::XLabeledDataSequence> xResult = newLabeledDataSequence();
675  xResult->setValues(assignValuesToDataSequence(i));
676  xResult->setLabel(assignLabelsToDataSequence(i));
677  aLabeledSequences.push_back(xResult);
678  }
679  }
680 
681  xDataSource.set(new PivotTableDataSource(aLabeledSequences));
682  return xDataSource;
683 }
684 
685 
686 uno::Sequence<beans::PropertyValue> SAL_CALL PivotTableDataProvider::detectArguments(
687  const uno::Reference<chart2::data::XDataSource> & xDataSource)
688 {
689  if (!m_pDocument ||!xDataSource.is())
690  return uno::Sequence<beans::PropertyValue>();
691 
693  { "CellRangeRepresentation", uno::Any(OUString("PivotChart")) },
694  { "DataRowSource", uno::Any(chart::ChartDataRowSource_COLUMNS) },
695  { "FirstCellAsLabel", uno::Any(false) },
696  { "HasCategories", uno::Any(true) }
697  });
698 }
699 
700 sal_Bool SAL_CALL PivotTableDataProvider::createDataSequenceByRangeRepresentationPossible(const OUString& /*aRangeRepresentation*/)
701 {
702  return false;
703 }
704 
705 uno::Reference<chart2::data::XDataSequence> SAL_CALL
706  PivotTableDataProvider::createDataSequenceByRangeRepresentation(const OUString& /*rRangeRepresentation*/)
707 {
708  uno::Reference<chart2::data::XDataSequence> xDataSequence;
709  return xDataSequence;
710 }
711 
712 uno::Reference<chart2::data::XDataSequence> SAL_CALL
713  PivotTableDataProvider::createDataSequenceByValueArray(const OUString& /*aRole*/,
714  const OUString& /*aRangeRepresentation*/)
715 {
716  return uno::Reference<chart2::data::XDataSequence>();
717 }
718 
719 uno::Reference<sheet::XRangeSelection> SAL_CALL PivotTableDataProvider::getRangeSelection()
720 {
721  uno::Reference<sheet::XRangeSelection> xResult;
722 
723  uno::Reference<frame::XModel> xModel(lcl_GetXModel(m_pDocument));
724  if (xModel.is())
725  xResult.set(xModel->getCurrentController(), uno::UNO_QUERY);
726 
727  return xResult;
728 }
729 
730 // XPivotTableDataProvider ========================================================
731 
732 uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getColumnFields()
733 {
734  return comphelper::containerToSequence(m_aColumnFields);
735 }
736 
737 uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getRowFields()
738 {
739  return comphelper::containerToSequence(m_aRowFields);
740 }
741 
742 uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getPageFields()
743 {
744  return comphelper::containerToSequence(m_aPageFields);
745 }
746 
747 uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getDataFields()
748 {
749  return comphelper::containerToSequence(m_aDataFields);
750 }
751 
752 OUString PivotTableDataProvider::getPivotTableName()
753 {
754  return m_sPivotTableName;
755 }
756 
757 void PivotTableDataProvider::setPivotTableName(const OUString& sPivotTableName)
758 {
759  ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
760  ScDPObject* pDPObject = pDPCollection->GetByName(sPivotTableName);
761  if (pDPObject)
762  m_sPivotTableName = sPivotTableName;
763 }
764 
765 sal_Bool PivotTableDataProvider::hasPivotTable()
766 {
767  if (m_sPivotTableName.isEmpty())
768  return false;
769 
770  ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
771  ScDPObject* pDPObject = pDPCollection->GetByName(m_sPivotTableName);
772 
773  if (pDPObject)
774  return true;
775 
776  return false;
777 }
778 
779 uno::Reference<chart2::data::XDataSequence>
780  PivotTableDataProvider::createDataSequenceOfValuesByIndex(sal_Int32 nIndex)
781 {
782  SolarMutexGuard aGuard;
783 
784  if (m_bNeedsUpdate)
785  collectPivotTableData();
786 
787  return assignValuesToDataSequence(size_t(nIndex));
788 }
789 
790 uno::Reference<css::chart2::data::XDataSequence>
791  PivotTableDataProvider::createDataSequenceOfLabelsByIndex(sal_Int32 nIndex)
792 {
793  SolarMutexGuard aGuard;
794 
795  if (m_bNeedsUpdate)
796  collectPivotTableData();
797 
798  return assignLabelsToDataSequence(size_t(nIndex));
799 }
800 
801 uno::Reference<css::chart2::data::XDataSequence>
802  PivotTableDataProvider::createDataSequenceOfCategories()
803 {
804  SolarMutexGuard aGuard;
805 
806  if (m_bNeedsUpdate)
807  collectPivotTableData();
808 
809  return assignFirstCategoriesToDataSequence();
810 }
811 
812 OUString PivotTableDataProvider::getFieldOutputDescription(sal_Int32 nDimensionIndex)
813 {
814  if (nDimensionIndex < 0)
815  return OUString();
816  return m_aFieldOutputDescriptionMap[size_t(nDimensionIndex)];
817 }
818 
819 // XModifyBroadcaster ========================================================
820 
821 void SAL_CALL PivotTableDataProvider::addModifyListener(const uno::Reference< util::XModifyListener>& aListener)
822 {
823  SolarMutexGuard aGuard;
824 
825  m_aValueListeners.emplace_back(aListener);
826 }
827 
828 void SAL_CALL PivotTableDataProvider::removeModifyListener(const uno::Reference<util::XModifyListener>& aListener )
829 {
830  SolarMutexGuard aGuard;
831 
832  sal_uInt16 nCount = m_aValueListeners.size();
833  for (sal_uInt16 n = nCount; n--;)
834  {
835  uno::Reference<util::XModifyListener>& rObject = m_aValueListeners[n];
836  if (rObject == aListener)
837  {
838  m_aValueListeners.erase(m_aValueListeners.begin() + n);
839  }
840  }
841 }
842 
843 // DataProvider XPropertySet ========================================================
844 
845 uno::Reference< beans::XPropertySetInfo> SAL_CALL
846  PivotTableDataProvider::getPropertySetInfo()
847 {
848  SolarMutexGuard aGuard;
849  static uno::Reference<beans::XPropertySetInfo> aRef =
850  new SfxItemPropertySetInfo( m_aPropSet.getPropertyMap() );
851  return aRef;
852 }
853 
854 void SAL_CALL PivotTableDataProvider::setPropertyValue(const OUString& rPropertyName, const uno::Any& rValue)
855 {
856  if (rPropertyName != SC_UNONAME_INCLUDEHIDDENCELLS)
857  throw beans::UnknownPropertyException(rPropertyName);
858 
859  if (!(rValue >>= m_bIncludeHiddenCells))
860  throw lang::IllegalArgumentException();
861 }
862 
863 uno::Any SAL_CALL PivotTableDataProvider::getPropertyValue(const OUString& rPropertyName)
864 {
865  uno::Any aRet;
866  if (rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS)
867  aRet <<= m_bIncludeHiddenCells;
868  else if (rPropertyName == SC_UNONAME_USE_INTERNAL_DATA_PROVIDER)
869  {
870  // This is a read-only property.
871  aRet <<= m_pDocument->PastingDrawFromOtherDoc();
872  }
873  else
874  throw beans::UnknownPropertyException(rPropertyName);
875  return aRet;
876 }
877 
878 void SAL_CALL PivotTableDataProvider::addPropertyChangeListener(
879  const OUString& /*rPropertyName*/,
880  const uno::Reference<beans::XPropertyChangeListener>& /*xListener*/)
881 {
882  OSL_FAIL("Not yet implemented");
883 }
884 
885 void SAL_CALL PivotTableDataProvider::removePropertyChangeListener(
886  const OUString& /*rPropertyName*/,
887  const uno::Reference<beans::XPropertyChangeListener>& /*rListener*/)
888 {
889  OSL_FAIL("Not yet implemented");
890 }
891 
892 void SAL_CALL PivotTableDataProvider::addVetoableChangeListener(
893  const OUString& /*rPropertyName*/,
894  const uno::Reference<beans::XVetoableChangeListener>& /*rListener*/)
895 {
896  OSL_FAIL("Not yet implemented");
897 }
898 
899 void SAL_CALL PivotTableDataProvider::removeVetoableChangeListener(
900  const OUString& /*rPropertyName*/,
901  const uno::Reference<beans::XVetoableChangeListener>& /*rListener*/ )
902 {
903  OSL_FAIL("Not yet implemented");
904 }
905 
906 } // end sc namespace
907 
908 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
#define SC_UNONAME_INCLUDEHIDDENCELLS
Definition: unonames.hxx:678
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:679
long Long
sal_Int64 n
static EnumT GetEnumProperty(const css::uno::Reference< css::beans::XPropertySet > &xProp, const OUString &rName, EnumT nDefault)
Definition: miscuno.hxx:160
#define SC_UNO_DP_POSITION
Definition: unonames.hxx:593
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:3692
SfxHintId GetId() const
#define SC_UNO_DP_LAYOUTNAME
Definition: unonames.hxx:611
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:479
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:64
#define SC_UNO_DP_HAS_HIDDEN_MEMBER
Definition: unonames.hxx:614
#define SC_UNO_DP_ORIENTATION
Definition: unonames.hxx:592
#define SC_UNO_DP_USEDHIERARCHY
Definition: unonames.hxx:596
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
#define SC_UNO_DP_ISVISIBLE
Definition: unonames.hxx:602
OUString aLabel
SfxObjectShell * GetDocumentShell() const
Definition: document.hxx:1055
Reference< XModel > xModel
#define SC_UNO_DP_ISDATALAYOUT
Definition: unonames.hxx:591
Reference< XComponentContext > m_xContext
#define SC_SERVICENAME_CHART_PIVOTTABLE_DATAPROVIDER
Definition: unonames.hxx:35
#define SC_UNO_DP_NUMBERFO
Definition: unonames.hxx:607
AnyEventRef aEvent