fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / core / data / dpobject.cxx
blobab982c4ef6c8fb3107f2c6b32320c6455ad66b80
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include "dpobject.hxx"
21 #include "dptabsrc.hxx"
22 #include "dpsave.hxx"
23 #include "dpdimsave.hxx"
24 #include "dpoutput.hxx"
25 #include "dpshttab.hxx"
26 #include "dpsdbtab.hxx"
27 #include "dpgroup.hxx"
28 #include "document.hxx"
29 #include "rechead.hxx"
30 #include "pivot.hxx"
31 #include "dapiuno.hxx"
32 #include "miscuno.hxx"
33 #include "scerrors.hxx"
34 #include "refupdat.hxx"
35 #include "scresid.hxx"
36 #include "sc.hrc"
37 #include "attrib.hxx"
38 #include "scitems.hxx"
39 #include "unonames.hxx"
40 #include "dpglobal.hxx"
41 #include "globstr.hrc"
42 #include "queryentry.hxx"
43 #include "dputil.hxx"
45 #include <com/sun/star/beans/XPropertySet.hpp>
46 #include <com/sun/star/sdb/XCompletedExecution.hpp>
47 #include <com/sun/star/sdbc/DataType.hpp>
48 #include <com/sun/star/sdbc/XResultSetMetaData.hpp>
49 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
50 #include <com/sun/star/sdbc/XRow.hpp>
51 #include <com/sun/star/sdbc/XRowSet.hpp>
52 #include <com/sun/star/sheet/GeneralFunction.hpp>
53 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
54 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
55 #include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
56 #include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
57 #include <com/sun/star/sheet/DataPilotTablePositionData.hpp>
58 #include <com/sun/star/sheet/DataPilotTablePositionType.hpp>
59 #include <com/sun/star/sheet/DimensionFlags.hpp>
60 #include <com/sun/star/task/InteractionHandler.hpp>
61 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
62 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
63 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
64 #include <com/sun/star/lang/XInitialization.hpp>
65 #include <com/sun/star/container/XContentEnumerationAccess.hpp>
66 #include <com/sun/star/sheet/XDrillDownDataSupplier.hpp>
68 #include <comphelper/processfactory.hxx>
69 #include <comphelper/string.hxx>
70 #include <comphelper/types.hxx>
71 #include <o3tl/ptr_container.hxx>
72 #include <sal/macros.h>
73 #include <tools/debug.hxx>
74 #include <tools/diagnose_ex.h>
75 #include <svl/zforlist.hxx>
76 #include <vcl/msgbox.hxx>
78 #include <utility>
79 #include <vector>
80 #include <memory>
81 #include <algorithm>
83 using namespace com::sun::star;
84 using ::std::vector;
85 using ::std::unary_function;
86 using ::boost::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 #define SC_SERVICE_ROWSET "com.sun.star.sdb.RowSet"
100 #define SC_DBPROP_DATASOURCENAME "DataSourceName"
101 #define SC_DBPROP_COMMAND "Command"
102 #define SC_DBPROP_COMMANDTYPE "CommandType"
104 #define SCDPSOURCE_SERVICE "com.sun.star.sheet.DataPilotSource"
106 namespace {
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
115 ScDPCache& mrCache;
117 uno::Reference<sdbc::XRowSet> mxRowSet;
118 uno::Reference<sdbc::XRow> mxRow;
119 uno::Reference<sdbc::XResultSetMetaData> mxMetaData;
120 Date maNullDate;
122 public:
123 DBConnector(ScDPCache& rCache, const uno::Reference<sdbc::XRowSet>& xRowSet, const Date& rNullDate);
125 bool isValid() const;
127 virtual void getValue(long nCol, ScDPItemData &rData, short& rNumType) const SAL_OVERRIDE;
128 virtual OUString getColumnLabel(long nCol) const SAL_OVERRIDE;
129 virtual long getColumnCount() const SAL_OVERRIDE;
130 virtual bool first() SAL_OVERRIDE;
131 virtual bool next() SAL_OVERRIDE;
132 virtual void finish() SAL_OVERRIDE;
135 DBConnector::DBConnector(ScDPCache& rCache, const uno::Reference<sdbc::XRowSet>& xRowSet, const Date& rNullDate) :
136 mrCache(rCache), mxRowSet(xRowSet), maNullDate(rNullDate)
138 Reference<sdbc::XResultSetMetaDataSupplier> xMetaSupp(mxRowSet, UNO_QUERY);
139 if (xMetaSupp.is())
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 long DBConnector::getColumnCount() const
167 return mxMetaData->getColumnCount();
170 OUString DBConnector::getColumnLabel(long nCol) const
172 return mxMetaData->getColumnLabel(nCol+1);
175 void DBConnector::getValue(long nCol, ScDPItemData &rData, short& rNumType) const
177 rNumType = css::util::NumberFormat::NUMBER;
178 sal_Int32 nType = mxMetaData->getColumnType(nCol+1);
182 double fValue = 0.0;
183 switch (nType)
185 case sdbc::DataType::BIT:
186 case sdbc::DataType::BOOLEAN:
188 rNumType = css::util::NumberFormat::LOGICAL;
189 fValue = mxRow->getBoolean(nCol+1) ? 1 : 0;
190 rData.SetValue(fValue);
191 break;
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);
206 break;
208 case sdbc::DataType::DATE:
210 rNumType = css::util::NumberFormat::DATE;
212 util::Date aDate = mxRow->getDate(nCol+1);
213 fValue = Date(aDate.Day, aDate.Month, aDate.Year) - maNullDate;
214 rData.SetValue(fValue);
215 break;
217 case sdbc::DataType::TIME:
219 rNumType = css::util::NumberFormat::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);
227 break;
229 case sdbc::DataType::TIMESTAMP:
231 rNumType = css::util::NumberFormat::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);
240 break;
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:
249 default:
250 rData.SetString(mrCache.InternString(mxRow->getString(nCol+1)));
253 catch (uno::Exception&)
255 rData.SetEmpty();
261 sal_uInt16 lcl_GetDataGetOrientation( const uno::Reference<sheet::XDimensionsSupplier>& xSource )
263 long nRet = sheet::DataPilotFieldOrientation_HIDDEN;
264 if ( xSource.is() )
266 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
267 uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
268 long nIntCount = xIntDims->getCount();
269 bool bFound = false;
270 for (long nIntDim=0; nIntDim<nIntCount && !bFound; nIntDim++)
272 uno::Reference<uno::XInterface> xIntDim =
273 ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nIntDim) );
274 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
275 if ( xDimProp.is() )
277 bFound = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
278 OUString(SC_UNO_DP_ISDATALAYOUT) );
279 //TODO: error checking -- is "IsDataLayoutDimension" property required??
280 if (bFound)
281 nRet = ScUnoHelpFunctions::GetEnumProperty(
282 xDimProp, OUString(SC_UNO_DP_ORIENTATION),
283 sheet::DataPilotFieldOrientation_HIDDEN );
287 return static_cast< sal_uInt16 >( nRet );
290 ScDPServiceDesc::ScDPServiceDesc(
291 const OUString& rServ, const OUString& rSrc, const OUString& rNam,
292 const OUString& rUser, const OUString& rPass ) :
293 aServiceName( rServ ),
294 aParSource( rSrc ),
295 aParName( rNam ),
296 aParUser( rUser ),
297 aParPass( rPass ) {}
299 bool ScDPServiceDesc::operator== ( const ScDPServiceDesc& rOther ) const
301 return aServiceName == rOther.aServiceName &&
302 aParSource == rOther.aParSource &&
303 aParName == rOther.aParName &&
304 aParUser == rOther.aParUser &&
305 aParPass == rOther.aParPass;
308 ScDPObject::ScDPObject( ScDocument* pD ) :
309 pDoc( pD ),
310 pSaveData( NULL ),
311 pSheetDesc( NULL ),
312 pImpDesc( NULL ),
313 pServDesc( NULL ),
314 mpTableData(static_cast<ScDPTableData*>(NULL)),
315 pOutput( NULL ),
316 mnAutoFormatIndex( 65535 ),
317 nHeaderRows( 0 ),
318 mbHeaderLayout(false),
319 bAllowMove(false),
320 bSettingsChanged(false),
321 mbEnableGetPivotData(true)
325 ScDPObject::ScDPObject(const ScDPObject& r) :
326 pDoc( r.pDoc ),
327 pSaveData( NULL ),
328 aTableName( r.aTableName ),
329 aTableTag( r.aTableTag ),
330 aOutRange( r.aOutRange ),
331 pSheetDesc( NULL ),
332 pImpDesc( NULL ),
333 pServDesc( NULL ),
334 mpTableData(static_cast<ScDPTableData*>(NULL)),
335 pOutput( NULL ),
336 mnAutoFormatIndex( r.mnAutoFormatIndex ),
337 nHeaderRows( r.nHeaderRows ),
338 mbHeaderLayout( r.mbHeaderLayout ),
339 bAllowMove(false),
340 bSettingsChanged(false),
341 mbEnableGetPivotData(r.mbEnableGetPivotData)
343 if (r.pSaveData)
344 pSaveData = new ScDPSaveData(*r.pSaveData);
345 if (r.pSheetDesc)
346 pSheetDesc = new ScSheetSourceDesc(*r.pSheetDesc);
347 if (r.pImpDesc)
348 pImpDesc = new ScImportSourceDesc(*r.pImpDesc);
349 if (r.pServDesc)
350 pServDesc = new ScDPServiceDesc(*r.pServDesc);
351 // xSource (and pOutput) is not copied
354 ScDPObject::~ScDPObject()
356 Clear();
359 ScDPObject& ScDPObject::operator= (const ScDPObject& r)
361 Clear();
363 pDoc = r.pDoc;
364 aTableName = r.aTableName;
365 aTableTag = r.aTableTag;
366 aOutRange = r.aOutRange;
367 mnAutoFormatIndex = r.mnAutoFormatIndex;
368 nHeaderRows = r.nHeaderRows;
369 mbHeaderLayout = r.mbHeaderLayout;
370 bAllowMove = false;
371 bSettingsChanged = false;
372 mbEnableGetPivotData = r.mbEnableGetPivotData;
374 if (r.pSaveData)
375 pSaveData = new ScDPSaveData(*r.pSaveData);
376 if (r.pSheetDesc)
377 pSheetDesc = new ScSheetSourceDesc(*r.pSheetDesc);
378 if (r.pImpDesc)
379 pImpDesc = new ScImportSourceDesc(*r.pImpDesc);
380 if (r.pServDesc)
381 pServDesc = new ScDPServiceDesc(*r.pServDesc);
383 return *this;
386 void ScDPObject::EnableGetPivotData(bool b)
388 mbEnableGetPivotData = b;
391 void ScDPObject::SetAllowMove(bool bSet)
393 bAllowMove = bSet;
396 void ScDPObject::SetSaveData(const ScDPSaveData& rData)
398 if ( pSaveData != &rData ) // API implementation modifies the original SaveData object
400 delete pSaveData;
401 pSaveData = new ScDPSaveData( rData );
404 InvalidateData(); // re-init source from SaveData
407 void ScDPObject::SetHeaderLayout (bool bUseGrid)
409 mbHeaderLayout = bUseGrid;
412 void ScDPObject::SetOutRange(const ScRange& rRange)
414 aOutRange = rRange;
416 if ( pOutput )
417 pOutput->SetPosition( rRange.aStart );
420 const ScRange& ScDPObject::GetOutRange() const
422 return aOutRange;
425 void ScDPObject::SetSheetDesc(const ScSheetSourceDesc& rDesc, bool /*bFromRefUpdate*/)
427 if ( pSheetDesc && rDesc == *pSheetDesc )
428 return; // nothing to do
430 DELETEZ( pImpDesc );
431 DELETEZ( pServDesc );
433 delete pSheetDesc;
434 pSheetDesc = new ScSheetSourceDesc(rDesc);
436 // make valid QueryParam
438 const ScRange& rSrcRange = pSheetDesc->GetSourceRange();
439 ScQueryParam aParam = pSheetDesc->GetQueryParam();
440 aParam.nCol1 = rSrcRange.aStart.Col();
441 aParam.nRow1 = rSrcRange.aStart.Row();
442 aParam.nCol2 = rSrcRange.aEnd.Col();
443 aParam.nRow2 = rSrcRange.aEnd.Row();
444 aParam.bHasHeader = true;
445 pSheetDesc->SetQueryParam(aParam);
447 ClearTableData(); // new source must be created
450 void ScDPObject::SetImportDesc(const ScImportSourceDesc& rDesc)
452 if ( pImpDesc && rDesc == *pImpDesc )
453 return; // nothing to do
455 DELETEZ( pSheetDesc );
456 DELETEZ( pServDesc );
458 delete pImpDesc;
459 pImpDesc = new ScImportSourceDesc(rDesc);
461 ClearTableData(); // new source must be created
464 void ScDPObject::SetServiceData(const ScDPServiceDesc& rDesc)
466 if ( pServDesc && rDesc == *pServDesc )
467 return; // nothing to do
469 DELETEZ( pSheetDesc );
470 DELETEZ( pImpDesc );
472 delete pServDesc;
473 pServDesc = new ScDPServiceDesc(rDesc);
475 ClearTableData(); // new source must be created
478 void ScDPObject::WriteSourceDataTo( ScDPObject& rDest ) const
480 if ( pSheetDesc )
481 rDest.SetSheetDesc( *pSheetDesc );
482 else if ( pImpDesc )
483 rDest.SetImportDesc( *pImpDesc );
484 else if ( pServDesc )
485 rDest.SetServiceData( *pServDesc );
487 // name/tag are not source data, but needed along with source data
489 rDest.aTableName = aTableName;
490 rDest.aTableTag = aTableTag;
493 void ScDPObject::WriteTempDataTo( ScDPObject& rDest ) const
495 rDest.nHeaderRows = nHeaderRows;
498 bool ScDPObject::IsSheetData() const
500 return ( pSheetDesc != NULL );
503 void ScDPObject::SetName(const OUString& rNew)
505 aTableName = rNew;
508 void ScDPObject::SetTag(const OUString& rNew)
510 aTableTag = rNew;
513 bool ScDPObject::IsDataDescriptionCell(const ScAddress& rPos)
515 if (!pSaveData)
516 return false;
518 long nDataDimCount = pSaveData->GetDataDimensionCount();
519 if (nDataDimCount != 1)
520 // There has to be exactly one data dimension for the description to
521 // appear at top-left corner.
522 return false;
524 CreateOutput();
525 ScRange aTabRange = pOutput->GetOutputRange(sheet::DataPilotOutputRangeType::TABLE);
526 return (rPos == aTabRange.aStart);
529 uno::Reference<sheet::XDimensionsSupplier> ScDPObject::GetSource()
531 CreateObjects();
532 return xSource;
535 void ScDPObject::CreateOutput()
537 CreateObjects();
538 if (!pOutput)
540 bool bFilterButton = IsSheetData() && pSaveData && pSaveData->GetFilterButton();
541 pOutput = new ScDPOutput( pDoc, xSource, aOutRange.aStart, bFilterButton );
542 pOutput->SetHeaderLayout ( mbHeaderLayout );
544 long nOldRows = nHeaderRows;
545 nHeaderRows = pOutput->GetHeaderRows();
547 if ( bAllowMove && nHeaderRows != nOldRows )
549 long nDiff = nOldRows - nHeaderRows;
550 if ( nOldRows == 0 )
551 --nDiff;
552 if ( nHeaderRows == 0 )
553 ++nDiff;
555 long nNewRow = aOutRange.aStart.Row() + nDiff;
556 if ( nNewRow < 0 )
557 nNewRow = 0;
559 ScAddress aStart( aOutRange.aStart );
560 aStart.SetRow(nNewRow);
561 pOutput->SetPosition( aStart );
563 //TODO: modify aOutRange?
565 bAllowMove = false; // use only once
570 namespace {
572 class DisableGetPivotData
574 ScDPObject& mrDPObj;
575 bool mbOldState;
576 public:
577 DisableGetPivotData(ScDPObject& rObj, bool bOld) : mrDPObj(rObj), mbOldState(bOld)
579 mrDPObj.EnableGetPivotData(false);
582 ~DisableGetPivotData()
584 mrDPObj.EnableGetPivotData(mbOldState);
588 class FindIntersectingTable : std::unary_function<ScDPObject, bool>
590 ScRange maRange;
591 public:
592 FindIntersectingTable(const ScRange& rRange) : maRange(rRange) {}
594 bool operator() (const ScDPObject& rObj) const
596 return maRange.Intersects(rObj.GetOutRange());
600 class FindIntersetingTableByColumns : std::unary_function<ScDPObject, bool>
602 SCCOL mnCol1;
603 SCCOL mnCol2;
604 SCROW mnRow;
605 SCTAB mnTab;
606 public:
607 FindIntersetingTableByColumns(SCCOL nCol1, SCCOL nCol2, SCROW nRow, SCTAB nTab) :
608 mnCol1(nCol1), mnCol2(nCol2), mnRow(nRow), mnTab(nTab) {}
610 bool operator() (const ScDPObject& rObj) const
612 const ScRange& rRange = rObj.GetOutRange();
613 if (mnTab != rRange.aStart.Tab())
614 // Not on this sheet.
615 return false;
617 if (rRange.aEnd.Row() < mnRow)
618 // This table is above the row. It's safe.
619 return false;
621 if (mnCol1 <= rRange.aStart.Col() && rRange.aEnd.Col() <= mnCol2)
622 // This table is fully enclosed in this column range.
623 return false;
625 if (rRange.aEnd.Col() < mnCol1 || mnCol2 < rRange.aStart.Col())
626 // This table is entirely outside this column range.
627 return false;
629 // This table must be intersected by this column range.
630 return true;
634 class FindIntersectingTableByRows : std::unary_function<ScDPObject, bool>
636 SCCOL mnCol;
637 SCROW mnRow1;
638 SCROW mnRow2;
639 SCTAB mnTab;
640 public:
641 FindIntersectingTableByRows(SCCOL nCol, SCROW nRow1, SCROW nRow2, SCTAB nTab) :
642 mnCol(nCol), mnRow1(nRow1), mnRow2(nRow2), mnTab(nTab) {}
644 bool operator() (const ScDPObject& rObj) const
646 const ScRange& rRange = rObj.GetOutRange();
647 if (mnTab != rRange.aStart.Tab())
648 // Not on this sheet.
649 return false;
651 if (rRange.aEnd.Col() < mnCol)
652 // This table is to the left of the column. It's safe.
653 return false;
655 if (mnRow1 <= rRange.aStart.Row() && rRange.aEnd.Row() <= mnRow2)
656 // This table is fully enclosed in this row range.
657 return false;
659 if (rRange.aEnd.Row() < mnRow1 || mnRow2 < rRange.aStart.Row())
660 // This table is entirely outside this row range.
661 return false;
663 // This table must be intersected by this row range.
664 return true;
668 class AccumulateOutputRanges : std::unary_function<ScDPObject, void>
670 ScRangeList maRanges;
671 SCTAB mnTab;
672 public:
673 AccumulateOutputRanges(SCTAB nTab) : mnTab(nTab) {}
674 AccumulateOutputRanges(const AccumulateOutputRanges& r) : maRanges(r.maRanges), mnTab(r.mnTab) {}
676 void operator() (const ScDPObject& rObj)
678 const ScRange& rRange = rObj.GetOutRange();
679 if (mnTab != rRange.aStart.Tab())
680 // Not on this sheet.
681 return;
683 maRanges.Join(rRange);
686 ScRangeList getRanges() const { return maRanges; }
691 ScDPTableData* ScDPObject::GetTableData()
693 if (!mpTableData)
695 shared_ptr<ScDPTableData> pData;
696 const ScDPDimensionSaveData* pDimData = pSaveData ? pSaveData->GetExistingDimensionData() : NULL;
698 if ( pImpDesc )
700 // database data
701 const ScDPCache* pCache = pImpDesc->CreateCache(pDimData);
702 if (pCache)
704 pCache->AddReference(this);
705 pData.reset(new ScDatabaseDPData(pDoc, *pCache));
708 else
710 // cell data
711 if (!pSheetDesc)
713 OSL_FAIL("no source descriptor");
714 pSheetDesc = new ScSheetSourceDesc(pDoc); // dummy defaults
718 // Temporarily disable GETPIVOTDATA to avoid having
719 // GETPIVOTDATA called onto itself from within the source
720 // range.
721 DisableGetPivotData aSwitch(*this, mbEnableGetPivotData);
722 const ScDPCache* pCache = pSheetDesc->CreateCache(pDimData);
723 if (pCache)
725 pCache->AddReference(this);
726 pData.reset(new ScSheetDPData(pDoc, *pSheetDesc, *pCache));
731 // grouping (for cell or database data)
732 if (pData && pDimData)
734 shared_ptr<ScDPGroupTableData> pGroupData(new ScDPGroupTableData(pData, pDoc));
735 pDimData->WriteToData(*pGroupData);
736 pData = pGroupData;
739 mpTableData = pData; // after SetCacheId
742 return mpTableData.get();
745 void ScDPObject::CreateObjects()
747 if (!xSource.is())
749 DELETEZ( pOutput ); // not valid when xSource is changed
751 if ( pServDesc )
753 xSource = CreateSource( *pServDesc );
756 if ( !xSource.is() ) // database or sheet data, or error in CreateSource
758 OSL_ENSURE( !pServDesc, "DPSource could not be created" );
759 ScDPTableData* pData = GetTableData();
760 if (pData)
762 if (pSaveData)
763 // Make sure to transfer these flags to the table data
764 // since they may have changed.
765 pData->SetEmptyFlags(pSaveData->GetIgnoreEmptyRows(), pSaveData->GetRepeatIfEmpty());
767 pData->ReloadCacheTable();
768 ScDPSource* pSource = new ScDPSource( pData );
769 xSource = pSource;
773 if (pSaveData)
774 pSaveData->WriteToSource( xSource );
776 else if (bSettingsChanged)
778 DELETEZ( pOutput ); // not valid when xSource is changed
780 uno::Reference<util::XRefreshable> xRef( xSource, uno::UNO_QUERY );
781 if (xRef.is())
785 xRef->refresh();
787 catch(uno::Exception&)
789 OSL_FAIL("exception in refresh");
793 if (pSaveData)
794 pSaveData->WriteToSource( xSource );
796 bSettingsChanged = false;
799 void ScDPObject::InvalidateData()
801 bSettingsChanged = true;
804 void ScDPObject::Clear()
806 delete pOutput;
807 delete pSaveData;
808 delete pSheetDesc;
809 delete pImpDesc;
810 delete pServDesc;
811 pOutput = NULL;
812 pSaveData = NULL;
813 pSheetDesc = NULL;
814 pImpDesc = NULL;
815 pServDesc = NULL;
816 ClearTableData();
819 void ScDPObject::ClearTableData()
821 ClearSource();
823 if (mpTableData)
824 mpTableData->GetCacheTable().getCache().RemoveReference(this);
825 mpTableData.reset();
828 void ScDPObject::ReloadGroupTableData()
830 ClearSource();
832 if (!mpTableData)
833 // Table data not built yet. No need to reload the group data.
834 return;
836 if (!pSaveData)
837 // How could it not have the save data... but whatever.
838 return;
840 const ScDPDimensionSaveData* pDimData = pSaveData->GetExistingDimensionData();
841 if (!pDimData || !pDimData->HasGroupDimensions())
843 // No group dimensions exist. Check if it currently has group
844 // dimensions, and if so, remove all of them.
845 ScDPGroupTableData* pData = dynamic_cast<ScDPGroupTableData*>(mpTableData.get());
846 if (pData)
848 // Replace the existing group table data with the source data.
849 shared_ptr<ScDPTableData> pSource = pData->GetSourceTableData();
850 mpTableData = pSource;
852 return;
855 ScDPGroupTableData* pData = dynamic_cast<ScDPGroupTableData*>(mpTableData.get());
856 if (pData)
858 // This is already a group table data. Salvage the source data and
859 // re-create a new group data.
860 shared_ptr<ScDPTableData> pSource = pData->GetSourceTableData();
861 shared_ptr<ScDPGroupTableData> pGroupData(new ScDPGroupTableData(pSource, pDoc));
862 pDimData->WriteToData(*pGroupData);
863 mpTableData = pGroupData;
865 else
867 // This is a source data. Create a group data based on it.
868 shared_ptr<ScDPGroupTableData> pGroupData(new ScDPGroupTableData(mpTableData, pDoc));
869 pDimData->WriteToData(*pGroupData);
870 mpTableData = pGroupData;
873 bSettingsChanged = true;
876 void ScDPObject::ClearSource()
878 Reference< XComponent > xObjectComp( xSource, UNO_QUERY );
879 if (xObjectComp.is())
883 xObjectComp->dispose();
885 catch( const Exception& )
887 DBG_UNHANDLED_EXCEPTION();
890 xSource = NULL;
893 ScRange ScDPObject::GetNewOutputRange( bool& rOverflow )
895 CreateOutput(); // create xSource and pOutput if not already done
897 rOverflow = pOutput->HasError(); // range overflow or exception from source
898 if ( rOverflow )
899 return ScRange( aOutRange.aStart );
900 else
902 // don't store the result in aOutRange, because nothing has been output yet
903 return pOutput->GetOutputRange();
907 void ScDPObject::Output( const ScAddress& rPos )
909 // clear old output area
910 pDoc->DeleteAreaTab( aOutRange.aStart.Col(), aOutRange.aStart.Row(),
911 aOutRange.aEnd.Col(), aOutRange.aEnd.Row(),
912 aOutRange.aStart.Tab(), IDF_ALL );
913 pDoc->RemoveFlagsTab( aOutRange.aStart.Col(), aOutRange.aStart.Row(),
914 aOutRange.aEnd.Col(), aOutRange.aEnd.Row(),
915 aOutRange.aStart.Tab(), SC_MF_AUTO );
917 CreateOutput(); // create xSource and pOutput if not already done
919 pOutput->SetPosition( rPos );
921 pOutput->Output();
923 // aOutRange is always the range that was last output to the document
924 aOutRange = pOutput->GetOutputRange();
925 const ScAddress& s = aOutRange.aStart;
926 const ScAddress& e = aOutRange.aEnd;
927 pDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
930 ScRange ScDPObject::GetOutputRangeByType( sal_Int32 nType )
932 CreateOutput();
934 if (pOutput->HasError())
935 return ScRange(aOutRange.aStart);
937 return pOutput->GetOutputRange(nType);
940 ScRange ScDPObject::GetOutputRangeByType( sal_Int32 nType ) const
942 if (!pOutput || pOutput->HasError())
943 return ScRange(ScAddress::INITIALIZE_INVALID);
945 return pOutput->GetOutputRange(nType);
948 static bool lcl_HasButton( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
950 return static_cast<const ScMergeFlagAttr*>(pDoc->GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG ))->HasPivotButton();
953 void ScDPObject::RefreshAfterLoad()
955 // apply drop-down attribute, initialize nHeaderRows, without accessing the source
956 // (button attribute must be present)
958 // simple test: block of button cells at the top, followed by an empty cell
960 SCCOL nFirstCol = aOutRange.aStart.Col();
961 SCROW nFirstRow = aOutRange.aStart.Row();
962 SCTAB nTab = aOutRange.aStart.Tab();
964 SCROW nInitial = 0;
965 SCROW nOutRows = aOutRange.aEnd.Row() + 1 - aOutRange.aStart.Row();
966 while ( nInitial + 1 < nOutRows && lcl_HasButton( pDoc, nFirstCol, nFirstRow + nInitial, nTab ) )
967 ++nInitial;
969 if ( nInitial + 1 < nOutRows &&
970 pDoc->IsBlockEmpty( nTab, nFirstCol, nFirstRow + nInitial, nFirstCol, nFirstRow + nInitial ) &&
971 aOutRange.aEnd.Col() > nFirstCol )
973 nHeaderRows = nInitial;
975 else
976 nHeaderRows = 0; // nothing found, no drop-down lists
979 void ScDPObject::BuildAllDimensionMembers()
981 if (!pSaveData)
982 return;
984 // #i111857# don't always create empty mpTableData for external service.
985 if (pServDesc)
986 return;
988 ScDPTableData* pTableData = GetTableData();
989 if(pTableData)
990 pSaveData->BuildAllDimensionMembers(pTableData);
993 bool ScDPObject::SyncAllDimensionMembers()
995 if (!pSaveData)
996 return false;
998 // #i111857# don't always create empty mpTableData for external service.
999 // Ideally, xSource should be used instead of mpTableData.
1000 if (pServDesc)
1001 return false;
1003 ScDPTableData* pData = GetTableData();
1004 if (!pData)
1005 // No table data exists. This can happen when refreshing from an
1006 // external source which doesn't exist.
1007 return false;
1009 // Refresh the cache wrapper since the cache may have changed.
1010 pData->SetEmptyFlags(pSaveData->GetIgnoreEmptyRows(), pSaveData->GetRepeatIfEmpty());
1011 pData->ReloadCacheTable();
1012 pSaveData->SyncAllDimensionMembers(pData);
1013 return true;
1016 bool ScDPObject::GetMemberNames( sal_Int32 nDim, Sequence<OUString>& rNames )
1018 vector<ScDPLabelData::Member> aMembers;
1019 if (!GetMembers(nDim, GetUsedHierarchy(nDim), aMembers))
1020 return false;
1022 size_t n = aMembers.size();
1023 rNames.realloc(n);
1024 for (size_t i = 0; i < n; ++i)
1025 rNames[i] = aMembers[i].maName;
1027 return true;
1030 bool ScDPObject::GetMembers( sal_Int32 nDim, sal_Int32 nHier, vector<ScDPLabelData::Member>& rMembers )
1032 Reference< container::XNameAccess > xMembersNA;
1033 if (!GetMembersNA( nDim, nHier, xMembersNA ))
1034 return false;
1036 Reference<container::XIndexAccess> xMembersIA( new ScNameToIndexAccess(xMembersNA) );
1037 sal_Int32 nCount = xMembersIA->getCount();
1038 vector<ScDPLabelData::Member> aMembers;
1039 aMembers.reserve(nCount);
1041 for (sal_Int32 i = 0; i < nCount; ++i)
1043 Reference<container::XNamed> xMember(xMembersIA->getByIndex(i), UNO_QUERY);
1044 ScDPLabelData::Member aMem;
1046 if (xMember.is())
1047 aMem.maName = xMember->getName();
1049 Reference<beans::XPropertySet> xMemProp(xMember, UNO_QUERY);
1050 if (xMemProp.is())
1052 aMem.mbVisible = ScUnoHelpFunctions::GetBoolProperty(xMemProp, OUString(SC_UNO_DP_ISVISIBLE));
1053 aMem.mbShowDetails = ScUnoHelpFunctions::GetBoolProperty(xMemProp, OUString(SC_UNO_DP_SHOWDETAILS));
1055 aMem.maLayoutName = ScUnoHelpFunctions::GetStringProperty(
1056 xMemProp, OUString(SC_UNO_DP_LAYOUTNAME), OUString());
1059 aMembers.push_back(aMem);
1061 rMembers.swap(aMembers);
1062 return true;
1065 void ScDPObject::UpdateReference( UpdateRefMode eUpdateRefMode,
1066 const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
1068 // Output area
1070 SCCOL nCol1 = aOutRange.aStart.Col();
1071 SCROW nRow1 = aOutRange.aStart.Row();
1072 SCTAB nTab1 = aOutRange.aStart.Tab();
1073 SCCOL nCol2 = aOutRange.aEnd.Col();
1074 SCROW nRow2 = aOutRange.aEnd.Row();
1075 SCTAB nTab2 = aOutRange.aEnd.Tab();
1077 ScRefUpdateRes eRes =
1078 ScRefUpdate::Update( pDoc, 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 ( pSheetDesc )
1089 const OUString& rRangeName = pSheetDesc->GetRangeName();
1090 if (!rRangeName.isEmpty())
1091 // Source range is a named range. No need to update.
1092 return;
1094 const ScRange& rSrcRange = pSheetDesc->GetSourceRange();
1095 nCol1 = rSrcRange.aStart.Col();
1096 nRow1 = rSrcRange.aStart.Row();
1097 nTab1 = rSrcRange.aStart.Tab();
1098 nCol2 = rSrcRange.aEnd.Col();
1099 nRow2 = rSrcRange.aEnd.Row();
1100 nTab2 = rSrcRange.aEnd.Tab();
1102 eRes = ScRefUpdate::Update( pDoc, eUpdateRefMode,
1103 rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
1104 rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz,
1105 nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
1106 if ( eRes != UR_NOTHING )
1108 SCsCOL nDiffX = nCol1 - pSheetDesc->GetSourceRange().aStart.Col();
1109 SCsROW nDiffY = nRow1 - pSheetDesc->GetSourceRange().aStart.Row();
1111 ScQueryParam aParam = pSheetDesc->GetQueryParam();
1112 aParam.nCol1 = sal::static_int_cast<SCCOL>( aParam.nCol1 + nDiffX );
1113 aParam.nCol2 = sal::static_int_cast<SCCOL>( aParam.nCol2 + nDiffX );
1114 aParam.nRow1 += nDiffY; //TODO: used?
1115 aParam.nRow2 += nDiffY; //TODO: used?
1116 SCSIZE nEC = aParam.GetEntryCount();
1117 for (SCSIZE i=0; i<nEC; i++)
1118 if (aParam.GetEntry(i).bDoQuery)
1119 aParam.GetEntry(i).nField += nDiffX;
1121 pSheetDesc->SetQueryParam(aParam);
1122 pSheetDesc->SetSourceRange(ScRange(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2));
1127 bool ScDPObject::RefsEqual( const ScDPObject& r ) const
1129 if ( aOutRange != r.aOutRange )
1130 return false;
1132 if ( pSheetDesc && r.pSheetDesc )
1134 if ( pSheetDesc->GetSourceRange() != r.pSheetDesc->GetSourceRange() )
1135 return false;
1137 else if ( pSheetDesc || r.pSheetDesc )
1139 OSL_FAIL("RefsEqual: SheetDesc set at only one object");
1140 return false;
1143 return true;
1146 void ScDPObject::WriteRefsTo( ScDPObject& r ) const
1148 r.SetOutRange( aOutRange );
1149 if ( pSheetDesc )
1150 r.SetSheetDesc( *pSheetDesc, true );
1153 void ScDPObject::GetPositionData(const ScAddress& rPos, DataPilotTablePositionData& rPosData)
1155 CreateOutput();
1156 pOutput->GetPositionData(rPos, rPosData);
1159 bool ScDPObject::GetDataFieldPositionData(
1160 const ScAddress& rPos, Sequence<sheet::DataPilotFieldFilter>& rFilters)
1162 CreateOutput();
1164 vector<sheet::DataPilotFieldFilter> aFilters;
1165 if (!pOutput->GetDataResultPositionData(aFilters, rPos))
1166 return false;
1168 sal_Int32 n = static_cast<sal_Int32>(aFilters.size());
1169 rFilters.realloc(n);
1170 for (sal_Int32 i = 0; i < n; ++i)
1171 rFilters[i] = aFilters[i];
1173 return true;
1176 void ScDPObject::GetDrillDownData(const ScAddress& rPos, Sequence< Sequence<Any> >& rTableData)
1178 CreateOutput();
1180 Reference<sheet::XDrillDownDataSupplier> xDrillDownData(xSource, UNO_QUERY);
1181 if (!xDrillDownData.is())
1182 return;
1184 Sequence<sheet::DataPilotFieldFilter> filters;
1185 if (!GetDataFieldPositionData(rPos, filters))
1186 return;
1188 rTableData = xDrillDownData->getDrillDownData(filters);
1191 bool ScDPObject::IsDimNameInUse(const OUString& rName) const
1193 if (!xSource.is())
1194 return false;
1196 Reference<container::XNameAccess> xDims = xSource->getDimensions();
1197 Sequence<OUString> aDimNames = xDims->getElementNames();
1198 sal_Int32 n = aDimNames.getLength();
1199 for (sal_Int32 i = 0; i < n; ++i)
1201 const OUString& rDimName = aDimNames[i];
1202 if (rDimName.equalsIgnoreAsciiCase(rName))
1203 return true;
1205 Reference<beans::XPropertySet> xPropSet(xDims->getByName(rDimName), UNO_QUERY);
1206 if (!xPropSet.is())
1207 continue;
1209 OUString aLayoutName = ScUnoHelpFunctions::GetStringProperty(
1210 xPropSet, OUString(SC_UNO_DP_LAYOUTNAME), OUString());
1211 if (aLayoutName.equalsIgnoreAsciiCase(rName))
1212 return true;
1214 return false;
1217 OUString ScDPObject::GetDimName( long nDim, bool& rIsDataLayout, sal_Int32* pFlags )
1219 rIsDataLayout = false;
1220 OUString aRet;
1222 if ( xSource.is() )
1224 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1225 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
1226 long nDimCount = xDims->getCount();
1227 if ( nDim < nDimCount )
1229 uno::Reference<uno::XInterface> xIntDim =
1230 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
1231 uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
1232 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
1233 if ( xDimName.is() && xDimProp.is() )
1235 bool bData = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1236 OUString(SC_UNO_DP_ISDATALAYOUT) );
1237 //TODO: error checking -- is "IsDataLayoutDimension" property required??
1239 OUString aName;
1242 aName = xDimName->getName();
1244 catch(uno::Exception&)
1247 if ( bData )
1248 rIsDataLayout = true;
1249 else
1250 aRet = aName;
1252 if (pFlags)
1253 *pFlags = ScUnoHelpFunctions::GetLongProperty( xDimProp,
1254 OUString(SC_UNO_DP_FLAGS), 0 );
1259 return aRet;
1262 bool ScDPObject::IsDuplicated( long nDim )
1264 bool bDuplicated = false;
1265 if ( xSource.is() )
1267 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1268 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
1269 long nDimCount = xDims->getCount();
1270 if ( nDim < nDimCount )
1272 uno::Reference<uno::XInterface> xIntDim =
1273 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
1274 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
1275 if ( xDimProp.is() )
1279 uno::Any aOrigAny = xDimProp->getPropertyValue(
1280 OUString(SC_UNO_DP_ORIGINAL) );
1281 uno::Reference<uno::XInterface> xIntOrig;
1282 if ( (aOrigAny >>= xIntOrig) && xIntOrig.is() )
1283 bDuplicated = true;
1285 catch(uno::Exception&)
1291 return bDuplicated;
1294 long ScDPObject::GetDimCount()
1296 long nRet = 0;
1297 if ( xSource.is() )
1301 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1302 if ( xDimsName.is() )
1303 nRet = xDimsName->getElementNames().getLength();
1305 catch(uno::Exception&)
1309 return nRet;
1312 void ScDPObject::GetHeaderPositionData(const ScAddress& rPos, DataPilotTableHeaderData& rData)
1314 using namespace ::com::sun::star::sheet::DataPilotTablePositionType;
1316 CreateOutput(); // create xSource and pOutput if not already done
1318 // Reset member values to invalid state.
1319 rData.Dimension = rData.Hierarchy = rData.Level = -1;
1320 rData.Flags = 0;
1322 DataPilotTablePositionData aPosData;
1323 pOutput->GetPositionData(rPos, aPosData);
1324 const sal_Int32 nPosType = aPosData.PositionType;
1325 if (nPosType == COLUMN_HEADER || nPosType == ROW_HEADER)
1326 aPosData.PositionData >>= rData;
1329 namespace {
1331 class FindByName : std::unary_function<const ScDPSaveDimension*, bool>
1333 OUString maName; // must be all uppercase.
1334 public:
1335 FindByName(const OUString& rName) : maName(rName) {}
1336 bool operator() (const ScDPSaveDimension* pDim) const
1338 // Layout name takes precedence.
1339 const OUString* pLayoutName = pDim->GetLayoutName();
1340 if (pLayoutName && ScGlobal::pCharClass->uppercase(*pLayoutName) == maName)
1341 return true;
1343 sheet::GeneralFunction eGenFunc = static_cast<sheet::GeneralFunction>(pDim->GetFunction());
1344 ScSubTotalFunc eFunc = ScDPUtil::toSubTotalFunc(eGenFunc);
1345 OUString aSrcName = ScDPUtil::getSourceDimensionName(pDim->GetName());
1346 OUString aFuncName = ScDPUtil::getDisplayedMeasureName(aSrcName, eFunc);
1347 if (maName == ScGlobal::pCharClass->uppercase(aFuncName))
1348 return true;
1350 return maName == ScGlobal::pCharClass->uppercase(aSrcName);
1354 class LessByDimOrder : std::binary_function<sheet::DataPilotFieldFilter, sheet::DataPilotFieldFilter, bool>
1356 const ScDPSaveData::DimOrderType& mrDimOrder;
1358 public:
1359 LessByDimOrder(const ScDPSaveData::DimOrderType& rDimOrder) : mrDimOrder(rDimOrder) {}
1361 bool operator() (const sheet::DataPilotFieldFilter& r1, const sheet::DataPilotFieldFilter& r2) const
1363 size_t nRank1 = mrDimOrder.size();
1364 size_t nRank2 = mrDimOrder.size();
1365 ScDPSaveData::DimOrderType::const_iterator it1 = mrDimOrder.find(r1.FieldName);
1366 if (it1 != mrDimOrder.end())
1367 nRank1 = it1->second;
1369 ScDPSaveData::DimOrderType::const_iterator it2 = mrDimOrder.find(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 double fRet;
1382 rtl::math::setNan(&fRet);
1383 if (!mbEnableGetPivotData)
1384 return fRet;
1386 CreateObjects();
1388 std::vector<const ScDPSaveDimension*> aDataDims;
1389 pSaveData->GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_DATA, aDataDims);
1390 if (aDataDims.empty())
1391 return fRet;
1393 std::vector<const ScDPSaveDimension*>::iterator it = std::find_if(
1394 aDataDims.begin(), aDataDims.end(),
1395 FindByName(ScGlobal::pCharClass->uppercase(rDataFieldName)));
1397 if (it == aDataDims.end())
1398 return fRet;
1400 size_t nDataIndex = std::distance(aDataDims.begin(), it);
1402 uno::Reference<sheet::XDataPilotResults> xDPResults(xSource, uno::UNO_QUERY);
1403 if (!xDPResults.is())
1404 return fRet;
1406 // Dimensions must be sorted in order of appearance, and row dimensions
1407 // must come before column dimensions.
1408 std::sort(rFilters.begin(), rFilters.end(), LessByDimOrder(pSaveData->GetDimensionSortOrder()));
1410 size_t n = rFilters.size();
1411 uno::Sequence<sheet::DataPilotFieldFilter> aFilters(n);
1412 for (size_t i = 0; i < n; ++i)
1413 aFilters[i] = rFilters[i];
1415 uno::Sequence<double> aRes = xDPResults->getFilteredResults(aFilters);
1416 if (static_cast<sal_Int32>(nDataIndex) >= aRes.getLength())
1417 return fRet;
1419 return aRes[nDataIndex];
1422 bool ScDPObject::IsFilterButton( const ScAddress& rPos )
1424 CreateOutput(); // create xSource and pOutput if not already done
1426 return pOutput->IsFilterButton( rPos );
1429 long ScDPObject::GetHeaderDim( const ScAddress& rPos, sal_uInt16& rOrient )
1431 CreateOutput(); // create xSource and pOutput if not already done
1433 return pOutput->GetHeaderDim( rPos, rOrient );
1436 bool ScDPObject::GetHeaderDrag( const ScAddress& rPos, bool bMouseLeft, bool bMouseTop, long nDragDim,
1437 Rectangle& rPosRect, sal_uInt16& rOrient, long& rDimPos )
1439 CreateOutput(); // create xSource and pOutput if not already done
1441 return pOutput->GetHeaderDrag( rPos, bMouseLeft, bMouseTop, nDragDim, rPosRect, rOrient, rDimPos );
1444 void ScDPObject::GetMemberResultNames(ScDPUniqueStringSet& rNames, long nDimension)
1446 CreateOutput(); // create xSource and pOutput if not already done
1448 pOutput->GetMemberResultNames(rNames, nDimension); // used only with table data -> level not needed
1451 namespace {
1453 bool dequote( const OUString& rSource, sal_Int32 nStartPos, sal_Int32& rEndPos, OUString& rResult )
1455 // nStartPos has to point to opening quote
1457 bool bRet = false;
1458 const sal_Unicode cQuote = '\'';
1460 if (rSource[nStartPos] == cQuote)
1462 OUStringBuffer aBuffer;
1463 sal_Int32 nPos = nStartPos + 1;
1464 const sal_Int32 nLen = rSource.getLength();
1466 while ( nPos < nLen )
1468 const sal_Unicode cNext = rSource[nPos];
1469 if ( cNext == cQuote )
1471 if (nPos+1 < nLen && rSource[nPos+1] == cQuote)
1473 // double quote is used for an embedded quote
1474 aBuffer.append( cNext ); // append one quote
1475 ++nPos; // skip the next one
1477 else
1479 // end of quoted string
1480 rResult = aBuffer.makeStringAndClear();
1481 rEndPos = nPos + 1; // behind closing quote
1482 return true;
1485 else
1486 aBuffer.append( cNext );
1488 ++nPos;
1490 // no closing quote before the end of the string -> error (bRet still false)
1493 return bRet;
1496 struct ScGetPivotDataFunctionEntry
1498 const sal_Char* pName;
1499 sheet::GeneralFunction eFunc;
1502 bool parseFunction( const OUString& rList, sal_Int32 nStartPos, sal_Int32& rEndPos, sheet::GeneralFunction& rFunc )
1504 static const ScGetPivotDataFunctionEntry aFunctions[] =
1506 // our names
1507 { "Sum", sheet::GeneralFunction_SUM },
1508 { "Count", sheet::GeneralFunction_COUNT },
1509 { "Average", sheet::GeneralFunction_AVERAGE },
1510 { "Max", sheet::GeneralFunction_MAX },
1511 { "Min", sheet::GeneralFunction_MIN },
1512 { "Product", sheet::GeneralFunction_PRODUCT },
1513 { "CountNums", sheet::GeneralFunction_COUNTNUMS },
1514 { "StDev", sheet::GeneralFunction_STDEV },
1515 { "StDevp", sheet::GeneralFunction_STDEVP },
1516 { "Var", sheet::GeneralFunction_VAR },
1517 { "VarP", sheet::GeneralFunction_VARP },
1518 // compatibility names
1519 { "Count Nums", sheet::GeneralFunction_COUNTNUMS },
1520 { "StdDev", sheet::GeneralFunction_STDEV },
1521 { "StdDevp", sheet::GeneralFunction_STDEVP }
1524 const sal_Int32 nListLen = rList.getLength();
1525 while (nStartPos < nListLen && rList[nStartPos] == ' ')
1526 ++nStartPos;
1528 bool bParsed = false;
1529 bool bFound = false;
1530 OUString aFuncStr;
1531 sal_Int32 nFuncEnd = 0;
1532 if (nStartPos < nListLen && rList[nStartPos] == '\'')
1533 bParsed = dequote( rList, nStartPos, nFuncEnd, aFuncStr );
1534 else
1536 nFuncEnd = rList.indexOf(']', nStartPos);
1537 if (nFuncEnd >= 0)
1539 aFuncStr = rList.copy(nStartPos, nFuncEnd - nStartPos);
1540 bParsed = true;
1544 if ( bParsed )
1546 aFuncStr = comphelper::string::strip(aFuncStr, ' ');
1548 const sal_Int32 nFuncCount = sizeof(aFunctions) / sizeof(aFunctions[0]);
1549 for ( sal_Int32 nFunc=0; nFunc<nFuncCount && !bFound; nFunc++ )
1551 if (aFuncStr.equalsIgnoreAsciiCaseAscii(aFunctions[nFunc].pName))
1553 rFunc = aFunctions[nFunc].eFunc;
1554 bFound = true;
1556 while (nFuncEnd < nListLen && rList[nFuncEnd] == ' ')
1557 ++nFuncEnd;
1558 rEndPos = nFuncEnd;
1563 return bFound;
1566 bool isAtStart(
1567 const OUString& rList, const OUString& rSearch, sal_Int32& rMatched,
1568 bool bAllowBracket, sheet::GeneralFunction* pFunc )
1570 sal_Int32 nMatchList = 0;
1571 sal_Int32 nMatchSearch = 0;
1572 sal_Unicode cFirst = rList[0];
1573 if ( cFirst == '\'' || cFirst == '[' )
1575 // quoted string or string in brackets must match completely
1577 OUString aDequoted;
1578 sal_Int32 nQuoteEnd = 0;
1579 bool bParsed = false;
1581 if ( cFirst == '\'' )
1582 bParsed = dequote( rList, 0, nQuoteEnd, aDequoted );
1583 else if ( cFirst == '[' )
1585 // skip spaces after the opening bracket
1587 sal_Int32 nStartPos = 1;
1588 const sal_Int32 nListLen = rList.getLength();
1589 while (nStartPos < nListLen && rList[nStartPos] == ' ')
1590 ++nStartPos;
1592 if (nStartPos < nListLen && rList[nStartPos] == '\'') // quoted within the brackets?
1594 if ( dequote( rList, nStartPos, nQuoteEnd, aDequoted ) )
1596 // after the quoted string, there must be the closing bracket, optionally preceded by spaces,
1597 // and/or a function name
1598 while (nQuoteEnd < nListLen && rList[nQuoteEnd] == ' ')
1599 ++nQuoteEnd;
1601 // semicolon separates function name
1602 if (nQuoteEnd < nListLen && rList[nQuoteEnd] == ';' && pFunc)
1604 sal_Int32 nFuncEnd = 0;
1605 if ( parseFunction( rList, nQuoteEnd + 1, nFuncEnd, *pFunc ) )
1606 nQuoteEnd = nFuncEnd;
1608 if (nQuoteEnd < nListLen && rList[nQuoteEnd] == ']')
1610 ++nQuoteEnd; // include the closing bracket for the matched length
1611 bParsed = true;
1615 else
1617 // implicit quoting to the closing bracket
1619 sal_Int32 nClosePos = rList.indexOf(']', nStartPos);
1620 if (nClosePos >= 0)
1622 sal_Int32 nNameEnd = nClosePos;
1623 sal_Int32 nSemiPos = rList.indexOf(';', nStartPos);
1624 if (nSemiPos >= 0 && nSemiPos < nClosePos && pFunc)
1626 sal_Int32 nFuncEnd = 0;
1627 if (parseFunction(rList, nSemiPos+1, nFuncEnd, *pFunc))
1628 nNameEnd = nSemiPos;
1631 aDequoted = rList.copy(nStartPos, nNameEnd - nStartPos);
1632 // spaces before the closing bracket or semicolon
1633 aDequoted = comphelper::string::stripEnd(aDequoted, ' ');
1634 nQuoteEnd = nClosePos + 1;
1635 bParsed = true;
1640 if ( bParsed && ScGlobal::GetpTransliteration()->isEqual( aDequoted, rSearch ) )
1642 nMatchList = nQuoteEnd; // match count in the list string, including quotes
1643 nMatchSearch = rSearch.getLength();
1646 else
1648 // otherwise look for search string at the start of rList
1649 ScGlobal::GetpTransliteration()->equals(
1650 rList, 0, rList.getLength(), nMatchList, rSearch, 0, rSearch.getLength(), nMatchSearch);
1653 if (nMatchSearch == rSearch.getLength())
1655 // search string is at start of rList - look for following space or end of string
1657 bool bValid = false;
1658 if ( sal::static_int_cast<sal_Int32>(nMatchList) >= rList.getLength() )
1659 bValid = true;
1660 else
1662 sal_Unicode cNext = rList[nMatchList];
1663 if ( cNext == ' ' || ( bAllowBracket && cNext == '[' ) )
1664 bValid = true;
1667 if ( bValid )
1669 rMatched = nMatchList;
1670 return true;
1674 return false;
1677 } // anonymous namespace
1679 bool ScDPObject::ParseFilters(
1680 OUString& rDataFieldName,
1681 std::vector<sheet::DataPilotFieldFilter>& rFilters,
1682 std::vector<sheet::GeneralFunction>& rFilterFuncs, const OUString& rFilterList )
1684 // parse the string rFilterList into parameters for GetPivotData
1686 CreateObjects(); // create xSource if not already done
1688 std::vector<OUString> aDataNames; // data fields (source name)
1689 std::vector<OUString> aGivenNames; // data fields (compound name)
1690 std::vector<OUString> aFieldNames; // column/row/data fields
1691 std::vector< uno::Sequence<OUString> > aFieldValues;
1693 // get all the field and item names
1695 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1696 uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
1697 sal_Int32 nDimCount = xIntDims->getCount();
1698 for ( sal_Int32 nDim = 0; nDim<nDimCount; nDim++ )
1700 uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nDim) );
1701 uno::Reference<container::XNamed> xDim( xIntDim, uno::UNO_QUERY );
1702 uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
1703 uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDim, uno::UNO_QUERY );
1704 bool bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1705 OUString(SC_UNO_DP_ISDATALAYOUT) );
1706 sal_Int32 nOrient = ScUnoHelpFunctions::GetEnumProperty(
1707 xDimProp, OUString(SC_UNO_DP_ORIENTATION),
1708 sheet::DataPilotFieldOrientation_HIDDEN );
1709 if ( !bDataLayout )
1711 if ( nOrient == sheet::DataPilotFieldOrientation_DATA )
1713 OUString aSourceName;
1714 OUString aGivenName;
1715 ScDPOutput::GetDataDimensionNames( aSourceName, aGivenName, xIntDim );
1716 aDataNames.push_back( aSourceName );
1717 aGivenNames.push_back( aGivenName );
1719 else if ( nOrient != sheet::DataPilotFieldOrientation_HIDDEN )
1721 // get level names, as in ScDPOutput
1723 uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
1724 sal_Int32 nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
1725 OUString(SC_UNO_DP_USEDHIERARCHY) );
1726 if ( nHierarchy >= xHiers->getCount() )
1727 nHierarchy = 0;
1729 uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
1730 xHiers->getByIndex(nHierarchy) );
1731 uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
1732 if ( xHierSupp.is() )
1734 uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
1735 sal_Int32 nLevCount = xLevels->getCount();
1736 for (sal_Int32 nLev=0; nLev<nLevCount; nLev++)
1738 uno::Reference<uno::XInterface> xLevel = ScUnoHelpFunctions::AnyToInterface(
1739 xLevels->getByIndex(nLev) );
1740 uno::Reference<container::XNamed> xLevNam( xLevel, uno::UNO_QUERY );
1741 uno::Reference<sheet::XMembersSupplier> xLevSupp( xLevel, uno::UNO_QUERY );
1742 if ( xLevNam.is() && xLevSupp.is() )
1744 uno::Reference<container::XNameAccess> xMembers = xLevSupp->getMembers();
1746 OUString aFieldName( xLevNam->getName() );
1747 uno::Sequence<OUString> aMemberNames( xMembers->getElementNames() );
1749 aFieldNames.push_back( aFieldName );
1750 aFieldValues.push_back( aMemberNames );
1758 // compare and build filters
1760 SCSIZE nDataFields = aDataNames.size();
1761 SCSIZE nFieldCount = aFieldNames.size();
1762 OSL_ENSURE( aGivenNames.size() == nDataFields && aFieldValues.size() == nFieldCount, "wrong count" );
1764 bool bError = false;
1765 bool bHasData = false;
1766 OUString aRemaining(comphelper::string::strip(rFilterList, ' '));
1767 while (!aRemaining.isEmpty() && !bError)
1769 bool bUsed = false;
1771 // look for data field name
1773 for ( SCSIZE nDataPos=0; nDataPos<nDataFields && !bUsed; nDataPos++ )
1775 OUString aFound;
1776 sal_Int32 nMatched = 0;
1777 if (isAtStart(aRemaining, aDataNames[nDataPos], nMatched, false, NULL))
1778 aFound = aDataNames[nDataPos];
1779 else if (isAtStart(aRemaining, aGivenNames[nDataPos], nMatched, false, NULL))
1780 aFound = aGivenNames[nDataPos];
1782 if (!aFound.isEmpty())
1784 rDataFieldName = aFound;
1785 aRemaining = aRemaining.copy(nMatched);
1786 bHasData = true;
1787 bUsed = true;
1791 // look for field name
1793 OUString aSpecField;
1794 bool bHasFieldName = false;
1795 if ( !bUsed )
1797 sal_Int32 nMatched = 0;
1798 for ( SCSIZE nField=0; nField<nFieldCount && !bHasFieldName; nField++ )
1800 if (isAtStart(aRemaining, aFieldNames[nField], nMatched, true, NULL))
1802 aSpecField = aFieldNames[nField];
1803 aRemaining = aRemaining.copy(nMatched);
1804 aRemaining = comphelper::string::stripStart(aRemaining, ' ');
1806 // field name has to be followed by item name in brackets
1807 if (aRemaining.startsWith("["))
1809 bHasFieldName = true;
1810 // bUsed remains false - still need the item
1812 else
1814 bUsed = true;
1815 bError = true;
1821 // look for field item
1823 if ( !bUsed )
1825 bool bItemFound = false;
1826 sal_Int32 nMatched = 0;
1827 OUString aFoundName;
1828 OUString aFoundValue;
1829 sheet::GeneralFunction eFunc = sheet::GeneralFunction_NONE;
1830 sheet::GeneralFunction eFoundFunc = sheet::GeneralFunction_NONE;
1832 for ( SCSIZE nField=0; nField<nFieldCount; nField++ )
1834 // If a field name is given, look in that field only, otherwise in all fields.
1835 // aSpecField is initialized from aFieldNames array, so exact comparison can be used.
1836 if ( !bHasFieldName || aFieldNames[nField] == aSpecField )
1838 const uno::Sequence<OUString>& rItems = aFieldValues[nField];
1839 sal_Int32 nItemCount = rItems.getLength();
1840 const OUString* pItemArr = rItems.getConstArray();
1841 for ( sal_Int32 nItem=0; nItem<nItemCount; nItem++ )
1843 if ( isAtStart( aRemaining, pItemArr[nItem], nMatched, false, &eFunc ) )
1845 if ( bItemFound )
1846 bError = true; // duplicate (also across fields)
1847 else
1849 aFoundName = aFieldNames[nField];
1850 aFoundValue = pItemArr[nItem];
1851 eFoundFunc = eFunc;
1852 bItemFound = true;
1853 bUsed = true;
1860 if ( bItemFound && !bError )
1862 sheet::DataPilotFieldFilter aField;
1863 aField.FieldName = aFoundName;
1864 aField.MatchValue = aFoundValue;
1865 rFilters.push_back(aField);
1866 rFilterFuncs.push_back(eFoundFunc);
1867 aRemaining = aRemaining.copy(nMatched);
1871 if ( !bUsed )
1872 bError = true;
1874 // remove any number of spaces between entries
1875 aRemaining = comphelper::string::stripStart(aRemaining, ' ');
1878 if ( !bError && !bHasData && aDataNames.size() == 1 )
1880 // if there's only one data field, its name need not be specified
1881 rDataFieldName = aDataNames[0];
1882 bHasData = true;
1885 return bHasData && !bError;
1888 void ScDPObject::ToggleDetails(const DataPilotTableHeaderData& rElemDesc, ScDPObject* pDestObj)
1890 CreateObjects(); // create xSource if not already done
1892 // find dimension name
1894 uno::Reference<container::XNamed> xDim;
1895 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1896 uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
1897 long nIntCount = xIntDims->getCount();
1898 if ( rElemDesc.Dimension < nIntCount )
1900 uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface(
1901 xIntDims->getByIndex(rElemDesc.Dimension) );
1902 xDim = uno::Reference<container::XNamed>( xIntDim, uno::UNO_QUERY );
1904 OSL_ENSURE( xDim.is(), "dimension not found" );
1905 if ( !xDim.is() ) return;
1906 OUString aDimName = xDim->getName();
1908 uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
1909 bool bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1910 OUString(SC_UNO_DP_ISDATALAYOUT) );
1911 if (bDataLayout)
1913 // the elements of the data layout dimension can't be found by their names
1914 // -> don't change anything
1915 return;
1918 // query old state
1920 long nHierCount = 0;
1921 uno::Reference<container::XIndexAccess> xHiers;
1922 uno::Reference<sheet::XHierarchiesSupplier> xHierSupp( xDim, uno::UNO_QUERY );
1923 if ( xHierSupp.is() )
1925 uno::Reference<container::XNameAccess> xHiersName = xHierSupp->getHierarchies();
1926 xHiers = new ScNameToIndexAccess( xHiersName );
1927 nHierCount = xHiers->getCount();
1929 uno::Reference<uno::XInterface> xHier;
1930 if ( rElemDesc.Hierarchy < nHierCount )
1931 xHier = ScUnoHelpFunctions::AnyToInterface( xHiers->getByIndex(rElemDesc.Hierarchy) );
1932 OSL_ENSURE( xHier.is(), "hierarchy not found" );
1933 if ( !xHier.is() ) return;
1935 long nLevCount = 0;
1936 uno::Reference<container::XIndexAccess> xLevels;
1937 uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHier, uno::UNO_QUERY );
1938 if ( xLevSupp.is() )
1940 uno::Reference<container::XNameAccess> xLevsName = xLevSupp->getLevels();
1941 xLevels = new ScNameToIndexAccess( xLevsName );
1942 nLevCount = xLevels->getCount();
1944 uno::Reference<uno::XInterface> xLevel;
1945 if ( rElemDesc.Level < nLevCount )
1946 xLevel = ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex(rElemDesc.Level) );
1947 OSL_ENSURE( xLevel.is(), "level not found" );
1948 if ( !xLevel.is() ) return;
1950 uno::Reference<container::XNameAccess> xMembers;
1951 uno::Reference<sheet::XMembersSupplier> xMbrSupp( xLevel, uno::UNO_QUERY );
1952 if ( xMbrSupp.is() )
1953 xMembers = xMbrSupp->getMembers();
1955 bool bFound = false;
1956 bool bShowDetails = true;
1958 if ( xMembers.is() )
1960 if ( xMembers->hasByName(rElemDesc.MemberName) )
1962 uno::Reference<uno::XInterface> xMemberInt = ScUnoHelpFunctions::AnyToInterface(
1963 xMembers->getByName(rElemDesc.MemberName) );
1964 uno::Reference<beans::XPropertySet> xMbrProp( xMemberInt, uno::UNO_QUERY );
1965 if ( xMbrProp.is() )
1967 bShowDetails = ScUnoHelpFunctions::GetBoolProperty( xMbrProp,
1968 OUString(SC_UNO_DP_SHOWDETAILS) );
1969 //TODO: don't set bFound if property is unknown?
1970 bFound = true;
1975 OSL_ENSURE( bFound, "member not found" );
1976 (void)bFound;
1978 //TODO: use Hierarchy and Level in SaveData !!!!
1980 // modify pDestObj if set, this object otherwise
1981 ScDPSaveData* pModifyData = pDestObj ? ( pDestObj->pSaveData ) : pSaveData;
1982 OSL_ENSURE( pModifyData, "no data?" );
1983 if ( pModifyData )
1985 const OUString aName = rElemDesc.MemberName;
1986 pModifyData->GetDimensionByName(aDimName)->
1987 GetMemberByName(aName)->SetShowDetails( !bShowDetails ); // toggle
1989 if ( pDestObj )
1990 pDestObj->InvalidateData(); // re-init source from SaveData
1991 else
1992 InvalidateData(); // re-init source from SaveData
1996 static sal_uInt16 lcl_FirstSubTotal( const uno::Reference<beans::XPropertySet>& xDimProp ) // PIVOT_FUNC mask
1998 uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDimProp, uno::UNO_QUERY );
1999 if ( xDimProp.is() && xDimSupp.is() )
2001 uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
2002 long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
2003 OUString(SC_UNO_DP_USEDHIERARCHY) );
2004 if ( nHierarchy >= xHiers->getCount() )
2005 nHierarchy = 0;
2007 uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
2008 xHiers->getByIndex(nHierarchy) );
2009 uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
2010 if ( xHierSupp.is() )
2012 uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
2013 uno::Reference<uno::XInterface> xLevel =
2014 ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex( 0 ) );
2015 uno::Reference<beans::XPropertySet> xLevProp( xLevel, uno::UNO_QUERY );
2016 if ( xLevProp.is() )
2018 uno::Any aSubAny;
2021 aSubAny = xLevProp->getPropertyValue(
2022 OUString(SC_UNO_DP_SUBTOTAL) );
2024 catch(uno::Exception&)
2027 uno::Sequence<sheet::GeneralFunction> aSeq;
2028 if ( aSubAny >>= aSeq )
2030 sal_uInt16 nMask = 0;
2031 const sheet::GeneralFunction* pArray = aSeq.getConstArray();
2032 long nCount = aSeq.getLength();
2033 for (long i=0; i<nCount; i++)
2034 nMask |= ScDataPilotConversion::FunctionBit(pArray[i]);
2035 return nMask;
2041 OSL_FAIL("FirstSubTotal: NULL");
2042 return 0;
2045 namespace {
2047 class FindByColumn : public std::unary_function<ScPivotField, bool>
2049 SCsCOL mnCol;
2050 sal_uInt16 mnMask;
2051 public:
2052 FindByColumn(SCsCOL nCol, sal_uInt16 nMask) : mnCol(nCol), mnMask(nMask) {}
2053 bool operator() (const ScPivotField& r) const
2055 return r.nCol == mnCol && r.nFuncMask == mnMask;
2061 void lcl_FillOldFields( ScPivotFieldVector& rFields,
2062 const uno::Reference<sheet::XDimensionsSupplier>& xSource,
2063 sal_uInt16 nOrient, bool bAddData )
2065 ScPivotFieldVector aFields;
2067 bool bDataFound = false;
2069 //TODO: merge multiple occurrences (data field with different functions)
2070 //TODO: force data field in one dimension
2072 vector<long> aPos;
2074 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
2075 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
2076 long nDimCount = xDims->getCount();
2077 for (long nDim = 0; nDim < nDimCount; ++nDim)
2079 // Get dimension object.
2080 uno::Reference<uno::XInterface> xIntDim =
2081 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
2083 // dimension properties
2084 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
2086 // dimension orientation, hidden by default.
2087 long nDimOrient = ScUnoHelpFunctions::GetEnumProperty(
2088 xDimProp, OUString(SC_UNO_DP_ORIENTATION),
2089 sheet::DataPilotFieldOrientation_HIDDEN );
2091 if ( xDimProp.is() && nDimOrient == nOrient )
2093 // Let's take this dimension.
2095 // function mask.
2096 sal_uInt16 nMask = 0;
2097 if ( nOrient == sheet::DataPilotFieldOrientation_DATA )
2099 sheet::GeneralFunction eFunc = (sheet::GeneralFunction)ScUnoHelpFunctions::GetEnumProperty(
2100 xDimProp, OUString(SC_UNO_DP_FUNCTION),
2101 sheet::GeneralFunction_NONE );
2102 if ( eFunc == sheet::GeneralFunction_AUTO )
2104 //TODO: test for numeric data
2105 eFunc = sheet::GeneralFunction_SUM;
2107 nMask = ScDataPilotConversion::FunctionBit(eFunc);
2109 else
2110 nMask = lcl_FirstSubTotal( xDimProp ); // from first hierarchy
2112 // is this data layout dimension?
2113 bool bDataLayout = ScUnoHelpFunctions::GetBoolProperty(
2114 xDimProp, OUString(SC_UNO_DP_ISDATALAYOUT));
2116 // is this dimension cloned?
2117 long nDupSource = -1;
2120 uno::Any aOrigAny = xDimProp->getPropertyValue(
2121 OUString(SC_UNO_DP_ORIGINAL_POS));
2122 sal_Int32 nTmp = 0;
2123 if (aOrigAny >>= nTmp)
2124 nDupSource = static_cast<sal_Int32>(nTmp);
2126 catch(uno::Exception&)
2130 sal_uInt8 nDupCount = 0;
2131 if (nDupSource >= 0)
2133 // this dimension is cloned.
2135 SCsCOL nCompCol; // ID of the original dimension.
2136 if ( bDataLayout )
2137 nCompCol = PIVOT_DATA_FIELD;
2138 else
2139 nCompCol = static_cast<SCsCOL>(nDupSource); //TODO: seek source column from name
2141 ScPivotFieldVector::iterator it = std::find_if(aFields.begin(), aFields.end(), FindByColumn(nCompCol, nMask));
2142 if (it != aFields.end())
2143 nDupCount = it->mnDupCount + 1;
2146 aFields.push_back(ScPivotField());
2147 ScPivotField& rField = aFields.back();
2148 if (bDataLayout)
2150 rField.nCol = PIVOT_DATA_FIELD;
2151 bDataFound = true;
2153 else
2155 rField.mnOriginalDim = nDupSource;
2156 rField.nCol = static_cast<SCCOL>(nDim); //TODO: seek source column from name
2159 rField.nFuncMask = nMask;
2160 rField.mnDupCount = nDupCount;
2161 long nPos = ScUnoHelpFunctions::GetLongProperty(
2162 xDimProp, OUString(SC_UNO_DP_POSITION));
2163 aPos.push_back(nPos);
2167 if (nOrient == sheet::DataPilotFieldOrientation_DATA)
2168 xDimProp->getPropertyValue(OUString(SC_UNO_DP_REFVALUE))
2169 >>= rField.maFieldRef;
2171 catch (uno::Exception&)
2177 // sort by getPosition() value
2179 size_t nOutCount = aFields.size();
2180 if (nOutCount >= 1)
2182 for (size_t i = 0; i < nOutCount - 1; ++i)
2184 for (size_t j = 0; j + i < nOutCount - 1; ++j)
2186 if ( aPos[j+1] < aPos[j] )
2188 std::swap( aPos[j], aPos[j+1] );
2189 std::swap( aFields[j], aFields[j+1] );
2195 if (bAddData && !bDataFound)
2196 aFields.push_back(ScPivotField(PIVOT_DATA_FIELD, 0));
2198 rFields.swap(aFields);
2201 bool ScDPObject::FillOldParam(ScPivotParam& rParam) const
2203 const_cast<ScDPObject*>(this)->CreateObjects(); // xSource is needed for field numbers
2205 if (!xSource.is())
2206 return false;
2208 rParam.nCol = aOutRange.aStart.Col();
2209 rParam.nRow = aOutRange.aStart.Row();
2210 rParam.nTab = aOutRange.aStart.Tab();
2211 // ppLabelArr / nLabels is not changed
2213 bool bAddData = ( lcl_GetDataGetOrientation( xSource ) == sheet::DataPilotFieldOrientation_HIDDEN );
2214 lcl_FillOldFields(
2215 rParam.maPageFields, xSource, sheet::DataPilotFieldOrientation_PAGE, false);
2216 lcl_FillOldFields(
2217 rParam.maColFields, xSource, sheet::DataPilotFieldOrientation_COLUMN, bAddData);
2218 lcl_FillOldFields(
2219 rParam.maRowFields, xSource, sheet::DataPilotFieldOrientation_ROW, false);
2220 lcl_FillOldFields(
2221 rParam.maDataFields, xSource, sheet::DataPilotFieldOrientation_DATA, false);
2223 uno::Reference<beans::XPropertySet> xProp( xSource, uno::UNO_QUERY );
2224 if (xProp.is())
2228 rParam.bMakeTotalCol = ScUnoHelpFunctions::GetBoolProperty( xProp,
2229 OUString(SC_UNO_DP_COLGRAND), true );
2230 rParam.bMakeTotalRow = ScUnoHelpFunctions::GetBoolProperty( xProp,
2231 OUString(SC_UNO_DP_ROWGRAND), true );
2233 // following properties may be missing for external sources
2234 rParam.bIgnoreEmptyRows = ScUnoHelpFunctions::GetBoolProperty( xProp,
2235 OUString(SC_UNO_DP_IGNOREEMPTY) );
2236 rParam.bDetectCategories = ScUnoHelpFunctions::GetBoolProperty( xProp,
2237 OUString(SC_UNO_DP_REPEATEMPTY) );
2239 catch(uno::Exception&)
2241 // no error
2244 return true;
2247 static void lcl_FillLabelData( ScDPLabelData& rData, const uno::Reference< beans::XPropertySet >& xDimProp )
2249 uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDimProp, uno::UNO_QUERY );
2250 if (!xDimProp.is() || !xDimSupp.is())
2251 return;
2253 uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
2254 long nHierarchy = ScUnoHelpFunctions::GetLongProperty(
2255 xDimProp, OUString(SC_UNO_DP_USEDHIERARCHY));
2256 if ( nHierarchy >= xHiers->getCount() )
2257 nHierarchy = 0;
2258 rData.mnUsedHier = nHierarchy;
2260 uno::Reference<uno::XInterface> xHier =
2261 ScUnoHelpFunctions::AnyToInterface(xHiers->getByIndex(nHierarchy));
2263 uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
2264 if (!xHierSupp.is())
2265 return;
2267 uno::Reference<container::XIndexAccess> xLevels =
2268 new ScNameToIndexAccess( xHierSupp->getLevels() );
2270 uno::Reference<uno::XInterface> xLevel =
2271 ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex(0) );
2272 uno::Reference<beans::XPropertySet> xLevProp( xLevel, uno::UNO_QUERY );
2273 if (!xLevProp.is())
2274 return;
2276 rData.mbShowAll = ScUnoHelpFunctions::GetBoolProperty(
2277 xLevProp, OUString(SC_UNO_DP_SHOWEMPTY));
2279 rData.mbRepeatItemLabels = ScUnoHelpFunctions::GetBoolProperty(
2280 xLevProp, OUString(SC_UNO_DP_REPEATITEMLABELS));
2284 xLevProp->getPropertyValue( OUString( SC_UNO_DP_SORTING ) )
2285 >>= rData.maSortInfo;
2286 xLevProp->getPropertyValue( OUString( SC_UNO_DP_LAYOUT ) )
2287 >>= rData.maLayoutInfo;
2288 xLevProp->getPropertyValue( OUString( SC_UNO_DP_AUTOSHOW ) )
2289 >>= rData.maShowInfo;
2291 catch(uno::Exception&)
2296 bool ScDPObject::FillLabelDataForDimension(
2297 const uno::Reference<container::XIndexAccess>& xDims, sal_Int32 nDim, ScDPLabelData& rLabelData)
2299 uno::Reference<uno::XInterface> xIntDim =
2300 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
2301 uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
2302 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
2304 if (!xDimName.is() || !xDimProp.is())
2305 return false;
2307 bool bData = ScUnoHelpFunctions::GetBoolProperty(
2308 xDimProp, OUString(SC_UNO_DP_ISDATALAYOUT));
2309 //TODO: error checking -- is "IsDataLayoutDimension" property required??
2311 sal_Int32 nOrigPos = -1;
2312 OUString aFieldName;
2315 aFieldName = xDimName->getName();
2316 uno::Any aOrigAny = xDimProp->getPropertyValue(
2317 OUString(SC_UNO_DP_ORIGINAL_POS));
2318 aOrigAny >>= nOrigPos;
2320 catch(uno::Exception&)
2324 OUString aLayoutName = ScUnoHelpFunctions::GetStringProperty(
2325 xDimProp, OUString(SC_UNO_DP_LAYOUTNAME), OUString());
2327 OUString aSubtotalName = ScUnoHelpFunctions::GetStringProperty(
2328 xDimProp, OUString(SC_UNO_DP_FIELD_SUBTOTALNAME), OUString());
2330 bool bIsValue = true; //TODO: check
2332 // Name from the UNO dimension object may have trailing '*'s in which
2333 // case it's a duplicate dimension. Convert that to a duplicate index.
2335 sal_uInt8 nDupCount = ScDPUtil::getDuplicateIndex(aFieldName);
2336 aFieldName = ScDPUtil::getSourceDimensionName(aFieldName);
2338 rLabelData.maName = aFieldName;
2339 rLabelData.mnCol = static_cast<SCCOL>(nDim);
2340 rLabelData.mnDupCount = nDupCount;
2341 rLabelData.mbDataLayout = bData;
2342 rLabelData.mbIsValue = bIsValue;
2344 if (!bData)
2346 rLabelData.mnOriginalDim = static_cast<long>(nOrigPos);
2347 rLabelData.maLayoutName = aLayoutName;
2348 rLabelData.maSubtotalName = aSubtotalName;
2349 if (nOrigPos >= 0)
2350 // This is a duplicated dimension. Use the original dimension index.
2351 nDim = nOrigPos;
2352 GetHierarchies(nDim, rLabelData.maHiers);
2353 GetMembers(nDim, GetUsedHierarchy(nDim), rLabelData.maMembers);
2354 lcl_FillLabelData(rLabelData, xDimProp);
2355 rLabelData.mnFlags = ScUnoHelpFunctions::GetLongProperty(
2356 xDimProp, OUString(SC_UNO_DP_FLAGS), 0);
2358 return true;
2361 bool ScDPObject::FillLabelData(sal_Int32 nDim, ScDPLabelData& rLabels)
2363 CreateObjects();
2364 if (!xSource.is())
2365 return false;
2367 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
2368 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
2369 sal_Int32 nDimCount = xDims->getCount();
2370 if (nDimCount <= 0 || nDim >= nDimCount)
2371 return false;
2373 return FillLabelDataForDimension(xDims, nDim, rLabels);
2376 bool ScDPObject::FillLabelData(ScPivotParam& rParam)
2378 rParam.maLabelArray.clear();
2380 CreateObjects();
2381 if (!xSource.is())
2382 return false;
2384 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
2385 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
2386 sal_Int32 nDimCount = xDims->getCount();
2387 if (nDimCount <= 0)
2388 return false;
2390 for (sal_Int32 nDim = 0; nDim < nDimCount; ++nDim)
2392 std::unique_ptr<ScDPLabelData> pNewLabel(new ScDPLabelData);
2393 FillLabelDataForDimension(xDims, nDim, *pNewLabel);
2394 o3tl::ptr_container::push_back(rParam.maLabelArray, std::move(pNewLabel));
2397 return true;
2400 bool ScDPObject::GetHierarchiesNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xHiers )
2402 bool bRet = false;
2403 uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
2404 uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
2405 if( xIntDims.is() )
2407 uno::Reference<sheet::XHierarchiesSupplier> xHierSup(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
2408 if (xHierSup.is())
2410 xHiers.set( xHierSup->getHierarchies() );
2411 bRet = xHiers.is();
2414 return bRet;
2417 bool ScDPObject::GetHierarchies( sal_Int32 nDim, uno::Sequence< OUString >& rHiers )
2419 bool bRet = false;
2420 uno::Reference< container::XNameAccess > xHiersNA;
2421 if( GetHierarchiesNA( nDim, xHiersNA ) )
2423 rHiers = xHiersNA->getElementNames();
2424 bRet = true;
2426 return bRet;
2429 sal_Int32 ScDPObject::GetUsedHierarchy( sal_Int32 nDim )
2431 sal_Int32 nHier = 0;
2432 uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
2433 uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
2434 uno::Reference<beans::XPropertySet> xDim(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
2435 if (xDim.is())
2436 nHier = ScUnoHelpFunctions::GetLongProperty( xDim, OUString( SC_UNO_DP_USEDHIERARCHY ) );
2437 return nHier;
2440 bool ScDPObject::GetMembersNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xMembers )
2442 return GetMembersNA( nDim, GetUsedHierarchy( nDim ), xMembers );
2445 bool ScDPObject::GetMembersNA( sal_Int32 nDim, sal_Int32 nHier, uno::Reference< container::XNameAccess >& xMembers )
2447 bool bRet = false;
2448 uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
2449 uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
2450 uno::Reference<beans::XPropertySet> xDim(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
2451 if (xDim.is())
2453 uno::Reference<sheet::XHierarchiesSupplier> xHierSup(xDim, uno::UNO_QUERY);
2454 if (xHierSup.is())
2456 uno::Reference<container::XIndexAccess> xHiers(new ScNameToIndexAccess(xHierSup->getHierarchies()));
2457 uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHiers->getByIndex(nHier), uno::UNO_QUERY );
2458 if ( xLevSupp.is() )
2460 uno::Reference<container::XIndexAccess> xLevels(new ScNameToIndexAccess( xLevSupp->getLevels()));
2461 if (xLevels.is())
2463 sal_Int32 nLevCount = xLevels->getCount();
2464 if (nLevCount > 0)
2466 uno::Reference<sheet::XMembersSupplier> xMembSupp( xLevels->getByIndex(0), uno::UNO_QUERY );
2467 if ( xMembSupp.is() )
2469 xMembers.set(xMembSupp->getMembers());
2470 bRet = true;
2477 return bRet;
2480 // convert old pivot tables into new datapilot tables
2482 namespace {
2484 OUString lcl_GetDimName( const uno::Reference<sheet::XDimensionsSupplier>& xSource, long nDim )
2486 OUString aName;
2487 if ( xSource.is() )
2489 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
2490 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
2491 long nDimCount = xDims->getCount();
2492 if ( nDim < nDimCount )
2494 uno::Reference<uno::XInterface> xIntDim =
2495 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
2496 uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
2497 if (xDimName.is())
2501 aName = xDimName->getName();
2503 catch(uno::Exception&)
2509 return aName;
2512 bool hasFieldColumn(const vector<ScPivotField>* pRefFields, SCCOL nCol)
2514 if (!pRefFields)
2515 return false;
2517 vector<ScPivotField>::const_iterator itr = pRefFields->begin(), itrEnd = pRefFields->end();
2518 for (; itr != itrEnd; ++itr)
2520 if (itr->nCol == nCol)
2521 // This array of fields contains the specified column.
2522 return true;
2524 return false;
2527 class FindByOriginalDim : public std::unary_function<ScPivotField, bool>
2529 long mnDim;
2530 public:
2531 FindByOriginalDim(long nDim) : mnDim(nDim) {}
2532 bool operator() (const ScPivotField& r) const
2534 return mnDim == r.getOriginalDim();
2540 void ScDPObject::ConvertOrientation(
2541 ScDPSaveData& rSaveData, const ScPivotFieldVector& rFields, sal_uInt16 nOrient,
2542 const Reference<XDimensionsSupplier>& xSource,
2543 const ScDPLabelDataVector& rLabels,
2544 const ScPivotFieldVector* pRefColFields,
2545 const ScPivotFieldVector* pRefRowFields,
2546 const ScPivotFieldVector* pRefPageFields )
2548 ScPivotFieldVector::const_iterator itr, itrBeg = rFields.begin(), itrEnd = rFields.end();
2549 for (itr = itrBeg; itr != itrEnd; ++itr)
2551 const ScPivotField& rField = *itr;
2553 long nCol = rField.getOriginalDim();
2554 sal_uInt16 nFuncs = rField.nFuncMask;
2555 const sheet::DataPilotFieldReference& rFieldRef = rField.maFieldRef;
2557 ScDPSaveDimension* pDim = NULL;
2558 if ( nCol == PIVOT_DATA_FIELD )
2559 pDim = rSaveData.GetDataLayoutDimension();
2560 else
2562 OUString aDocStr = lcl_GetDimName( xSource, nCol ); // cols must start at 0
2563 if (!aDocStr.isEmpty())
2564 pDim = rSaveData.GetDimensionByName(aDocStr);
2565 else
2566 pDim = NULL;
2569 if (!pDim)
2570 continue;
2572 if ( nOrient == sheet::DataPilotFieldOrientation_DATA ) // set summary function
2574 // generate an individual entry for each function
2575 bool bFirst = true;
2577 // if a dimension is used for column/row/page and data,
2578 // use duplicated dimensions for all data occurrences
2579 if (hasFieldColumn(pRefColFields, nCol))
2580 bFirst = false;
2582 if (bFirst && hasFieldColumn(pRefRowFields, nCol))
2583 bFirst = false;
2585 if (bFirst && hasFieldColumn(pRefPageFields, nCol))
2586 bFirst = false;
2588 if (bFirst)
2590 // if set via api, a data column may occur several times
2591 // (if the function hasn't been changed yet) -> also look for duplicate data column
2592 bFirst = std::none_of(itrBeg, itr, FindByOriginalDim(nCol));
2595 sheet::GeneralFunction eFunc = ScDataPilotConversion::FirstFunc(rField.nFuncMask);
2596 if (!bFirst)
2597 pDim = rSaveData.DuplicateDimension(pDim->GetName());
2598 pDim->SetOrientation(nOrient);
2599 pDim->SetFunction(sal::static_int_cast<sal_uInt16>(eFunc));
2601 if( rFieldRef.ReferenceType == sheet::DataPilotFieldReferenceType::NONE )
2602 pDim->SetReferenceValue(0);
2603 else
2604 pDim->SetReferenceValue(&rFieldRef);
2606 else // set SubTotals
2608 pDim->SetOrientation( nOrient );
2610 sal_uInt16 nFuncArray[16];
2611 sal_uInt16 nFuncCount = 0;
2612 sal_uInt16 nMask = 1;
2613 for (sal_uInt16 nBit=0; nBit<16; nBit++)
2615 if ( nFuncs & nMask )
2616 nFuncArray[nFuncCount++] = sal::static_int_cast<sal_uInt16>(ScDataPilotConversion::FirstFunc( nMask ));
2617 nMask *= 2;
2619 pDim->SetSubTotals( nFuncCount, nFuncArray );
2621 // ShowEmpty was implicit in old tables,
2622 // must be set for data layout dimension (not accessible in dialog)
2623 if ( nCol == PIVOT_DATA_FIELD )
2624 pDim->SetShowEmpty( true );
2627 size_t nDimIndex = rField.nCol;
2628 pDim->RemoveLayoutName();
2629 pDim->RemoveSubtotalName();
2630 if (nDimIndex < rLabels.size())
2632 const ScDPLabelData& rLabel = rLabels[nDimIndex];
2633 if (!rLabel.maLayoutName.isEmpty())
2634 pDim->SetLayoutName(rLabel.maLayoutName);
2635 if (!rLabel.maSubtotalName.isEmpty())
2636 pDim->SetSubtotalName(rLabel.maSubtotalName);
2641 bool ScDPObject::IsOrientationAllowed( sal_uInt16 nOrient, sal_Int32 nDimFlags )
2643 bool bAllowed = true;
2644 switch (nOrient)
2646 case sheet::DataPilotFieldOrientation_PAGE:
2647 bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_PAGE_ORIENTATION ) == 0;
2648 break;
2649 case sheet::DataPilotFieldOrientation_COLUMN:
2650 bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_COLUMN_ORIENTATION ) == 0;
2651 break;
2652 case sheet::DataPilotFieldOrientation_ROW:
2653 bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_ROW_ORIENTATION ) == 0;
2654 break;
2655 case sheet::DataPilotFieldOrientation_DATA:
2656 bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_DATA_ORIENTATION ) == 0;
2657 break;
2658 default:
2660 // allowed to remove from previous orientation
2663 return bAllowed;
2666 bool ScDPObject::HasRegisteredSources()
2668 bool bFound = false;
2670 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
2671 uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
2672 if ( xEnAc.is() )
2674 uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
2675 OUString( SCDPSOURCE_SERVICE ) );
2676 if ( xEnum.is() && xEnum->hasMoreElements() )
2677 bFound = true;
2680 return bFound;
2683 uno::Sequence<OUString> ScDPObject::GetRegisteredSources()
2685 uno::Sequence<OUString> aSeq(0);
2687 // use implementation names...
2689 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
2690 uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
2691 if ( xEnAc.is() )
2693 uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
2694 OUString( SCDPSOURCE_SERVICE ) );
2695 if ( xEnum.is() )
2697 long nCount = 0;
2698 while ( xEnum->hasMoreElements() )
2700 uno::Any aAddInAny = xEnum->nextElement();
2701 // if ( aAddInAny.getReflection()->getTypeClass() == TypeClass_INTERFACE )
2703 uno::Reference<uno::XInterface> xIntFac;
2704 aAddInAny >>= xIntFac;
2705 if ( xIntFac.is() )
2707 uno::Reference<lang::XServiceInfo> xInfo( xIntFac, uno::UNO_QUERY );
2708 if ( xInfo.is() )
2710 OUString sName = xInfo->getImplementationName();
2712 aSeq.realloc( nCount+1 );
2713 aSeq.getArray()[nCount] = sName;
2714 ++nCount;
2722 return aSeq;
2725 uno::Reference<sheet::XDimensionsSupplier> ScDPObject::CreateSource( const ScDPServiceDesc& rDesc )
2727 OUString aImplName = rDesc.aServiceName;
2728 uno::Reference<sheet::XDimensionsSupplier> xRet = NULL;
2730 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
2731 uno::Reference<container::XContentEnumerationAccess> xEnAc(xManager, uno::UNO_QUERY);
2732 if (!xEnAc.is())
2733 return xRet;
2735 uno::Reference<container::XEnumeration> xEnum =
2736 xEnAc->createContentEnumeration(OUString(SCDPSOURCE_SERVICE));
2737 if (!xEnum.is())
2738 return xRet;
2740 while (xEnum->hasMoreElements() && !xRet.is())
2742 uno::Any aAddInAny = xEnum->nextElement();
2743 uno::Reference<uno::XInterface> xIntFac;
2744 aAddInAny >>= xIntFac;
2745 if (!xIntFac.is())
2746 continue;
2748 uno::Reference<lang::XServiceInfo> xInfo(xIntFac, uno::UNO_QUERY);
2749 if (!xInfo.is() || xInfo->getImplementationName() != aImplName)
2750 continue;
2754 // #i113160# try XSingleComponentFactory in addition to (old) XSingleServiceFactory,
2755 // passing the context to the component (see ScUnoAddInCollection::Initialize)
2757 uno::Reference<uno::XInterface> xInterface;
2758 uno::Reference<uno::XComponentContext> xCtx(
2759 comphelper::getComponentContext(xManager));
2760 uno::Reference<lang::XSingleComponentFactory> xCFac( xIntFac, uno::UNO_QUERY );
2761 if (xCFac.is())
2762 xInterface = xCFac->createInstanceWithContext(xCtx);
2764 if (!xInterface.is())
2766 uno::Reference<lang::XSingleServiceFactory> xFac( xIntFac, uno::UNO_QUERY );
2767 if ( xFac.is() )
2768 xInterface = xFac->createInstance();
2771 uno::Reference<lang::XInitialization> xInit( xInterface, uno::UNO_QUERY );
2772 if (xInit.is())
2774 // initialize
2775 uno::Sequence<uno::Any> aSeq(4);
2776 uno::Any* pArray = aSeq.getArray();
2777 pArray[0] <<= OUString( rDesc.aParSource );
2778 pArray[1] <<= OUString( rDesc.aParName );
2779 pArray[2] <<= OUString( rDesc.aParUser );
2780 pArray[3] <<= OUString( rDesc.aParPass );
2781 xInit->initialize( aSeq );
2783 xRet = uno::Reference<sheet::XDimensionsSupplier>( xInterface, uno::UNO_QUERY );
2785 catch(uno::Exception&)
2790 return xRet;
2793 #if DEBUG_PIVOT_TABLE
2794 void ScDPObject::DumpCache() const
2796 if (!mpTableData)
2797 return;
2799 const ScDPCache* pCache = mpTableData->GetCacheTable().getCache();
2800 if (!pCache)
2801 return;
2803 pCache->Dump();
2805 #endif
2807 ScDPCollection::SheetCaches::SheetCaches(ScDocument* pDoc) : mpDoc(pDoc) {}
2809 namespace {
2811 struct FindInvalidRange : public std::unary_function<ScRange, bool>
2813 bool operator() (const ScRange& r) const
2815 return !r.IsValid();
2819 void setGroupItemsToCache( ScDPCache& rCache, const std::set<ScDPObject*>& rRefs )
2821 // Go through all referencing pivot tables, and re-fill the group dimension info.
2822 std::set<ScDPObject*>::const_iterator itRef = rRefs.begin(), itRefEnd = rRefs.end();
2823 for (; itRef != itRefEnd; ++itRef)
2825 const ScDPObject* pObj = *itRef;
2826 const ScDPSaveData* pSave = pObj->GetSaveData();
2827 if (!pSave)
2828 continue;
2830 const ScDPDimensionSaveData* pGroupDims = pSave->GetExistingDimensionData();
2831 if (!pGroupDims)
2832 continue;
2834 pGroupDims->WriteToCache(rCache);
2840 bool ScDPCollection::SheetCaches::hasCache(const ScRange& rRange) const
2842 RangeIndexType::const_iterator it = std::find(maRanges.begin(), maRanges.end(), rRange);
2843 if (it == maRanges.end())
2844 return false;
2846 // Already cached.
2847 size_t nIndex = std::distance(maRanges.begin(), it);
2848 CachesType::const_iterator itCache = maCaches.find(nIndex);
2849 return itCache != maCaches.end();
2852 const ScDPCache* ScDPCollection::SheetCaches::getCache(const ScRange& rRange, const ScDPDimensionSaveData* pDimData)
2854 RangeIndexType::iterator it = std::find(maRanges.begin(), maRanges.end(), rRange);
2855 if (it != maRanges.end())
2857 // Already cached.
2858 size_t nIndex = std::distance(maRanges.begin(), it);
2859 CachesType::iterator itCache = maCaches.find(nIndex);
2860 if (itCache == maCaches.end())
2862 OSL_FAIL("Cache pool and index pool out-of-sync !!!");
2863 return NULL;
2866 if (pDimData)
2867 pDimData->WriteToCache(*itCache->second);
2869 return itCache->second;
2872 // Not cached. Create a new cache.
2873 ::std::unique_ptr<ScDPCache> pCache(new ScDPCache(mpDoc));
2874 pCache->InitFromDoc(mpDoc, rRange);
2875 if (pDimData)
2876 pDimData->WriteToCache(*pCache);
2878 // Get the smallest available range index.
2879 it = std::find_if(maRanges.begin(), maRanges.end(), FindInvalidRange());
2881 size_t nIndex = maRanges.size();
2882 if (it == maRanges.end())
2884 // All range indices are valid. Append a new index.
2885 maRanges.push_back(rRange);
2887 else
2889 // Slot with invalid range. Re-use this slot.
2890 *it = rRange;
2891 nIndex = std::distance(maRanges.begin(), it);
2894 const ScDPCache* p = pCache.get();
2895 o3tl::ptr_container::insert(maCaches, nIndex, std::move(pCache));
2896 return p;
2899 ScDPCache* ScDPCollection::SheetCaches::getExistingCache(const ScRange& rRange)
2901 RangeIndexType::iterator it = std::find(maRanges.begin(), maRanges.end(), rRange);
2902 if (it == maRanges.end())
2903 // Not cached.
2904 return NULL;
2906 // Already cached.
2907 size_t nIndex = std::distance(maRanges.begin(), it);
2908 CachesType::iterator itCache = maCaches.find(nIndex);
2909 if (itCache == maCaches.end())
2911 OSL_FAIL("Cache pool and index pool out-of-sync !!!");
2912 return NULL;
2915 return itCache->second;
2918 const ScDPCache* ScDPCollection::SheetCaches::getExistingCache(const ScRange& rRange) const
2920 RangeIndexType::const_iterator it = std::find(maRanges.begin(), maRanges.end(), rRange);
2921 if (it == maRanges.end())
2922 // Not cached.
2923 return NULL;
2925 // Already cached.
2926 size_t nIndex = std::distance(maRanges.begin(), it);
2927 CachesType::const_iterator itCache = maCaches.find(nIndex);
2928 if (itCache == maCaches.end())
2930 OSL_FAIL("Cache pool and index pool out-of-sync !!!");
2931 return NULL;
2934 return itCache->second;
2937 size_t ScDPCollection::SheetCaches::size() const
2939 return maCaches.size();
2942 void ScDPCollection::SheetCaches::updateReference(
2943 UpdateRefMode eMode, const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz)
2945 if (maRanges.empty())
2946 // No caches.
2947 return;
2949 RangeIndexType::iterator it = maRanges.begin(), itEnd = maRanges.end();
2950 for (; it != itEnd; ++it)
2952 const ScRange& rKeyRange = *it;
2953 SCCOL nCol1 = rKeyRange.aStart.Col();
2954 SCROW nRow1 = rKeyRange.aStart.Row();
2955 SCTAB nTab1 = rKeyRange.aStart.Tab();
2956 SCCOL nCol2 = rKeyRange.aEnd.Col();
2957 SCROW nRow2 = rKeyRange.aEnd.Row();
2958 SCTAB nTab2 = rKeyRange.aEnd.Tab();
2960 ScRefUpdateRes eRes = ScRefUpdate::Update(
2961 mpDoc, eMode,
2962 r.aStart.Col(), r.aStart.Row(), r.aStart.Tab(),
2963 r.aEnd.Col(), r.aEnd.Row(), r.aEnd.Tab(), nDx, nDy, nDz,
2964 nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
2966 if (eRes != UR_NOTHING)
2968 // range updated.
2969 ScRange aNew(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
2970 *it = aNew;
2975 void ScDPCollection::SheetCaches::updateCache(const ScRange& rRange, std::set<ScDPObject*>& rRefs)
2977 RangeIndexType::iterator it = std::find(maRanges.begin(), maRanges.end(), rRange);
2978 if (it == maRanges.end())
2980 // Not cached. Nothing to do.
2981 rRefs.clear();
2982 return;
2985 size_t nIndex = std::distance(maRanges.begin(), it);
2986 CachesType::iterator itCache = maCaches.find(nIndex);
2987 if (itCache == maCaches.end())
2989 OSL_FAIL("Cache pool and index pool out-of-sync !!!");
2990 rRefs.clear();
2991 return;
2994 ScDPCache& rCache = *itCache->second;
2996 // Update the cache with new cell values. This will clear all group dimension info.
2997 rCache.InitFromDoc(mpDoc, rRange);
2999 std::set<ScDPObject*> aRefs(rCache.GetAllReferences());
3000 rRefs.swap(aRefs);
3002 // Make sure to re-populate the group dimension info.
3003 setGroupItemsToCache(rCache, rRefs);
3006 bool ScDPCollection::SheetCaches::remove(const ScDPCache* p)
3008 CachesType::iterator it = maCaches.begin(), itEnd = maCaches.end();
3009 for (; it != itEnd; ++it)
3011 if (it->second == p)
3013 size_t idx = it->first;
3014 maCaches.erase(it);
3015 maRanges[idx].SetInvalid();
3016 return true;
3019 return false;
3022 const std::vector<ScRange>& ScDPCollection::SheetCaches::getAllRanges() const
3024 return maRanges;
3027 ScDPCollection::NameCaches::NameCaches(ScDocument* pDoc) : mpDoc(pDoc) {}
3029 bool ScDPCollection::NameCaches::hasCache(const OUString& rName) const
3031 return maCaches.count(rName) != 0;
3034 const ScDPCache* ScDPCollection::NameCaches::getCache(
3035 const OUString& rName, const ScRange& rRange, const ScDPDimensionSaveData* pDimData)
3037 CachesType::const_iterator itr = maCaches.find(rName);
3038 if (itr != maCaches.end())
3039 // already cached.
3040 return itr->second;
3042 ::std::unique_ptr<ScDPCache> pCache(new ScDPCache(mpDoc));
3043 pCache->InitFromDoc(mpDoc, rRange);
3044 if (pDimData)
3045 pDimData->WriteToCache(*pCache);
3047 const ScDPCache* p = pCache.get();
3048 o3tl::ptr_container::insert(maCaches, rName, std::move(pCache));
3049 return p;
3052 ScDPCache* ScDPCollection::NameCaches::getExistingCache(const OUString& rName)
3054 CachesType::iterator itr = maCaches.find(rName);
3055 return itr != maCaches.end() ? itr->second : NULL;
3058 size_t ScDPCollection::NameCaches::size() const
3060 return maCaches.size();
3063 void ScDPCollection::NameCaches::updateCache(
3064 const OUString& rName, const ScRange& rRange, std::set<ScDPObject*>& rRefs)
3066 CachesType::iterator itr = maCaches.find(rName);
3067 if (itr == maCaches.end())
3069 rRefs.clear();
3070 return;
3073 ScDPCache& rCache = *itr->second;
3074 // Update the cache with new cell values. This will clear all group dimension info.
3075 rCache.InitFromDoc(mpDoc, rRange);
3077 std::set<ScDPObject*> aRefs(rCache.GetAllReferences());
3078 rRefs.swap(aRefs);
3080 // Make sure to re-populate the group dimension info.
3081 setGroupItemsToCache(rCache, rRefs);
3084 bool ScDPCollection::NameCaches::remove(const ScDPCache* p)
3086 CachesType::iterator it = maCaches.begin(), itEnd = maCaches.end();
3087 for (; it != itEnd; ++it)
3089 if (it->second == p)
3091 maCaches.erase(it);
3092 return true;
3095 return false;
3098 ScDPCollection::DBType::DBType(sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand) :
3099 mnSdbType(nSdbType), maDBName(rDBName), maCommand(rCommand) {}
3101 bool ScDPCollection::DBType::less::operator() (const DBType& left, const DBType& right) const
3103 return left < right;
3106 ScDPCollection::DBCaches::DBCaches(ScDocument* pDoc) : mpDoc(pDoc) {}
3108 bool ScDPCollection::DBCaches::hasCache(sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand) const
3110 DBType aType(nSdbType, rDBName, rCommand);
3111 CachesType::const_iterator itr = maCaches.find(aType);
3112 return itr != maCaches.end();
3115 const ScDPCache* ScDPCollection::DBCaches::getCache(
3116 sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand,
3117 const ScDPDimensionSaveData* pDimData)
3119 DBType aType(nSdbType, rDBName, rCommand);
3120 CachesType::const_iterator itr = maCaches.find(aType);
3121 if (itr != maCaches.end())
3122 // already cached.
3123 return itr->second;
3125 uno::Reference<sdbc::XRowSet> xRowSet = createRowSet(nSdbType, rDBName, rCommand);
3126 if (!xRowSet.is())
3127 return NULL;
3129 ::std::unique_ptr<ScDPCache> pCache(new ScDPCache(mpDoc));
3130 SvNumberFormatter aFormat( comphelper::getProcessComponentContext(), ScGlobal::eLnge);
3131 DBConnector aDB(*pCache, xRowSet, *aFormat.GetNullDate());
3132 if (!aDB.isValid())
3133 return NULL;
3135 if (!pCache->InitFromDataBase(aDB))
3137 // initialization failed.
3138 comphelper::disposeComponent(xRowSet);
3139 return NULL;
3142 if (pDimData)
3143 pDimData->WriteToCache(*pCache);
3145 ::comphelper::disposeComponent(xRowSet);
3146 const ScDPCache* p = pCache.get();
3147 o3tl::ptr_container::insert(maCaches, aType, std::move(pCache));
3148 return p;
3151 ScDPCache* ScDPCollection::DBCaches::getExistingCache(
3152 sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand)
3154 DBType aType(nSdbType, rDBName, rCommand);
3155 CachesType::iterator itr = maCaches.find(aType);
3156 return itr != maCaches.end() ? itr->second : NULL;
3159 uno::Reference<sdbc::XRowSet> ScDPCollection::DBCaches::createRowSet(
3160 sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand)
3162 uno::Reference<sdbc::XRowSet> xRowSet;
3165 xRowSet = uno::Reference<sdbc::XRowSet>(
3166 comphelper::getProcessServiceFactory()->createInstance(
3167 OUString(SC_SERVICE_ROWSET)),
3168 UNO_QUERY);
3170 uno::Reference<beans::XPropertySet> xRowProp(xRowSet, UNO_QUERY);
3171 OSL_ENSURE( xRowProp.is(), "can't get RowSet" );
3172 if (!xRowProp.is())
3174 xRowSet.set(NULL);
3175 return xRowSet;
3178 // set source parameters
3180 uno::Any aAny;
3181 aAny <<= rDBName;
3182 xRowProp->setPropertyValue(
3183 OUString(SC_DBPROP_DATASOURCENAME), aAny );
3185 aAny <<= rCommand;
3186 xRowProp->setPropertyValue(
3187 OUString(SC_DBPROP_COMMAND), aAny );
3189 aAny <<= nSdbType;
3190 xRowProp->setPropertyValue(
3191 OUString(SC_DBPROP_COMMANDTYPE), aAny );
3193 uno::Reference<sdb::XCompletedExecution> xExecute( xRowSet, uno::UNO_QUERY );
3194 if ( xExecute.is() )
3196 uno::Reference<task::XInteractionHandler> xHandler(
3197 task::InteractionHandler::createWithParent(comphelper::getProcessComponentContext(), 0),
3198 uno::UNO_QUERY_THROW);
3199 xExecute->executeWithCompletion( xHandler );
3201 else
3202 xRowSet->execute();
3204 return xRowSet;
3206 catch ( const sdbc::SQLException& rError )
3208 //! store error message
3209 ScopedVclPtrInstance< InfoBox > aInfoBox( nullptr, OUString(rError.Message) );
3210 aInfoBox->Execute();
3212 catch ( uno::Exception& )
3214 OSL_FAIL("Unexpected exception in database");
3217 xRowSet.set(NULL);
3218 return xRowSet;
3221 void ScDPCollection::DBCaches::updateCache(
3222 sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand,
3223 std::set<ScDPObject*>& rRefs)
3225 DBType aType(nSdbType, rDBName, rCommand);
3226 CachesType::iterator it = maCaches.find(aType);
3227 if (it == maCaches.end())
3229 // not cached.
3230 rRefs.clear();
3231 return;
3234 ScDPCache& rCache = *it->second;
3236 uno::Reference<sdbc::XRowSet> xRowSet = createRowSet(nSdbType, rDBName, rCommand);
3237 if (!xRowSet.is())
3239 rRefs.clear();
3240 return;
3243 SvNumberFormatter aFormat( comphelper::getProcessComponentContext(), ScGlobal::eLnge);
3244 DBConnector aDB(rCache, xRowSet, *aFormat.GetNullDate());
3245 if (!aDB.isValid())
3246 return;
3248 if (!rCache.InitFromDataBase(aDB))
3250 // initialization failed.
3251 rRefs.clear();
3252 comphelper::disposeComponent(xRowSet);
3253 return;
3256 comphelper::disposeComponent(xRowSet);
3257 std::set<ScDPObject*> aRefs(rCache.GetAllReferences());
3258 aRefs.swap(rRefs);
3260 // Make sure to re-populate the group dimension info.
3261 setGroupItemsToCache(rCache, rRefs);
3264 bool ScDPCollection::DBCaches::remove(const ScDPCache* p)
3266 CachesType::iterator it = maCaches.begin(), itEnd = maCaches.end();
3267 for (; it != itEnd; ++it)
3269 if (it->second == p)
3271 maCaches.erase(it);
3272 return true;
3275 return false;
3278 ScDPCollection::ScDPCollection(ScDocument* pDocument) :
3279 mpDoc( pDocument ),
3280 maSheetCaches(pDocument),
3281 maNameCaches(pDocument),
3282 maDBCaches(pDocument)
3286 ScDPCollection::ScDPCollection(const ScDPCollection& r) :
3287 mpDoc(r.mpDoc),
3288 maSheetCaches(r.mpDoc),
3289 maNameCaches(r.mpDoc),
3290 maDBCaches(r.mpDoc)
3294 ScDPCollection::~ScDPCollection()
3296 maTables.clear();
3299 namespace {
3302 * Unary predicate to match DP objects by the table ID.
3304 class MatchByTable : public unary_function<ScDPObject, bool>
3306 SCTAB mnTab;
3307 public:
3308 MatchByTable(SCTAB nTab) : mnTab(nTab) {}
3310 bool operator() (const ScDPObject& rObj) const
3312 return rObj.GetOutRange().aStart.Tab() == mnTab;
3318 sal_uLong ScDPCollection::ReloadCache(ScDPObject* pDPObj, std::set<ScDPObject*>& rRefs)
3320 if (!pDPObj)
3321 return STR_ERR_DATAPILOTSOURCE;
3323 if (pDPObj->IsSheetData())
3325 // data source is internal sheet.
3326 const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc();
3327 if (!pDesc)
3328 return STR_ERR_DATAPILOTSOURCE;
3330 sal_uLong nErrId = pDesc->CheckSourceRange();
3331 if (nErrId)
3332 return nErrId;
3334 if (pDesc->HasRangeName())
3336 // cache by named range
3337 ScDPCollection::NameCaches& rCaches = GetNameCaches();
3338 if (rCaches.hasCache(pDesc->GetRangeName()))
3339 rCaches.updateCache(pDesc->GetRangeName(), pDesc->GetSourceRange(), rRefs);
3340 else
3342 // Not cached yet. Collect all tables that use this named
3343 // range as data source.
3344 GetAllTables(pDesc->GetRangeName(), rRefs);
3347 else
3349 // cache by cell range
3350 ScDPCollection::SheetCaches& rCaches = GetSheetCaches();
3351 if (rCaches.hasCache(pDesc->GetSourceRange()))
3352 rCaches.updateCache(pDesc->GetSourceRange(), rRefs);
3353 else
3355 // Not cached yet. Collect all tables that use this range as
3356 // data source.
3357 GetAllTables(pDesc->GetSourceRange(), rRefs);
3361 else if (pDPObj->IsImportData())
3363 // data source is external database.
3364 const ScImportSourceDesc* pDesc = pDPObj->GetImportSourceDesc();
3365 if (!pDesc)
3366 return STR_ERR_DATAPILOTSOURCE;
3368 ScDPCollection::DBCaches& rCaches = GetDBCaches();
3369 if (rCaches.hasCache(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject))
3370 rCaches.updateCache(
3371 pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, rRefs);
3372 else
3374 // Not cached yet. Collect all tables that use this range as
3375 // data source.
3376 GetAllTables(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, rRefs);
3379 return 0;
3382 bool ScDPCollection::ReloadGroupsInCache(ScDPObject* pDPObj, std::set<ScDPObject*>& rRefs)
3384 if (!pDPObj)
3385 return false;
3387 const ScDPSaveData* pSaveData = pDPObj->GetSaveData();
3388 if (!pSaveData)
3389 return false;
3391 // Note: Unlike reloading cache, when modifying the group dimensions the
3392 // cache may not have all its references when this method is called.
3393 // Therefore, we need to always call GetAllTables to get its correct
3394 // references even when the cache exists. This may become a non-issue
3395 // if/when we implement loading and saving of pivot caches.
3397 ScDPCache* pCache = NULL;
3399 if (pDPObj->IsSheetData())
3401 // data source is internal sheet.
3402 const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc();
3403 if (!pDesc)
3404 return false;
3406 if (pDesc->HasRangeName())
3408 // cache by named range
3409 ScDPCollection::NameCaches& rCaches = GetNameCaches();
3410 if (rCaches.hasCache(pDesc->GetRangeName()))
3411 pCache = rCaches.getExistingCache(pDesc->GetRangeName());
3412 else
3414 // Not cached yet. Cache the source dimensions. Groups will
3415 // be added below.
3416 pCache = const_cast<ScDPCache*>(
3417 rCaches.getCache(pDesc->GetRangeName(), pDesc->GetSourceRange(), NULL));
3419 GetAllTables(pDesc->GetRangeName(), rRefs);
3421 else
3423 // cache by cell range
3424 ScDPCollection::SheetCaches& rCaches = GetSheetCaches();
3425 if (rCaches.hasCache(pDesc->GetSourceRange()))
3426 pCache = rCaches.getExistingCache(pDesc->GetSourceRange());
3427 else
3429 // Not cached yet. Cache the source dimensions. Groups will
3430 // be added below.
3431 pCache = const_cast<ScDPCache*>(
3432 rCaches.getCache(pDesc->GetSourceRange(), NULL));
3434 GetAllTables(pDesc->GetSourceRange(), rRefs);
3437 else if (pDPObj->IsImportData())
3439 // data source is external database.
3440 const ScImportSourceDesc* pDesc = pDPObj->GetImportSourceDesc();
3441 if (!pDesc)
3442 return false;
3444 ScDPCollection::DBCaches& rCaches = GetDBCaches();
3445 if (rCaches.hasCache(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject))
3446 pCache = rCaches.getExistingCache(
3447 pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject);
3448 else
3450 // Not cached yet. Cache the source dimensions. Groups will
3451 // be added below.
3452 pCache = const_cast<ScDPCache*>(
3453 rCaches.getCache(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, NULL));
3455 GetAllTables(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, rRefs);
3458 if (!pCache)
3459 return false;
3461 // Clear the existing group data from the cache, and rebuild it from the
3462 // dimension data.
3463 pCache->ClearGroupFields();
3464 const ScDPDimensionSaveData* pDimData = pSaveData->GetExistingDimensionData();
3465 if (pDimData)
3466 pDimData->WriteToCache(*pCache);
3467 return true;
3470 void ScDPCollection::DeleteOnTab( SCTAB nTab )
3472 maTables.erase_if(MatchByTable(nTab));
3475 void ScDPCollection::UpdateReference( UpdateRefMode eUpdateRefMode,
3476 const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
3478 TablesType::iterator itr = maTables.begin(), itrEnd = maTables.end();
3479 for (; itr != itrEnd; ++itr)
3480 itr->UpdateReference(eUpdateRefMode, r, nDx, nDy, nDz);
3482 // Update the source ranges of the caches.
3483 maSheetCaches.updateReference(eUpdateRefMode, r, nDx, nDy, nDz);
3486 void ScDPCollection::CopyToTab( SCTAB nOld, SCTAB nNew )
3488 TablesType aAdded;
3489 TablesType::const_iterator it = maTables.begin(), itEnd = maTables.end();
3490 for (; it != itEnd; ++it)
3492 const ScDPObject& rObj = *it;
3493 ScRange aOutRange = rObj.GetOutRange();
3494 if (aOutRange.aStart.Tab() != nOld)
3495 continue;
3497 ScAddress& s = aOutRange.aStart;
3498 ScAddress& e = aOutRange.aEnd;
3499 s.SetTab(nNew);
3500 e.SetTab(nNew);
3501 std::unique_ptr<ScDPObject> pNew(new ScDPObject(rObj));
3502 pNew->SetOutRange(aOutRange);
3503 mpDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
3504 o3tl::ptr_container::push_back(aAdded, std::move(pNew));
3507 maTables.transfer(maTables.end(), aAdded.begin(), aAdded.end(), aAdded);
3510 bool ScDPCollection::RefsEqual( const ScDPCollection& r ) const
3512 if (maTables.size() != r.maTables.size())
3513 return false;
3515 TablesType::const_iterator itr = maTables.begin(), itr2 = r.maTables.begin(), itrEnd = maTables.end();
3516 for (; itr != itrEnd; ++itr, ++itr2)
3517 if (!itr->RefsEqual(*itr2))
3518 return false;
3520 return true;
3523 void ScDPCollection::WriteRefsTo( ScDPCollection& r ) const
3525 if ( maTables.size() == r.maTables.size() )
3527 //TODO: assert equal names?
3528 TablesType::const_iterator itr = maTables.begin(), itrEnd = maTables.end();
3529 TablesType::iterator itr2 = r.maTables.begin();
3530 for (; itr != itrEnd; ++itr, ++itr2)
3531 itr->WriteRefsTo(*itr2);
3533 else
3535 // #i8180# If data pilot tables were deleted with their sheet,
3536 // this collection contains extra entries that must be restored.
3537 // Matching objects are found by their names.
3538 size_t nSrcSize = maTables.size();
3539 size_t nDestSize = r.maTables.size();
3540 OSL_ENSURE( nSrcSize >= nDestSize, "WriteRefsTo: missing entries in document" );
3541 for (size_t nSrcPos = 0; nSrcPos < nSrcSize; ++nSrcPos)
3543 const ScDPObject& rSrcObj = maTables[nSrcPos];
3544 const OUString& aName = rSrcObj.GetName();
3545 bool bFound = false;
3546 for (size_t nDestPos = 0; nDestPos < nDestSize && !bFound; ++nDestPos)
3548 ScDPObject& rDestObj = r.maTables[nDestPos];
3549 if (rDestObj.GetName() == aName)
3551 rSrcObj.WriteRefsTo(rDestObj); // found object, copy refs
3552 bFound = true;
3556 if (!bFound)
3558 // none found, re-insert deleted object (see ScUndoDataPilot::Undo)
3560 ScDPObject* pDestObj = new ScDPObject(rSrcObj);
3561 r.InsertNewTable(pDestObj);
3564 OSL_ENSURE( maTables.size() == r.maTables.size(), "WriteRefsTo: couldn't restore all entries" );
3568 size_t ScDPCollection::GetCount() const
3570 return maTables.size();
3573 ScDPObject* ScDPCollection::operator [](size_t nIndex)
3575 return &maTables[nIndex];
3578 const ScDPObject* ScDPCollection::operator [](size_t nIndex) const
3580 return &maTables[nIndex];
3583 const ScDPObject* ScDPCollection::GetByName(const OUString& rName) const
3585 TablesType::const_iterator itr = maTables.begin(), itrEnd = maTables.end();
3586 for (; itr != itrEnd; ++itr)
3587 if (itr->GetName() == rName)
3588 return &(*itr);
3590 return NULL;
3593 OUString ScDPCollection::CreateNewName( sal_uInt16 nMin ) const
3595 OUString aBase("DataPilot");
3597 size_t n = maTables.size();
3598 for (size_t nAdd = 0; nAdd <= n; ++nAdd) // nCount+1 tries
3600 OUStringBuffer aBuf;
3601 aBuf.append(aBase);
3602 aBuf.append(static_cast<sal_Int32>(nMin + nAdd));
3603 OUString aNewName = aBuf.makeStringAndClear();
3604 bool bFound = false;
3605 TablesType::const_iterator itr = maTables.begin(), itrEnd = maTables.end();
3606 for (; itr != itrEnd; ++itr)
3608 if (itr->GetName() == aNewName)
3610 bFound = true;
3611 break;
3614 if (!bFound)
3615 return aNewName; // found unused Name
3617 return OUString(); // should not happen
3620 void ScDPCollection::FreeTable(ScDPObject* pDPObj)
3622 const ScRange& rOutRange = pDPObj->GetOutRange();
3623 const ScAddress& s = rOutRange.aStart;
3624 const ScAddress& e = rOutRange.aEnd;
3625 mpDoc->RemoveFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
3626 TablesType::iterator itr = maTables.begin(), itrEnd = maTables.end();
3627 for (; itr != itrEnd; ++itr)
3629 ScDPObject* p = &(*itr);
3630 if (p == pDPObj)
3632 maTables.erase(itr);
3633 break;
3638 bool ScDPCollection::InsertNewTable(ScDPObject* pDPObj)
3640 const ScRange& rOutRange = pDPObj->GetOutRange();
3641 const ScAddress& s = rOutRange.aStart;
3642 const ScAddress& e = rOutRange.aEnd;
3643 mpDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
3645 maTables.push_back(pDPObj);
3646 return true;
3649 ScDPCollection::SheetCaches& ScDPCollection::GetSheetCaches()
3651 return maSheetCaches;
3654 const ScDPCollection::SheetCaches& ScDPCollection::GetSheetCaches() const
3656 return maSheetCaches;
3659 ScDPCollection::NameCaches& ScDPCollection::GetNameCaches()
3661 return maNameCaches;
3664 const ScDPCollection::NameCaches& ScDPCollection::GetNameCaches() const
3666 return maNameCaches;
3669 ScDPCollection::DBCaches& ScDPCollection::GetDBCaches()
3671 return maDBCaches;
3674 const ScDPCollection::DBCaches& ScDPCollection::GetDBCaches() const
3676 return maDBCaches;
3679 ScRangeList ScDPCollection::GetAllTableRanges( SCTAB nTab ) const
3681 return std::for_each(maTables.begin(), maTables.end(), AccumulateOutputRanges(nTab)).getRanges();
3684 bool ScDPCollection::IntersectsTableByColumns( SCCOL nCol1, SCCOL nCol2, SCROW nRow, SCTAB nTab ) const
3686 return std::any_of(maTables.begin(), maTables.end(), FindIntersetingTableByColumns(nCol1, nCol2, nRow, nTab));
3689 bool ScDPCollection::IntersectsTableByRows( SCCOL nCol, SCROW nRow1, SCROW nRow2, SCTAB nTab ) const
3691 return std::any_of(maTables.begin(), maTables.end(), FindIntersectingTableByRows(nCol, nRow1, nRow2, nTab));
3694 bool ScDPCollection::HasTable( const ScRange& rRange ) const
3696 return std::any_of(maTables.begin(), maTables.end(), FindIntersectingTable(rRange));
3699 #if DEBUG_PIVOT_TABLE
3701 namespace {
3703 struct DumpTable : std::unary_function<ScDPObject, void>
3705 void operator() (const ScDPObject& rObj) const
3707 cout << "-- '" << rObj.GetName() << "'" << endl;
3708 ScDPSaveData* pSaveData = rObj.GetSaveData();
3709 if (!pSaveData)
3710 return;
3712 pSaveData->Dump();
3714 cout << endl; // blank line
3720 void ScDPCollection::DumpTables() const
3722 std::for_each(maTables.begin(), maTables.end(), DumpTable());
3725 #endif
3727 void ScDPCollection::RemoveCache(const ScDPCache* pCache)
3729 if (maSheetCaches.remove(pCache))
3730 // sheet cache removed.
3731 return;
3733 if (maNameCaches.remove(pCache))
3734 // named range cache removed.
3735 return;
3737 if (maDBCaches.remove(pCache))
3738 // database cache removed.
3739 return;
3742 void ScDPCollection::GetAllTables(const ScRange& rSrcRange, std::set<ScDPObject*>& rRefs) const
3744 std::set<ScDPObject*> aRefs;
3745 TablesType::const_iterator it = maTables.begin(), itEnd = maTables.end();
3746 for (; it != itEnd; ++it)
3748 const ScDPObject& rObj = *it;
3749 if (!rObj.IsSheetData())
3750 // Source is not a sheet range.
3751 continue;
3753 const ScSheetSourceDesc* pDesc = rObj.GetSheetDesc();
3754 if (!pDesc)
3755 continue;
3757 if (pDesc->HasRangeName())
3758 // This table has a range name as its source.
3759 continue;
3761 if (pDesc->GetSourceRange() != rSrcRange)
3762 // Different source range.
3763 continue;
3765 aRefs.insert(const_cast<ScDPObject*>(&rObj));
3768 rRefs.swap(aRefs);
3771 void ScDPCollection::GetAllTables(const OUString& rSrcName, std::set<ScDPObject*>& rRefs) const
3773 std::set<ScDPObject*> aRefs;
3774 TablesType::const_iterator it = maTables.begin(), itEnd = maTables.end();
3775 for (; it != itEnd; ++it)
3777 const ScDPObject& rObj = *it;
3778 if (!rObj.IsSheetData())
3779 // Source is not a sheet range.
3780 continue;
3782 const ScSheetSourceDesc* pDesc = rObj.GetSheetDesc();
3783 if (!pDesc)
3784 continue;
3786 if (!pDesc->HasRangeName())
3787 // This table probably has a sheet range as its source.
3788 continue;
3790 if (pDesc->GetRangeName() != rSrcName)
3791 // Different source name.
3792 continue;
3794 aRefs.insert(const_cast<ScDPObject*>(&rObj));
3797 rRefs.swap(aRefs);
3800 void ScDPCollection::GetAllTables(
3801 sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand,
3802 std::set<ScDPObject*>& rRefs) const
3804 std::set<ScDPObject*> aRefs;
3805 TablesType::const_iterator it = maTables.begin(), itEnd = maTables.end();
3806 for (; it != itEnd; ++it)
3808 const ScDPObject& rObj = *it;
3809 if (!rObj.IsImportData())
3810 // Source data is not a database.
3811 continue;
3813 const ScImportSourceDesc* pDesc = rObj.GetImportSourceDesc();
3814 if (!pDesc)
3815 continue;
3817 if (!pDesc->aDBName.equals(rDBName) || !pDesc->aObject.equals(rCommand) || pDesc->GetCommandType() != nSdbType)
3818 // Different database source.
3819 continue;
3821 aRefs.insert(const_cast<ScDPObject*>(&rObj));
3824 rRefs.swap(aRefs);
3827 bool operator<(const ScDPCollection::DBType& left, const ScDPCollection::DBType& right)
3829 if (left.mnSdbType != right.mnSdbType)
3830 return left.mnSdbType < right.mnSdbType;
3832 if (!left.maDBName.equals(right.maDBName))
3833 return left.maDBName < right.maDBName;
3835 return left.maCommand < right.maCommand;
3838 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */