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