1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "dpobject.hxx"
21 #include "dptabsrc.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"
31 #include "dapiuno.hxx"
32 #include "miscuno.hxx"
33 #include "scerrors.hxx"
34 #include "refupdat.hxx"
35 #include "scresid.hxx"
38 #include "scitems.hxx"
39 #include "unonames.hxx"
40 #include "dpglobal.hxx"
41 #include "globstr.hrc"
42 #include "queryentry.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>
83 using namespace com::sun::star
;
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"
109 * Database connection implementation for UNO database API. Note that in
110 * the UNO database API, column index is 1-based, whereas the interface
111 * requires that column index be 0-based.
113 class DBConnector
: public ScDPCache::DBConnector
117 uno::Reference
<sdbc::XRowSet
> mxRowSet
;
118 uno::Reference
<sdbc::XRow
> mxRow
;
119 uno::Reference
<sdbc::XResultSetMetaData
> mxMetaData
;
123 DBConnector(ScDPCache
& rCache
, 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
);
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);
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
);
193 case sdbc::DataType::TINYINT
:
194 case sdbc::DataType::SMALLINT
:
195 case sdbc::DataType::INTEGER
:
196 case sdbc::DataType::BIGINT
:
197 case sdbc::DataType::FLOAT
:
198 case sdbc::DataType::REAL
:
199 case sdbc::DataType::DOUBLE
:
200 case sdbc::DataType::NUMERIC
:
201 case sdbc::DataType::DECIMAL
:
203 //TODO: do the conversion here?
204 fValue
= mxRow
->getDouble(nCol
+1);
205 rData
.SetValue(fValue
);
208 case sdbc::DataType::DATE
:
210 rNumType
= 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
);
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
);
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
);
242 case sdbc::DataType::CHAR
:
243 case sdbc::DataType::VARCHAR
:
244 case sdbc::DataType::LONGVARCHAR
:
245 case sdbc::DataType::SQLNULL
:
246 case sdbc::DataType::BINARY
:
247 case sdbc::DataType::VARBINARY
:
248 case sdbc::DataType::LONGVARBINARY
:
250 rData
.SetString(mrCache
.InternString(mxRow
->getString(nCol
+1)));
253 catch (uno::Exception
&)
261 sal_uInt16
lcl_GetDataGetOrientation( const uno::Reference
<sheet::XDimensionsSupplier
>& xSource
)
263 long nRet
= sheet::DataPilotFieldOrientation_HIDDEN
;
266 uno::Reference
<container::XNameAccess
> xDimsName
= xSource
->getDimensions();
267 uno::Reference
<container::XIndexAccess
> xIntDims
= new ScNameToIndexAccess( xDimsName
);
268 long nIntCount
= xIntDims
->getCount();
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
);
277 bFound
= ScUnoHelpFunctions::GetBoolProperty( xDimProp
,
278 OUString(SC_UNO_DP_ISDATALAYOUT
) );
279 //TODO: error checking -- is "IsDataLayoutDimension" property required??
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
),
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
) :
314 mpTableData(static_cast<ScDPTableData
*>(NULL
)),
316 mnAutoFormatIndex( 65535 ),
318 mbHeaderLayout(false),
320 bSettingsChanged(false),
321 mbEnableGetPivotData(true)
325 ScDPObject::ScDPObject(const ScDPObject
& r
) :
328 aTableName( r
.aTableName
),
329 aTableTag( r
.aTableTag
),
330 aOutRange( r
.aOutRange
),
334 mpTableData(static_cast<ScDPTableData
*>(NULL
)),
336 mnAutoFormatIndex( r
.mnAutoFormatIndex
),
337 nHeaderRows( r
.nHeaderRows
),
338 mbHeaderLayout( r
.mbHeaderLayout
),
340 bSettingsChanged(false),
341 mbEnableGetPivotData(r
.mbEnableGetPivotData
)
344 pSaveData
= new ScDPSaveData(*r
.pSaveData
);
346 pSheetDesc
= new ScSheetSourceDesc(*r
.pSheetDesc
);
348 pImpDesc
= new ScImportSourceDesc(*r
.pImpDesc
);
350 pServDesc
= new ScDPServiceDesc(*r
.pServDesc
);
351 // xSource (and pOutput) is not copied
354 ScDPObject::~ScDPObject()
359 ScDPObject
& ScDPObject::operator= (const ScDPObject
& r
)
364 aTableName
= r
.aTableName
;
365 aTableTag
= r
.aTableTag
;
366 aOutRange
= r
.aOutRange
;
367 mnAutoFormatIndex
= r
.mnAutoFormatIndex
;
368 nHeaderRows
= r
.nHeaderRows
;
369 mbHeaderLayout
= r
.mbHeaderLayout
;
371 bSettingsChanged
= false;
372 mbEnableGetPivotData
= r
.mbEnableGetPivotData
;
375 pSaveData
= new ScDPSaveData(*r
.pSaveData
);
377 pSheetDesc
= new ScSheetSourceDesc(*r
.pSheetDesc
);
379 pImpDesc
= new ScImportSourceDesc(*r
.pImpDesc
);
381 pServDesc
= new ScDPServiceDesc(*r
.pServDesc
);
386 void ScDPObject::EnableGetPivotData(bool b
)
388 mbEnableGetPivotData
= b
;
391 void ScDPObject::SetAllowMove(bool bSet
)
396 void ScDPObject::SetSaveData(const ScDPSaveData
& rData
)
398 if ( pSaveData
!= &rData
) // API implementation modifies the original SaveData object
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
)
417 pOutput
->SetPosition( rRange
.aStart
);
420 const ScRange
& ScDPObject::GetOutRange() const
425 void ScDPObject::SetSheetDesc(const ScSheetSourceDesc
& rDesc
, bool /*bFromRefUpdate*/)
427 if ( pSheetDesc
&& rDesc
== *pSheetDesc
)
428 return; // nothing to do
431 DELETEZ( pServDesc
);
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
);
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
);
473 pServDesc
= new ScDPServiceDesc(rDesc
);
475 ClearTableData(); // new source must be created
478 void ScDPObject::WriteSourceDataTo( ScDPObject
& rDest
) const
481 rDest
.SetSheetDesc( *pSheetDesc
);
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
)
508 void ScDPObject::SetTag(const OUString
& rNew
)
513 bool ScDPObject::IsDataDescriptionCell(const ScAddress
& rPos
)
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.
525 ScRange aTabRange
= pOutput
->GetOutputRange(sheet::DataPilotOutputRangeType::TABLE
);
526 return (rPos
== aTabRange
.aStart
);
529 uno::Reference
<sheet::XDimensionsSupplier
> ScDPObject::GetSource()
535 void ScDPObject::CreateOutput()
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
;
552 if ( nHeaderRows
== 0 )
555 long nNewRow
= aOutRange
.aStart
.Row() + nDiff
;
559 ScAddress
aStart( aOutRange
.aStart
);
560 aStart
.SetRow(nNewRow
);
561 pOutput
->SetPosition( aStart
);
563 //TODO: modify aOutRange?
565 bAllowMove
= false; // use only once
572 class DisableGetPivotData
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>
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>
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.
617 if (rRange
.aEnd
.Row() < mnRow
)
618 // This table is above the row. It's safe.
621 if (mnCol1
<= rRange
.aStart
.Col() && rRange
.aEnd
.Col() <= mnCol2
)
622 // This table is fully enclosed in this column range.
625 if (rRange
.aEnd
.Col() < mnCol1
|| mnCol2
< rRange
.aStart
.Col())
626 // This table is entirely outside this column range.
629 // This table must be intersected by this column range.
634 class FindIntersectingTableByRows
: std::unary_function
<ScDPObject
, bool>
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.
651 if (rRange
.aEnd
.Col() < mnCol
)
652 // This table is to the left of the column. It's safe.
655 if (mnRow1
<= rRange
.aStart
.Row() && rRange
.aEnd
.Row() <= mnRow2
)
656 // This table is fully enclosed in this row range.
659 if (rRange
.aEnd
.Row() < mnRow1
|| mnRow2
< rRange
.aStart
.Row())
660 // This table is entirely outside this row range.
663 // This table must be intersected by this row range.
668 class AccumulateOutputRanges
: std::unary_function
<ScDPObject
, void>
670 ScRangeList maRanges
;
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.
683 maRanges
.Join(rRange
);
686 ScRangeList
getRanges() const { return maRanges
; }
691 ScDPTableData
* ScDPObject::GetTableData()
695 shared_ptr
<ScDPTableData
> pData
;
696 const ScDPDimensionSaveData
* pDimData
= pSaveData
? pSaveData
->GetExistingDimensionData() : NULL
;
701 const ScDPCache
* pCache
= pImpDesc
->CreateCache(pDimData
);
704 pCache
->AddReference(this);
705 pData
.reset(new ScDatabaseDPData(pDoc
, *pCache
));
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
721 DisableGetPivotData
aSwitch(*this, mbEnableGetPivotData
);
722 const ScDPCache
* pCache
= pSheetDesc
->CreateCache(pDimData
);
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
);
739 mpTableData
= pData
; // after SetCacheId
742 return mpTableData
.get();
745 void ScDPObject::CreateObjects()
749 DELETEZ( pOutput
); // not valid when xSource is changed
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();
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
);
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
);
787 catch(uno::Exception
&)
789 OSL_FAIL("exception in refresh");
794 pSaveData
->WriteToSource( xSource
);
796 bSettingsChanged
= false;
799 void ScDPObject::InvalidateData()
801 bSettingsChanged
= true;
804 void ScDPObject::Clear()
819 void ScDPObject::ClearTableData()
824 mpTableData
->GetCacheTable().getCache().RemoveReference(this);
828 void ScDPObject::ReloadGroupTableData()
833 // Table data not built yet. No need to reload the group data.
837 // How could it not have the save data... but whatever.
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());
848 // Replace the existing group table data with the source data.
849 shared_ptr
<ScDPTableData
> pSource
= pData
->GetSourceTableData();
850 mpTableData
= pSource
;
855 ScDPGroupTableData
* pData
= dynamic_cast<ScDPGroupTableData
*>(mpTableData
.get());
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
;
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();
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
899 return ScRange( aOutRange
.aStart
);
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
);
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
)
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();
965 SCROW nOutRows
= aOutRange
.aEnd
.Row() + 1 - aOutRange
.aStart
.Row();
966 while ( nInitial
+ 1 < nOutRows
&& lcl_HasButton( pDoc
, nFirstCol
, nFirstRow
+ nInitial
, nTab
) )
969 if ( nInitial
+ 1 < nOutRows
&&
970 pDoc
->IsBlockEmpty( nTab
, nFirstCol
, nFirstRow
+ nInitial
, nFirstCol
, nFirstRow
+ nInitial
) &&
971 aOutRange
.aEnd
.Col() > nFirstCol
)
973 nHeaderRows
= nInitial
;
976 nHeaderRows
= 0; // nothing found, no drop-down lists
979 void ScDPObject::BuildAllDimensionMembers()
984 // #i111857# don't always create empty mpTableData for external service.
988 ScDPTableData
* pTableData
= GetTableData();
990 pSaveData
->BuildAllDimensionMembers(pTableData
);
993 bool ScDPObject::SyncAllDimensionMembers()
998 // #i111857# don't always create empty mpTableData for external service.
999 // Ideally, xSource should be used instead of mpTableData.
1003 ScDPTableData
* pData
= GetTableData();
1005 // No table data exists. This can happen when refreshing from an
1006 // external source which doesn't exist.
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
);
1016 bool ScDPObject::GetMemberNames( sal_Int32 nDim
, Sequence
<OUString
>& rNames
)
1018 vector
<ScDPLabelData::Member
> aMembers
;
1019 if (!GetMembers(nDim
, GetUsedHierarchy(nDim
), aMembers
))
1022 size_t n
= aMembers
.size();
1024 for (size_t i
= 0; i
< n
; ++i
)
1025 rNames
[i
] = aMembers
[i
].maName
;
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
))
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
;
1047 aMem
.maName
= xMember
->getName();
1049 Reference
<beans::XPropertySet
> xMemProp(xMember
, UNO_QUERY
);
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
);
1065 void ScDPObject::UpdateReference( UpdateRefMode eUpdateRefMode
,
1066 const ScRange
& rRange
, SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
)
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
1089 const OUString
& rRangeName
= pSheetDesc
->GetRangeName();
1090 if (!rRangeName
.isEmpty())
1091 // Source range is a named range. No need to update.
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
)
1132 if ( pSheetDesc
&& r
.pSheetDesc
)
1134 if ( pSheetDesc
->GetSourceRange() != r
.pSheetDesc
->GetSourceRange() )
1137 else if ( pSheetDesc
|| r
.pSheetDesc
)
1139 OSL_FAIL("RefsEqual: SheetDesc set at only one object");
1146 void ScDPObject::WriteRefsTo( ScDPObject
& r
) const
1148 r
.SetOutRange( aOutRange
);
1150 r
.SetSheetDesc( *pSheetDesc
, true );
1153 void ScDPObject::GetPositionData(const ScAddress
& rPos
, DataPilotTablePositionData
& rPosData
)
1156 pOutput
->GetPositionData(rPos
, rPosData
);
1159 bool ScDPObject::GetDataFieldPositionData(
1160 const ScAddress
& rPos
, Sequence
<sheet::DataPilotFieldFilter
>& rFilters
)
1164 vector
<sheet::DataPilotFieldFilter
> aFilters
;
1165 if (!pOutput
->GetDataResultPositionData(aFilters
, rPos
))
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
];
1176 void ScDPObject::GetDrillDownData(const ScAddress
& rPos
, Sequence
< Sequence
<Any
> >& rTableData
)
1180 Reference
<sheet::XDrillDownDataSupplier
> xDrillDownData(xSource
, UNO_QUERY
);
1181 if (!xDrillDownData
.is())
1184 Sequence
<sheet::DataPilotFieldFilter
> filters
;
1185 if (!GetDataFieldPositionData(rPos
, filters
))
1188 rTableData
= xDrillDownData
->getDrillDownData(filters
);
1191 bool ScDPObject::IsDimNameInUse(const OUString
& rName
) const
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
))
1205 Reference
<beans::XPropertySet
> xPropSet(xDims
->getByName(rDimName
), UNO_QUERY
);
1209 OUString aLayoutName
= ScUnoHelpFunctions::GetStringProperty(
1210 xPropSet
, OUString(SC_UNO_DP_LAYOUTNAME
), OUString());
1211 if (aLayoutName
.equalsIgnoreAsciiCase(rName
))
1217 OUString
ScDPObject::GetDimName( long nDim
, bool& rIsDataLayout
, sal_Int32
* pFlags
)
1219 rIsDataLayout
= false;
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??
1242 aName
= xDimName
->getName();
1244 catch(uno::Exception
&)
1248 rIsDataLayout
= true;
1253 *pFlags
= ScUnoHelpFunctions::GetLongProperty( xDimProp
,
1254 OUString(SC_UNO_DP_FLAGS
), 0 );
1262 bool ScDPObject::IsDuplicated( long nDim
)
1264 bool bDuplicated
= false;
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() )
1285 catch(uno::Exception
&)
1294 long ScDPObject::GetDimCount()
1301 uno::Reference
<container::XNameAccess
> xDimsName
= xSource
->getDimensions();
1302 if ( xDimsName
.is() )
1303 nRet
= xDimsName
->getElementNames().getLength();
1305 catch(uno::Exception
&)
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;
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
;
1331 class FindByName
: std::unary_function
<const ScDPSaveDimension
*, bool>
1333 OUString maName
; // must be all uppercase.
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
)
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
))
1350 return maName
== ScGlobal::pCharClass
->uppercase(aSrcName
);
1354 class LessByDimOrder
: std::binary_function
<sheet::DataPilotFieldFilter
, sheet::DataPilotFieldFilter
, bool>
1356 const ScDPSaveData::DimOrderType
& mrDimOrder
;
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
)
1382 rtl::math::setNan(&fRet
);
1383 if (!mbEnableGetPivotData
)
1388 std::vector
<const ScDPSaveDimension
*> aDataDims
;
1389 pSaveData
->GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_DATA
, aDataDims
);
1390 if (aDataDims
.empty())
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())
1400 size_t nDataIndex
= std::distance(aDataDims
.begin(), it
);
1402 uno::Reference
<sheet::XDataPilotResults
> xDPResults(xSource
, uno::UNO_QUERY
);
1403 if (!xDPResults
.is())
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())
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
1453 bool dequote( const OUString
& rSource
, sal_Int32 nStartPos
, sal_Int32
& rEndPos
, OUString
& rResult
)
1455 // nStartPos has to point to opening quote
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
1479 // end of quoted string
1480 rResult
= aBuffer
.makeStringAndClear();
1481 rEndPos
= nPos
+ 1; // behind closing quote
1486 aBuffer
.append( cNext
);
1490 // no closing quote before the end of the string -> error (bRet still false)
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
[] =
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
] == ' ')
1528 bool bParsed
= false;
1529 bool bFound
= false;
1531 sal_Int32 nFuncEnd
= 0;
1532 if (nStartPos
< nListLen
&& rList
[nStartPos
] == '\'')
1533 bParsed
= dequote( rList
, nStartPos
, nFuncEnd
, aFuncStr
);
1536 nFuncEnd
= rList
.indexOf(']', nStartPos
);
1539 aFuncStr
= rList
.copy(nStartPos
, nFuncEnd
- nStartPos
);
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
;
1556 while (nFuncEnd
< nListLen
&& rList
[nFuncEnd
] == ' ')
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
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
] == ' ')
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
] == ' ')
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
1617 // implicit quoting to the closing bracket
1619 sal_Int32 nClosePos
= rList
.indexOf(']', nStartPos
);
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;
1640 if ( bParsed
&& ScGlobal::GetpTransliteration()->isEqual( aDequoted
, rSearch
) )
1642 nMatchList
= nQuoteEnd
; // match count in the list string, including quotes
1643 nMatchSearch
= rSearch
.getLength();
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() )
1662 sal_Unicode cNext
= rList
[nMatchList
];
1663 if ( cNext
== ' ' || ( bAllowBracket
&& cNext
== '[' ) )
1669 rMatched
= nMatchList
;
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
);
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() )
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
)
1771 // look for data field name
1773 for ( SCSIZE nDataPos
=0; nDataPos
<nDataFields
&& !bUsed
; nDataPos
++ )
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
);
1791 // look for field name
1793 OUString aSpecField
;
1794 bool bHasFieldName
= false;
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
1821 // look for field item
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
) )
1846 bError
= true; // duplicate (also across fields)
1849 aFoundName
= aFieldNames
[nField
];
1850 aFoundValue
= pItemArr
[nItem
];
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
);
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];
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
) );
1913 // the elements of the data layout dimension can't be found by their names
1914 // -> don't change anything
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;
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?
1975 OSL_ENSURE( bFound
, "member not found" );
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?" );
1985 const OUString aName
= rElemDesc
.MemberName
;
1986 pModifyData
->GetDimensionByName(aDimName
)->
1987 GetMemberByName(aName
)->SetShowDetails( !bShowDetails
); // toggle
1990 pDestObj
->InvalidateData(); // re-init source from SaveData
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() )
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() )
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
]);
2041 OSL_FAIL("FirstSubTotal: NULL");
2047 class FindByColumn
: public std::unary_function
<ScPivotField
, bool>
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
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.
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
);
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
));
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.
2137 nCompCol
= PIVOT_DATA_FIELD
;
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();
2150 rField
.nCol
= PIVOT_DATA_FIELD
;
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();
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
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
);
2215 rParam
.maPageFields
, xSource
, sheet::DataPilotFieldOrientation_PAGE
, false);
2217 rParam
.maColFields
, xSource
, sheet::DataPilotFieldOrientation_COLUMN
, bAddData
);
2219 rParam
.maRowFields
, xSource
, sheet::DataPilotFieldOrientation_ROW
, false);
2221 rParam
.maDataFields
, xSource
, sheet::DataPilotFieldOrientation_DATA
, false);
2223 uno::Reference
<beans::XPropertySet
> xProp( xSource
, uno::UNO_QUERY
);
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
&)
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())
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() )
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())
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
);
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())
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
;
2346 rLabelData
.mnOriginalDim
= static_cast<long>(nOrigPos
);
2347 rLabelData
.maLayoutName
= aLayoutName
;
2348 rLabelData
.maSubtotalName
= aSubtotalName
;
2350 // This is a duplicated dimension. Use the original dimension index.
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);
2361 bool ScDPObject::FillLabelData(sal_Int32 nDim
, ScDPLabelData
& rLabels
)
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
)
2373 return FillLabelDataForDimension(xDims
, nDim
, rLabels
);
2376 bool ScDPObject::FillLabelData(ScPivotParam
& rParam
)
2378 rParam
.maLabelArray
.clear();
2384 uno::Reference
<container::XNameAccess
> xDimsName
= xSource
->getDimensions();
2385 uno::Reference
<container::XIndexAccess
> xDims
= new ScNameToIndexAccess( xDimsName
);
2386 sal_Int32 nDimCount
= xDims
->getCount();
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
));
2400 bool ScDPObject::GetHierarchiesNA( sal_Int32 nDim
, uno::Reference
< container::XNameAccess
>& xHiers
)
2403 uno::Reference
<container::XNameAccess
> xDimsName( GetSource()->getDimensions() );
2404 uno::Reference
<container::XIndexAccess
> xIntDims(new ScNameToIndexAccess( xDimsName
));
2407 uno::Reference
<sheet::XHierarchiesSupplier
> xHierSup(xIntDims
->getByIndex( nDim
), uno::UNO_QUERY
);
2410 xHiers
.set( xHierSup
->getHierarchies() );
2417 bool ScDPObject::GetHierarchies( sal_Int32 nDim
, uno::Sequence
< OUString
>& rHiers
)
2420 uno::Reference
< container::XNameAccess
> xHiersNA
;
2421 if( GetHierarchiesNA( nDim
, xHiersNA
) )
2423 rHiers
= xHiersNA
->getElementNames();
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
);
2436 nHier
= ScUnoHelpFunctions::GetLongProperty( xDim
, OUString( SC_UNO_DP_USEDHIERARCHY
) );
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
)
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
);
2453 uno::Reference
<sheet::XHierarchiesSupplier
> xHierSup(xDim
, uno::UNO_QUERY
);
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()));
2463 sal_Int32 nLevCount
= xLevels
->getCount();
2466 uno::Reference
<sheet::XMembersSupplier
> xMembSupp( xLevels
->getByIndex(0), uno::UNO_QUERY
);
2467 if ( xMembSupp
.is() )
2469 xMembers
.set(xMembSupp
->getMembers());
2480 // convert old pivot tables into new datapilot tables
2484 OUString
lcl_GetDimName( const uno::Reference
<sheet::XDimensionsSupplier
>& xSource
, long nDim
)
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
);
2501 aName
= xDimName
->getName();
2503 catch(uno::Exception
&)
2512 bool hasFieldColumn(const vector
<ScPivotField
>* pRefFields
, SCCOL nCol
)
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.
2527 class FindByOriginalDim
: public std::unary_function
<ScPivotField
, bool>
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();
2562 OUString aDocStr
= lcl_GetDimName( xSource
, nCol
); // cols must start at 0
2563 if (!aDocStr
.isEmpty())
2564 pDim
= rSaveData
.GetDimensionByName(aDocStr
);
2572 if ( nOrient
== sheet::DataPilotFieldOrientation_DATA
) // set summary function
2574 // generate an individual entry for each function
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
))
2582 if (bFirst
&& hasFieldColumn(pRefRowFields
, nCol
))
2585 if (bFirst
&& hasFieldColumn(pRefPageFields
, nCol
))
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
);
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);
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
));
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;
2646 case sheet::DataPilotFieldOrientation_PAGE
:
2647 bAllowed
= ( nDimFlags
& sheet::DimensionFlags::NO_PAGE_ORIENTATION
) == 0;
2649 case sheet::DataPilotFieldOrientation_COLUMN
:
2650 bAllowed
= ( nDimFlags
& sheet::DimensionFlags::NO_COLUMN_ORIENTATION
) == 0;
2652 case sheet::DataPilotFieldOrientation_ROW
:
2653 bAllowed
= ( nDimFlags
& sheet::DimensionFlags::NO_ROW_ORIENTATION
) == 0;
2655 case sheet::DataPilotFieldOrientation_DATA
:
2656 bAllowed
= ( nDimFlags
& sheet::DimensionFlags::NO_DATA_ORIENTATION
) == 0;
2660 // allowed to remove from previous orientation
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
);
2674 uno::Reference
<container::XEnumeration
> xEnum
= xEnAc
->createContentEnumeration(
2675 OUString( SCDPSOURCE_SERVICE
) );
2676 if ( xEnum
.is() && xEnum
->hasMoreElements() )
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
);
2693 uno::Reference
<container::XEnumeration
> xEnum
= xEnAc
->createContentEnumeration(
2694 OUString( SCDPSOURCE_SERVICE
) );
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
;
2707 uno::Reference
<lang::XServiceInfo
> xInfo( xIntFac
, uno::UNO_QUERY
);
2710 OUString sName
= xInfo
->getImplementationName();
2712 aSeq
.realloc( nCount
+1 );
2713 aSeq
.getArray()[nCount
] = sName
;
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
);
2735 uno::Reference
<container::XEnumeration
> xEnum
=
2736 xEnAc
->createContentEnumeration(OUString(SCDPSOURCE_SERVICE
));
2740 while (xEnum
->hasMoreElements() && !xRet
.is())
2742 uno::Any aAddInAny
= xEnum
->nextElement();
2743 uno::Reference
<uno::XInterface
> xIntFac
;
2744 aAddInAny
>>= xIntFac
;
2748 uno::Reference
<lang::XServiceInfo
> xInfo(xIntFac
, uno::UNO_QUERY
);
2749 if (!xInfo
.is() || xInfo
->getImplementationName() != aImplName
)
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
);
2762 xInterface
= xCFac
->createInstanceWithContext(xCtx
);
2764 if (!xInterface
.is())
2766 uno::Reference
<lang::XSingleServiceFactory
> xFac( xIntFac
, uno::UNO_QUERY
);
2768 xInterface
= xFac
->createInstance();
2771 uno::Reference
<lang::XInitialization
> xInit( xInterface
, uno::UNO_QUERY
);
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
&)
2793 #if DEBUG_PIVOT_TABLE
2794 void ScDPObject::DumpCache() const
2799 const ScDPCache
* pCache
= mpTableData
->GetCacheTable().getCache();
2807 ScDPCollection::SheetCaches::SheetCaches(ScDocument
* pDoc
) : mpDoc(pDoc
) {}
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();
2830 const ScDPDimensionSaveData
* pGroupDims
= pSave
->GetExistingDimensionData();
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())
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())
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 !!!");
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
);
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
);
2889 // Slot with invalid range. Re-use this slot.
2891 nIndex
= std::distance(maRanges
.begin(), it
);
2894 const ScDPCache
* p
= pCache
.get();
2895 o3tl::ptr_container::insert(maCaches
, nIndex
, std::move(pCache
));
2899 ScDPCache
* ScDPCollection::SheetCaches::getExistingCache(const ScRange
& rRange
)
2901 RangeIndexType::iterator it
= std::find(maRanges
.begin(), maRanges
.end(), rRange
);
2902 if (it
== maRanges
.end())
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 !!!");
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())
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 !!!");
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())
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(
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
)
2969 ScRange
aNew(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
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.
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 !!!");
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());
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
;
3015 maRanges
[idx
].SetInvalid();
3022 const std::vector
<ScRange
>& ScDPCollection::SheetCaches::getAllRanges() const
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())
3042 ::std::unique_ptr
<ScDPCache
> pCache(new ScDPCache(mpDoc
));
3043 pCache
->InitFromDoc(mpDoc
, rRange
);
3045 pDimData
->WriteToCache(*pCache
);
3047 const ScDPCache
* p
= pCache
.get();
3048 o3tl::ptr_container::insert(maCaches
, rName
, std::move(pCache
));
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())
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());
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
)
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())
3125 uno::Reference
<sdbc::XRowSet
> xRowSet
= createRowSet(nSdbType
, rDBName
, rCommand
);
3129 ::std::unique_ptr
<ScDPCache
> pCache(new ScDPCache(mpDoc
));
3130 SvNumberFormatter
aFormat( comphelper::getProcessComponentContext(), ScGlobal::eLnge
);
3131 DBConnector
aDB(*pCache
, xRowSet
, *aFormat
.GetNullDate());
3135 if (!pCache
->InitFromDataBase(aDB
))
3137 // initialization failed.
3138 comphelper::disposeComponent(xRowSet
);
3143 pDimData
->WriteToCache(*pCache
);
3145 ::comphelper::disposeComponent(xRowSet
);
3146 const ScDPCache
* p
= pCache
.get();
3147 o3tl::ptr_container::insert(maCaches
, aType
, std::move(pCache
));
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
)),
3170 uno::Reference
<beans::XPropertySet
> xRowProp(xRowSet
, UNO_QUERY
);
3171 OSL_ENSURE( xRowProp
.is(), "can't get RowSet" );
3178 // set source parameters
3182 xRowProp
->setPropertyValue(
3183 OUString(SC_DBPROP_DATASOURCENAME
), aAny
);
3186 xRowProp
->setPropertyValue(
3187 OUString(SC_DBPROP_COMMAND
), aAny
);
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
);
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");
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())
3234 ScDPCache
& rCache
= *it
->second
;
3236 uno::Reference
<sdbc::XRowSet
> xRowSet
= createRowSet(nSdbType
, rDBName
, rCommand
);
3243 SvNumberFormatter
aFormat( comphelper::getProcessComponentContext(), ScGlobal::eLnge
);
3244 DBConnector
aDB(rCache
, xRowSet
, *aFormat
.GetNullDate());
3248 if (!rCache
.InitFromDataBase(aDB
))
3250 // initialization failed.
3252 comphelper::disposeComponent(xRowSet
);
3256 comphelper::disposeComponent(xRowSet
);
3257 std::set
<ScDPObject
*> aRefs(rCache
.GetAllReferences());
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
)
3278 ScDPCollection::ScDPCollection(ScDocument
* pDocument
) :
3280 maSheetCaches(pDocument
),
3281 maNameCaches(pDocument
),
3282 maDBCaches(pDocument
)
3286 ScDPCollection::ScDPCollection(const ScDPCollection
& r
) :
3288 maSheetCaches(r
.mpDoc
),
3289 maNameCaches(r
.mpDoc
),
3294 ScDPCollection::~ScDPCollection()
3302 * Unary predicate to match DP objects by the table ID.
3304 class MatchByTable
: public unary_function
<ScDPObject
, bool>
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
)
3321 return STR_ERR_DATAPILOTSOURCE
;
3323 if (pDPObj
->IsSheetData())
3325 // data source is internal sheet.
3326 const ScSheetSourceDesc
* pDesc
= pDPObj
->GetSheetDesc();
3328 return STR_ERR_DATAPILOTSOURCE
;
3330 sal_uLong nErrId
= pDesc
->CheckSourceRange();
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
);
3342 // Not cached yet. Collect all tables that use this named
3343 // range as data source.
3344 GetAllTables(pDesc
->GetRangeName(), rRefs
);
3349 // cache by cell range
3350 ScDPCollection::SheetCaches
& rCaches
= GetSheetCaches();
3351 if (rCaches
.hasCache(pDesc
->GetSourceRange()))
3352 rCaches
.updateCache(pDesc
->GetSourceRange(), rRefs
);
3355 // Not cached yet. Collect all tables that use this range as
3357 GetAllTables(pDesc
->GetSourceRange(), rRefs
);
3361 else if (pDPObj
->IsImportData())
3363 // data source is external database.
3364 const ScImportSourceDesc
* pDesc
= pDPObj
->GetImportSourceDesc();
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
);
3374 // Not cached yet. Collect all tables that use this range as
3376 GetAllTables(pDesc
->GetCommandType(), pDesc
->aDBName
, pDesc
->aObject
, rRefs
);
3382 bool ScDPCollection::ReloadGroupsInCache(ScDPObject
* pDPObj
, std::set
<ScDPObject
*>& rRefs
)
3387 const ScDPSaveData
* pSaveData
= pDPObj
->GetSaveData();
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();
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());
3414 // Not cached yet. Cache the source dimensions. Groups will
3416 pCache
= const_cast<ScDPCache
*>(
3417 rCaches
.getCache(pDesc
->GetRangeName(), pDesc
->GetSourceRange(), NULL
));
3419 GetAllTables(pDesc
->GetRangeName(), rRefs
);
3423 // cache by cell range
3424 ScDPCollection::SheetCaches
& rCaches
= GetSheetCaches();
3425 if (rCaches
.hasCache(pDesc
->GetSourceRange()))
3426 pCache
= rCaches
.getExistingCache(pDesc
->GetSourceRange());
3429 // Not cached yet. Cache the source dimensions. Groups will
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();
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
);
3450 // Not cached yet. Cache the source dimensions. Groups will
3452 pCache
= const_cast<ScDPCache
*>(
3453 rCaches
.getCache(pDesc
->GetCommandType(), pDesc
->aDBName
, pDesc
->aObject
, NULL
));
3455 GetAllTables(pDesc
->GetCommandType(), pDesc
->aDBName
, pDesc
->aObject
, rRefs
);
3461 // Clear the existing group data from the cache, and rebuild it from the
3463 pCache
->ClearGroupFields();
3464 const ScDPDimensionSaveData
* pDimData
= pSaveData
->GetExistingDimensionData();
3466 pDimData
->WriteToCache(*pCache
);
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
)
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
)
3497 ScAddress
& s
= aOutRange
.aStart
;
3498 ScAddress
& e
= aOutRange
.aEnd
;
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())
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
))
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
);
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
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
)
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
;
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
)
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
);
3632 maTables
.erase(itr
);
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
);
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()
3674 const ScDPCollection::DBCaches
& ScDPCollection::GetDBCaches() const
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
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();
3714 cout
<< endl
; // blank line
3720 void ScDPCollection::DumpTables() const
3722 std::for_each(maTables
.begin(), maTables
.end(), DumpTable());
3727 void ScDPCollection::RemoveCache(const ScDPCache
* pCache
)
3729 if (maSheetCaches
.remove(pCache
))
3730 // sheet cache removed.
3733 if (maNameCaches
.remove(pCache
))
3734 // named range cache removed.
3737 if (maDBCaches
.remove(pCache
))
3738 // database cache removed.
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.
3753 const ScSheetSourceDesc
* pDesc
= rObj
.GetSheetDesc();
3757 if (pDesc
->HasRangeName())
3758 // This table has a range name as its source.
3761 if (pDesc
->GetSourceRange() != rSrcRange
)
3762 // Different source range.
3765 aRefs
.insert(const_cast<ScDPObject
*>(&rObj
));
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.
3782 const ScSheetSourceDesc
* pDesc
= rObj
.GetSheetDesc();
3786 if (!pDesc
->HasRangeName())
3787 // This table probably has a sheet range as its source.
3790 if (pDesc
->GetRangeName() != rSrcName
)
3791 // Different source name.
3794 aRefs
.insert(const_cast<ScDPObject
*>(&rObj
));
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.
3813 const ScImportSourceDesc
* pDesc
= rObj
.GetImportSourceDesc();
3817 if (!pDesc
->aDBName
.equals(rDBName
) || !pDesc
->aObject
.equals(rCommand
) || pDesc
->GetCommandType() != nSdbType
)
3818 // Different database source.
3821 aRefs
.insert(const_cast<ScDPObject
*>(&rObj
));
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: */