1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <dpcache.hxx>
22 #include <dpobject.hxx>
23 #include <dptabsrc.hxx>
25 #include <dpdimsave.hxx>
26 #include <dpoutput.hxx>
27 #include <dpshttab.hxx>
28 #include <dpsdbtab.hxx>
29 #include <dpgroup.hxx>
30 #include <document.hxx>
32 #include <dapiuno.hxx>
33 #include <miscuno.hxx>
34 #include <refupdat.hxx>
36 #include <scitems.hxx>
37 #include <unonames.hxx>
38 #include <dpglobal.hxx>
39 #include <globstr.hrc>
40 #include <queryentry.hxx>
43 #include <com/sun/star/beans/XPropertySet.hpp>
44 #include <com/sun/star/sdb/XCompletedExecution.hpp>
45 #include <com/sun/star/sdbc/DataType.hpp>
46 #include <com/sun/star/sdbc/SQLException.hpp>
47 #include <com/sun/star/sdbc/XResultSetMetaData.hpp>
48 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
49 #include <com/sun/star/sdbc/XRow.hpp>
50 #include <com/sun/star/sdbc/XRowSet.hpp>
51 #include <com/sun/star/sheet/GeneralFunction2.hpp>
52 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
53 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
54 #include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
55 #include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
56 #include <com/sun/star/sheet/DataPilotTablePositionData.hpp>
57 #include <com/sun/star/sheet/DataPilotTablePositionType.hpp>
58 #include <com/sun/star/sheet/DimensionFlags.hpp>
59 #include <com/sun/star/task/InteractionHandler.hpp>
60 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
61 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
62 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
63 #include <com/sun/star/lang/XInitialization.hpp>
64 #include <com/sun/star/container/XContentEnumerationAccess.hpp>
65 #include <com/sun/star/sheet/XDrillDownDataSupplier.hpp>
67 #include <unotools/charclass.hxx>
68 #include <comphelper/processfactory.hxx>
69 #include <comphelper/string.hxx>
70 #include <comphelper/types.hxx>
71 #include <o3tl/safeint.hxx>
72 #include <sal/macros.h>
73 #include <svl/numformat.hxx>
74 #include <comphelper/diagnose_ex.hxx>
75 #include <svl/zforlist.hxx>
77 #include <vcl/svapp.hxx>
78 #include <vcl/weld.hxx>
84 using namespace com::sun::star
;
86 using ::std::shared_ptr
;
87 using ::com::sun::star::uno::Sequence
;
88 using ::com::sun::star::uno::Reference
;
89 using ::com::sun::star::uno::UNO_QUERY
;
90 using ::com::sun::star::uno::Any
;
91 using ::com::sun::star::uno::Exception
;
92 using ::com::sun::star::lang::XComponent
;
93 using ::com::sun::star::sheet::DataPilotTableHeaderData
;
94 using ::com::sun::star::sheet::DataPilotTablePositionData
;
95 using ::com::sun::star::sheet::XDimensionsSupplier
;
96 using ::com::sun::star::beans::XPropertySet
;
98 constexpr OUStringLiteral SC_SERVICE_ROWSET
= u
"com.sun.star.sdb.RowSet";
100 constexpr OUStringLiteral SC_DBPROP_DATASOURCENAME
= u
"DataSourceName";
101 constexpr OUStringLiteral SC_DBPROP_COMMAND
= u
"Command";
102 constexpr OUStringLiteral SC_DBPROP_COMMANDTYPE
= u
"CommandType";
104 constexpr OUString SCDPSOURCE_SERVICE
= u
"com.sun.star.sheet.DataPilotSource"_ustr
;
109 * Database connection implementation for UNO database API. Note that in
110 * the UNO database API, column index is 1-based, whereas the interface
111 * requires that column index be 0-based.
113 class DBConnector
: public ScDPCache::DBConnector
117 uno::Reference
<sdbc::XRowSet
> mxRowSet
;
118 uno::Reference
<sdbc::XRow
> mxRow
;
119 uno::Reference
<sdbc::XResultSetMetaData
> mxMetaData
;
123 DBConnector(ScDPCache
& rCache
, uno::Reference
<sdbc::XRowSet
> xRowSet
, const Date
& rNullDate
);
125 bool isValid() const;
127 virtual void getValue(tools::Long nCol
, ScDPItemData
&rData
, SvNumFormatType
& rNumType
) const override
;
128 virtual OUString
getColumnLabel(tools::Long nCol
) const override
;
129 virtual tools::Long
getColumnCount() const override
;
130 virtual bool first() override
;
131 virtual bool next() override
;
132 virtual void finish() override
;
135 DBConnector::DBConnector(ScDPCache
& rCache
, uno::Reference
<sdbc::XRowSet
> xRowSet
, const Date
& rNullDate
) :
136 mrCache(rCache
), mxRowSet(std::move(xRowSet
)), maNullDate(rNullDate
)
138 Reference
<sdbc::XResultSetMetaDataSupplier
> xMetaSupp(mxRowSet
, UNO_QUERY
);
140 mxMetaData
= xMetaSupp
->getMetaData();
142 mxRow
.set(mxRowSet
, UNO_QUERY
);
145 bool DBConnector::isValid() const
147 return mxRowSet
.is() && mxRow
.is() && mxMetaData
.is();
150 bool DBConnector::first()
152 return mxRowSet
->first();
155 bool DBConnector::next()
157 return mxRowSet
->next();
160 void DBConnector::finish()
162 mxRowSet
->beforeFirst();
165 tools::Long
DBConnector::getColumnCount() const
167 return mxMetaData
->getColumnCount();
170 OUString
DBConnector::getColumnLabel(tools::Long nCol
) const
172 return mxMetaData
->getColumnLabel(nCol
+1);
175 void DBConnector::getValue(tools::Long nCol
, ScDPItemData
&rData
, SvNumFormatType
& rNumType
) const
177 rNumType
= SvNumFormatType::NUMBER
;
178 sal_Int32 nType
= mxMetaData
->getColumnType(nCol
+1);
185 case sdbc::DataType::BIT
:
186 case sdbc::DataType::BOOLEAN
:
188 rNumType
= SvNumFormatType::LOGICAL
;
189 fValue
= mxRow
->getBoolean(nCol
+1) ? 1 : 0;
190 rData
.SetValue(fValue
);
193 case sdbc::DataType::TINYINT
:
194 case sdbc::DataType::SMALLINT
:
195 case sdbc::DataType::INTEGER
:
196 case sdbc::DataType::BIGINT
:
197 case sdbc::DataType::FLOAT
:
198 case sdbc::DataType::REAL
:
199 case sdbc::DataType::DOUBLE
:
200 case sdbc::DataType::NUMERIC
:
201 case sdbc::DataType::DECIMAL
:
203 //TODO: do the conversion here?
204 fValue
= mxRow
->getDouble(nCol
+1);
205 rData
.SetValue(fValue
);
208 case sdbc::DataType::DATE
:
210 rNumType
= SvNumFormatType::DATE
;
212 util::Date aDate
= mxRow
->getDate(nCol
+1);
213 fValue
= Date(aDate
.Day
, aDate
.Month
, aDate
.Year
) - maNullDate
;
214 rData
.SetValue(fValue
);
217 case sdbc::DataType::TIME
:
219 rNumType
= SvNumFormatType::TIME
;
221 util::Time aTime
= mxRow
->getTime(nCol
+1);
222 fValue
= aTime
.Hours
/ static_cast<double>(::tools::Time::hourPerDay
) +
223 aTime
.Minutes
/ static_cast<double>(::tools::Time::minutePerDay
) +
224 aTime
.Seconds
/ static_cast<double>(::tools::Time::secondPerDay
) +
225 aTime
.NanoSeconds
/ static_cast<double>(::tools::Time::nanoSecPerDay
);
226 rData
.SetValue(fValue
);
229 case sdbc::DataType::TIMESTAMP
:
231 rNumType
= SvNumFormatType::DATETIME
;
233 util::DateTime aStamp
= mxRow
->getTimestamp(nCol
+1);
234 fValue
= ( Date( aStamp
.Day
, aStamp
.Month
, aStamp
.Year
) - maNullDate
) +
235 aStamp
.Hours
/ static_cast<double>(::tools::Time::hourPerDay
) +
236 aStamp
.Minutes
/ static_cast<double>(::tools::Time::minutePerDay
) +
237 aStamp
.Seconds
/ static_cast<double>(::tools::Time::secondPerDay
) +
238 aStamp
.NanoSeconds
/ static_cast<double>(::tools::Time::nanoSecPerDay
);
239 rData
.SetValue(fValue
);
242 case sdbc::DataType::CHAR
:
243 case sdbc::DataType::VARCHAR
:
244 case sdbc::DataType::LONGVARCHAR
:
245 case sdbc::DataType::SQLNULL
:
246 case sdbc::DataType::BINARY
:
247 case sdbc::DataType::VARBINARY
:
248 case sdbc::DataType::LONGVARBINARY
:
250 // nCol is 0-based, and the left-most column always has nCol == 0.
251 rData
.SetStringInterned(
252 mrCache
.InternString(nCol
, mxRow
->getString(nCol
+1)));
255 catch (uno::Exception
&)
263 static sheet::DataPilotFieldOrientation
lcl_GetDataGetOrientation( const uno::Reference
<sheet::XDimensionsSupplier
>& xSource
)
265 sheet::DataPilotFieldOrientation nRet
= sheet::DataPilotFieldOrientation_HIDDEN
;
268 uno::Reference
<container::XNameAccess
> xDimNameAccess
= xSource
->getDimensions();
269 const uno::Sequence
<OUString
> aDimNames
= xDimNameAccess
->getElementNames();
270 for (const OUString
& rDimName
: aDimNames
)
272 uno::Reference
<beans::XPropertySet
> xDimProp(xDimNameAccess
->getByName(rDimName
),
276 const bool bFound
= ScUnoHelpFunctions::GetBoolProperty( xDimProp
,
277 SC_UNO_DP_ISDATALAYOUT
);
278 //TODO: error checking -- is "IsDataLayoutDimension" property required??
281 nRet
= ScUnoHelpFunctions::GetEnumProperty(
282 xDimProp
, SC_UNO_DP_ORIENTATION
,
283 sheet::DataPilotFieldOrientation_HIDDEN
);
292 ScDPServiceDesc::ScDPServiceDesc(
293 OUString aServ
, OUString aSrc
, OUString aNam
,
294 OUString aUser
, OUString aPass
) :
295 aServiceName(std::move( aServ
)),
296 aParSource(std::move( aSrc
)),
297 aParName(std::move( aNam
)),
298 aParUser(std::move( aUser
)),
299 aParPass(std::move( aPass
)) {}
301 bool ScDPServiceDesc::operator== ( const ScDPServiceDesc
& rOther
) const
303 return aServiceName
== rOther
.aServiceName
&&
304 aParSource
== rOther
.aParSource
&&
305 aParName
== rOther
.aParName
&&
306 aParUser
== rOther
.aParUser
&&
307 aParPass
== rOther
.aParPass
;
310 ScDPObject::ScDPObject(ScDocument
* pDocument
)
311 : mpDocument(pDocument
)
313 , mbHeaderLayout(false)
315 , mbSettingsChanged(false)
316 , mbEnableGetPivotData(true)
317 , mbHideHeader(false)
321 ScDPObject::ScDPObject(const ScDPObject
& rOther
)
322 : mpDocument(rOther
.mpDocument
)
323 , maTableName(rOther
.maTableName
)
324 , maTableTag(rOther
.maTableTag
)
325 , maOutputRange(rOther
.maOutputRange
)
326 , maInteropGrabBag(rOther
.maInteropGrabBag
)
327 , mnHeaderRows(rOther
.mnHeaderRows
)
328 , mbHeaderLayout(rOther
.mbHeaderLayout
)
330 , mbSettingsChanged(false)
331 , mbEnableGetPivotData(rOther
.mbEnableGetPivotData
)
332 , mbHideHeader(rOther
.mbHideHeader
)
334 if (rOther
.mpSaveData
)
335 mpSaveData
.reset(new ScDPSaveData(*rOther
.mpSaveData
));
336 if (rOther
.mpSheetDescription
)
337 mpSheetDescription
.reset(new ScSheetSourceDesc(*rOther
.mpSheetDescription
));
338 if (rOther
.mpImportDescription
)
339 mpImportDescription
.reset(new ScImportSourceDesc(*rOther
.mpImportDescription
));
340 if (rOther
.mpServiceDescription
)
341 mpServiceDescription
.reset(new ScDPServiceDesc(*rOther
.mpServiceDescription
));
342 // mxSource (and mpOutput) is not copied
345 ScDPObject::~ScDPObject()
350 ScDPObject
& ScDPObject::operator= (const ScDPObject
& rOther
)
356 mpDocument
= rOther
.mpDocument
;
357 maTableName
= rOther
.maTableName
;
358 maTableTag
= rOther
.maTableTag
;
359 maOutputRange
= rOther
.maOutputRange
;
360 maInteropGrabBag
= rOther
.maInteropGrabBag
;
361 mnHeaderRows
= rOther
.mnHeaderRows
;
362 mbHeaderLayout
=rOther
.mbHeaderLayout
;
364 mbSettingsChanged
= false;
365 mbEnableGetPivotData
= rOther
.mbEnableGetPivotData
;
366 mbHideHeader
= rOther
.mbHideHeader
;
368 if (rOther
.mpSaveData
)
369 mpSaveData
.reset(new ScDPSaveData(*rOther
.mpSaveData
));
370 if (rOther
.mpSheetDescription
)
371 mpSheetDescription
.reset(new ScSheetSourceDesc(*rOther
.mpSheetDescription
));
372 if (rOther
.mpImportDescription
)
373 mpImportDescription
.reset(new ScImportSourceDesc(*rOther
.mpImportDescription
));
374 if (rOther
.mpServiceDescription
)
375 mpServiceDescription
.reset(new ScDPServiceDesc(*rOther
.mpServiceDescription
));
380 void ScDPObject::EnableGetPivotData(bool b
)
382 mbEnableGetPivotData
= b
;
385 void ScDPObject::SetAllowMove(bool bSet
)
390 void ScDPObject::SetSaveData(const ScDPSaveData
& rData
)
392 if (mpSaveData
.get() != &rData
) // API implementation modifies the original SaveData object
394 mpSaveData
.reset(new ScDPSaveData(rData
));
397 InvalidateData(); // re-init source from SaveData
400 void ScDPObject::SetHeaderLayout (bool bUseGrid
)
402 mbHeaderLayout
= bUseGrid
;
405 void ScDPObject::SetHideHeader(bool bHideHeader
) { mbHideHeader
= bHideHeader
; }
407 void ScDPObject::SetOutRange(const ScRange
& rRange
)
409 maOutputRange
= rRange
;
412 mpOutput
->SetPosition( rRange
.aStart
);
415 const ScRange
& ScDPObject::GetOutRange() const
417 return maOutputRange
;
420 void ScDPObject::SetSheetDesc(const ScSheetSourceDesc
& rDesc
)
422 if (mpSheetDescription
&& rDesc
== *mpSheetDescription
)
423 return; // nothing to do
425 mpImportDescription
.reset();
426 mpServiceDescription
.reset();
428 mpSheetDescription
.reset( new ScSheetSourceDesc(rDesc
) );
430 // make valid QueryParam
432 const ScRange
& rSrcRange
= mpSheetDescription
->GetSourceRange();
433 ScQueryParam aParam
= mpSheetDescription
->GetQueryParam();
434 aParam
.nCol1
= rSrcRange
.aStart
.Col();
435 aParam
.nRow1
= rSrcRange
.aStart
.Row();
436 aParam
.nCol2
= rSrcRange
.aEnd
.Col();
437 aParam
.nRow2
= rSrcRange
.aEnd
.Row();
438 aParam
.bHasHeader
= true;
439 mpSheetDescription
->SetQueryParam(aParam
);
441 ClearTableData(); // new source must be created
444 void ScDPObject::SetImportDesc(const ScImportSourceDesc
& rDesc
)
446 if (mpImportDescription
&& rDesc
== *mpImportDescription
)
447 return; // nothing to do
449 mpSheetDescription
.reset();
450 mpServiceDescription
.reset();
452 mpImportDescription
.reset(new ScImportSourceDesc(rDesc
));
454 ClearTableData(); // new source must be created
457 void ScDPObject::SetServiceData(const ScDPServiceDesc
& rDesc
)
459 if (mpServiceDescription
&& rDesc
== *mpServiceDescription
)
460 return; // nothing to do
462 mpSheetDescription
.reset();
463 mpImportDescription
.reset();
465 mpServiceDescription
.reset(new ScDPServiceDesc(rDesc
));
467 ClearTableData(); // new source must be created
470 void ScDPObject::WriteSourceDataTo( ScDPObject
& rDest
) const
472 if (mpSheetDescription
)
473 rDest
.SetSheetDesc(*mpSheetDescription
);
474 else if (mpImportDescription
)
475 rDest
.SetImportDesc(*mpImportDescription
);
476 else if (mpServiceDescription
)
477 rDest
.SetServiceData(*mpServiceDescription
);
479 // name/tag are not source data, but needed along with source data
481 rDest
.maTableName
= maTableName
;
482 rDest
.maTableTag
= maTableTag
;
485 void ScDPObject::WriteTempDataTo( ScDPObject
& rDest
) const
487 rDest
.mnHeaderRows
= mnHeaderRows
;
490 bool ScDPObject::IsSheetData() const
492 return mpSheetDescription
!= nullptr;
495 void ScDPObject::SetName(const OUString
& rNew
)
500 void ScDPObject::SetTag(const OUString
& rNew
)
505 bool ScDPObject::IsDataDescriptionCell(const ScAddress
& rPos
)
510 tools::Long nDataDimCount
= mpSaveData
->GetDataDimensionCount();
511 if (nDataDimCount
!= 1)
512 // There has to be exactly one data dimension for the description to
513 // appear at top-left corner.
517 ScRange aTabRange
= mpOutput
->GetOutputRange(sheet::DataPilotOutputRangeType::TABLE
);
518 return (rPos
== aTabRange
.aStart
);
521 uno::Reference
<sheet::XDimensionsSupplier
> const & ScDPObject::GetSource()
527 void ScDPObject::CreateOutput()
533 bool bFilterButton
= IsSheetData() && mpSaveData
&& mpSaveData
->GetFilterButton();
534 bool bExpandCollapse
= mpSaveData
? mpSaveData
->GetExpandCollapse() : false;
536 mpOutput
.reset(new ScDPOutput(mpDocument
, mxSource
, maOutputRange
.aStart
, bFilterButton
, bExpandCollapse
, *this, mbHideHeader
));
537 mpOutput
->SetHeaderLayout(mbHeaderLayout
);
538 if (mpSaveData
->hasFormats())
539 mpOutput
->setFormats(mpSaveData
->getFormats());
541 sal_Int32 nOldRows
= mnHeaderRows
;
542 mnHeaderRows
= mpOutput
->GetHeaderRows();
544 if (!(mbAllowMove
&& mnHeaderRows
!= nOldRows
))
547 sal_Int32 nDiff
= nOldRows
- mnHeaderRows
;
550 if (mnHeaderRows
== 0)
553 sal_Int32 nNewRow
= maOutputRange
.aStart
.Row() + nDiff
;
557 ScAddress
aStart(maOutputRange
.aStart
);
558 aStart
.SetRow(nNewRow
);
559 mpOutput
->SetPosition( aStart
);
561 //TODO: modify maOutputRange?
563 mbAllowMove
= false; // use only once
568 class DisableGetPivotData
573 DisableGetPivotData(ScDPObject
& rObj
, bool bOld
) : mrDPObj(rObj
), mbOldState(bOld
)
575 mrDPObj
.EnableGetPivotData(false);
578 ~DisableGetPivotData()
580 mrDPObj
.EnableGetPivotData(mbOldState
);
584 class FindIntersectingTable
588 explicit FindIntersectingTable(const ScRange
& rRange
) : maRange(rRange
) {}
590 bool operator() (const std::unique_ptr
<ScDPObject
>& rObj
) const
592 return maRange
.Intersects(rObj
->GetOutRange());
596 class FindIntersectingTableByColumns
603 FindIntersectingTableByColumns(SCCOL nCol1
, SCCOL nCol2
, SCROW nRow
, SCTAB nTab
) :
604 mnCol1(nCol1
), mnCol2(nCol2
), mnRow(nRow
), mnTab(nTab
) {}
606 bool operator() (const std::unique_ptr
<ScDPObject
>& rObj
) const
608 const ScRange
& rRange
= rObj
->GetOutRange();
609 if (mnTab
!= rRange
.aStart
.Tab())
610 // Not on this sheet.
613 if (rRange
.aEnd
.Row() < mnRow
)
614 // This table is above the row. It's safe.
617 if (mnCol1
<= rRange
.aStart
.Col() && rRange
.aEnd
.Col() <= mnCol2
)
618 // This table is fully enclosed in this column range.
621 if (rRange
.aEnd
.Col() < mnCol1
|| mnCol2
< rRange
.aStart
.Col())
622 // This table is entirely outside this column range.
625 // This table must be intersected by this column range.
630 class FindIntersectingTableByRows
637 FindIntersectingTableByRows(SCCOL nCol
, SCROW nRow1
, SCROW nRow2
, SCTAB nTab
) :
638 mnCol(nCol
), mnRow1(nRow1
), mnRow2(nRow2
), mnTab(nTab
) {}
640 bool operator() (const std::unique_ptr
<ScDPObject
>& rObj
) const
642 const ScRange
& rRange
= rObj
->GetOutRange();
643 if (mnTab
!= rRange
.aStart
.Tab())
644 // Not on this sheet.
647 if (rRange
.aEnd
.Col() < mnCol
)
648 // This table is to the left of the column. It's safe.
651 if (mnRow1
<= rRange
.aStart
.Row() && rRange
.aEnd
.Row() <= mnRow2
)
652 // This table is fully enclosed in this row range.
655 if (rRange
.aEnd
.Row() < mnRow1
|| mnRow2
< rRange
.aStart
.Row())
656 // This table is entirely outside this row range.
659 // This table must be intersected by this row range.
664 class AccumulateOutputRanges
666 ScRangeList maRanges
;
669 explicit AccumulateOutputRanges(SCTAB nTab
) : mnTab(nTab
) {}
670 AccumulateOutputRanges(const AccumulateOutputRanges
& r
) : maRanges(r
.maRanges
), mnTab(r
.mnTab
) {}
672 void operator() (const std::unique_ptr
<ScDPObject
>& rObj
)
674 const ScRange
& rRange
= rObj
->GetOutRange();
675 if (mnTab
!= rRange
.aStart
.Tab())
676 // Not on this sheet.
679 maRanges
.Join(rRange
);
682 const ScRangeList
& getRanges() const { return maRanges
; }
687 ScDPTableData
* ScDPObject::GetTableData()
691 shared_ptr
<ScDPTableData
> pData
;
692 const ScDPDimensionSaveData
* pDimData
= mpSaveData
? mpSaveData
->GetExistingDimensionData() : nullptr;
694 if (mpImportDescription
)
697 const ScDPCache
* pCache
= mpImportDescription
->CreateCache(pDimData
);
700 pCache
->AddReference(this);
701 pData
= std::make_shared
<ScDatabaseDPData
>(mpDocument
, *pCache
);
707 if (!mpSheetDescription
)
709 OSL_FAIL("no source descriptor");
710 mpSheetDescription
.reset(new ScSheetSourceDesc(mpDocument
)); // dummy defaults
714 // Temporarily disable GETPIVOTDATA to avoid having
715 // GETPIVOTDATA called onto itself from within the source
717 DisableGetPivotData
aSwitch(*this, mbEnableGetPivotData
);
718 const ScDPCache
* pCache
= mpSheetDescription
->CreateCache(pDimData
);
721 pCache
->AddReference(this);
722 pData
= std::make_shared
<ScSheetDPData
>(mpDocument
, *mpSheetDescription
, *pCache
);
727 // grouping (for cell or database data)
728 if (pData
&& pDimData
)
730 auto pGroupData
= std::make_shared
<ScDPGroupTableData
>(pData
, mpDocument
);
731 pDimData
->WriteToData(*pGroupData
);
735 mpTableData
= std::move(pData
); // after SetCacheId
738 return mpTableData
.get();
741 void ScDPObject::CreateObjects()
745 mpOutput
.reset(); // not valid when mxSource is changed
747 if (mpServiceDescription
)
749 mxSource
= CreateSource(*mpServiceDescription
);
752 if (!mxSource
.is()) // database or sheet data, or error in CreateSource
754 OSL_ENSURE(!mpServiceDescription
, "DPSource could not be created");
755 ScDPTableData
* pData
= GetTableData();
759 // Make sure to transfer these flags to the table data
760 // since they may have changed.
761 pData
->SetEmptyFlags(mpSaveData
->GetIgnoreEmptyRows(), mpSaveData
->GetRepeatIfEmpty());
763 pData
->ReloadCacheTable();
764 mxSource
= new ScDPSource( pData
);
769 mpSaveData
->WriteToSource(mxSource
);
771 else if (mbSettingsChanged
)
773 mpOutput
.reset(); // not valid when mxSource is changed
775 uno::Reference
<util::XRefreshable
> xRef(mxSource
, uno::UNO_QUERY
);
782 catch(uno::Exception
&)
784 TOOLS_WARN_EXCEPTION( "sc", "exception in refresh");
789 mpSaveData
->WriteToSource(mxSource
);
791 mbSettingsChanged
= false;
794 void ScDPObject::InvalidateData()
796 mbSettingsChanged
= true;
799 void ScDPObject::Clear()
803 mpSheetDescription
.reset();
804 mpImportDescription
.reset();
805 mpServiceDescription
.reset();
807 maInteropGrabBag
.clear();
810 void ScDPObject::ClearTableData()
815 mpTableData
->GetCacheTable().getCache().RemoveReference(this);
819 void ScDPObject::ReloadGroupTableData()
824 // Table data not built yet. No need to reload the group data.
828 // How could it not have the save data... but whatever.
831 const ScDPDimensionSaveData
* pDimData
= mpSaveData
->GetExistingDimensionData();
832 if (!pDimData
|| !pDimData
->HasGroupDimensions())
834 // No group dimensions exist. Check if it currently has group
835 // dimensions, and if so, remove all of them.
836 ScDPGroupTableData
* pData
= dynamic_cast<ScDPGroupTableData
*>(mpTableData
.get());
839 // Replace the existing group table data with the source data.
840 mpTableData
= pData
->GetSourceTableData();
845 ScDPGroupTableData
* pData
= dynamic_cast<ScDPGroupTableData
*>(mpTableData
.get());
848 // This is already a group table data. Salvage the source data and
849 // re-create a new group data.
850 const shared_ptr
<ScDPTableData
>& pSource
= pData
->GetSourceTableData();
851 auto pGroupData
= std::make_shared
<ScDPGroupTableData
>(pSource
, mpDocument
);
852 pDimData
->WriteToData(*pGroupData
);
853 mpTableData
= pGroupData
;
857 // This is a source data. Create a group data based on it.
858 auto pGroupData
= std::make_shared
<ScDPGroupTableData
>(mpTableData
, mpDocument
);
859 pDimData
->WriteToData(*pGroupData
);
860 mpTableData
= pGroupData
;
863 mbSettingsChanged
= true;
866 void ScDPObject::ClearSource()
868 uno::Reference
<XComponent
> xObjectComp(mxSource
, UNO_QUERY
);
869 if (xObjectComp
.is())
873 xObjectComp
->dispose();
875 catch( const Exception
& )
877 DBG_UNHANDLED_EXCEPTION("sc.core");
883 ScRange
ScDPObject::GetNewOutputRange( bool& rOverflow
)
885 CreateOutput(); // create mxSource and mpOutput if not already done
887 rOverflow
= mpOutput
->HasError(); // range overflow or exception from source
889 return ScRange(maOutputRange
.aStart
);
892 // don't store the result in maOutputRange, because nothing has been output yet
893 return mpOutput
->GetOutputRange();
897 void ScDPObject::Output( const ScAddress
& rPos
)
899 // clear old output area
900 mpDocument
->DeleteAreaTab(maOutputRange
.aStart
.Col(), maOutputRange
.aStart
.Row(),
901 maOutputRange
.aEnd
.Col(), maOutputRange
.aEnd
.Row(),
902 maOutputRange
.aStart
.Tab(), InsertDeleteFlags::ALL
);
903 mpDocument
->RemoveFlagsTab( maOutputRange
.aStart
.Col(), maOutputRange
.aStart
.Row(),
904 maOutputRange
.aEnd
.Col(), maOutputRange
.aEnd
.Row(),
905 maOutputRange
.aStart
.Tab(), ScMF::Auto
);
907 CreateOutput(); // create mxSource and mpOutput if not already done
909 mpOutput
->SetPosition( rPos
);
913 // maOutputRange is always the range that was last output to the document
914 maOutputRange
= mpOutput
->GetOutputRange();
915 const ScAddress
& s
= maOutputRange
.aStart
;
916 const ScAddress
& e
= maOutputRange
.aEnd
;
917 mpDocument
->ApplyFlagsTab(s
.Col(), s
.Row(), e
.Col(), e
.Row(), s
.Tab(), ScMF::DpTable
);
920 ScRange
ScDPObject::GetOutputRangeByType( sal_Int32 nType
)
924 if (mpOutput
->HasError())
925 return ScRange(maOutputRange
.aStart
);
927 return mpOutput
->GetOutputRange(nType
);
930 ScRange
ScDPObject::GetOutputRangeByType( sal_Int32 nType
) const
932 if (!mpOutput
|| mpOutput
->HasError())
933 return ScRange(ScAddress::INITIALIZE_INVALID
);
935 return mpOutput
->GetOutputRange(nType
);
938 static bool lcl_HasButton( const ScDocument
* pDoc
, SCCOL nCol
, SCROW nRow
, SCTAB nTab
)
940 return pDoc
->GetAttr( nCol
, nRow
, nTab
, ATTR_MERGE_FLAG
)->HasPivotButton();
943 void ScDPObject::RefreshAfterLoad()
945 // apply drop-down attribute, initialize mnHeaderRows, without accessing the source
946 // (button attribute must be present)
948 // simple test: block of button cells at the top, followed by an empty cell
950 SCCOL nFirstCol
= maOutputRange
.aStart
.Col();
951 SCROW nFirstRow
= maOutputRange
.aStart
.Row();
952 SCTAB nTab
= maOutputRange
.aStart
.Tab();
955 SCROW nOutRows
= maOutputRange
.aEnd
.Row() + 1 - maOutputRange
.aStart
.Row();
956 while (nInitial
+ 1 < nOutRows
&& lcl_HasButton(mpDocument
, nFirstCol
, nFirstRow
+ nInitial
, nTab
))
959 if ( nInitial
+ 1 < nOutRows
&&
960 mpDocument
->IsBlockEmpty( nFirstCol
, nFirstRow
+ nInitial
, nFirstCol
, nFirstRow
+ nInitial
, nTab
) &&
961 maOutputRange
.aEnd
.Col() > nFirstCol
)
963 mnHeaderRows
= nInitial
;
966 mnHeaderRows
= 0; // nothing found, no drop-down lists
969 void ScDPObject::BuildAllDimensionMembers()
974 // #i111857# don't always create empty mpTableData for external service.
975 if (mpServiceDescription
)
978 ScDPTableData
* pTableData
= GetTableData();
980 mpSaveData
->BuildAllDimensionMembers(pTableData
);
983 bool ScDPObject::SyncAllDimensionMembers()
988 // #i111857# don't always create empty mpTableData for external service.
989 // Ideally, mxSource should be used instead of mpTableData.
990 if (mpServiceDescription
)
993 ScDPTableData
* pData
= GetTableData();
995 // No table data exists. This can happen when refreshing from an
996 // external source which doesn't exist.
999 // Refresh the cache wrapper since the cache may have changed.
1000 pData
->SetEmptyFlags(mpSaveData
->GetIgnoreEmptyRows(), mpSaveData
->GetRepeatIfEmpty());
1001 pData
->ReloadCacheTable();
1002 mpSaveData
->SyncAllDimensionMembers(pData
);
1006 bool ScDPObject::GetMemberNames( sal_Int32 nDim
, Sequence
<OUString
>& rNames
)
1008 vector
<ScDPLabelData::Member
> aMembers
;
1009 if (!GetMembers(nDim
, GetUsedHierarchy(nDim
), aMembers
))
1012 size_t n
= aMembers
.size();
1014 auto pNames
= rNames
.getArray();
1015 for (size_t i
= 0; i
< n
; ++i
)
1016 pNames
[i
] = aMembers
[i
].maName
;
1021 bool ScDPObject::GetMembers( sal_Int32 nDim
, sal_Int32 nHier
, vector
<ScDPLabelData::Member
>& rMembers
)
1023 Reference
< sheet::XMembersAccess
> xMembersNA
;
1024 if (!GetMembersNA( nDim
, nHier
, xMembersNA
))
1027 Reference
<container::XIndexAccess
> xMembersIA( new ScNameToIndexAccess(xMembersNA
) );
1028 sal_Int32 nCount
= xMembersIA
->getCount();
1029 vector
<ScDPLabelData::Member
> aMembers
;
1030 aMembers
.reserve(nCount
);
1032 for (sal_Int32 i
= 0; i
< nCount
; ++i
)
1034 Reference
<container::XNamed
> xMember
;
1037 xMember
= Reference
<container::XNamed
>(xMembersIA
->getByIndex(i
), UNO_QUERY
);
1039 catch (const container::NoSuchElementException
&)
1041 TOOLS_WARN_EXCEPTION("sc", "ScNameToIndexAccess getByIndex failed");
1044 ScDPLabelData::Member aMem
;
1047 aMem
.maName
= xMember
->getName();
1049 Reference
<beans::XPropertySet
> xMemProp(xMember
, UNO_QUERY
);
1052 aMem
.mbVisible
= ScUnoHelpFunctions::GetBoolProperty(xMemProp
, SC_UNO_DP_ISVISIBLE
);
1053 aMem
.mbShowDetails
= ScUnoHelpFunctions::GetBoolProperty(xMemProp
, SC_UNO_DP_SHOWDETAILS
);
1055 aMem
.maLayoutName
= ScUnoHelpFunctions::GetStringProperty(
1056 xMemProp
, SC_UNO_DP_LAYOUTNAME
, OUString());
1059 aMembers
.push_back(aMem
);
1061 rMembers
.swap(aMembers
);
1065 void ScDPObject::UpdateReference( UpdateRefMode eUpdateRefMode
,
1066 const ScRange
& rRange
, SCCOL nDx
, SCROW nDy
, SCTAB nDz
)
1070 SCCOL nCol1
= maOutputRange
.aStart
.Col();
1071 SCROW nRow1
= maOutputRange
.aStart
.Row();
1072 SCTAB nTab1
= maOutputRange
.aStart
.Tab();
1073 SCCOL nCol2
= maOutputRange
.aEnd
.Col();
1074 SCROW nRow2
= maOutputRange
.aEnd
.Row();
1075 SCTAB nTab2
= maOutputRange
.aEnd
.Tab();
1077 ScRefUpdateRes eRes
=
1078 ScRefUpdate::Update(mpDocument
, eUpdateRefMode
,
1079 rRange
.aStart
.Col(), rRange
.aStart
.Row(), rRange
.aStart
.Tab(),
1080 rRange
.aEnd
.Col(), rRange
.aEnd
.Row(), rRange
.aEnd
.Tab(), nDx
, nDy
, nDz
,
1081 nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
1082 if ( eRes
!= UR_NOTHING
)
1083 SetOutRange( ScRange( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
) );
1085 // sheet source data
1087 if (!mpSheetDescription
)
1090 const OUString
& rRangeName
= mpSheetDescription
->GetRangeName();
1091 if (!rRangeName
.isEmpty())
1092 // Source range is a named range. No need to update.
1095 const ScRange
& rSrcRange
= mpSheetDescription
->GetSourceRange();
1096 nCol1
= rSrcRange
.aStart
.Col();
1097 nRow1
= rSrcRange
.aStart
.Row();
1098 nTab1
= rSrcRange
.aStart
.Tab();
1099 nCol2
= rSrcRange
.aEnd
.Col();
1100 nRow2
= rSrcRange
.aEnd
.Row();
1101 nTab2
= rSrcRange
.aEnd
.Tab();
1103 eRes
= ScRefUpdate::Update(mpDocument
, eUpdateRefMode
,
1104 rRange
.aStart
.Col(), rRange
.aStart
.Row(), rRange
.aStart
.Tab(),
1105 rRange
.aEnd
.Col(), rRange
.aEnd
.Row(), rRange
.aEnd
.Tab(), nDx
, nDy
, nDz
,
1106 nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
1107 if ( eRes
== UR_NOTHING
)
1110 SCCOL nDiffX
= nCol1
- mpSheetDescription
->GetSourceRange().aStart
.Col();
1111 SCROW nDiffY
= nRow1
- mpSheetDescription
->GetSourceRange().aStart
.Row();
1113 ScQueryParam aParam
= mpSheetDescription
->GetQueryParam();
1114 aParam
.nCol1
= sal::static_int_cast
<SCCOL
>( aParam
.nCol1
+ nDiffX
);
1115 aParam
.nCol2
= sal::static_int_cast
<SCCOL
>( aParam
.nCol2
+ nDiffX
);
1116 aParam
.nRow1
+= nDiffY
; //TODO: used?
1117 aParam
.nRow2
+= nDiffY
; //TODO: used?
1118 SCSIZE nEC
= aParam
.GetEntryCount();
1119 for (SCSIZE i
=0; i
<nEC
; i
++)
1120 if (aParam
.GetEntry(i
).bDoQuery
)
1121 aParam
.GetEntry(i
).nField
+= nDiffX
;
1123 mpSheetDescription
->SetQueryParam(aParam
);
1124 mpSheetDescription
->SetSourceRange(ScRange(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
));
1127 bool ScDPObject::RefsEqual( const ScDPObject
& rOther
) const
1129 if (maOutputRange
!= rOther
.maOutputRange
)
1132 if (mpSheetDescription
&& rOther
.mpSheetDescription
)
1134 if (mpSheetDescription
->GetSourceRange() != rOther
.mpSheetDescription
->GetSourceRange())
1137 else if (mpSheetDescription
|| rOther
.mpSheetDescription
)
1139 OSL_FAIL("RefsEqual: SheetDesc set at only one object");
1146 void ScDPObject::WriteRefsTo(ScDPObject
& rObject
) const
1148 rObject
.SetOutRange(maOutputRange
);
1149 if (mpSheetDescription
)
1150 rObject
.SetSheetDesc(*mpSheetDescription
);
1153 void ScDPObject::GetPositionData(const ScAddress
& rPos
, DataPilotTablePositionData
& rPosData
)
1156 mpOutput
->GetPositionData(rPos
, rPosData
);
1159 bool ScDPObject::GetDataFieldPositionData(
1160 const ScAddress
& rPos
, Sequence
<sheet::DataPilotFieldFilter
>& rFilters
)
1164 vector
<sheet::DataPilotFieldFilter
> aFilters
;
1165 if (!mpOutput
->GetDataResultPositionData(aFilters
, rPos
))
1168 sal_Int32 n
= static_cast<sal_Int32
>(aFilters
.size());
1169 rFilters
.realloc(n
);
1170 auto pFilters
= rFilters
.getArray();
1171 for (sal_Int32 i
= 0; i
< n
; ++i
)
1172 pFilters
[i
] = aFilters
[i
];
1177 void ScDPObject::GetDrillDownData(const ScAddress
& rPos
, Sequence
< Sequence
<Any
> >& rTableData
)
1181 uno::Reference
<sheet::XDrillDownDataSupplier
> xDrillDownData(mxSource
, UNO_QUERY
);
1182 if (!xDrillDownData
.is())
1185 Sequence
<sheet::DataPilotFieldFilter
> filters
;
1186 if (!GetDataFieldPositionData(rPos
, filters
))
1189 rTableData
= xDrillDownData
->getDrillDownData(filters
);
1192 bool ScDPObject::IsDimNameInUse(std::u16string_view rName
) const
1197 Reference
<container::XNameAccess
> xDims
= mxSource
->getDimensions();
1198 const Sequence
<OUString
> aDimNames
= xDims
->getElementNames();
1199 for (const OUString
& rDimName
: aDimNames
)
1201 if (rDimName
.equalsIgnoreAsciiCase(rName
))
1204 Reference
<beans::XPropertySet
> xPropSet(xDims
->getByName(rDimName
), UNO_QUERY
);
1208 OUString aLayoutName
= ScUnoHelpFunctions::GetStringProperty(
1209 xPropSet
, SC_UNO_DP_LAYOUTNAME
, OUString());
1210 if (aLayoutName
.equalsIgnoreAsciiCase(rName
))
1216 OUString
ScDPObject::GetDimName( tools::Long nDim
, bool& rIsDataLayout
, sal_Int32
* pFlags
)
1218 rIsDataLayout
= false;
1223 uno::Reference
<container::XNameAccess
> xDimsName
= mxSource
->getDimensions();
1224 uno::Reference
<container::XIndexAccess
> xDims
= new ScNameToIndexAccess( xDimsName
);
1225 tools::Long nDimCount
= xDims
->getCount();
1226 if ( nDim
< nDimCount
)
1228 uno::Reference
<uno::XInterface
> xIntDim(xDims
->getByIndex(nDim
), uno::UNO_QUERY
);
1229 uno::Reference
<container::XNamed
> xDimName( xIntDim
, uno::UNO_QUERY
);
1230 uno::Reference
<beans::XPropertySet
> xDimProp( xIntDim
, uno::UNO_QUERY
);
1231 if ( xDimName
.is() && xDimProp
.is() )
1233 bool bData
= ScUnoHelpFunctions::GetBoolProperty( xDimProp
,
1234 SC_UNO_DP_ISDATALAYOUT
);
1235 //TODO: error checking -- is "IsDataLayoutDimension" property required??
1240 aName
= xDimName
->getName();
1242 catch(uno::Exception
&)
1246 rIsDataLayout
= true;
1251 *pFlags
= ScUnoHelpFunctions::GetLongProperty( xDimProp
,
1256 else if (ScDPTableData
* pData
= GetTableData())
1258 aRet
= pData
->getDimensionName(nDim
);
1259 rIsDataLayout
= pData
->getIsDataLayoutDimension(nDim
);
1265 bool ScDPObject::IsDuplicated( tools::Long nDim
)
1267 bool bDuplicated
= false;
1270 uno::Reference
<container::XNameAccess
> xDimsName
= mxSource
->getDimensions();
1271 uno::Reference
<container::XIndexAccess
> xDims
= new ScNameToIndexAccess( xDimsName
);
1272 tools::Long nDimCount
= xDims
->getCount();
1273 if ( nDim
< nDimCount
)
1275 uno::Reference
<beans::XPropertySet
> xDimProp(xDims
->getByIndex(nDim
), uno::UNO_QUERY
);
1276 if ( xDimProp
.is() )
1280 uno::Any aOrigAny
= xDimProp
->getPropertyValue( SC_UNO_DP_ORIGINAL
);
1281 uno::Reference
<uno::XInterface
> xIntOrig
;
1282 if ( (aOrigAny
>>= xIntOrig
) && xIntOrig
.is() )
1285 catch(uno::Exception
&)
1294 tools::Long
ScDPObject::GetDimCount()
1296 tools::Long nRet
= 0;
1301 uno::Reference
<container::XNameAccess
> xDimsName
= mxSource
->getDimensions();
1302 if ( xDimsName
.is() )
1303 nRet
= xDimsName
->getElementNames().getLength();
1305 catch(uno::Exception
&)
1312 void ScDPObject::GetHeaderPositionData(const ScAddress
& rPos
, DataPilotTableHeaderData
& rData
)
1314 CreateOutput(); // create mxSource and mpOutput if not already done
1316 // Reset member values to invalid state.
1317 rData
.Dimension
= rData
.Hierarchy
= rData
.Level
= -1;
1320 DataPilotTablePositionData aPosData
;
1321 mpOutput
->GetPositionData(rPos
, aPosData
);
1322 const sal_Int32 nPosType
= aPosData
.PositionType
;
1323 if (nPosType
== css::sheet::DataPilotTablePositionType::COLUMN_HEADER
|| nPosType
== css::sheet::DataPilotTablePositionType::ROW_HEADER
)
1324 aPosData
.PositionData
>>= rData
;
1331 OUString maName
; // must be all uppercase.
1333 explicit FindByName(OUString aName
) : maName(std::move(aName
)) {}
1334 bool operator() (const ScDPSaveDimension
* pDim
) const
1336 // Layout name takes precedence.
1337 const std::optional
<OUString
> & pLayoutName
= pDim
->GetLayoutName();
1338 if (pLayoutName
&& ScGlobal::getCharClass().uppercase(*pLayoutName
) == maName
)
1341 ScGeneralFunction eGenFunc
= pDim
->GetFunction();
1342 ScSubTotalFunc eFunc
= ScDPUtil::toSubTotalFunc(eGenFunc
);
1343 OUString aSrcName
= ScDPUtil::getSourceDimensionName(pDim
->GetName());
1344 OUString aFuncName
= ScDPUtil::getDisplayedMeasureName(aSrcName
, eFunc
);
1345 if (maName
== ScGlobal::getCharClass().uppercase(aFuncName
))
1348 return maName
== ScGlobal::getCharClass().uppercase(aSrcName
);
1352 class LessByDimOrder
1354 const ScDPSaveData::DimOrderType
& mrDimOrder
;
1357 explicit LessByDimOrder(const ScDPSaveData::DimOrderType
& rDimOrder
) : mrDimOrder(rDimOrder
) {}
1359 bool operator() (const sheet::DataPilotFieldFilter
& r1
, const sheet::DataPilotFieldFilter
& r2
) const
1361 size_t nRank1
= mrDimOrder
.size();
1362 size_t nRank2
= mrDimOrder
.size();
1363 ScDPSaveData::DimOrderType::const_iterator it1
= mrDimOrder
.find(
1364 ScGlobal::getCharClass().uppercase(r1
.FieldName
));
1365 if (it1
!= mrDimOrder
.end())
1366 nRank1
= it1
->second
;
1368 ScDPSaveData::DimOrderType::const_iterator it2
= mrDimOrder
.find(
1369 ScGlobal::getCharClass().uppercase(r2
.FieldName
));
1370 if (it2
!= mrDimOrder
.end())
1371 nRank2
= it2
->second
;
1373 return nRank1
< nRank2
;
1379 double ScDPObject::GetPivotData(const OUString
& rDataFieldName
, std::vector
<sheet::DataPilotFieldFilter
>& rFilters
)
1381 if (!mbEnableGetPivotData
)
1382 return std::numeric_limits
<double>::quiet_NaN();
1386 std::vector
<const ScDPSaveDimension
*> aDataDims
;
1387 mpSaveData
->GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_DATA
, aDataDims
);
1388 if (aDataDims
.empty())
1389 return std::numeric_limits
<double>::quiet_NaN();
1391 std::vector
<const ScDPSaveDimension
*>::iterator it
= std::find_if(
1392 aDataDims
.begin(), aDataDims
.end(),
1393 FindByName(ScGlobal::getCharClass().uppercase(rDataFieldName
)));
1395 if (it
== aDataDims
.end())
1396 return std::numeric_limits
<double>::quiet_NaN();
1398 size_t nDataIndex
= std::distance(aDataDims
.begin(), it
);
1400 uno::Reference
<sheet::XDataPilotResults
> xDPResults(mxSource
, uno::UNO_QUERY
);
1401 if (!xDPResults
.is())
1402 return std::numeric_limits
<double>::quiet_NaN();
1404 // Dimensions must be sorted in order of appearance, and row dimensions
1405 // must come before column dimensions.
1406 std::sort(rFilters
.begin(), rFilters
.end(), LessByDimOrder(mpSaveData
->GetDimensionSortOrder()));
1408 size_t n
= rFilters
.size();
1409 uno::Sequence
<sheet::DataPilotFieldFilter
> aFilters(n
);
1410 auto aFiltersRange
= asNonConstRange(aFilters
);
1411 for (size_t i
= 0; i
< n
; ++i
)
1412 aFiltersRange
[i
] = rFilters
[i
];
1414 uno::Sequence
<double> aRes
= xDPResults
->getFilteredResults(aFilters
);
1415 if (nDataIndex
>= o3tl::make_unsigned(aRes
.getLength()))
1416 return std::numeric_limits
<double>::quiet_NaN();
1418 return aRes
[nDataIndex
];
1421 bool ScDPObject::IsFilterButton( const ScAddress
& rPos
)
1423 CreateOutput(); // create mxSource and mpOutput if not already done
1425 return mpOutput
->IsFilterButton( rPos
);
1428 tools::Long
ScDPObject::GetHeaderDim( const ScAddress
& rPos
, sheet::DataPilotFieldOrientation
& rOrient
)
1430 CreateOutput(); // create mxSource and mpOutput if not already done
1432 return mpOutput
->GetHeaderDim( rPos
, rOrient
);
1435 bool ScDPObject::GetHeaderDrag( const ScAddress
& rPos
, bool bMouseLeft
, bool bMouseTop
, tools::Long nDragDim
,
1436 tools::Rectangle
& rPosRect
, sheet::DataPilotFieldOrientation
& rOrient
, tools::Long
& rDimPos
)
1438 CreateOutput();// create mxSource and mpOutput if not already done
1440 return mpOutput
->GetHeaderDrag( rPos
, bMouseLeft
, bMouseTop
, nDragDim
, rPosRect
, rOrient
, rDimPos
);
1443 void ScDPObject::GetMemberResultNames(ScDPUniqueStringSet
& rNames
, tools::Long nDimension
)
1445 CreateOutput();// create mxSource and mpOutput if not already done
1447 mpOutput
->GetMemberResultNames(rNames
, nDimension
); // used only with table data -> level not needed
1450 OUString
ScDPObject::GetFormattedString(ScDPTableData
* pTableData
, tools::Long nDimension
, const double fValue
)
1452 ScDPItemData aItemData
;
1453 aItemData
.SetValue(fValue
);
1454 return pTableData
->GetFormattedString(nDimension
, aItemData
, false);
1457 OUString
ScDPObject::GetFormattedString(std::u16string_view rDimName
, const double fValue
)
1459 ScDPTableData
* pTableData
= GetTableData();
1464 for (nDim
= 0; nDim
< pTableData
->GetColumnCount(); ++nDim
)
1466 if(rDimName
== pTableData
->getDimensionName(nDim
))
1470 return GetFormattedString(pTableData
, nDim
, fValue
);
1476 bool dequote( std::u16string_view rSource
, sal_Int32 nStartPos
, sal_Int32
& rEndPos
, OUString
& rResult
)
1478 // nStartPos has to point to opening quote
1480 const sal_Unicode cQuote
= '\'';
1482 if (rSource
[nStartPos
] == cQuote
)
1484 OUStringBuffer aBuffer
;
1485 sal_Int32 nPos
= nStartPos
+ 1;
1486 const sal_Int32 nLen
= rSource
.size();
1488 while ( nPos
< nLen
)
1490 const sal_Unicode cNext
= rSource
[nPos
];
1491 if ( cNext
== cQuote
)
1493 if (nPos
+1 < nLen
&& rSource
[nPos
+1] == cQuote
)
1495 // double quote is used for an embedded quote
1496 aBuffer
.append( cNext
); // append one quote
1497 ++nPos
; // skip the next one
1501 // end of quoted string
1502 rResult
= aBuffer
.makeStringAndClear();
1503 rEndPos
= nPos
+ 1; // behind closing quote
1508 aBuffer
.append( cNext
);
1512 // no closing quote before the end of the string -> error (bRet still false)
1518 struct ScGetPivotDataFunctionEntry
1524 bool parseFunction( std::u16string_view rList
, sal_Int32 nStartPos
, sal_Int32
& rEndPos
, sal_Int16
& rFunc
)
1526 static const ScGetPivotDataFunctionEntry aFunctions
[] =
1529 { "Sum", sheet::GeneralFunction2::SUM
},
1530 { "Count", sheet::GeneralFunction2::COUNT
},
1531 { "Average", sheet::GeneralFunction2::AVERAGE
},
1532 { "Max", sheet::GeneralFunction2::MAX
},
1533 { "Min", sheet::GeneralFunction2::MIN
},
1534 { "Product", sheet::GeneralFunction2::PRODUCT
},
1535 { "CountNums", sheet::GeneralFunction2::COUNTNUMS
},
1536 { "StDev", sheet::GeneralFunction2::STDEV
},
1537 { "StDevp", sheet::GeneralFunction2::STDEVP
},
1538 { "Var", sheet::GeneralFunction2::VAR
},
1539 { "VarP", sheet::GeneralFunction2::VARP
},
1540 // compatibility names
1541 { "Count Nums", sheet::GeneralFunction2::COUNTNUMS
},
1542 { "StdDev", sheet::GeneralFunction2::STDEV
},
1543 { "StdDevp", sheet::GeneralFunction2::STDEVP
}
1546 const sal_Int32 nListLen
= rList
.size();
1547 while (nStartPos
< nListLen
&& rList
[nStartPos
] == ' ')
1550 bool bParsed
= false;
1551 bool bFound
= false;
1553 sal_Int32 nFuncEnd
= 0;
1554 if (nStartPos
< nListLen
&& rList
[nStartPos
] == '\'')
1555 bParsed
= dequote( rList
, nStartPos
, nFuncEnd
, aFuncStr
);
1558 nFuncEnd
= rList
.find(']', nStartPos
);
1561 aFuncStr
= rList
.substr(nStartPos
, nFuncEnd
- nStartPos
);
1568 aFuncStr
= comphelper::string::strip(aFuncStr
, ' ');
1570 const sal_Int32 nFuncCount
= SAL_N_ELEMENTS(aFunctions
);
1571 for ( sal_Int32 nFunc
=0; nFunc
<nFuncCount
&& !bFound
; nFunc
++ )
1573 if (aFuncStr
.equalsIgnoreAsciiCaseAscii(aFunctions
[nFunc
].pName
))
1575 rFunc
= aFunctions
[nFunc
].eFunc
;
1578 while (nFuncEnd
< nListLen
&& rList
[nFuncEnd
] == ' ')
1588 bool extractAtStart( std::u16string_view rList
, sal_Int32
& rMatched
, bool bAllowBracket
, sal_Int16
* pFunc
,
1589 OUString
& rDequoted
)
1591 size_t nMatchList
= 0;
1592 sal_Unicode cFirst
= rList
[0];
1593 bool bParsed
= false;
1594 if ( cFirst
== '\'' || cFirst
== '[' )
1596 // quoted string or string in brackets must match completely
1599 sal_Int32 nQuoteEnd
= 0;
1601 if ( cFirst
== '\'' )
1602 bParsed
= dequote( rList
, 0, nQuoteEnd
, aDequoted
);
1603 else if ( cFirst
== '[' )
1605 // skip spaces after the opening bracket
1607 sal_Int32 nStartPos
= 1;
1608 const sal_Int32 nListLen
= rList
.size();
1609 while (nStartPos
< nListLen
&& rList
[nStartPos
] == ' ')
1612 if (nStartPos
< nListLen
&& rList
[nStartPos
] == '\'') // quoted within the brackets?
1614 if ( dequote( rList
, nStartPos
, nQuoteEnd
, aDequoted
) )
1616 // after the quoted string, there must be the closing bracket, optionally preceded by spaces,
1617 // and/or a function name
1618 while (nQuoteEnd
< nListLen
&& rList
[nQuoteEnd
] == ' ')
1621 // semicolon separates function name
1622 if (nQuoteEnd
< nListLen
&& rList
[nQuoteEnd
] == ';' && pFunc
)
1624 sal_Int32 nFuncEnd
= 0;
1625 if ( parseFunction( rList
, nQuoteEnd
+ 1, nFuncEnd
, *pFunc
) )
1626 nQuoteEnd
= nFuncEnd
;
1628 if (nQuoteEnd
< nListLen
&& rList
[nQuoteEnd
] == ']')
1630 ++nQuoteEnd
; // include the closing bracket for the matched length
1637 // implicit quoting to the closing bracket
1639 sal_Int32 nClosePos
= rList
.find(']', nStartPos
);
1642 sal_Int32 nNameEnd
= nClosePos
;
1643 sal_Int32 nSemiPos
= rList
.find(';', nStartPos
);
1644 if (nSemiPos
>= 0 && nSemiPos
< nClosePos
&& pFunc
)
1646 sal_Int32 nFuncEnd
= 0;
1647 if (parseFunction(rList
, nSemiPos
+1, nFuncEnd
, *pFunc
))
1648 nNameEnd
= nSemiPos
;
1651 aDequoted
= rList
.substr(nStartPos
, nNameEnd
- nStartPos
);
1652 // spaces before the closing bracket or semicolon
1653 aDequoted
= comphelper::string::stripEnd(aDequoted
, ' ');
1654 nQuoteEnd
= nClosePos
+ 1;
1662 nMatchList
= nQuoteEnd
; // match count in the list string, including quotes
1663 rDequoted
= aDequoted
;
1669 // look for following space or end of string
1671 bool bValid
= false;
1672 if ( nMatchList
>= rList
.size() )
1676 sal_Unicode cNext
= rList
[nMatchList
];
1677 if ( cNext
== ' ' || ( bAllowBracket
&& cNext
== '[' ) )
1683 rMatched
= nMatchList
;
1692 const OUString
& rList
, const OUString
& rSearch
, sal_Int32
& rMatched
,
1693 bool bAllowBracket
, sal_Int16
* pFunc
)
1695 sal_Int32 nMatchList
= 0;
1696 sal_Int32 nMatchSearch
= 0;
1697 sal_Unicode cFirst
= rList
[0];
1698 if ( cFirst
== '\'' || cFirst
== '[' )
1701 bool bParsed
= extractAtStart( rList
, rMatched
, bAllowBracket
, pFunc
, aDequoted
);
1702 if ( bParsed
&& ScGlobal::GetTransliteration().isEqual( aDequoted
, rSearch
) )
1704 nMatchList
= rMatched
; // match count in the list string, including quotes
1705 nMatchSearch
= rSearch
.getLength();
1710 // otherwise look for search string at the start of rList
1711 ScGlobal::GetTransliteration().equals(
1712 rList
, 0, rList
.getLength(), nMatchList
, rSearch
, 0, rSearch
.getLength(), nMatchSearch
);
1715 if (nMatchSearch
== rSearch
.getLength())
1717 // search string is at start of rList - look for following space or end of string
1719 bool bValid
= false;
1720 if ( sal::static_int_cast
<sal_Int32
>(nMatchList
) >= rList
.getLength() )
1724 sal_Unicode cNext
= rList
[nMatchList
];
1725 if ( cNext
== ' ' || ( bAllowBracket
&& cNext
== '[' ) )
1731 rMatched
= nMatchList
;
1739 } // anonymous namespace
1741 bool ScDPObject::ParseFilters(
1742 OUString
& rDataFieldName
,
1743 std::vector
<sheet::DataPilotFieldFilter
>& rFilters
,
1744 std::vector
<sal_Int16
>& rFilterFuncs
, std::u16string_view rFilterList
)
1746 // parse the string rFilterList into parameters for GetPivotData
1748 CreateObjects(); // create mxSource if not already done
1750 std::vector
<OUString
> aDataNames
; // data fields (source name)
1751 std::vector
<OUString
> aGivenNames
; // data fields (compound name)
1752 std::vector
<OUString
> aFieldNames
; // column/row/data fields
1753 std::vector
< uno::Sequence
<OUString
> > aFieldValueNames
;
1754 std::vector
< uno::Sequence
<OUString
> > aFieldValues
;
1756 // get all the field and item names
1758 uno::Reference
<container::XNameAccess
> xDimsName
= mxSource
->getDimensions();
1759 uno::Reference
<container::XIndexAccess
> xIntDims
= new ScNameToIndexAccess( xDimsName
);
1760 sal_Int32 nDimCount
= xIntDims
->getCount();
1761 for ( sal_Int32 nDim
= 0; nDim
<nDimCount
; nDim
++ )
1763 uno::Reference
<uno::XInterface
> xIntDim(xIntDims
->getByIndex(nDim
), uno::UNO_QUERY
);
1764 uno::Reference
<container::XNamed
> xDim( xIntDim
, uno::UNO_QUERY
);
1765 uno::Reference
<beans::XPropertySet
> xDimProp( xDim
, uno::UNO_QUERY
);
1766 uno::Reference
<sheet::XHierarchiesSupplier
> xDimSupp( xDim
, uno::UNO_QUERY
);
1767 bool bDataLayout
= ScUnoHelpFunctions::GetBoolProperty( xDimProp
,
1768 SC_UNO_DP_ISDATALAYOUT
);
1769 sheet::DataPilotFieldOrientation nOrient
= ScUnoHelpFunctions::GetEnumProperty(
1770 xDimProp
, SC_UNO_DP_ORIENTATION
,
1771 sheet::DataPilotFieldOrientation_HIDDEN
);
1774 if ( nOrient
== sheet::DataPilotFieldOrientation_DATA
)
1776 OUString aSourceName
;
1777 OUString aGivenName
;
1778 ScDPOutput::GetDataDimensionNames( aSourceName
, aGivenName
, xIntDim
);
1779 aDataNames
.push_back( aSourceName
);
1780 aGivenNames
.push_back( aGivenName
);
1782 else if ( nOrient
!= sheet::DataPilotFieldOrientation_HIDDEN
)
1784 // get level names, as in ScDPOutput
1786 uno::Reference
<container::XIndexAccess
> xHiers
= new ScNameToIndexAccess( xDimSupp
->getHierarchies() );
1787 sal_Int32 nHierarchy
= ScUnoHelpFunctions::GetLongProperty( xDimProp
,
1788 SC_UNO_DP_USEDHIERARCHY
);
1789 if ( nHierarchy
>= xHiers
->getCount() )
1792 uno::Reference
<sheet::XLevelsSupplier
> xHierSupp(xHiers
->getByIndex(nHierarchy
),
1794 if ( xHierSupp
.is() )
1796 uno::Reference
<container::XIndexAccess
> xLevels
= new ScNameToIndexAccess( xHierSupp
->getLevels() );
1797 sal_Int32 nLevCount
= xLevels
->getCount();
1798 for (sal_Int32 nLev
=0; nLev
<nLevCount
; nLev
++)
1800 uno::Reference
<uno::XInterface
> xLevel(xLevels
->getByIndex(nLev
),
1802 uno::Reference
<container::XNamed
> xLevNam( xLevel
, uno::UNO_QUERY
);
1803 uno::Reference
<sheet::XMembersSupplier
> xLevSupp( xLevel
, uno::UNO_QUERY
);
1804 if ( xLevNam
.is() && xLevSupp
.is() )
1806 uno::Reference
<sheet::XMembersAccess
> xMembers
= xLevSupp
->getMembers();
1808 OUString
aFieldName( xLevNam
->getName() );
1809 // getElementNames() and getLocaleIndependentElementNames()
1810 // must be consecutive calls to obtain strings in matching order.
1811 uno::Sequence
<OUString
> aMemberValueNames( xMembers
->getElementNames() );
1812 uno::Sequence
<OUString
> aMemberValues( xMembers
->getLocaleIndependentElementNames() );
1814 aFieldNames
.push_back( aFieldName
);
1815 aFieldValueNames
.push_back( aMemberValueNames
);
1816 aFieldValues
.push_back( aMemberValues
);
1824 // compare and build filters
1826 SCSIZE nDataFields
= aDataNames
.size();
1827 SCSIZE nFieldCount
= aFieldNames
.size();
1828 OSL_ENSURE( aGivenNames
.size() == nDataFields
&& aFieldValueNames
.size() == nFieldCount
&&
1829 aFieldValues
.size() == nFieldCount
, "wrong count" );
1831 bool bError
= false;
1832 bool bHasData
= false;
1833 OUString
aRemaining(comphelper::string::strip(rFilterList
, ' '));
1834 while (!aRemaining
.isEmpty() && !bError
)
1838 // look for data field name
1840 for ( SCSIZE nDataPos
=0; nDataPos
<nDataFields
&& !bUsed
; nDataPos
++ )
1843 sal_Int32 nMatched
= 0;
1844 if (isAtStart(aRemaining
, aDataNames
[nDataPos
], nMatched
, false, nullptr))
1845 aFound
= aDataNames
[nDataPos
];
1846 else if (isAtStart(aRemaining
, aGivenNames
[nDataPos
], nMatched
, false, nullptr))
1847 aFound
= aGivenNames
[nDataPos
];
1849 if (!aFound
.isEmpty())
1851 rDataFieldName
= aFound
;
1852 aRemaining
= aRemaining
.copy(nMatched
);
1858 // look for field name
1860 OUString aSpecField
;
1861 bool bHasFieldName
= false;
1864 sal_Int32 nMatched
= 0;
1865 for ( SCSIZE nField
=0; nField
<nFieldCount
&& !bHasFieldName
; nField
++ )
1867 if (isAtStart(aRemaining
, aFieldNames
[nField
], nMatched
, true, nullptr))
1869 aSpecField
= aFieldNames
[nField
];
1870 aRemaining
= aRemaining
.copy(nMatched
);
1871 aRemaining
= comphelper::string::stripStart(aRemaining
, ' ');
1873 // field name has to be followed by item name in brackets
1874 if (aRemaining
.startsWith("["))
1876 bHasFieldName
= true;
1877 // bUsed remains false - still need the item
1888 // look for field item
1892 bool bItemFound
= false;
1893 sal_Int32 nMatched
= 0;
1894 OUString aFoundName
;
1895 OUString aFoundValueName
;
1896 OUString aFoundValue
;
1897 sal_Int16 eFunc
= sheet::GeneralFunction2::NONE
;
1898 sal_Int16 eFoundFunc
= sheet::GeneralFunction2::NONE
;
1900 OUString aQueryValueName
;
1901 const bool bHasQuery
= extractAtStart( aRemaining
, nMatched
, false, &eFunc
, aQueryValueName
);
1903 OUString aQueryValue
= aQueryValueName
;
1906 ScInterpreterContext
& rContext
= mpTableData
->GetCacheTable().getCache().GetInterpreterContext();
1907 // Parse possible number from aQueryValueName and format
1908 // locale independent as aQueryValue.
1909 sal_uInt32 nNumFormat
= 0;
1911 if (rContext
.NFIsNumberFormat(aQueryValueName
, nNumFormat
, fValue
))
1912 aQueryValue
= ScDPCache::GetLocaleIndependentFormattedString(fValue
, rContext
, nNumFormat
);
1915 for ( SCSIZE nField
=0; nField
<nFieldCount
; nField
++ )
1917 // If a field name is given, look in that field only, otherwise in all fields.
1918 // aSpecField is initialized from aFieldNames array, so exact comparison can be used.
1919 if ( !bHasFieldName
|| aFieldNames
[nField
] == aSpecField
)
1921 const uno::Sequence
<OUString
>& rItemNames
= aFieldValueNames
[nField
];
1922 const uno::Sequence
<OUString
>& rItemValues
= aFieldValues
[nField
];
1923 sal_Int32 nItemCount
= rItemNames
.getLength();
1924 assert(nItemCount
== rItemValues
.getLength());
1925 const OUString
* pItemNamesArr
= rItemNames
.getConstArray();
1926 const OUString
* pItemValuesArr
= rItemValues
.getConstArray();
1927 for ( sal_Int32 nItem
=0; nItem
<nItemCount
; nItem
++ )
1929 bool bThisItemFound
;
1932 // First check given value name against both.
1933 bThisItemFound
= ScGlobal::GetTransliteration().isEqual(
1934 aQueryValueName
, pItemNamesArr
[nItem
]);
1935 if (!bThisItemFound
&& pItemValuesArr
[nItem
] != pItemNamesArr
[nItem
])
1936 bThisItemFound
= ScGlobal::GetTransliteration().isEqual(
1937 aQueryValueName
, pItemValuesArr
[nItem
]);
1938 if (!bThisItemFound
&& aQueryValueName
!= aQueryValue
)
1940 // Second check locale independent value
1942 /* TODO: or check only value string against
1943 * value string, not against the value name? */
1944 bThisItemFound
= ScGlobal::GetTransliteration().isEqual(
1945 aQueryValue
, pItemNamesArr
[nItem
]);
1946 if (!bThisItemFound
&& pItemValuesArr
[nItem
] != pItemNamesArr
[nItem
])
1947 bThisItemFound
= ScGlobal::GetTransliteration().isEqual(
1948 aQueryValue
, pItemValuesArr
[nItem
]);
1953 bThisItemFound
= isAtStart( aRemaining
, pItemNamesArr
[nItem
], nMatched
, false, &eFunc
);
1954 if (!bThisItemFound
&& pItemValuesArr
[nItem
] != pItemNamesArr
[nItem
])
1955 bThisItemFound
= isAtStart( aRemaining
, pItemValuesArr
[nItem
], nMatched
, false, &eFunc
);
1956 /* TODO: this checks only the given value name,
1957 * check also locale independent value. But we'd
1958 * have to do that in each iteration of the loop
1959 * inside isAtStart() since a query could not be
1960 * extracted and a match could be on the passed
1961 * item value name string or item value string
1962 * starting at aRemaining. */
1967 bError
= true; // duplicate (also across fields)
1970 aFoundName
= aFieldNames
[nField
];
1971 aFoundValueName
= pItemNamesArr
[nItem
];
1972 aFoundValue
= pItemValuesArr
[nItem
];
1982 if ( bItemFound
&& !bError
)
1984 sheet::DataPilotFieldFilter aField
;
1985 aField
.FieldName
= aFoundName
;
1986 aField
.MatchValueName
= aFoundValueName
;
1987 aField
.MatchValue
= aFoundValue
;
1988 rFilters
.push_back(aField
);
1989 rFilterFuncs
.push_back(eFoundFunc
);
1990 aRemaining
= aRemaining
.copy(nMatched
);
1997 // remove any number of spaces between entries
1998 aRemaining
= comphelper::string::stripStart(aRemaining
, ' ');
2001 if ( !bError
&& !bHasData
&& aDataNames
.size() == 1 )
2003 // if there's only one data field, its name need not be specified
2004 rDataFieldName
= aDataNames
[0];
2008 return bHasData
&& !bError
;
2011 void ScDPObject::ToggleDetails(const DataPilotTableHeaderData
& rElemDesc
, ScDPObject
* pDestObj
)
2013 CreateObjects(); // create mxSource if not already done
2015 // find dimension name
2017 uno::Reference
<container::XNamed
> xDim
;
2018 uno::Reference
<container::XNameAccess
> xDimsName
= mxSource
->getDimensions();
2019 uno::Reference
<container::XIndexAccess
> xIntDims
= new ScNameToIndexAccess( xDimsName
);
2020 tools::Long nIntCount
= xIntDims
->getCount();
2021 if ( rElemDesc
.Dimension
< nIntCount
)
2023 xDim
.set(xIntDims
->getByIndex(rElemDesc
.Dimension
), uno::UNO_QUERY
);
2025 OSL_ENSURE( xDim
.is(), "dimension not found" );
2026 if ( !xDim
.is() ) return;
2027 OUString aDimName
= xDim
->getName();
2029 uno::Reference
<beans::XPropertySet
> xDimProp( xDim
, uno::UNO_QUERY
);
2030 bool bDataLayout
= ScUnoHelpFunctions::GetBoolProperty( xDimProp
,
2031 SC_UNO_DP_ISDATALAYOUT
);
2034 // the elements of the data layout dimension can't be found by their names
2035 // -> don't change anything
2041 tools::Long nHierCount
= 0;
2042 uno::Reference
<container::XIndexAccess
> xHiers
;
2043 uno::Reference
<sheet::XHierarchiesSupplier
> xHierSupp( xDim
, uno::UNO_QUERY
);
2044 if ( xHierSupp
.is() )
2046 uno::Reference
<container::XNameAccess
> xHiersName
= xHierSupp
->getHierarchies();
2047 xHiers
= new ScNameToIndexAccess( xHiersName
);
2048 nHierCount
= xHiers
->getCount();
2050 uno::Reference
<uno::XInterface
> xHier
;
2051 if ( rElemDesc
.Hierarchy
< nHierCount
)
2052 xHier
.set(xHiers
->getByIndex(rElemDesc
.Hierarchy
), uno::UNO_QUERY
);
2053 OSL_ENSURE( xHier
.is(), "hierarchy not found" );
2054 if ( !xHier
.is() ) return;
2056 tools::Long nLevCount
= 0;
2057 uno::Reference
<container::XIndexAccess
> xLevels
;
2058 uno::Reference
<sheet::XLevelsSupplier
> xLevSupp( xHier
, uno::UNO_QUERY
);
2059 if ( xLevSupp
.is() )
2061 uno::Reference
<container::XNameAccess
> xLevsName
= xLevSupp
->getLevels();
2062 xLevels
= new ScNameToIndexAccess( xLevsName
);
2063 nLevCount
= xLevels
->getCount();
2065 uno::Reference
<uno::XInterface
> xLevel
;
2066 if ( rElemDesc
.Level
< nLevCount
)
2067 xLevel
.set(xLevels
->getByIndex(rElemDesc
.Level
), uno::UNO_QUERY
);
2068 OSL_ENSURE( xLevel
.is(), "level not found" );
2069 if ( !xLevel
.is() ) return;
2071 uno::Reference
<sheet::XMembersAccess
> xMembers
;
2072 uno::Reference
<sheet::XMembersSupplier
> xMbrSupp( xLevel
, uno::UNO_QUERY
);
2073 if ( xMbrSupp
.is() )
2074 xMembers
= xMbrSupp
->getMembers();
2076 bool bFound
= false;
2077 bool bShowDetails
= true;
2079 if ( xMembers
.is() )
2081 if ( xMembers
->hasByName(rElemDesc
.MemberName
) )
2083 uno::Reference
<beans::XPropertySet
> xMbrProp(xMembers
->getByName(rElemDesc
.MemberName
),
2085 if ( xMbrProp
.is() )
2087 bShowDetails
= ScUnoHelpFunctions::GetBoolProperty( xMbrProp
,
2088 SC_UNO_DP_SHOWDETAILS
);
2089 //TODO: don't set bFound if property is unknown?
2095 OSL_ENSURE( bFound
, "member not found" );
2097 //TODO: use Hierarchy and Level in SaveData !!!!
2099 // modify pDestObj if set, this object otherwise
2100 ScDPSaveData
* pModifyData
= pDestObj
? ( pDestObj
->mpSaveData
.get() ) : mpSaveData
.get();
2101 OSL_ENSURE( pModifyData
, "no data?" );
2104 const OUString aName
= rElemDesc
.MemberName
;
2105 pModifyData
->GetDimensionByName(aDimName
)->
2106 GetMemberByName(aName
)->SetShowDetails( !bShowDetails
); // toggle
2109 pDestObj
->InvalidateData(); // re-init source from SaveData
2111 InvalidateData(); // re-init source from SaveData
2115 static PivotFunc
lcl_FirstSubTotal( const uno::Reference
<beans::XPropertySet
>& xDimProp
) // PIVOT_FUNC mask
2117 uno::Reference
<sheet::XHierarchiesSupplier
> xDimSupp( xDimProp
, uno::UNO_QUERY
);
2118 if ( xDimProp
.is() && xDimSupp
.is() )
2120 uno::Reference
<container::XIndexAccess
> xHiers
= new ScNameToIndexAccess( xDimSupp
->getHierarchies() );
2121 tools::Long nHierarchy
= ScUnoHelpFunctions::GetLongProperty( xDimProp
,
2122 SC_UNO_DP_USEDHIERARCHY
);
2123 if ( nHierarchy
>= xHiers
->getCount() )
2126 uno::Reference
<sheet::XLevelsSupplier
> xHierSupp(xHiers
->getByIndex(nHierarchy
),
2128 if ( xHierSupp
.is() )
2130 uno::Reference
<container::XIndexAccess
> xLevels
= new ScNameToIndexAccess( xHierSupp
->getLevels() );
2131 uno::Reference
<uno::XInterface
> xLevel(xLevels
->getByIndex(0), uno::UNO_QUERY
);
2132 uno::Reference
<beans::XPropertySet
> xLevProp( xLevel
, uno::UNO_QUERY
);
2133 if ( xLevProp
.is() )
2138 aSubAny
= xLevProp
->getPropertyValue( SC_UNO_DP_SUBTOTAL2
);
2140 catch(uno::Exception
&)
2143 uno::Sequence
<sal_Int16
> aSeq
;
2144 if ( aSubAny
>>= aSeq
)
2146 PivotFunc nMask
= PivotFunc::NONE
;
2147 for (const sal_Int16 nElem
: aSeq
)
2148 nMask
|= ScDataPilotConversion::FunctionBit(nElem
);
2155 OSL_FAIL("FirstSubTotal: NULL");
2156 return PivotFunc::NONE
;
2166 FindByColumn(SCCOL nCol
, PivotFunc nMask
) : mnCol(nCol
), mnMask(nMask
) {}
2167 bool operator() (const ScPivotField
& r
) const
2169 return r
.nCol
== mnCol
&& r
.nFuncMask
== mnMask
;
2175 static void lcl_FillOldFields( ScPivotFieldVector
& rFields
,
2176 const uno::Reference
<sheet::XDimensionsSupplier
>& xSource
,
2177 sheet::DataPilotFieldOrientation nOrient
, bool bAddData
)
2179 ScPivotFieldVector aFields
;
2181 bool bDataFound
= false;
2183 //TODO: merge multiple occurrences (data field with different functions)
2184 //TODO: force data field in one dimension
2186 vector
<tools::Long
> aPos
;
2188 uno::Reference
<container::XNameAccess
> xDimsName
= xSource
->getDimensions();
2189 uno::Reference
<container::XIndexAccess
> xDims
= new ScNameToIndexAccess( xDimsName
);
2190 tools::Long nDimCount
= xDims
->getCount();
2191 for (tools::Long nDim
= 0; nDim
< nDimCount
; ++nDim
)
2193 // dimension properties
2194 uno::Reference
<beans::XPropertySet
> xDimProp(xDims
->getByIndex(nDim
), uno::UNO_QUERY
);
2196 // dimension orientation, hidden by default.
2197 sheet::DataPilotFieldOrientation nDimOrient
= ScUnoHelpFunctions::GetEnumProperty(
2198 xDimProp
, SC_UNO_DP_ORIENTATION
,
2199 sheet::DataPilotFieldOrientation_HIDDEN
);
2201 if ( xDimProp
.is() && nDimOrient
== nOrient
)
2203 // Let's take this dimension.
2206 PivotFunc nMask
= PivotFunc::NONE
;
2207 if ( nOrient
== sheet::DataPilotFieldOrientation_DATA
)
2209 sal_Int16 eFunc
= ScUnoHelpFunctions::GetShortProperty(
2210 xDimProp
, SC_UNO_DP_FUNCTION2
,
2211 sheet::GeneralFunction2::NONE
);
2212 if ( eFunc
== sheet::GeneralFunction2::AUTO
)
2214 //TODO: test for numeric data
2215 eFunc
= sheet::GeneralFunction2::SUM
;
2217 nMask
= ScDataPilotConversion::FunctionBit(eFunc
);
2220 nMask
= lcl_FirstSubTotal( xDimProp
); // from first hierarchy
2222 // is this data layout dimension?
2223 bool bDataLayout
= ScUnoHelpFunctions::GetBoolProperty(
2224 xDimProp
, SC_UNO_DP_ISDATALAYOUT
);
2226 // is this dimension cloned?
2227 tools::Long nDupSource
= -1;
2230 uno::Any aOrigAny
= xDimProp
->getPropertyValue(SC_UNO_DP_ORIGINAL_POS
);
2232 if (aOrigAny
>>= nTmp
)
2235 catch(uno::Exception
&)
2239 sal_uInt8 nDupCount
= 0;
2240 if (nDupSource
>= 0)
2242 // this dimension is cloned.
2244 SCCOL nCompCol
; // ID of the original dimension.
2246 nCompCol
= PIVOT_DATA_FIELD
;
2248 nCompCol
= static_cast<SCCOL
>(nDupSource
); //TODO: seek source column from name
2250 ScPivotFieldVector::iterator it
= std::find_if(aFields
.begin(), aFields
.end(), FindByColumn(nCompCol
, nMask
));
2251 if (it
!= aFields
.end())
2252 nDupCount
= it
->mnDupCount
+ 1;
2255 aFields
.emplace_back();
2256 ScPivotField
& rField
= aFields
.back();
2259 rField
.nCol
= PIVOT_DATA_FIELD
;
2264 rField
.mnOriginalDim
= nDupSource
;
2265 rField
.nCol
= static_cast<SCCOL
>(nDim
); //TODO: seek source column from name
2268 rField
.nFuncMask
= nMask
;
2269 rField
.mnDupCount
= nDupCount
;
2270 tools::Long nPos
= ScUnoHelpFunctions::GetLongProperty(
2271 xDimProp
, SC_UNO_DP_POSITION
);
2272 aPos
.push_back(nPos
);
2276 if (nOrient
== sheet::DataPilotFieldOrientation_DATA
)
2277 xDimProp
->getPropertyValue(SC_UNO_DP_REFVALUE
)
2278 >>= rField
.maFieldRef
;
2280 catch (uno::Exception
&)
2286 // sort by getPosition() value
2288 size_t nOutCount
= aFields
.size();
2291 for (size_t i
= 0; i
< nOutCount
- 1; ++i
)
2293 for (size_t j
= 0; j
+ i
< nOutCount
- 1; ++j
)
2295 if ( aPos
[j
+1] < aPos
[j
] )
2297 std::swap( aPos
[j
], aPos
[j
+1] );
2298 std::swap( aFields
[j
], aFields
[j
+1] );
2304 if (bAddData
&& !bDataFound
)
2305 aFields
.emplace_back(PIVOT_DATA_FIELD
);
2307 rFields
.swap(aFields
);
2310 void ScDPObject::FillOldParam(ScPivotParam
& rParam
) const
2312 const_cast<ScDPObject
*>(this)->CreateObjects(); // mxSource is needed for field numbers
2317 rParam
.nCol
= maOutputRange
.aStart
.Col();
2318 rParam
.nRow
= maOutputRange
.aStart
.Row();
2319 rParam
.nTab
= maOutputRange
.aStart
.Tab();
2320 // ppLabelArr / nLabels is not changed
2322 bool bAddData
= lcl_GetDataGetOrientation(mxSource
) == sheet::DataPilotFieldOrientation_HIDDEN
;
2324 rParam
.maPageFields
, mxSource
, sheet::DataPilotFieldOrientation_PAGE
, false);
2326 rParam
.maColFields
, mxSource
, sheet::DataPilotFieldOrientation_COLUMN
, bAddData
);
2328 rParam
.maRowFields
, mxSource
, sheet::DataPilotFieldOrientation_ROW
, false);
2330 rParam
.maDataFields
, mxSource
, sheet::DataPilotFieldOrientation_DATA
, false);
2332 uno::Reference
<beans::XPropertySet
> xProp(mxSource
, uno::UNO_QUERY
);
2338 rParam
.bMakeTotalCol
= ScUnoHelpFunctions::GetBoolProperty( xProp
,
2339 SC_UNO_DP_COLGRAND
, true );
2340 rParam
.bMakeTotalRow
= ScUnoHelpFunctions::GetBoolProperty( xProp
,
2341 SC_UNO_DP_ROWGRAND
, true );
2343 // following properties may be missing for external sources
2344 rParam
.bIgnoreEmptyRows
= ScUnoHelpFunctions::GetBoolProperty( xProp
,
2345 SC_UNO_DP_IGNOREEMPTY
);
2346 rParam
.bDetectCategories
= ScUnoHelpFunctions::GetBoolProperty( xProp
,
2347 SC_UNO_DP_REPEATEMPTY
);
2349 catch(uno::Exception
&)
2355 static void lcl_FillLabelData( ScDPLabelData
& rData
, const uno::Reference
< beans::XPropertySet
>& xDimProp
)
2357 uno::Reference
<sheet::XHierarchiesSupplier
> xDimSupp( xDimProp
, uno::UNO_QUERY
);
2358 if (!xDimProp
.is() || !xDimSupp
.is())
2361 uno::Reference
<container::XIndexAccess
> xHiers
= new ScNameToIndexAccess( xDimSupp
->getHierarchies() );
2362 tools::Long nHierarchy
= ScUnoHelpFunctions::GetLongProperty(
2363 xDimProp
, SC_UNO_DP_USEDHIERARCHY
);
2364 if ( nHierarchy
>= xHiers
->getCount() )
2366 rData
.mnUsedHier
= nHierarchy
;
2368 uno::Reference
<sheet::XLevelsSupplier
> xHierSupp(xHiers
->getByIndex(nHierarchy
),
2370 if (!xHierSupp
.is())
2373 uno::Reference
<container::XIndexAccess
> xLevels
=
2374 new ScNameToIndexAccess( xHierSupp
->getLevels() );
2376 uno::Reference
<beans::XPropertySet
> xLevProp(xLevels
->getByIndex(0), uno::UNO_QUERY
);
2380 rData
.mbShowAll
= ScUnoHelpFunctions::GetBoolProperty(
2381 xLevProp
, SC_UNO_DP_SHOWEMPTY
);
2383 rData
.mbRepeatItemLabels
= ScUnoHelpFunctions::GetBoolProperty(
2384 xLevProp
, SC_UNO_DP_REPEATITEMLABELS
);
2388 xLevProp
->getPropertyValue( SC_UNO_DP_SORTING
)
2389 >>= rData
.maSortInfo
;
2390 xLevProp
->getPropertyValue( SC_UNO_DP_LAYOUT
)
2391 >>= rData
.maLayoutInfo
;
2392 xLevProp
->getPropertyValue( SC_UNO_DP_AUTOSHOW
)
2393 >>= rData
.maShowInfo
;
2395 catch(uno::Exception
&)
2400 void ScDPObject::FillLabelDataForDimension(
2401 const uno::Reference
<container::XIndexAccess
>& xDims
, sal_Int32 nDim
, ScDPLabelData
& rLabelData
)
2403 uno::Reference
<uno::XInterface
> xIntDim(xDims
->getByIndex(nDim
), uno::UNO_QUERY
);
2404 uno::Reference
<container::XNamed
> xDimName( xIntDim
, uno::UNO_QUERY
);
2405 uno::Reference
<beans::XPropertySet
> xDimProp( xIntDim
, uno::UNO_QUERY
);
2407 if (!xDimName
.is() || !xDimProp
.is())
2410 bool bData
= ScUnoHelpFunctions::GetBoolProperty(
2411 xDimProp
, SC_UNO_DP_ISDATALAYOUT
);
2412 //TODO: error checking -- is "IsDataLayoutDimension" property required??
2414 sal_Int32 nOrigPos
= -1;
2415 OUString aFieldName
;
2418 aFieldName
= xDimName
->getName();
2419 uno::Any aOrigAny
= xDimProp
->getPropertyValue(SC_UNO_DP_ORIGINAL_POS
);
2420 aOrigAny
>>= nOrigPos
;
2422 catch(uno::Exception
&)
2426 OUString aLayoutName
= ScUnoHelpFunctions::GetStringProperty(
2427 xDimProp
, SC_UNO_DP_LAYOUTNAME
, OUString());
2429 OUString aSubtotalName
= ScUnoHelpFunctions::GetStringProperty(
2430 xDimProp
, SC_UNO_DP_FIELD_SUBTOTALNAME
, OUString());
2432 // Name from the UNO dimension object may have trailing '*'s in which
2433 // case it's a duplicate dimension. Convert that to a duplicate index.
2435 sal_uInt8 nDupCount
= ScDPUtil::getDuplicateIndex(aFieldName
);
2436 aFieldName
= ScDPUtil::getSourceDimensionName(aFieldName
);
2438 rLabelData
.maName
= aFieldName
;
2439 rLabelData
.mnCol
= static_cast<SCCOL
>(nDim
);
2440 rLabelData
.mnDupCount
= nDupCount
;
2441 rLabelData
.mbDataLayout
= bData
;
2442 rLabelData
.mbIsValue
= true; //TODO: check
2447 rLabelData
.mnOriginalDim
= static_cast<tools::Long
>(nOrigPos
);
2448 rLabelData
.maLayoutName
= aLayoutName
;
2449 rLabelData
.maSubtotalName
= aSubtotalName
;
2451 // This is a duplicated dimension. Use the original dimension index.
2453 GetHierarchies(nDim
, rLabelData
.maHiers
);
2454 GetMembers(nDim
, GetUsedHierarchy(nDim
), rLabelData
.maMembers
);
2455 lcl_FillLabelData(rLabelData
, xDimProp
);
2456 rLabelData
.mnFlags
= ScUnoHelpFunctions::GetLongProperty(
2457 xDimProp
, SC_UNO_DP_FLAGS
);
2460 void ScDPObject::FillLabelData(sal_Int32 nDim
, ScDPLabelData
& rLabels
)
2466 uno::Reference
<container::XNameAccess
> xDimsName
= mxSource
->getDimensions();
2467 uno::Reference
<container::XIndexAccess
> xDims
= new ScNameToIndexAccess( xDimsName
);
2468 sal_Int32 nDimCount
= xDims
->getCount();
2469 if (nDimCount
<= 0 || nDim
>= nDimCount
)
2472 FillLabelDataForDimension(xDims
, nDim
, rLabels
);
2475 void ScDPObject::FillLabelData(ScPivotParam
& rParam
)
2477 rParam
.maLabelArray
.clear();
2483 uno::Reference
<container::XNameAccess
> xDimsName
= mxSource
->getDimensions();
2484 uno::Reference
<container::XIndexAccess
> xDims
= new ScNameToIndexAccess( xDimsName
);
2485 sal_Int32 nDimCount
= xDims
->getCount();
2489 for (sal_Int32 nDim
= 0; nDim
< nDimCount
; ++nDim
)
2491 ScDPLabelData
* pNewLabel
= new ScDPLabelData
;
2492 FillLabelDataForDimension(xDims
, nDim
, *pNewLabel
);
2493 rParam
.maLabelArray
.push_back(std::unique_ptr
<ScDPLabelData
>(pNewLabel
));
2497 void ScDPObject::GetFieldIdsNames(sheet::DataPilotFieldOrientation nOrient
, std::vector
<tools::Long
>& rIndices
,
2498 std::vector
<OUString
>& rNames
)
2504 uno::Reference
<container::XNameAccess
> xDimsName
= mxSource
->getDimensions();
2505 uno::Reference
<container::XIndexAccess
> xDims
= new ScNameToIndexAccess( xDimsName
);
2506 tools::Long nDimCount
= xDims
->getCount();
2507 for (tools::Long nDim
= 0; nDim
< nDimCount
; ++nDim
)
2509 uno::Reference
<uno::XInterface
> xIntDim(xDims
->getByIndex(nDim
), uno::UNO_QUERY
);
2510 uno::Reference
<container::XNamed
> xDimName(xIntDim
, uno::UNO_QUERY
);
2511 uno::Reference
<beans::XPropertySet
> xDimProp(xIntDim
, uno::UNO_QUERY
);
2513 sheet::DataPilotFieldOrientation nDimOrient
= ScUnoHelpFunctions::GetEnumProperty(
2514 xDimProp
, SC_UNO_DP_ORIENTATION
,
2515 sheet::DataPilotFieldOrientation_HIDDEN
);
2517 if ( xDimProp
.is() && nDimOrient
== nOrient
)
2519 rIndices
.push_back(nDim
);
2520 rNames
.push_back(xDimName
->getName());
2525 bool ScDPObject::GetHierarchiesNA( sal_Int32 nDim
, uno::Reference
< container::XNameAccess
>& xHiers
)
2528 uno::Reference
<container::XNameAccess
> xDimsName( GetSource()->getDimensions() );
2529 uno::Reference
<container::XIndexAccess
> xIntDims(new ScNameToIndexAccess( xDimsName
));
2532 uno::Reference
<sheet::XHierarchiesSupplier
> xHierSup(xIntDims
->getByIndex( nDim
), uno::UNO_QUERY
);
2535 xHiers
.set( xHierSup
->getHierarchies() );
2542 void ScDPObject::GetHierarchies( sal_Int32 nDim
, uno::Sequence
< OUString
>& rHiers
)
2544 uno::Reference
< container::XNameAccess
> xHiersNA
;
2545 if( GetHierarchiesNA( nDim
, xHiersNA
) )
2547 rHiers
= xHiersNA
->getElementNames();
2551 sal_Int32
ScDPObject::GetUsedHierarchy( sal_Int32 nDim
)
2553 sal_Int32 nHier
= 0;
2554 uno::Reference
<container::XNameAccess
> xDimsName( GetSource()->getDimensions() );
2555 uno::Reference
<container::XIndexAccess
> xIntDims(new ScNameToIndexAccess( xDimsName
));
2556 uno::Reference
<beans::XPropertySet
> xDim(xIntDims
->getByIndex( nDim
), uno::UNO_QUERY
);
2558 nHier
= ScUnoHelpFunctions::GetLongProperty( xDim
, SC_UNO_DP_USEDHIERARCHY
);
2562 bool ScDPObject::GetMembersNA( sal_Int32 nDim
, uno::Reference
< sheet::XMembersAccess
>& xMembers
)
2564 return GetMembersNA( nDim
, GetUsedHierarchy( nDim
), xMembers
);
2567 bool ScDPObject::GetMembersNA( sal_Int32 nDim
, sal_Int32 nHier
, uno::Reference
< sheet::XMembersAccess
>& xMembers
)
2570 uno::Reference
<container::XNameAccess
> xDimsName( GetSource()->getDimensions() );
2571 uno::Reference
<container::XIndexAccess
> xIntDims(new ScNameToIndexAccess( xDimsName
));
2572 uno::Reference
<beans::XPropertySet
> xDim(xIntDims
->getByIndex( nDim
), uno::UNO_QUERY
);
2575 uno::Reference
<sheet::XHierarchiesSupplier
> xHierSup(xDim
, uno::UNO_QUERY
);
2578 uno::Reference
<container::XIndexAccess
> xHiers(new ScNameToIndexAccess(xHierSup
->getHierarchies()));
2579 uno::Reference
<sheet::XLevelsSupplier
> xLevSupp( xHiers
->getByIndex(nHier
), uno::UNO_QUERY
);
2580 if ( xLevSupp
.is() )
2582 uno::Reference
<container::XIndexAccess
> xLevels(new ScNameToIndexAccess( xLevSupp
->getLevels()));
2585 sal_Int32 nLevCount
= xLevels
->getCount();
2588 uno::Reference
<sheet::XMembersSupplier
> xMembSupp( xLevels
->getByIndex(0), uno::UNO_QUERY
);
2589 if ( xMembSupp
.is() )
2591 xMembers
.set(xMembSupp
->getMembers());
2602 // convert old pivot tables into new datapilot tables
2606 OUString
lcl_GetDimName( const uno::Reference
<sheet::XDimensionsSupplier
>& xSource
, tools::Long nDim
)
2611 uno::Reference
<container::XNameAccess
> xDimsName
= xSource
->getDimensions();
2612 uno::Reference
<container::XIndexAccess
> xDims
= new ScNameToIndexAccess( xDimsName
);
2613 tools::Long nDimCount
= xDims
->getCount();
2614 if ( nDim
< nDimCount
)
2616 uno::Reference
<container::XNamed
> xDimName(xDims
->getByIndex(nDim
), uno::UNO_QUERY
);
2621 aName
= xDimName
->getName();
2623 catch(uno::Exception
&)
2632 bool hasFieldColumn(const vector
<ScPivotField
>* pRefFields
, SCCOL nCol
)
2637 return std::any_of(pRefFields
->begin(), pRefFields
->end(),
2638 [&nCol
](const ScPivotField
& rField
) {
2639 // This array of fields contains the specified column.
2640 return rField
.nCol
== nCol
; });
2643 class FindByOriginalDim
2647 explicit FindByOriginalDim(tools::Long nDim
) : mnDim(nDim
) {}
2648 bool operator() (const ScPivotField
& r
) const
2650 return mnDim
== r
.getOriginalDim();
2656 void ScDPObject::ConvertOrientation(
2657 ScDPSaveData
& rSaveData
, const ScPivotFieldVector
& rFields
, sheet::DataPilotFieldOrientation nOrient
,
2658 const Reference
<XDimensionsSupplier
>& xSource
,
2659 const ScDPLabelDataVector
& rLabels
,
2660 const ScPivotFieldVector
* pRefColFields
,
2661 const ScPivotFieldVector
* pRefRowFields
,
2662 const ScPivotFieldVector
* pRefPageFields
)
2664 ScPivotFieldVector::const_iterator itr
, itrBeg
= rFields
.begin(), itrEnd
= rFields
.end();
2665 for (itr
= itrBeg
; itr
!= itrEnd
; ++itr
)
2667 const ScPivotField
& rField
= *itr
;
2669 tools::Long nCol
= rField
.getOriginalDim();
2670 PivotFunc nFuncs
= rField
.nFuncMask
;
2671 const sheet::DataPilotFieldReference
& rFieldRef
= rField
.maFieldRef
;
2673 ScDPSaveDimension
* pDim
= nullptr;
2674 if ( nCol
== PIVOT_DATA_FIELD
)
2675 pDim
= rSaveData
.GetDataLayoutDimension();
2678 OUString aDocStr
= lcl_GetDimName( xSource
, nCol
); // cols must start at 0
2679 if (!aDocStr
.isEmpty())
2680 pDim
= rSaveData
.GetDimensionByName(aDocStr
);
2688 if ( nOrient
== sheet::DataPilotFieldOrientation_DATA
) // set summary function
2690 // generate an individual entry for each function
2693 // if a dimension is used for column/row/page and data,
2694 // use duplicated dimensions for all data occurrences
2695 if (hasFieldColumn(pRefColFields
, nCol
))
2698 if (bFirst
&& hasFieldColumn(pRefRowFields
, nCol
))
2701 if (bFirst
&& hasFieldColumn(pRefPageFields
, nCol
))
2706 // if set via api, a data column may occur several times
2707 // (if the function hasn't been changed yet) -> also look for duplicate data column
2708 bFirst
= std::none_of(itrBeg
, itr
, FindByOriginalDim(nCol
));
2711 ScGeneralFunction eFunc
= ScDataPilotConversion::FirstFunc(rField
.nFuncMask
);
2713 pDim
= rSaveData
.DuplicateDimension(pDim
->GetName());
2714 pDim
->SetOrientation(nOrient
);
2715 pDim
->SetFunction(eFunc
);
2717 if( rFieldRef
.ReferenceType
== sheet::DataPilotFieldReferenceType::NONE
)
2718 pDim
->SetReferenceValue(nullptr);
2720 pDim
->SetReferenceValue(&rFieldRef
);
2722 else // set SubTotals
2724 pDim
->SetOrientation( nOrient
);
2726 std::vector
<ScGeneralFunction
> nSubTotalFuncs
;
2727 nSubTotalFuncs
.reserve(16);
2728 sal_uInt16 nMask
= 1;
2729 for (sal_uInt16 nBit
=0; nBit
<16; nBit
++)
2731 if ( nFuncs
& static_cast<PivotFunc
>(nMask
) )
2732 nSubTotalFuncs
.push_back( ScDataPilotConversion::FirstFunc( static_cast<PivotFunc
>(nMask
) ) );
2735 pDim
->SetSubTotals( std::move(nSubTotalFuncs
) );
2737 // ShowEmpty was implicit in old tables,
2738 // must be set for data layout dimension (not accessible in dialog)
2739 if ( nCol
== PIVOT_DATA_FIELD
)
2740 pDim
->SetShowEmpty( true );
2743 size_t nDimIndex
= rField
.nCol
;
2744 pDim
->RemoveLayoutName();
2745 pDim
->RemoveSubtotalName();
2746 if (nDimIndex
< rLabels
.size())
2748 const ScDPLabelData
& rLabel
= *rLabels
[nDimIndex
];
2749 if (!rLabel
.maLayoutName
.isEmpty())
2750 pDim
->SetLayoutName(rLabel
.maLayoutName
);
2751 if (!rLabel
.maSubtotalName
.isEmpty())
2752 pDim
->SetSubtotalName(rLabel
.maSubtotalName
);
2757 bool ScDPObject::IsOrientationAllowed( sheet::DataPilotFieldOrientation nOrient
, sal_Int32 nDimFlags
)
2759 bool bAllowed
= true;
2762 case sheet::DataPilotFieldOrientation_PAGE
:
2763 bAllowed
= ( nDimFlags
& sheet::DimensionFlags::NO_PAGE_ORIENTATION
) == 0;
2765 case sheet::DataPilotFieldOrientation_COLUMN
:
2766 bAllowed
= ( nDimFlags
& sheet::DimensionFlags::NO_COLUMN_ORIENTATION
) == 0;
2768 case sheet::DataPilotFieldOrientation_ROW
:
2769 bAllowed
= ( nDimFlags
& sheet::DimensionFlags::NO_ROW_ORIENTATION
) == 0;
2771 case sheet::DataPilotFieldOrientation_DATA
:
2772 bAllowed
= ( nDimFlags
& sheet::DimensionFlags::NO_DATA_ORIENTATION
) == 0;
2776 // allowed to remove from previous orientation
2782 bool ScDPObject::HasRegisteredSources()
2784 bool bFound
= false;
2786 uno::Reference
<lang::XMultiServiceFactory
> xManager
= comphelper::getProcessServiceFactory();
2787 uno::Reference
<container::XContentEnumerationAccess
> xEnAc( xManager
, uno::UNO_QUERY
);
2790 uno::Reference
<container::XEnumeration
> xEnum
= xEnAc
->createContentEnumeration(
2791 SCDPSOURCE_SERVICE
);
2792 if ( xEnum
.is() && xEnum
->hasMoreElements() )
2799 std::vector
<OUString
> ScDPObject::GetRegisteredSources()
2801 std::vector
<OUString
> aVec
;
2803 // use implementation names...
2805 uno::Reference
<lang::XMultiServiceFactory
> xManager
= comphelper::getProcessServiceFactory();
2806 uno::Reference
<container::XContentEnumerationAccess
> xEnAc( xManager
, uno::UNO_QUERY
);
2809 uno::Reference
<container::XEnumeration
> xEnum
= xEnAc
->createContentEnumeration(
2810 SCDPSOURCE_SERVICE
);
2813 while ( xEnum
->hasMoreElements() )
2815 uno::Any aAddInAny
= xEnum
->nextElement();
2816 // if ( aAddInAny.getReflection()->getTypeClass() == TypeClass_INTERFACE )
2818 uno::Reference
<uno::XInterface
> xIntFac
;
2819 aAddInAny
>>= xIntFac
;
2822 uno::Reference
<lang::XServiceInfo
> xInfo( xIntFac
, uno::UNO_QUERY
);
2825 OUString sName
= xInfo
->getImplementationName();
2826 aVec
.push_back( sName
);
2837 uno::Reference
<sheet::XDimensionsSupplier
> ScDPObject::CreateSource( const ScDPServiceDesc
& rDesc
)
2839 OUString aImplName
= rDesc
.aServiceName
;
2840 uno::Reference
<sheet::XDimensionsSupplier
> xRet
;
2842 uno::Reference
<lang::XMultiServiceFactory
> xManager
= comphelper::getProcessServiceFactory();
2843 uno::Reference
<container::XContentEnumerationAccess
> xEnAc(xManager
, uno::UNO_QUERY
);
2847 uno::Reference
<container::XEnumeration
> xEnum
=
2848 xEnAc
->createContentEnumeration(SCDPSOURCE_SERVICE
);
2852 while (xEnum
->hasMoreElements() && !xRet
.is())
2854 uno::Any aAddInAny
= xEnum
->nextElement();
2855 uno::Reference
<uno::XInterface
> xIntFac
;
2856 aAddInAny
>>= xIntFac
;
2860 uno::Reference
<lang::XServiceInfo
> xInfo(xIntFac
, uno::UNO_QUERY
);
2861 if (!xInfo
.is() || xInfo
->getImplementationName() != aImplName
)
2866 // #i113160# try XSingleComponentFactory in addition to (old) XSingleServiceFactory,
2867 // passing the context to the component (see ScUnoAddInCollection::Initialize)
2869 uno::Reference
<uno::XInterface
> xInterface
;
2870 uno::Reference
<uno::XComponentContext
> xCtx(
2871 comphelper::getComponentContext(xManager
));
2872 uno::Reference
<lang::XSingleComponentFactory
> xCFac( xIntFac
, uno::UNO_QUERY
);
2874 xInterface
= xCFac
->createInstanceWithContext(xCtx
);
2876 if (!xInterface
.is())
2878 uno::Reference
<lang::XSingleServiceFactory
> xFac( xIntFac
, uno::UNO_QUERY
);
2880 xInterface
= xFac
->createInstance();
2883 uno::Reference
<lang::XInitialization
> xInit( xInterface
, uno::UNO_QUERY
);
2887 uno::Sequence
<uno::Any
> aSeq(4);
2888 uno::Any
* pArray
= aSeq
.getArray();
2889 pArray
[0] <<= rDesc
.aParSource
;
2890 pArray
[1] <<= rDesc
.aParName
;
2891 pArray
[2] <<= rDesc
.aParUser
;
2892 pArray
[3] <<= rDesc
.aParPass
;
2893 xInit
->initialize( aSeq
);
2895 xRet
.set( xInterface
, uno::UNO_QUERY
);
2897 catch(uno::Exception
&)
2905 #if DUMP_PIVOT_TABLE
2907 void ScDPObject::Dump() const
2913 mpTableData
->Dump();
2916 void ScDPObject::DumpCache() const
2921 const ScDPCache
&rCache
= mpTableData
->GetCacheTable().getCache();
2927 ScDPCollection::SheetCaches::SheetCaches(ScDocument
& rDoc
) : mrDoc(rDoc
) {}
2931 struct FindInvalidRange
2933 bool operator() (const ScRange
& r
) const
2935 return !r
.IsValid();
2939 void setGroupItemsToCache( ScDPCache
& rCache
, const o3tl::sorted_vector
<ScDPObject
*>& rRefs
)
2941 // Go through all referencing pivot tables, and re-fill the group dimension info.
2942 for (const ScDPObject
* pObj
: rRefs
)
2944 const ScDPSaveData
* pSave
= pObj
->GetSaveData();
2948 const ScDPDimensionSaveData
* pGroupDims
= pSave
->GetExistingDimensionData();
2952 pGroupDims
->WriteToCache(rCache
);
2958 bool ScDPCollection::SheetCaches::hasCache(const ScRange
& rRange
) const
2960 RangeIndexType::const_iterator it
= std::find(maRanges
.begin(), maRanges
.end(), rRange
);
2961 if (it
== maRanges
.end())
2965 size_t nIndex
= std::distance(maRanges
.begin(), it
);
2966 CachesType::const_iterator
const itCache
= m_Caches
.find(nIndex
);
2967 return itCache
!= m_Caches
.end();
2970 const ScDPCache
* ScDPCollection::SheetCaches::getCache(const ScRange
& rRange
, const ScDPDimensionSaveData
* pDimData
)
2972 RangeIndexType::iterator it
= std::find(maRanges
.begin(), maRanges
.end(), rRange
);
2973 if (it
!= maRanges
.end())
2976 size_t nIndex
= std::distance(maRanges
.begin(), it
);
2977 CachesType::iterator
const itCache
= m_Caches
.find(nIndex
);
2978 if (itCache
== m_Caches
.end())
2980 OSL_FAIL("Cache pool and index pool out-of-sync !!!");
2986 (itCache
->second
)->ClearGroupFields();
2987 pDimData
->WriteToCache(*itCache
->second
);
2990 return itCache
->second
.get();
2993 // Not cached. Create a new cache.
2994 ::std::unique_ptr
<ScDPCache
> pCache(new ScDPCache(mrDoc
));
2995 pCache
->InitFromDoc(mrDoc
, rRange
);
2997 pDimData
->WriteToCache(*pCache
);
2999 // Get the smallest available range index.
3000 it
= std::find_if(maRanges
.begin(), maRanges
.end(), FindInvalidRange());
3002 size_t nIndex
= maRanges
.size();
3003 if (it
== maRanges
.end())
3005 // All range indices are valid. Append a new index.
3006 maRanges
.push_back(rRange
);
3010 // Slot with invalid range. Re-use this slot.
3012 nIndex
= std::distance(maRanges
.begin(), it
);
3015 const ScDPCache
* p
= pCache
.get();
3016 m_Caches
.insert(std::make_pair(nIndex
, std::move(pCache
)));
3020 ScDPCache
* ScDPCollection::SheetCaches::getExistingCache(const ScRange
& rRange
)
3022 RangeIndexType::iterator it
= std::find(maRanges
.begin(), maRanges
.end(), rRange
);
3023 if (it
== maRanges
.end())
3028 size_t nIndex
= std::distance(maRanges
.begin(), it
);
3029 CachesType::iterator
const itCache
= m_Caches
.find(nIndex
);
3030 if (itCache
== m_Caches
.end())
3032 OSL_FAIL("Cache pool and index pool out-of-sync !!!");
3036 return itCache
->second
.get();
3039 const ScDPCache
* ScDPCollection::SheetCaches::getExistingCache(const ScRange
& rRange
) const
3041 RangeIndexType::const_iterator it
= std::find(maRanges
.begin(), maRanges
.end(), rRange
);
3042 if (it
== maRanges
.end())
3047 size_t nIndex
= std::distance(maRanges
.begin(), it
);
3048 CachesType::const_iterator
const itCache
= m_Caches
.find(nIndex
);
3049 if (itCache
== m_Caches
.end())
3051 OSL_FAIL("Cache pool and index pool out-of-sync !!!");
3055 return itCache
->second
.get();
3058 size_t ScDPCollection::SheetCaches::size() const
3060 return m_Caches
.size();
3063 void ScDPCollection::SheetCaches::updateReference(
3064 UpdateRefMode eMode
, const ScRange
& r
, SCCOL nDx
, SCROW nDy
, SCTAB nDz
)
3066 if (maRanges
.empty())
3070 for (ScRange
& rKeyRange
: maRanges
)
3072 SCCOL nCol1
= rKeyRange
.aStart
.Col();
3073 SCROW nRow1
= rKeyRange
.aStart
.Row();
3074 SCTAB nTab1
= rKeyRange
.aStart
.Tab();
3075 SCCOL nCol2
= rKeyRange
.aEnd
.Col();
3076 SCROW nRow2
= rKeyRange
.aEnd
.Row();
3077 SCTAB nTab2
= rKeyRange
.aEnd
.Tab();
3079 ScRefUpdateRes eRes
= ScRefUpdate::Update(
3081 r
.aStart
.Col(), r
.aStart
.Row(), r
.aStart
.Tab(),
3082 r
.aEnd
.Col(), r
.aEnd
.Row(), r
.aEnd
.Tab(), nDx
, nDy
, nDz
,
3083 nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3085 if (eRes
!= UR_NOTHING
)
3088 ScRange
aNew(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3094 void ScDPCollection::SheetCaches::updateCache(const ScRange
& rRange
, o3tl::sorted_vector
<ScDPObject
*>& rRefs
)
3096 RangeIndexType::iterator it
= std::find(maRanges
.begin(), maRanges
.end(), rRange
);
3097 if (it
== maRanges
.end())
3099 // Not cached. Nothing to do.
3104 size_t nIndex
= std::distance(maRanges
.begin(), it
);
3105 CachesType::iterator
const itCache
= m_Caches
.find(nIndex
);
3106 if (itCache
== m_Caches
.end())
3108 OSL_FAIL("Cache pool and index pool out-of-sync !!!");
3113 ScDPCache
& rCache
= *itCache
->second
;
3115 // Update the cache with new cell values. This will clear all group dimension info.
3116 rCache
.InitFromDoc(mrDoc
, rRange
);
3118 o3tl::sorted_vector
<ScDPObject
*> aRefs(rCache
.GetAllReferences());
3121 // Make sure to re-populate the group dimension info.
3122 setGroupItemsToCache(rCache
, rRefs
);
3125 bool ScDPCollection::SheetCaches::remove(const ScDPCache
* p
)
3127 CachesType::iterator it
= std::find_if(m_Caches
.begin(), m_Caches
.end(),
3128 [&p
](const CachesType::value_type
& rEntry
) { return rEntry
.second
.get() == p
; });
3129 if (it
!= m_Caches
.end())
3131 size_t idx
= it
->first
;
3133 maRanges
[idx
].SetInvalid();
3139 const std::vector
<ScRange
>& ScDPCollection::SheetCaches::getAllRanges() const
3144 ScDPCollection::NameCaches::NameCaches(ScDocument
& rDoc
) : mrDoc(rDoc
) {}
3146 bool ScDPCollection::NameCaches::hasCache(const OUString
& rName
) const
3148 return m_Caches
.count(rName
) != 0;
3151 const ScDPCache
* ScDPCollection::NameCaches::getCache(
3152 const OUString
& rName
, const ScRange
& rRange
, const ScDPDimensionSaveData
* pDimData
)
3154 CachesType::const_iterator
const itr
= m_Caches
.find(rName
);
3155 if (itr
!= m_Caches
.end())
3157 return itr
->second
.get();
3159 ::std::unique_ptr
<ScDPCache
> pCache(new ScDPCache(mrDoc
));
3160 pCache
->InitFromDoc(mrDoc
, rRange
);
3162 pDimData
->WriteToCache(*pCache
);
3164 const ScDPCache
*const p
= pCache
.get();
3165 m_Caches
.insert(std::make_pair(rName
, std::move(pCache
)));
3169 ScDPCache
* ScDPCollection::NameCaches::getExistingCache(const OUString
& rName
)
3171 CachesType::iterator
const itr
= m_Caches
.find(rName
);
3172 return itr
!= m_Caches
.end() ? itr
->second
.get() : nullptr;
3175 size_t ScDPCollection::NameCaches::size() const
3177 return m_Caches
.size();
3180 void ScDPCollection::NameCaches::updateCache(
3181 const OUString
& rName
, const ScRange
& rRange
, o3tl::sorted_vector
<ScDPObject
*>& rRefs
)
3183 CachesType::iterator
const itr
= m_Caches
.find(rName
);
3184 if (itr
== m_Caches
.end())
3190 ScDPCache
& rCache
= *itr
->second
;
3191 // Update the cache with new cell values. This will clear all group dimension info.
3192 rCache
.InitFromDoc(mrDoc
, rRange
);
3194 o3tl::sorted_vector
<ScDPObject
*> aRefs(rCache
.GetAllReferences());
3197 // Make sure to re-populate the group dimension info.
3198 setGroupItemsToCache(rCache
, rRefs
);
3201 bool ScDPCollection::NameCaches::remove(const ScDPCache
* p
)
3203 CachesType::iterator it
= std::find_if(m_Caches
.begin(), m_Caches
.end(),
3204 [&p
](const CachesType::value_type
& rEntry
) { return rEntry
.second
.get() == p
; });
3205 if (it
!= m_Caches
.end())
3213 ScDPCollection::DBType::DBType(sal_Int32 nSdbType
, OUString aDBName
, OUString aCommand
) :
3214 mnSdbType(nSdbType
), maDBName(std::move(aDBName
)), maCommand(std::move(aCommand
)) {}
3216 bool ScDPCollection::DBType::less::operator() (const DBType
& left
, const DBType
& right
) const
3218 return left
< right
;
3221 ScDPCollection::DBCaches::DBCaches(ScDocument
& rDoc
) : mrDoc(rDoc
) {}
3223 bool ScDPCollection::DBCaches::hasCache(sal_Int32 nSdbType
, const OUString
& rDBName
, const OUString
& rCommand
) const
3225 DBType
aType(nSdbType
, rDBName
, rCommand
);
3226 CachesType::const_iterator
const itr
= m_Caches
.find(aType
);
3227 return itr
!= m_Caches
.end();
3230 const ScDPCache
* ScDPCollection::DBCaches::getCache(
3231 sal_Int32 nSdbType
, const OUString
& rDBName
, const OUString
& rCommand
,
3232 const ScDPDimensionSaveData
* pDimData
)
3234 DBType
aType(nSdbType
, rDBName
, rCommand
);
3235 CachesType::const_iterator
const itr
= m_Caches
.find(aType
);
3236 if (itr
!= m_Caches
.end())
3238 return itr
->second
.get();
3240 uno::Reference
<sdbc::XRowSet
> xRowSet
= createRowSet(nSdbType
, rDBName
, rCommand
);
3244 ::std::unique_ptr
<ScDPCache
> pCache(new ScDPCache(mrDoc
));
3245 SvNumberFormatter
aFormat( comphelper::getProcessComponentContext(), ScGlobal::eLnge
);
3246 DBConnector
aDB(*pCache
, xRowSet
, aFormat
.GetNullDate());
3250 if (!pCache
->InitFromDataBase(aDB
))
3252 // initialization failed.
3253 comphelper::disposeComponent(xRowSet
);
3258 pDimData
->WriteToCache(*pCache
);
3260 ::comphelper::disposeComponent(xRowSet
);
3261 const ScDPCache
* p
= pCache
.get();
3262 m_Caches
.insert(std::make_pair(aType
, std::move(pCache
)));
3266 ScDPCache
* ScDPCollection::DBCaches::getExistingCache(
3267 sal_Int32 nSdbType
, const OUString
& rDBName
, const OUString
& rCommand
)
3269 DBType
aType(nSdbType
, rDBName
, rCommand
);
3270 CachesType::iterator
const itr
= m_Caches
.find(aType
);
3271 return itr
!= m_Caches
.end() ? itr
->second
.get() : nullptr;
3274 uno::Reference
<sdbc::XRowSet
> ScDPCollection::DBCaches::createRowSet(
3275 sal_Int32 nSdbType
, const OUString
& rDBName
, const OUString
& rCommand
)
3277 uno::Reference
<sdbc::XRowSet
> xRowSet
;
3280 xRowSet
.set(comphelper::getProcessServiceFactory()->createInstance(
3284 uno::Reference
<beans::XPropertySet
> xRowProp(xRowSet
, UNO_QUERY
);
3285 OSL_ENSURE( xRowProp
.is(), "can't get RowSet" );
3292 // set source parameters
3294 xRowProp
->setPropertyValue( SC_DBPROP_DATASOURCENAME
, Any(rDBName
) );
3295 xRowProp
->setPropertyValue( SC_DBPROP_COMMAND
, Any(rCommand
) );
3296 xRowProp
->setPropertyValue( SC_DBPROP_COMMANDTYPE
, Any(nSdbType
) );
3298 uno::Reference
<sdb::XCompletedExecution
> xExecute( xRowSet
, uno::UNO_QUERY
);
3299 if ( xExecute
.is() )
3301 uno::Reference
<task::XInteractionHandler
> xHandler(
3302 task::InteractionHandler::createWithParent(comphelper::getProcessComponentContext(), nullptr),
3303 uno::UNO_QUERY_THROW
);
3304 xExecute
->executeWithCompletion( xHandler
);
3311 catch ( const sdbc::SQLException
& rError
)
3313 //! store error message
3314 std::unique_ptr
<weld::MessageDialog
> xInfoBox(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(),
3315 VclMessageType::Info
, VclButtonsType::Ok
,
3319 catch ( uno::Exception
& )
3321 TOOLS_WARN_EXCEPTION( "sc", "Unexpected exception in database");
3328 void ScDPCollection::DBCaches::updateCache(
3329 sal_Int32 nSdbType
, const OUString
& rDBName
, const OUString
& rCommand
,
3330 o3tl::sorted_vector
<ScDPObject
*>& rRefs
)
3332 DBType
aType(nSdbType
, rDBName
, rCommand
);
3333 CachesType::iterator
const it
= m_Caches
.find(aType
);
3334 if (it
== m_Caches
.end())
3341 ScDPCache
& rCache
= *it
->second
;
3343 uno::Reference
<sdbc::XRowSet
> xRowSet
= createRowSet(nSdbType
, rDBName
, rCommand
);
3350 SvNumberFormatter
aFormat( comphelper::getProcessComponentContext(), ScGlobal::eLnge
);
3351 DBConnector
aDB(rCache
, xRowSet
, aFormat
.GetNullDate());
3355 if (!rCache
.InitFromDataBase(aDB
))
3357 // initialization failed.
3359 comphelper::disposeComponent(xRowSet
);
3363 comphelper::disposeComponent(xRowSet
);
3364 o3tl::sorted_vector
<ScDPObject
*> aRefs(rCache
.GetAllReferences());
3367 // Make sure to re-populate the group dimension info.
3368 setGroupItemsToCache(rCache
, rRefs
);
3371 bool ScDPCollection::DBCaches::remove(const ScDPCache
* p
)
3373 CachesType::iterator it
= std::find_if(m_Caches
.begin(), m_Caches
.end(),
3374 [&p
](const CachesType::value_type
& rEntry
) { return rEntry
.second
.get() == p
; });
3375 if (it
!= m_Caches
.end())
3383 ScDPCollection::ScDPCollection(ScDocument
& rDocument
) :
3385 maSheetCaches(rDocument
),
3386 maNameCaches(rDocument
),
3387 maDBCaches(rDocument
)
3391 ScDPCollection::ScDPCollection(const ScDPCollection
& r
) :
3393 maSheetCaches(r
.mrDoc
),
3394 maNameCaches(r
.mrDoc
),
3399 ScDPCollection::~ScDPCollection()
3407 * Unary predicate to match DP objects by the table ID.
3413 explicit MatchByTable(SCTAB nTab
) : mnTab(nTab
) {}
3415 bool operator() (const std::unique_ptr
<ScDPObject
>& rObj
) const
3417 return rObj
->GetOutRange().aStart
.Tab() == mnTab
;
3423 TranslateId
ScDPCollection::ReloadCache(const ScDPObject
* pDPObj
, o3tl::sorted_vector
<ScDPObject
*>& rRefs
)
3426 return STR_ERR_DATAPILOTSOURCE
;
3428 if (pDPObj
->IsSheetData())
3430 // data source is internal sheet.
3431 const ScSheetSourceDesc
* pDesc
= pDPObj
->GetSheetDesc();
3433 return STR_ERR_DATAPILOTSOURCE
;
3435 TranslateId pErrId
= pDesc
->CheckSourceRange();
3439 if (pDesc
->HasRangeName())
3441 // cache by named range
3442 ScDPCollection::NameCaches
& rCaches
= GetNameCaches();
3443 if (rCaches
.hasCache(pDesc
->GetRangeName()))
3444 rCaches
.updateCache(pDesc
->GetRangeName(), pDesc
->GetSourceRange(), rRefs
);
3447 // Not cached yet. Collect all tables that use this named
3448 // range as data source.
3449 GetAllTables(pDesc
->GetRangeName(), rRefs
);
3454 // cache by cell range
3455 ScDPCollection::SheetCaches
& rCaches
= GetSheetCaches();
3456 if (rCaches
.hasCache(pDesc
->GetSourceRange()))
3457 rCaches
.updateCache(pDesc
->GetSourceRange(), rRefs
);
3460 // Not cached yet. Collect all tables that use this range as
3462 GetAllTables(pDesc
->GetSourceRange(), rRefs
);
3466 else if (pDPObj
->IsImportData())
3468 // data source is external database.
3469 const ScImportSourceDesc
* pDesc
= pDPObj
->GetImportSourceDesc();
3471 return STR_ERR_DATAPILOTSOURCE
;
3473 ScDPCollection::DBCaches
& rCaches
= GetDBCaches();
3474 if (rCaches
.hasCache(pDesc
->GetCommandType(), pDesc
->aDBName
, pDesc
->aObject
))
3475 rCaches
.updateCache(
3476 pDesc
->GetCommandType(), pDesc
->aDBName
, pDesc
->aObject
, rRefs
);
3479 // Not cached yet. Collect all tables that use this range as
3481 GetAllTables(pDesc
->GetCommandType(), pDesc
->aDBName
, pDesc
->aObject
, rRefs
);
3487 bool ScDPCollection::ReloadGroupsInCache(const ScDPObject
* pDPObj
, o3tl::sorted_vector
<ScDPObject
*>& rRefs
)
3492 const ScDPSaveData
* pSaveData
= pDPObj
->GetSaveData();
3496 // Note: Unlike reloading cache, when modifying the group dimensions the
3497 // cache may not have all its references when this method is called.
3498 // Therefore, we need to always call GetAllTables to get its correct
3499 // references even when the cache exists. This may become a non-issue
3500 // if/when we implement loading and saving of pivot caches.
3502 ScDPCache
* pCache
= nullptr;
3504 if (pDPObj
->IsSheetData())
3506 // data source is internal sheet.
3507 const ScSheetSourceDesc
* pDesc
= pDPObj
->GetSheetDesc();
3511 if (pDesc
->HasRangeName())
3513 // cache by named range
3514 ScDPCollection::NameCaches
& rCaches
= GetNameCaches();
3515 if (rCaches
.hasCache(pDesc
->GetRangeName()))
3516 pCache
= rCaches
.getExistingCache(pDesc
->GetRangeName());
3519 // Not cached yet. Cache the source dimensions. Groups will
3521 pCache
= const_cast<ScDPCache
*>(
3522 rCaches
.getCache(pDesc
->GetRangeName(), pDesc
->GetSourceRange(), nullptr));
3524 GetAllTables(pDesc
->GetRangeName(), rRefs
);
3528 // cache by cell range
3529 ScDPCollection::SheetCaches
& rCaches
= GetSheetCaches();
3530 if (rCaches
.hasCache(pDesc
->GetSourceRange()))
3531 pCache
= rCaches
.getExistingCache(pDesc
->GetSourceRange());
3534 // Not cached yet. Cache the source dimensions. Groups will
3536 pCache
= const_cast<ScDPCache
*>(
3537 rCaches
.getCache(pDesc
->GetSourceRange(), nullptr));
3539 GetAllTables(pDesc
->GetSourceRange(), rRefs
);
3542 else if (pDPObj
->IsImportData())
3544 // data source is external database.
3545 const ScImportSourceDesc
* pDesc
= pDPObj
->GetImportSourceDesc();
3549 ScDPCollection::DBCaches
& rCaches
= GetDBCaches();
3550 if (rCaches
.hasCache(pDesc
->GetCommandType(), pDesc
->aDBName
, pDesc
->aObject
))
3551 pCache
= rCaches
.getExistingCache(
3552 pDesc
->GetCommandType(), pDesc
->aDBName
, pDesc
->aObject
);
3555 // Not cached yet. Cache the source dimensions. Groups will
3557 pCache
= const_cast<ScDPCache
*>(
3558 rCaches
.getCache(pDesc
->GetCommandType(), pDesc
->aDBName
, pDesc
->aObject
, nullptr));
3560 GetAllTables(pDesc
->GetCommandType(), pDesc
->aDBName
, pDesc
->aObject
, rRefs
);
3566 // Clear the existing group/field data from the cache, and rebuild it from the
3568 pCache
->ClearAllFields();
3569 const ScDPDimensionSaveData
* pDimData
= pSaveData
->GetExistingDimensionData();
3571 pDimData
->WriteToCache(*pCache
);
3575 bool ScDPCollection::GetReferenceGroups(const ScDPObject
& rDPObj
, const ScDPDimensionSaveData
** pGroups
) const
3577 for (const std::unique_ptr
<ScDPObject
>& aTable
: maTables
)
3579 const ScDPObject
& rRefObj
= *aTable
;
3581 if (&rRefObj
== &rDPObj
)
3584 if (rDPObj
.IsSheetData()){
3585 if(!rRefObj
.IsSheetData())
3588 const ScSheetSourceDesc
* pDesc
= rDPObj
.GetSheetDesc();
3589 const ScSheetSourceDesc
* pRefDesc
= rRefObj
.GetSheetDesc();
3590 if (pDesc
== nullptr || pRefDesc
== nullptr)
3593 if (pDesc
->HasRangeName())
3595 if (!pRefDesc
->HasRangeName())
3598 if (pDesc
->GetRangeName() == pRefDesc
->GetRangeName())
3600 *pGroups
= rRefObj
.GetSaveData()->GetExistingDimensionData();
3606 if (pRefDesc
->HasRangeName())
3609 if (pDesc
->GetSourceRange() == pRefDesc
->GetSourceRange())
3611 *pGroups
= rRefObj
.GetSaveData()->GetExistingDimensionData();
3616 else if (rDPObj
.IsImportData())
3618 if (!rRefObj
.IsImportData ())
3621 const ScImportSourceDesc
* pDesc
= rDPObj
.GetImportSourceDesc();
3622 const ScImportSourceDesc
* pRefDesc
= rRefObj
.GetImportSourceDesc();
3623 if (pDesc
== nullptr || pRefDesc
== nullptr)
3626 if (pDesc
->aDBName
== pRefDesc
->aDBName
&&
3627 pDesc
->aObject
== pRefDesc
->aObject
&&
3628 pDesc
->GetCommandType() == pRefDesc
->GetCommandType())
3630 *pGroups
= rRefObj
.GetSaveData()->GetExistingDimensionData();
3640 void ScDPCollection::DeleteOnTab( SCTAB nTab
)
3642 std::erase_if(maTables
, MatchByTable(nTab
));
3645 void ScDPCollection::UpdateReference( UpdateRefMode eUpdateRefMode
,
3646 const ScRange
& r
, SCCOL nDx
, SCROW nDy
, SCTAB nDz
)
3648 for (auto& rxTable
: maTables
)
3649 rxTable
->UpdateReference(eUpdateRefMode
, r
, nDx
, nDy
, nDz
);
3651 // Update the source ranges of the caches.
3652 maSheetCaches
.updateReference(eUpdateRefMode
, r
, nDx
, nDy
, nDz
);
3655 void ScDPCollection::CopyToTab( SCTAB nOld
, SCTAB nNew
)
3658 for (const auto& rxTable
: maTables
)
3660 const ScDPObject
& rObj
= *rxTable
;
3661 ScRange maOutputRange
= rObj
.GetOutRange();
3662 if (maOutputRange
.aStart
.Tab() != nOld
)
3665 ScAddress
& start
= maOutputRange
.aStart
;
3666 ScAddress
& end
= maOutputRange
.aEnd
;
3669 ScDPObject
* pNew
= new ScDPObject(rObj
);
3670 pNew
->SetOutRange(maOutputRange
);
3671 mrDoc
.ApplyFlagsTab(start
.Col(), start
.Row(), end
.Col(), end
.Row(), start
.Tab(), ScMF::DpTable
);
3672 aAdded
.push_back(std::unique_ptr
<ScDPObject
>(pNew
));
3675 std::move(aAdded
.begin(), aAdded
.end(), std::back_inserter(maTables
));
3678 bool ScDPCollection::RefsEqual( const ScDPCollection
& r
) const
3680 return std::equal(maTables
.begin(), maTables
.end(), r
.maTables
.begin(), r
.maTables
.end(),
3681 [](const TablesType::value_type
& a
, const TablesType::value_type
& b
) { return a
->RefsEqual(*b
); });
3684 void ScDPCollection::WriteRefsTo( ScDPCollection
& r
) const
3686 if ( maTables
.size() == r
.maTables
.size() )
3688 //TODO: assert equal names?
3689 TablesType::iterator itr2
= r
.maTables
.begin();
3690 for (const auto& rxTable
: maTables
)
3692 rxTable
->WriteRefsTo(**itr2
);
3698 // #i8180# If data pilot tables were deleted with their sheet,
3699 // this collection contains extra entries that must be restored.
3700 // Matching objects are found by their names.
3701 size_t nSrcSize
= maTables
.size();
3702 size_t nDestSize
= r
.maTables
.size();
3703 OSL_ENSURE( nSrcSize
>= nDestSize
, "WriteRefsTo: missing entries in document" );
3704 for (size_t nSrcPos
= 0; nSrcPos
< nSrcSize
; ++nSrcPos
)
3706 const ScDPObject
& rSrcObj
= *maTables
[nSrcPos
];
3707 const OUString
& aName
= rSrcObj
.GetName();
3708 bool bFound
= false;
3709 for (size_t nDestPos
= 0; nDestPos
< nDestSize
&& !bFound
; ++nDestPos
)
3711 ScDPObject
& rDestObj
= *r
.maTables
[nDestPos
];
3712 if (rDestObj
.GetName() == aName
)
3714 rSrcObj
.WriteRefsTo(rDestObj
); // found object, copy refs
3721 // none found, re-insert deleted object (see ScUndoDataPilot::Undo)
3722 r
.InsertNewTable(std::make_unique
<ScDPObject
>(rSrcObj
));
3725 OSL_ENSURE( maTables
.size() == r
.maTables
.size(), "WriteRefsTo: couldn't restore all entries" );
3729 size_t ScDPCollection::GetCount() const
3731 return maTables
.size();
3734 ScDPObject
& ScDPCollection::operator [](size_t nIndex
)
3736 return *maTables
[nIndex
];
3739 const ScDPObject
& ScDPCollection::operator [](size_t nIndex
) const
3741 return *maTables
[nIndex
];
3744 ScDPObject
* ScDPCollection::GetByName(std::u16string_view rName
) const
3746 for (std::unique_ptr
<ScDPObject
> const & pObject
: maTables
)
3748 if (pObject
->GetName() == rName
)
3749 return pObject
.get();
3755 OUString
ScDPCollection::CreateNewName() const
3757 size_t n
= maTables
.size();
3758 for (size_t nAdd
= 0; nAdd
<= n
; ++nAdd
) // nCount+1 tries
3760 OUString aNewName
= "DataPilot" + OUString::number(1 + nAdd
);
3761 if (std::none_of(maTables
.begin(), maTables
.end(),
3762 [&aNewName
](const TablesType::value_type
& rxObj
) { return rxObj
->GetName() == aNewName
; }))
3763 return aNewName
; // found unused Name
3765 return OUString(); // should not happen
3768 void ScDPCollection::FreeTable(const ScDPObject
* pDPObject
)
3770 const ScRange
& rOutRange
= pDPObject
->GetOutRange();
3771 const ScAddress
& s
= rOutRange
.aStart
;
3772 const ScAddress
& e
= rOutRange
.aEnd
;
3773 mrDoc
.RemoveFlagsTab(s
.Col(), s
.Row(), e
.Col(), e
.Row(), s
.Tab(), ScMF::DpTable
);
3775 auto funcRemoveCondition
= [pDPObject
] (std::unique_ptr
<ScDPObject
> const & pCurrent
)
3777 return pCurrent
.get() == pDPObject
;
3780 std::erase_if(maTables
, funcRemoveCondition
);
3783 ScDPObject
* ScDPCollection::InsertNewTable(std::unique_ptr
<ScDPObject
> pDPObj
)
3785 const ScRange
& rOutRange
= pDPObj
->GetOutRange();
3786 const ScAddress
& s
= rOutRange
.aStart
;
3787 const ScAddress
& e
= rOutRange
.aEnd
;
3788 mrDoc
.ApplyFlagsTab(s
.Col(), s
.Row(), e
.Col(), e
.Row(), s
.Tab(), ScMF::DpTable
);
3790 maTables
.push_back(std::move(pDPObj
));
3791 return maTables
.back().get();
3794 bool ScDPCollection::HasTable(const ScDPObject
* pDPObj
) const
3796 for (const std::unique_ptr
<ScDPObject
>& aTable
: maTables
)
3798 if (aTable
.get() == pDPObj
)
3806 ScDPCollection::SheetCaches
& ScDPCollection::GetSheetCaches()
3808 return maSheetCaches
;
3811 const ScDPCollection::SheetCaches
& ScDPCollection::GetSheetCaches() const
3813 return maSheetCaches
;
3816 ScDPCollection::NameCaches
& ScDPCollection::GetNameCaches()
3818 return maNameCaches
;
3821 const ScDPCollection::NameCaches
& ScDPCollection::GetNameCaches() const
3823 return maNameCaches
;
3826 ScDPCollection::DBCaches
& ScDPCollection::GetDBCaches()
3831 const ScDPCollection::DBCaches
& ScDPCollection::GetDBCaches() const
3836 ScRangeList
ScDPCollection::GetAllTableRanges( SCTAB nTab
) const
3838 return std::for_each(maTables
.begin(), maTables
.end(), AccumulateOutputRanges(nTab
)).getRanges();
3841 bool ScDPCollection::IntersectsTableByColumns( SCCOL nCol1
, SCCOL nCol2
, SCROW nRow
, SCTAB nTab
) const
3843 return std::any_of(maTables
.begin(), maTables
.end(), FindIntersectingTableByColumns(nCol1
, nCol2
, nRow
, nTab
));
3846 bool ScDPCollection::IntersectsTableByRows( SCCOL nCol
, SCROW nRow1
, SCROW nRow2
, SCTAB nTab
) const
3848 return std::any_of(maTables
.begin(), maTables
.end(), FindIntersectingTableByRows(nCol
, nRow1
, nRow2
, nTab
));
3851 bool ScDPCollection::HasTable( const ScRange
& rRange
) const
3853 return std::any_of(maTables
.begin(), maTables
.end(), FindIntersectingTable(rRange
));
3856 #if DEBUG_PIVOT_TABLE
3862 void operator() (const std::unique_ptr
<ScDPObject
>& rObj
) const
3864 cout
<< "-- '" << rObj
->GetName() << "'" << endl
;
3865 ScDPSaveData
* pSaveData
= rObj
->GetSaveData();
3871 cout
<< endl
; // blank line
3877 void ScDPCollection::DumpTables() const
3879 std::for_each(maTables
.begin(), maTables
.end(), DumpTable());
3884 void ScDPCollection::RemoveCache(const ScDPCache
* pCache
)
3886 if (maSheetCaches
.remove(pCache
))
3887 // sheet cache removed.
3890 if (maNameCaches
.remove(pCache
))
3891 // named range cache removed.
3894 if (maDBCaches
.remove(pCache
))
3895 // database cache removed.
3899 void ScDPCollection::GetAllTables(const ScRange
& rSrcRange
, o3tl::sorted_vector
<ScDPObject
*>& rRefs
) const
3901 o3tl::sorted_vector
<ScDPObject
*> aRefs
;
3902 for (const auto& rxTable
: maTables
)
3904 const ScDPObject
& rObj
= *rxTable
;
3905 if (!rObj
.IsSheetData())
3906 // Source is not a sheet range.
3909 const ScSheetSourceDesc
* pDesc
= rObj
.GetSheetDesc();
3913 if (pDesc
->HasRangeName())
3914 // This table has a range name as its source.
3917 if (pDesc
->GetSourceRange() != rSrcRange
)
3918 // Different source range.
3921 aRefs
.insert(const_cast<ScDPObject
*>(&rObj
));
3927 void ScDPCollection::GetAllTables(std::u16string_view rSrcName
, o3tl::sorted_vector
<ScDPObject
*>& rRefs
) const
3929 o3tl::sorted_vector
<ScDPObject
*> aRefs
;
3930 for (const auto& rxTable
: maTables
)
3932 const ScDPObject
& rObj
= *rxTable
;
3933 if (!rObj
.IsSheetData())
3934 // Source is not a sheet range.
3937 const ScSheetSourceDesc
* pDesc
= rObj
.GetSheetDesc();
3941 if (!pDesc
->HasRangeName())
3942 // This table probably has a sheet range as its source.
3945 if (pDesc
->GetRangeName() != rSrcName
)
3946 // Different source name.
3949 aRefs
.insert(const_cast<ScDPObject
*>(&rObj
));
3955 void ScDPCollection::GetAllTables(
3956 sal_Int32 nSdbType
, std::u16string_view rDBName
, std::u16string_view rCommand
,
3957 o3tl::sorted_vector
<ScDPObject
*>& rRefs
) const
3959 o3tl::sorted_vector
<ScDPObject
*> aRefs
;
3960 for (const auto& rxTable
: maTables
)
3962 const ScDPObject
& rObj
= *rxTable
;
3963 if (!rObj
.IsImportData())
3964 // Source data is not a database.
3967 const ScImportSourceDesc
* pDesc
= rObj
.GetImportSourceDesc();
3971 if (pDesc
->aDBName
!= rDBName
|| pDesc
->aObject
!= rCommand
|| pDesc
->GetCommandType() != nSdbType
)
3972 // Different database source.
3975 aRefs
.insert(const_cast<ScDPObject
*>(&rObj
));
3981 bool operator<(const ScDPCollection::DBType
& left
, const ScDPCollection::DBType
& right
)
3983 if (left
.mnSdbType
!= right
.mnSdbType
)
3984 return left
.mnSdbType
< right
.mnSdbType
;
3986 if (left
.maDBName
!= right
.maDBName
)
3987 return left
.maDBName
< right
.maDBName
;
3989 return left
.maCommand
< right
.maCommand
;
3992 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */