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 <sal/macros.h>
72 #include <tools/debug.hxx>
73 #include <tools/diagnose_ex.h>
74 #include <svl/zforlist.hxx>
75 #include <vcl/msgbox.hxx>
80 #include <boost/unordered_map.hpp>
82 using namespace com::sun::star
;
84 using ::std::unary_function
;
85 using ::boost::shared_ptr
;
86 using ::com::sun::star::uno::Sequence
;
87 using ::com::sun::star::uno::Reference
;
88 using ::com::sun::star::uno::UNO_QUERY
;
89 using ::com::sun::star::uno::Any
;
90 using ::com::sun::star::uno::Exception
;
91 using ::com::sun::star::lang::XComponent
;
92 using ::com::sun::star::sheet::DataPilotTableHeaderData
;
93 using ::com::sun::star::sheet::DataPilotTablePositionData
;
94 using ::com::sun::star::sheet::XDimensionsSupplier
;
95 using ::com::sun::star::beans::XPropertySet
;
97 #define SC_SERVICE_ROWSET "com.sun.star.sdb.RowSet"
99 #define SC_DBPROP_DATASOURCENAME "DataSourceName"
100 #define SC_DBPROP_COMMAND "Command"
101 #define SC_DBPROP_COMMANDTYPE "CommandType"
103 // -----------------------------------------------------------------------
105 #define SCDPSOURCE_SERVICE "com.sun.star.sheet.DataPilotSource"
110 * Database connection implementation for UNO database API. Note that in
111 * the UNO database API, column index is 1-based, whereas the interface
112 * requires that column index be 0-based.
114 class DBConnector
: public ScDPCache::DBConnector
118 uno::Reference
<sdbc::XRowSet
> mxRowSet
;
119 uno::Reference
<sdbc::XRow
> mxRow
;
120 uno::Reference
<sdbc::XResultSetMetaData
> mxMetaData
;
124 DBConnector(ScDPCache
& rCache
, const uno::Reference
<sdbc::XRowSet
>& xRowSet
, const Date
& rNullDate
);
126 bool isValid() const;
128 virtual void getValue(long nCol
, ScDPItemData
&rData
, short& rNumType
) const;
129 virtual OUString
getColumnLabel(long nCol
) const;
130 virtual long getColumnCount() const;
131 virtual bool first();
133 virtual void finish();
136 DBConnector::DBConnector(ScDPCache
& rCache
, const uno::Reference
<sdbc::XRowSet
>& xRowSet
, const Date
& rNullDate
) :
137 mrCache(rCache
), mxRowSet(xRowSet
), maNullDate(rNullDate
)
139 Reference
<sdbc::XResultSetMetaDataSupplier
> xMetaSupp(mxRowSet
, UNO_QUERY
);
141 mxMetaData
= xMetaSupp
->getMetaData();
143 mxRow
.set(mxRowSet
, UNO_QUERY
);
146 bool DBConnector::isValid() const
148 return mxRowSet
.is() && mxRow
.is() && mxMetaData
.is();
151 bool DBConnector::first()
153 return mxRowSet
->first();
156 bool DBConnector::next()
158 return mxRowSet
->next();
161 void DBConnector::finish()
163 mxRowSet
->beforeFirst();
166 long DBConnector::getColumnCount() const
168 return mxMetaData
->getColumnCount();
171 OUString
DBConnector::getColumnLabel(long nCol
) const
173 return mxMetaData
->getColumnLabel(nCol
+1);
176 void DBConnector::getValue(long nCol
, ScDPItemData
&rData
, short& rNumType
) const
178 rNumType
= NUMBERFORMAT_NUMBER
;
179 sal_Int32 nType
= mxMetaData
->getColumnType(nCol
+1);
186 case sdbc::DataType::BIT
:
187 case sdbc::DataType::BOOLEAN
:
189 rNumType
= NUMBERFORMAT_LOGICAL
;
190 fValue
= mxRow
->getBoolean(nCol
+1) ? 1 : 0;
191 rData
.SetValue(fValue
);
194 case sdbc::DataType::TINYINT
:
195 case sdbc::DataType::SMALLINT
:
196 case sdbc::DataType::INTEGER
:
197 case sdbc::DataType::BIGINT
:
198 case sdbc::DataType::FLOAT
:
199 case sdbc::DataType::REAL
:
200 case sdbc::DataType::DOUBLE
:
201 case sdbc::DataType::NUMERIC
:
202 case sdbc::DataType::DECIMAL
:
204 //! do the conversion here?
205 fValue
= mxRow
->getDouble(nCol
+1);
206 rData
.SetValue(fValue
);
209 case sdbc::DataType::DATE
:
211 rNumType
= NUMBERFORMAT_DATE
;
213 util::Date aDate
= mxRow
->getDate(nCol
+1);
214 fValue
= Date(aDate
.Day
, aDate
.Month
, aDate
.Year
) - maNullDate
;
215 rData
.SetValue(fValue
);
218 case sdbc::DataType::TIME
:
220 rNumType
= NUMBERFORMAT_TIME
;
222 util::Time aTime
= mxRow
->getTime(nCol
+1);
223 fValue
= aTime
.Hours
/ static_cast<double>(::Time::hourPerDay
) +
224 aTime
.Minutes
/ static_cast<double>(::Time::minutePerDay
) +
225 aTime
.Seconds
/ static_cast<double>(::Time::secondPerDay
) +
226 aTime
.NanoSeconds
/ static_cast<double>(::Time::nanoSecPerDay
);
227 rData
.SetValue(fValue
);
230 case sdbc::DataType::TIMESTAMP
:
232 rNumType
= NUMBERFORMAT_DATETIME
;
234 util::DateTime aStamp
= mxRow
->getTimestamp(nCol
+1);
235 fValue
= ( Date( aStamp
.Day
, aStamp
.Month
, aStamp
.Year
) - maNullDate
) +
236 aStamp
.Hours
/ static_cast<double>(::Time::hourPerDay
) +
237 aStamp
.Minutes
/ static_cast<double>(::Time::minutePerDay
) +
238 aStamp
.Seconds
/ static_cast<double>(::Time::secondPerDay
) +
239 aStamp
.NanoSeconds
/ static_cast<double>(::Time::nanoSecPerDay
);
240 rData
.SetValue(fValue
);
243 case sdbc::DataType::CHAR
:
244 case sdbc::DataType::VARCHAR
:
245 case sdbc::DataType::LONGVARCHAR
:
246 case sdbc::DataType::SQLNULL
:
247 case sdbc::DataType::BINARY
:
248 case sdbc::DataType::VARBINARY
:
249 case sdbc::DataType::LONGVARBINARY
:
251 rData
.SetString(mrCache
.InternString(mxRow
->getString(nCol
+1)));
254 catch (uno::Exception
&)
262 sal_uInt16
lcl_GetDataGetOrientation( const uno::Reference
<sheet::XDimensionsSupplier
>& xSource
)
264 long nRet
= sheet::DataPilotFieldOrientation_HIDDEN
;
267 uno::Reference
<container::XNameAccess
> xDimsName
= xSource
->getDimensions();
268 uno::Reference
<container::XIndexAccess
> xIntDims
= new ScNameToIndexAccess( xDimsName
);
269 long nIntCount
= xIntDims
->getCount();
270 sal_Bool bFound
= false;
271 for (long nIntDim
=0; nIntDim
<nIntCount
&& !bFound
; nIntDim
++)
273 uno::Reference
<uno::XInterface
> xIntDim
=
274 ScUnoHelpFunctions::AnyToInterface( xIntDims
->getByIndex(nIntDim
) );
275 uno::Reference
<beans::XPropertySet
> xDimProp( xIntDim
, uno::UNO_QUERY
);
278 bFound
= ScUnoHelpFunctions::GetBoolProperty( xDimProp
,
279 OUString(SC_UNO_DP_ISDATALAYOUT
) );
280 //! error checking -- is "IsDataLayoutDimension" property required??
282 nRet
= ScUnoHelpFunctions::GetEnumProperty(
283 xDimProp
, OUString(SC_UNO_DP_ORIENTATION
),
284 sheet::DataPilotFieldOrientation_HIDDEN
);
288 return static_cast< sal_uInt16
>( nRet
);
291 ScDPServiceDesc::ScDPServiceDesc(
292 const OUString
& rServ
, const OUString
& rSrc
, const OUString
& rNam
,
293 const OUString
& rUser
, const OUString
& rPass
) :
294 aServiceName( rServ
),
300 bool ScDPServiceDesc::operator== ( const ScDPServiceDesc
& rOther
) const
302 return aServiceName
== rOther
.aServiceName
&&
303 aParSource
== rOther
.aParSource
&&
304 aParName
== rOther
.aParName
&&
305 aParUser
== rOther
.aParUser
&&
306 aParPass
== rOther
.aParPass
;
309 ScDPObject::ScDPObject( ScDocument
* pD
) :
315 mpTableData(static_cast<ScDPTableData
*>(NULL
)),
317 mnAutoFormatIndex( 65535 ),
319 mbHeaderLayout(false),
321 bSettingsChanged(false),
322 mbEnableGetPivotData(true)
326 ScDPObject::ScDPObject(const ScDPObject
& r
) :
329 aTableName( r
.aTableName
),
330 aTableTag( r
.aTableTag
),
331 aOutRange( r
.aOutRange
),
335 mpTableData(static_cast<ScDPTableData
*>(NULL
)),
337 mnAutoFormatIndex( r
.mnAutoFormatIndex
),
338 nHeaderRows( r
.nHeaderRows
),
339 mbHeaderLayout( r
.mbHeaderLayout
),
341 bSettingsChanged(false),
342 mbEnableGetPivotData(r
.mbEnableGetPivotData
)
345 pSaveData
= new ScDPSaveData(*r
.pSaveData
);
347 pSheetDesc
= new ScSheetSourceDesc(*r
.pSheetDesc
);
349 pImpDesc
= new ScImportSourceDesc(*r
.pImpDesc
);
351 pServDesc
= new ScDPServiceDesc(*r
.pServDesc
);
352 // xSource (and pOutput) is not copied
355 ScDPObject::~ScDPObject()
360 ScDPObject
& ScDPObject::operator= (const ScDPObject
& r
)
365 aTableName
= r
.aTableName
;
366 aTableTag
= r
.aTableTag
;
367 aOutRange
= r
.aOutRange
;
368 mnAutoFormatIndex
= r
.mnAutoFormatIndex
;
369 nHeaderRows
= r
.nHeaderRows
;
370 mbHeaderLayout
= r
.mbHeaderLayout
;
372 bSettingsChanged
= false;
373 mbEnableGetPivotData
= r
.mbEnableGetPivotData
;
376 pSaveData
= new ScDPSaveData(*r
.pSaveData
);
378 pSheetDesc
= new ScSheetSourceDesc(*r
.pSheetDesc
);
380 pImpDesc
= new ScImportSourceDesc(*r
.pImpDesc
);
382 pServDesc
= new ScDPServiceDesc(*r
.pServDesc
);
387 void ScDPObject::EnableGetPivotData(bool b
)
389 mbEnableGetPivotData
= b
;
392 void ScDPObject::SetAllowMove(bool bSet
)
397 void ScDPObject::SetSaveData(const ScDPSaveData
& rData
)
399 if ( pSaveData
!= &rData
) // API implementation modifies the original SaveData object
402 pSaveData
= new ScDPSaveData( rData
);
405 InvalidateData(); // re-init source from SaveData
408 void ScDPObject::SetHeaderLayout (bool bUseGrid
)
410 mbHeaderLayout
= bUseGrid
;
413 bool ScDPObject::GetHeaderLayout() const
415 return mbHeaderLayout
;
418 void ScDPObject::SetOutRange(const ScRange
& rRange
)
423 pOutput
->SetPosition( rRange
.aStart
);
426 void ScDPObject::SetSheetDesc(const ScSheetSourceDesc
& rDesc
, bool /*bFromRefUpdate*/)
428 if ( pSheetDesc
&& rDesc
== *pSheetDesc
)
429 return; // nothing to do
432 DELETEZ( pServDesc
);
435 pSheetDesc
= new ScSheetSourceDesc(rDesc
);
437 // make valid QueryParam
439 const ScRange
& rSrcRange
= pSheetDesc
->GetSourceRange();
440 ScQueryParam aParam
= pSheetDesc
->GetQueryParam();
441 aParam
.nCol1
= rSrcRange
.aStart
.Col();
442 aParam
.nRow1
= rSrcRange
.aStart
.Row();
443 aParam
.nCol2
= rSrcRange
.aEnd
.Col();
444 aParam
.nRow2
= rSrcRange
.aEnd
.Row();
445 aParam
.bHasHeader
= true;
446 pSheetDesc
->SetQueryParam(aParam
);
448 ClearTableData(); // new source must be created
451 void ScDPObject::SetImportDesc(const ScImportSourceDesc
& rDesc
)
453 if ( pImpDesc
&& rDesc
== *pImpDesc
)
454 return; // nothing to do
456 DELETEZ( pSheetDesc
);
457 DELETEZ( pServDesc
);
460 pImpDesc
= new ScImportSourceDesc(rDesc
);
462 ClearTableData(); // new source must be created
465 void ScDPObject::SetServiceData(const ScDPServiceDesc
& rDesc
)
467 if ( pServDesc
&& rDesc
== *pServDesc
)
468 return; // nothing to do
470 DELETEZ( pSheetDesc
);
474 pServDesc
= new ScDPServiceDesc(rDesc
);
476 ClearTableData(); // new source must be created
479 void ScDPObject::WriteSourceDataTo( ScDPObject
& rDest
) const
482 rDest
.SetSheetDesc( *pSheetDesc
);
484 rDest
.SetImportDesc( *pImpDesc
);
485 else if ( pServDesc
)
486 rDest
.SetServiceData( *pServDesc
);
488 // name/tag are not source data, but needed along with source data
490 rDest
.aTableName
= aTableName
;
491 rDest
.aTableTag
= aTableTag
;
494 void ScDPObject::WriteTempDataTo( ScDPObject
& rDest
) const
496 rDest
.nHeaderRows
= nHeaderRows
;
499 bool ScDPObject::IsSheetData() const
501 return ( pSheetDesc
!= NULL
);
504 void ScDPObject::SetName(const OUString
& rNew
)
509 void ScDPObject::SetTag(const OUString
& rNew
)
514 bool ScDPObject::IsDataDescriptionCell(const ScAddress
& rPos
)
519 long nDataDimCount
= pSaveData
->GetDataDimensionCount();
520 if (nDataDimCount
!= 1)
521 // There has to be exactly one data dimension for the description to
522 // appear at top-left corner.
526 ScRange aTabRange
= pOutput
->GetOutputRange(sheet::DataPilotOutputRangeType::TABLE
);
527 return (rPos
== aTabRange
.aStart
);
530 uno::Reference
<sheet::XDimensionsSupplier
> ScDPObject::GetSource()
536 void ScDPObject::CreateOutput()
541 sal_Bool bFilterButton
= IsSheetData() && pSaveData
&& pSaveData
->GetFilterButton();
542 pOutput
= new ScDPOutput( pDoc
, xSource
, aOutRange
.aStart
, bFilterButton
);
543 pOutput
->SetHeaderLayout ( mbHeaderLayout
);
545 long nOldRows
= nHeaderRows
;
546 nHeaderRows
= pOutput
->GetHeaderRows();
548 if ( bAllowMove
&& nHeaderRows
!= nOldRows
)
550 long nDiff
= nOldRows
- nHeaderRows
;
553 if ( nHeaderRows
== 0 )
556 long nNewRow
= aOutRange
.aStart
.Row() + nDiff
;
560 ScAddress
aStart( aOutRange
.aStart
);
561 aStart
.SetRow(nNewRow
);
562 pOutput
->SetPosition( aStart
);
564 //! modify aOutRange?
566 bAllowMove
= false; // use only once
573 class DisableGetPivotData
578 DisableGetPivotData(ScDPObject
& rObj
, bool bOld
) : mrDPObj(rObj
), mbOldState(bOld
)
580 mrDPObj
.EnableGetPivotData(false);
583 ~DisableGetPivotData()
585 mrDPObj
.EnableGetPivotData(mbOldState
);
589 class FindIntersectingTable
: std::unary_function
<ScDPObject
, bool>
593 FindIntersectingTable(const ScRange
& rRange
) : maRange(rRange
) {}
595 bool operator() (const ScDPObject
& rObj
) const
597 return maRange
.Intersects(rObj
.GetOutRange());
601 class FindIntersetingTableByColumns
: std::unary_function
<ScDPObject
, bool>
608 FindIntersetingTableByColumns(SCCOL nCol1
, SCCOL nCol2
, SCROW nRow
, SCTAB nTab
) :
609 mnCol1(nCol1
), mnCol2(nCol2
), mnRow(nRow
), mnTab(nTab
) {}
611 bool operator() (const ScDPObject
& rObj
) const
613 const ScRange
& rRange
= rObj
.GetOutRange();
614 if (mnTab
!= rRange
.aStart
.Tab())
615 // Not on this sheet.
618 if (rRange
.aEnd
.Row() < mnRow
)
619 // This table is above the row. It's safe.
622 if (mnCol1
<= rRange
.aStart
.Col() && rRange
.aEnd
.Col() <= mnCol2
)
623 // This table is fully enclosed in this column range.
626 if (rRange
.aEnd
.Col() < mnCol1
|| mnCol2
< rRange
.aStart
.Col())
627 // This table is entirely outside this column range.
630 // This table must be intersected by this column range.
635 class FindIntersectingTableByRows
: std::unary_function
<ScDPObject
, bool>
642 FindIntersectingTableByRows(SCCOL nCol
, SCROW nRow1
, SCROW nRow2
, SCTAB nTab
) :
643 mnCol(nCol
), mnRow1(nRow1
), mnRow2(nRow2
), mnTab(nTab
) {}
645 bool operator() (const ScDPObject
& rObj
) const
647 const ScRange
& rRange
= rObj
.GetOutRange();
648 if (mnTab
!= rRange
.aStart
.Tab())
649 // Not on this sheet.
652 if (rRange
.aEnd
.Col() < mnCol
)
653 // This table is to the left of the column. It's safe.
656 if (mnRow1
<= rRange
.aStart
.Row() && rRange
.aEnd
.Row() <= mnRow2
)
657 // This table is fully enclosed in this row range.
660 if (rRange
.aEnd
.Row() < mnRow1
|| mnRow2
< rRange
.aStart
.Row())
661 // This table is entirely outside this row range.
664 // This table must be intersected by this row range.
669 class AccumulateOutputRanges
: std::unary_function
<ScDPObject
, void>
671 ScRangeList maRanges
;
674 AccumulateOutputRanges(SCTAB nTab
) : mnTab(nTab
) {}
675 AccumulateOutputRanges(const AccumulateOutputRanges
& r
) : maRanges(r
.maRanges
), mnTab(r
.mnTab
) {}
677 void operator() (const ScDPObject
& rObj
)
679 const ScRange
& rRange
= rObj
.GetOutRange();
680 if (mnTab
!= rRange
.aStart
.Tab())
681 // Not on this sheet.
684 maRanges
.Join(rRange
);
687 ScRangeList
getRanges() const { return maRanges
; }
692 ScDPTableData
* ScDPObject::GetTableData()
696 shared_ptr
<ScDPTableData
> pData
;
697 const ScDPDimensionSaveData
* pDimData
= pSaveData
? pSaveData
->GetExistingDimensionData() : NULL
;
702 const ScDPCache
* pCache
= pImpDesc
->CreateCache(pDimData
);
705 pCache
->AddReference(this);
706 pData
.reset(new ScDatabaseDPData(pDoc
, *pCache
));
714 OSL_FAIL("no source descriptor");
715 pSheetDesc
= new ScSheetSourceDesc(pDoc
); // dummy defaults
719 // Temporarily disable GETPIVOTDATA to avoid having
720 // GETPIVOTDATA called onto itself from within the source
722 DisableGetPivotData
aSwitch(*this, mbEnableGetPivotData
);
723 const ScDPCache
* pCache
= pSheetDesc
->CreateCache(pDimData
);
726 pCache
->AddReference(this);
727 pData
.reset(new ScSheetDPData(pDoc
, *pSheetDesc
, *pCache
));
732 // grouping (for cell or database data)
733 if (pData
&& pDimData
)
735 shared_ptr
<ScDPGroupTableData
> pGroupData(new ScDPGroupTableData(pData
, pDoc
));
736 pDimData
->WriteToData(*pGroupData
);
740 mpTableData
= pData
; // after SetCacheId
743 return mpTableData
.get();
746 void ScDPObject::CreateObjects()
750 DELETEZ( pOutput
); // not valid when xSource is changed
754 xSource
= CreateSource( *pServDesc
);
757 if ( !xSource
.is() ) // database or sheet data, or error in CreateSource
759 OSL_ENSURE( !pServDesc
, "DPSource could not be created" );
760 ScDPTableData
* pData
= GetTableData();
764 // Make sure to transfer these flags to the table data
765 // since they may have changed.
766 pData
->SetEmptyFlags(pSaveData
->GetIgnoreEmptyRows(), pSaveData
->GetRepeatIfEmpty());
768 pData
->ReloadCacheTable();
769 ScDPSource
* pSource
= new ScDPSource( pData
);
775 pSaveData
->WriteToSource( xSource
);
777 else if (bSettingsChanged
)
779 DELETEZ( pOutput
); // not valid when xSource is changed
781 uno::Reference
<util::XRefreshable
> xRef( xSource
, uno::UNO_QUERY
);
788 catch(uno::Exception
&)
790 OSL_FAIL("exception in refresh");
795 pSaveData
->WriteToSource( xSource
);
797 bSettingsChanged
= false;
800 void ScDPObject::InvalidateData()
802 bSettingsChanged
= true;
805 void ScDPObject::Clear()
820 void ScDPObject::ClearTableData()
825 mpTableData
->GetCacheTable().getCache()->RemoveReference(this);
829 void ScDPObject::ReloadGroupTableData()
834 // Table data not built yet. No need to reload the group data.
838 // How could it not have the save data... but whatever.
841 const ScDPDimensionSaveData
* pDimData
= pSaveData
->GetExistingDimensionData();
842 if (!pDimData
|| !pDimData
->HasGroupDimensions())
844 // No group dimensions exist. Check if it currently has group
845 // dimensions, and if so, remove all of them.
846 ScDPGroupTableData
* pData
= dynamic_cast<ScDPGroupTableData
*>(mpTableData
.get());
849 // Replace the existing group table data with the source data.
850 shared_ptr
<ScDPTableData
> pSource
= pData
->GetSourceTableData();
851 mpTableData
= pSource
;
856 ScDPGroupTableData
* pData
= dynamic_cast<ScDPGroupTableData
*>(mpTableData
.get());
859 // This is already a group table data. Salvage the source data and
860 // re-create a new group data.
861 shared_ptr
<ScDPTableData
> pSource
= pData
->GetSourceTableData();
862 shared_ptr
<ScDPGroupTableData
> pGroupData(new ScDPGroupTableData(pSource
, pDoc
));
863 pDimData
->WriteToData(*pGroupData
);
864 mpTableData
= pGroupData
;
868 // This is a source data. Create a group data based on it.
869 shared_ptr
<ScDPGroupTableData
> pGroupData(new ScDPGroupTableData(mpTableData
, pDoc
));
870 pDimData
->WriteToData(*pGroupData
);
871 mpTableData
= pGroupData
;
874 bSettingsChanged
= true;
877 void ScDPObject::ClearSource()
879 Reference
< XComponent
> xObjectComp( xSource
, UNO_QUERY
);
880 if (xObjectComp
.is())
884 xObjectComp
->dispose();
886 catch( const Exception
& )
888 DBG_UNHANDLED_EXCEPTION();
894 ScRange
ScDPObject::GetNewOutputRange( bool& rOverflow
)
896 CreateOutput(); // create xSource and pOutput if not already done
898 rOverflow
= pOutput
->HasError(); // range overflow or exception from source
900 return ScRange( aOutRange
.aStart
);
903 // don't store the result in aOutRange, because nothing has been output yet
904 return pOutput
->GetOutputRange();
908 void ScDPObject::Output( const ScAddress
& rPos
)
910 // clear old output area
911 pDoc
->DeleteAreaTab( aOutRange
.aStart
.Col(), aOutRange
.aStart
.Row(),
912 aOutRange
.aEnd
.Col(), aOutRange
.aEnd
.Row(),
913 aOutRange
.aStart
.Tab(), IDF_ALL
);
914 pDoc
->RemoveFlagsTab( aOutRange
.aStart
.Col(), aOutRange
.aStart
.Row(),
915 aOutRange
.aEnd
.Col(), aOutRange
.aEnd
.Row(),
916 aOutRange
.aStart
.Tab(), SC_MF_AUTO
);
918 CreateOutput(); // create xSource and pOutput if not already done
920 pOutput
->SetPosition( rPos
);
924 // aOutRange is always the range that was last output to the document
925 aOutRange
= pOutput
->GetOutputRange();
926 const ScAddress
& s
= aOutRange
.aStart
;
927 const ScAddress
& e
= aOutRange
.aEnd
;
928 pDoc
->ApplyFlagsTab(s
.Col(), s
.Row(), e
.Col(), e
.Row(), s
.Tab(), SC_MF_DP_TABLE
);
931 const ScRange
ScDPObject::GetOutputRangeByType( sal_Int32 nType
)
935 if (pOutput
->HasError())
936 return ScRange(aOutRange
.aStart
);
938 return pOutput
->GetOutputRange(nType
);
941 static sal_Bool
lcl_HasButton( ScDocument
* pDoc
, SCCOL nCol
, SCROW nRow
, SCTAB nTab
)
943 return ((const ScMergeFlagAttr
*)pDoc
->GetAttr( nCol
, nRow
, nTab
, ATTR_MERGE_FLAG
))->HasPivotButton();
946 void ScDPObject::RefreshAfterLoad()
948 // apply drop-down attribute, initialize nHeaderRows, without accessing the source
949 // (button attribute must be present)
951 // simple test: block of button cells at the top, followed by an empty cell
953 SCCOL nFirstCol
= aOutRange
.aStart
.Col();
954 SCROW nFirstRow
= aOutRange
.aStart
.Row();
955 SCTAB nTab
= aOutRange
.aStart
.Tab();
958 SCROW nOutRows
= aOutRange
.aEnd
.Row() + 1 - aOutRange
.aStart
.Row();
959 while ( nInitial
+ 1 < nOutRows
&& lcl_HasButton( pDoc
, nFirstCol
, nFirstRow
+ nInitial
, nTab
) )
962 if ( nInitial
+ 1 < nOutRows
&&
963 pDoc
->IsBlockEmpty( nTab
, nFirstCol
, nFirstRow
+ nInitial
, nFirstCol
, nFirstRow
+ nInitial
) &&
964 aOutRange
.aEnd
.Col() > nFirstCol
)
966 nHeaderRows
= nInitial
;
969 nHeaderRows
= 0; // nothing found, no drop-down lists
972 void ScDPObject::BuildAllDimensionMembers()
977 // #i111857# don't always create empty mpTableData for external service.
981 pSaveData
->BuildAllDimensionMembers(GetTableData());
984 bool ScDPObject::SyncAllDimensionMembers()
989 // #i111857# don't always create empty mpTableData for external service.
990 // Ideally, xSource should be used instead of mpTableData.
994 ScDPTableData
* pData
= GetTableData();
996 // No table data exists. This can happen when refreshing from an
997 // external source which doesn't exist.
1000 // Refresh the cache wrapper since the cache may have changed.
1001 pData
->SetEmptyFlags(pSaveData
->GetIgnoreEmptyRows(), pSaveData
->GetRepeatIfEmpty());
1002 pData
->ReloadCacheTable();
1003 pSaveData
->SyncAllDimensionMembers(pData
);
1007 bool ScDPObject::GetMemberNames( sal_Int32 nDim
, Sequence
<OUString
>& rNames
)
1009 vector
<ScDPLabelData::Member
> aMembers
;
1010 if (!GetMembers(nDim
, GetUsedHierarchy(nDim
), aMembers
))
1013 size_t n
= aMembers
.size();
1015 for (size_t i
= 0; i
< n
; ++i
)
1016 rNames
[i
] = aMembers
[i
].maName
;
1021 bool ScDPObject::GetMembers( sal_Int32 nDim
, sal_Int32 nHier
, vector
<ScDPLabelData::Member
>& rMembers
)
1023 Reference
< container::XNameAccess
> xMembersNA
;
1024 if (!GetMembersNA( nDim
, nHier
, xMembersNA
))
1027 Reference
<container::XIndexAccess
> xMembersIA( new ScNameToIndexAccess(xMembersNA
) );
1028 sal_Int32 nCount
= xMembersIA
->getCount();
1029 vector
<ScDPLabelData::Member
> aMembers
;
1030 aMembers
.reserve(nCount
);
1032 for (sal_Int32 i
= 0; i
< nCount
; ++i
)
1034 Reference
<container::XNamed
> xMember(xMembersIA
->getByIndex(i
), UNO_QUERY
);
1035 ScDPLabelData::Member aMem
;
1038 aMem
.maName
= xMember
->getName();
1040 Reference
<beans::XPropertySet
> xMemProp(xMember
, UNO_QUERY
);
1043 aMem
.mbVisible
= ScUnoHelpFunctions::GetBoolProperty(xMemProp
, OUString(SC_UNO_DP_ISVISIBLE
));
1044 aMem
.mbShowDetails
= ScUnoHelpFunctions::GetBoolProperty(xMemProp
, OUString(SC_UNO_DP_SHOWDETAILS
));
1046 aMem
.maLayoutName
= ScUnoHelpFunctions::GetStringProperty(
1047 xMemProp
, OUString(SC_UNO_DP_LAYOUTNAME
), OUString());
1050 aMembers
.push_back(aMem
);
1052 rMembers
.swap(aMembers
);
1056 void ScDPObject::UpdateReference( UpdateRefMode eUpdateRefMode
,
1057 const ScRange
& rRange
, SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
)
1061 SCCOL nCol1
= aOutRange
.aStart
.Col();
1062 SCROW nRow1
= aOutRange
.aStart
.Row();
1063 SCTAB nTab1
= aOutRange
.aStart
.Tab();
1064 SCCOL nCol2
= aOutRange
.aEnd
.Col();
1065 SCROW nRow2
= aOutRange
.aEnd
.Row();
1066 SCTAB nTab2
= aOutRange
.aEnd
.Tab();
1068 ScRefUpdateRes eRes
=
1069 ScRefUpdate::Update( pDoc
, eUpdateRefMode
,
1070 rRange
.aStart
.Col(), rRange
.aStart
.Row(), rRange
.aStart
.Tab(),
1071 rRange
.aEnd
.Col(), rRange
.aEnd
.Row(), rRange
.aEnd
.Tab(), nDx
, nDy
, nDz
,
1072 nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
1073 if ( eRes
!= UR_NOTHING
)
1074 SetOutRange( ScRange( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
) );
1076 // sheet source data
1080 const OUString
& rRangeName
= pSheetDesc
->GetRangeName();
1081 if (!rRangeName
.isEmpty())
1082 // Source range is a named range. No need to update.
1085 const ScRange
& rSrcRange
= pSheetDesc
->GetSourceRange();
1086 nCol1
= rSrcRange
.aStart
.Col();
1087 nRow1
= rSrcRange
.aStart
.Row();
1088 nTab1
= rSrcRange
.aStart
.Tab();
1089 nCol2
= rSrcRange
.aEnd
.Col();
1090 nRow2
= rSrcRange
.aEnd
.Row();
1091 nTab2
= rSrcRange
.aEnd
.Tab();
1093 eRes
= ScRefUpdate::Update( pDoc
, eUpdateRefMode
,
1094 rRange
.aStart
.Col(), rRange
.aStart
.Row(), rRange
.aStart
.Tab(),
1095 rRange
.aEnd
.Col(), rRange
.aEnd
.Row(), rRange
.aEnd
.Tab(), nDx
, nDy
, nDz
,
1096 nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
1097 if ( eRes
!= UR_NOTHING
)
1099 SCsCOL nDiffX
= nCol1
- pSheetDesc
->GetSourceRange().aStart
.Col();
1100 SCsROW nDiffY
= nRow1
- pSheetDesc
->GetSourceRange().aStart
.Row();
1102 ScQueryParam aParam
= pSheetDesc
->GetQueryParam();
1103 aParam
.nCol1
= sal::static_int_cast
<SCCOL
>( aParam
.nCol1
+ nDiffX
);
1104 aParam
.nCol2
= sal::static_int_cast
<SCCOL
>( aParam
.nCol2
+ nDiffX
);
1105 aParam
.nRow1
+= nDiffY
; //! used?
1106 aParam
.nRow2
+= nDiffY
; //! used?
1107 SCSIZE nEC
= aParam
.GetEntryCount();
1108 for (SCSIZE i
=0; i
<nEC
; i
++)
1109 if (aParam
.GetEntry(i
).bDoQuery
)
1110 aParam
.GetEntry(i
).nField
+= nDiffX
;
1112 pSheetDesc
->SetQueryParam(aParam
);
1113 pSheetDesc
->SetSourceRange(ScRange(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
));
1118 bool ScDPObject::RefsEqual( const ScDPObject
& r
) const
1120 if ( aOutRange
!= r
.aOutRange
)
1123 if ( pSheetDesc
&& r
.pSheetDesc
)
1125 if ( pSheetDesc
->GetSourceRange() != r
.pSheetDesc
->GetSourceRange() )
1128 else if ( pSheetDesc
|| r
.pSheetDesc
)
1130 OSL_FAIL("RefsEqual: SheetDesc set at only one object");
1137 void ScDPObject::WriteRefsTo( ScDPObject
& r
) const
1139 r
.SetOutRange( aOutRange
);
1141 r
.SetSheetDesc( *pSheetDesc
, true );
1144 void ScDPObject::GetPositionData(const ScAddress
& rPos
, DataPilotTablePositionData
& rPosData
)
1147 pOutput
->GetPositionData(rPos
, rPosData
);
1150 bool ScDPObject::GetDataFieldPositionData(
1151 const ScAddress
& rPos
, Sequence
<sheet::DataPilotFieldFilter
>& rFilters
)
1155 vector
<sheet::DataPilotFieldFilter
> aFilters
;
1156 if (!pOutput
->GetDataResultPositionData(aFilters
, rPos
))
1159 sal_Int32 n
= static_cast<sal_Int32
>(aFilters
.size());
1160 rFilters
.realloc(n
);
1161 for (sal_Int32 i
= 0; i
< n
; ++i
)
1162 rFilters
[i
] = aFilters
[i
];
1167 void ScDPObject::GetDrillDownData(const ScAddress
& rPos
, Sequence
< Sequence
<Any
> >& rTableData
)
1171 Reference
<sheet::XDrillDownDataSupplier
> xDrillDownData(xSource
, UNO_QUERY
);
1172 if (!xDrillDownData
.is())
1175 Sequence
<sheet::DataPilotFieldFilter
> filters
;
1176 if (!GetDataFieldPositionData(rPos
, filters
))
1179 rTableData
= xDrillDownData
->getDrillDownData(filters
);
1182 bool ScDPObject::IsDimNameInUse(const OUString
& rName
) const
1187 Reference
<container::XNameAccess
> xDims
= xSource
->getDimensions();
1188 Sequence
<OUString
> aDimNames
= xDims
->getElementNames();
1189 sal_Int32 n
= aDimNames
.getLength();
1190 for (sal_Int32 i
= 0; i
< n
; ++i
)
1192 const OUString
& rDimName
= aDimNames
[i
];
1193 if (rDimName
.equalsIgnoreAsciiCase(rName
))
1196 Reference
<beans::XPropertySet
> xPropSet(xDims
->getByName(rDimName
), UNO_QUERY
);
1200 OUString aLayoutName
= ScUnoHelpFunctions::GetStringProperty(
1201 xPropSet
, OUString(SC_UNO_DP_LAYOUTNAME
), OUString());
1202 if (aLayoutName
.equalsIgnoreAsciiCase(rName
))
1208 OUString
ScDPObject::GetDimName( long nDim
, bool& rIsDataLayout
, sal_Int32
* pFlags
)
1210 rIsDataLayout
= false;
1215 uno::Reference
<container::XNameAccess
> xDimsName
= xSource
->getDimensions();
1216 uno::Reference
<container::XIndexAccess
> xDims
= new ScNameToIndexAccess( xDimsName
);
1217 long nDimCount
= xDims
->getCount();
1218 if ( nDim
< nDimCount
)
1220 uno::Reference
<uno::XInterface
> xIntDim
=
1221 ScUnoHelpFunctions::AnyToInterface( xDims
->getByIndex(nDim
) );
1222 uno::Reference
<container::XNamed
> xDimName( xIntDim
, uno::UNO_QUERY
);
1223 uno::Reference
<beans::XPropertySet
> xDimProp( xIntDim
, uno::UNO_QUERY
);
1224 if ( xDimName
.is() && xDimProp
.is() )
1226 sal_Bool bData
= ScUnoHelpFunctions::GetBoolProperty( xDimProp
,
1227 OUString(SC_UNO_DP_ISDATALAYOUT
) );
1228 //! error checking -- is "IsDataLayoutDimension" property required??
1233 aName
= xDimName
->getName();
1235 catch(uno::Exception
&)
1239 rIsDataLayout
= true;
1244 *pFlags
= ScUnoHelpFunctions::GetLongProperty( xDimProp
,
1245 OUString(SC_UNO_DP_FLAGS
), 0 );
1253 bool ScDPObject::IsDuplicated( long nDim
)
1255 bool bDuplicated
= false;
1258 uno::Reference
<container::XNameAccess
> xDimsName
= xSource
->getDimensions();
1259 uno::Reference
<container::XIndexAccess
> xDims
= new ScNameToIndexAccess( xDimsName
);
1260 long nDimCount
= xDims
->getCount();
1261 if ( nDim
< nDimCount
)
1263 uno::Reference
<uno::XInterface
> xIntDim
=
1264 ScUnoHelpFunctions::AnyToInterface( xDims
->getByIndex(nDim
) );
1265 uno::Reference
<beans::XPropertySet
> xDimProp( xIntDim
, uno::UNO_QUERY
);
1266 if ( xDimProp
.is() )
1270 uno::Any aOrigAny
= xDimProp
->getPropertyValue(
1271 OUString(SC_UNO_DP_ORIGINAL
) );
1272 uno::Reference
<uno::XInterface
> xIntOrig
;
1273 if ( (aOrigAny
>>= xIntOrig
) && xIntOrig
.is() )
1276 catch(uno::Exception
&)
1285 long ScDPObject::GetDimCount()
1292 uno::Reference
<container::XNameAccess
> xDimsName
= xSource
->getDimensions();
1293 if ( xDimsName
.is() )
1294 nRet
= xDimsName
->getElementNames().getLength();
1296 catch(uno::Exception
&)
1303 void ScDPObject::GetHeaderPositionData(const ScAddress
& rPos
, DataPilotTableHeaderData
& rData
)
1305 using namespace ::com::sun::star::sheet::DataPilotTablePositionType
;
1307 CreateOutput(); // create xSource and pOutput if not already done
1309 // Reset member values to invalid state.
1310 rData
.Dimension
= rData
.Hierarchy
= rData
.Level
= -1;
1313 DataPilotTablePositionData aPosData
;
1314 pOutput
->GetPositionData(rPos
, aPosData
);
1315 const sal_Int32 nPosType
= aPosData
.PositionType
;
1316 if (nPosType
== COLUMN_HEADER
|| nPosType
== ROW_HEADER
)
1317 aPosData
.PositionData
>>= rData
;
1322 class FindByName
: std::unary_function
<const ScDPSaveDimension
*, bool>
1324 OUString maName
; // must be all uppercase.
1326 FindByName(const OUString
& rName
) : maName(rName
) {}
1327 bool operator() (const ScDPSaveDimension
* pDim
) const
1329 // Layout name takes precedence.
1330 const OUString
* pLayoutName
= pDim
->GetLayoutName();
1331 if (pLayoutName
&& ScGlobal::pCharClass
->uppercase(*pLayoutName
) == maName
)
1334 sheet::GeneralFunction eGenFunc
= static_cast<sheet::GeneralFunction
>(pDim
->GetFunction());
1335 ScSubTotalFunc eFunc
= ScDPUtil::toSubTotalFunc(eGenFunc
);
1336 OUString aSrcName
= ScDPUtil::getSourceDimensionName(pDim
->GetName());
1337 OUString aFuncName
= ScDPUtil::getDisplayedMeasureName(aSrcName
, eFunc
);
1338 if (maName
== ScGlobal::pCharClass
->uppercase(aFuncName
))
1341 return maName
== ScGlobal::pCharClass
->uppercase(aSrcName
);
1345 class LessByDimOrder
: std::binary_function
<sheet::DataPilotFieldFilter
, sheet::DataPilotFieldFilter
, bool>
1347 const ScDPSaveData::DimOrderType
& mrDimOrder
;
1350 LessByDimOrder(const ScDPSaveData::DimOrderType
& rDimOrder
) : mrDimOrder(rDimOrder
) {}
1352 bool operator() (const sheet::DataPilotFieldFilter
& r1
, const sheet::DataPilotFieldFilter
& r2
) const
1354 size_t nRank1
= mrDimOrder
.size();
1355 size_t nRank2
= mrDimOrder
.size();
1356 ScDPSaveData::DimOrderType::const_iterator it1
= mrDimOrder
.find(r1
.FieldName
);
1357 if (it1
!= mrDimOrder
.end())
1358 nRank1
= it1
->second
;
1360 ScDPSaveData::DimOrderType::const_iterator it2
= mrDimOrder
.find(r2
.FieldName
);
1361 if (it2
!= mrDimOrder
.end())
1362 nRank2
= it2
->second
;
1364 return nRank1
< nRank2
;
1370 double ScDPObject::GetPivotData(const OUString
& rDataFieldName
, std::vector
<sheet::DataPilotFieldFilter
>& rFilters
)
1373 rtl::math::setNan(&fRet
);
1374 if (!mbEnableGetPivotData
)
1379 std::vector
<const ScDPSaveDimension
*> aDataDims
;
1380 pSaveData
->GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_DATA
, aDataDims
);
1381 if (aDataDims
.empty())
1384 std::vector
<const ScDPSaveDimension
*>::iterator it
= std::find_if(
1385 aDataDims
.begin(), aDataDims
.end(),
1386 FindByName(ScGlobal::pCharClass
->uppercase(rDataFieldName
)));
1388 if (it
== aDataDims
.end())
1391 size_t nDataIndex
= std::distance(aDataDims
.begin(), it
);
1393 uno::Reference
<sheet::XDataPilotResults
> xDPResults(xSource
, uno::UNO_QUERY
);
1394 if (!xDPResults
.is())
1397 // Dimensions must be sorted in order of appearance, and row dimensions
1398 // must come before column dimensions.
1399 std::sort(rFilters
.begin(), rFilters
.end(), LessByDimOrder(pSaveData
->GetDimensionSortOrder()));
1401 size_t n
= rFilters
.size();
1402 uno::Sequence
<sheet::DataPilotFieldFilter
> aFilters(n
);
1403 for (size_t i
= 0; i
< n
; ++i
)
1404 aFilters
[i
] = rFilters
[i
];
1406 uno::Sequence
<double> aRes
= xDPResults
->getFilteredResults(aFilters
);
1407 if (static_cast<sal_Int32
>(nDataIndex
) >= aRes
.getLength())
1410 return aRes
[nDataIndex
];
1413 bool ScDPObject::IsFilterButton( const ScAddress
& rPos
)
1415 CreateOutput(); // create xSource and pOutput if not already done
1417 return pOutput
->IsFilterButton( rPos
);
1420 long ScDPObject::GetHeaderDim( const ScAddress
& rPos
, sal_uInt16
& rOrient
)
1422 CreateOutput(); // create xSource and pOutput if not already done
1424 return pOutput
->GetHeaderDim( rPos
, rOrient
);
1427 bool ScDPObject::GetHeaderDrag( const ScAddress
& rPos
, bool bMouseLeft
, bool bMouseTop
, long nDragDim
,
1428 Rectangle
& rPosRect
, sal_uInt16
& rOrient
, long& rDimPos
)
1430 CreateOutput(); // create xSource and pOutput if not already done
1432 return pOutput
->GetHeaderDrag( rPos
, bMouseLeft
, bMouseTop
, nDragDim
, rPosRect
, rOrient
, rDimPos
);
1435 void ScDPObject::GetMemberResultNames(ScDPUniqueStringSet
& rNames
, long nDimension
)
1437 CreateOutput(); // create xSource and pOutput if not already done
1439 pOutput
->GetMemberResultNames(rNames
, nDimension
); // used only with table data -> level not needed
1444 bool dequote( const OUString
& rSource
, sal_Int32 nStartPos
, sal_Int32
& rEndPos
, OUString
& rResult
)
1446 // nStartPos has to point to opening quote
1449 const sal_Unicode cQuote
= '\'';
1451 if (rSource
[nStartPos
] == cQuote
)
1453 OUStringBuffer aBuffer
;
1454 sal_Int32 nPos
= nStartPos
+ 1;
1455 const sal_Int32 nLen
= rSource
.getLength();
1457 while ( nPos
< nLen
)
1459 const sal_Unicode cNext
= rSource
[nPos
];
1460 if ( cNext
== cQuote
)
1462 if (nPos
+1 < nLen
&& rSource
[nPos
+1] == cQuote
)
1464 // double quote is used for an embedded quote
1465 aBuffer
.append( cNext
); // append one quote
1466 ++nPos
; // skip the next one
1470 // end of quoted string
1471 rResult
= aBuffer
.makeStringAndClear();
1472 rEndPos
= nPos
+ 1; // behind closing quote
1477 aBuffer
.append( cNext
);
1481 // no closing quote before the end of the string -> error (bRet still false)
1487 struct ScGetPivotDataFunctionEntry
1489 const sal_Char
* pName
;
1490 sheet::GeneralFunction eFunc
;
1493 bool parseFunction( const OUString
& rList
, sal_Int32 nStartPos
, sal_Int32
& rEndPos
, sheet::GeneralFunction
& rFunc
)
1495 static const ScGetPivotDataFunctionEntry aFunctions
[] =
1498 { "Sum", sheet::GeneralFunction_SUM
},
1499 { "Count", sheet::GeneralFunction_COUNT
},
1500 { "Average", sheet::GeneralFunction_AVERAGE
},
1501 { "Max", sheet::GeneralFunction_MAX
},
1502 { "Min", sheet::GeneralFunction_MIN
},
1503 { "Product", sheet::GeneralFunction_PRODUCT
},
1504 { "CountNums", sheet::GeneralFunction_COUNTNUMS
},
1505 { "StDev", sheet::GeneralFunction_STDEV
},
1506 { "StDevp", sheet::GeneralFunction_STDEVP
},
1507 { "Var", sheet::GeneralFunction_VAR
},
1508 { "VarP", sheet::GeneralFunction_VARP
},
1509 // compatibility names
1510 { "Count Nums", sheet::GeneralFunction_COUNTNUMS
},
1511 { "StdDev", sheet::GeneralFunction_STDEV
},
1512 { "StdDevp", sheet::GeneralFunction_STDEVP
}
1515 const sal_Int32 nListLen
= rList
.getLength();
1516 while (nStartPos
< nListLen
&& rList
[nStartPos
] == ' ')
1519 bool bParsed
= false;
1520 bool bFound
= false;
1522 sal_Int32 nFuncEnd
= 0;
1523 if (nStartPos
< nListLen
&& rList
[nStartPos
] == '\'')
1524 bParsed
= dequote( rList
, nStartPos
, nFuncEnd
, aFuncStr
);
1527 nFuncEnd
= rList
.indexOf(']', nStartPos
);
1530 aFuncStr
= rList
.copy(nStartPos
, nFuncEnd
- nStartPos
);
1537 aFuncStr
= comphelper::string::strip(aFuncStr
, ' ');
1539 const sal_Int32 nFuncCount
= sizeof(aFunctions
) / sizeof(aFunctions
[0]);
1540 for ( sal_Int32 nFunc
=0; nFunc
<nFuncCount
&& !bFound
; nFunc
++ )
1542 if (aFuncStr
.equalsIgnoreAsciiCaseAscii(aFunctions
[nFunc
].pName
))
1544 rFunc
= aFunctions
[nFunc
].eFunc
;
1547 while (nFuncEnd
< nListLen
&& rList
[nFuncEnd
] == ' ')
1558 const OUString
& rList
, const OUString
& rSearch
, sal_Int32
& rMatched
,
1559 bool bAllowBracket
, sheet::GeneralFunction
* pFunc
)
1561 sal_Int32 nMatchList
= 0;
1562 sal_Int32 nMatchSearch
= 0;
1563 sal_Unicode cFirst
= rList
[0];
1564 if ( cFirst
== '\'' || cFirst
== '[' )
1566 // quoted string or string in brackets must match completely
1569 sal_Int32 nQuoteEnd
= 0;
1570 bool bParsed
= false;
1572 if ( cFirst
== '\'' )
1573 bParsed
= dequote( rList
, 0, nQuoteEnd
, aDequoted
);
1574 else if ( cFirst
== '[' )
1576 // skip spaces after the opening bracket
1578 sal_Int32 nStartPos
= 1;
1579 const sal_Int32 nListLen
= rList
.getLength();
1580 while (nStartPos
< nListLen
&& rList
[nStartPos
] == ' ')
1583 if (nStartPos
< nListLen
&& rList
[nStartPos
] == '\'') // quoted within the brackets?
1585 if ( dequote( rList
, nStartPos
, nQuoteEnd
, aDequoted
) )
1587 // after the quoted string, there must be the closing bracket, optionally preceded by spaces,
1588 // and/or a function name
1589 while (nQuoteEnd
< nListLen
&& rList
[nQuoteEnd
] == ' ')
1592 // semicolon separates function name
1593 if (nQuoteEnd
< nListLen
&& rList
[nQuoteEnd
] == ';' && pFunc
)
1595 sal_Int32 nFuncEnd
= 0;
1596 if ( parseFunction( rList
, nQuoteEnd
+ 1, nFuncEnd
, *pFunc
) )
1597 nQuoteEnd
= nFuncEnd
;
1599 if (nQuoteEnd
< nListLen
&& rList
[nQuoteEnd
] == ']')
1601 ++nQuoteEnd
; // include the closing bracket for the matched length
1608 // implicit quoting to the closing bracket
1610 sal_Int32 nClosePos
= rList
.indexOf(']', nStartPos
);
1613 sal_Int32 nNameEnd
= nClosePos
;
1614 sal_Int32 nSemiPos
= rList
.indexOf(';', nStartPos
);
1615 if (nSemiPos
>= 0 && nSemiPos
< nClosePos
&& pFunc
)
1617 sal_Int32 nFuncEnd
= 0;
1618 if (parseFunction(rList
, nSemiPos
+1, nFuncEnd
, *pFunc
))
1619 nNameEnd
= nSemiPos
;
1622 aDequoted
= rList
.copy(nStartPos
, nNameEnd
- nStartPos
);
1623 // spaces before the closing bracket or semicolon
1624 aDequoted
= comphelper::string::stripEnd(aDequoted
, ' ');
1625 nQuoteEnd
= nClosePos
+ 1;
1631 if ( bParsed
&& ScGlobal::GetpTransliteration()->isEqual( aDequoted
, rSearch
) )
1633 nMatchList
= nQuoteEnd
; // match count in the list string, including quotes
1634 nMatchSearch
= rSearch
.getLength();
1639 // otherwise look for search string at the start of rList
1640 ScGlobal::GetpTransliteration()->equals(
1641 rList
, 0, rList
.getLength(), nMatchList
, rSearch
, 0, rSearch
.getLength(), nMatchSearch
);
1644 if (nMatchSearch
== rSearch
.getLength())
1646 // search string is at start of rList - look for following space or end of string
1648 bool bValid
= false;
1649 if ( sal::static_int_cast
<sal_Int32
>(nMatchList
) >= rList
.getLength() )
1653 sal_Unicode cNext
= rList
[nMatchList
];
1654 if ( cNext
== ' ' || ( bAllowBracket
&& cNext
== '[' ) )
1660 rMatched
= nMatchList
;
1668 } // anonymous namespace
1670 bool ScDPObject::ParseFilters(
1671 OUString
& rDataFieldName
,
1672 std::vector
<sheet::DataPilotFieldFilter
>& rFilters
,
1673 std::vector
<sheet::GeneralFunction
>& rFilterFuncs
, const OUString
& rFilterList
)
1675 // parse the string rFilterList into parameters for GetPivotData
1677 CreateObjects(); // create xSource if not already done
1679 std::vector
<OUString
> aDataNames
; // data fields (source name)
1680 std::vector
<OUString
> aGivenNames
; // data fields (compound name)
1681 std::vector
<OUString
> aFieldNames
; // column/row/data fields
1682 std::vector
< uno::Sequence
<OUString
> > aFieldValues
;
1685 // get all the field and item names
1688 uno::Reference
<container::XNameAccess
> xDimsName
= xSource
->getDimensions();
1689 uno::Reference
<container::XIndexAccess
> xIntDims
= new ScNameToIndexAccess( xDimsName
);
1690 sal_Int32 nDimCount
= xIntDims
->getCount();
1691 for ( sal_Int32 nDim
= 0; nDim
<nDimCount
; nDim
++ )
1693 uno::Reference
<uno::XInterface
> xIntDim
= ScUnoHelpFunctions::AnyToInterface( xIntDims
->getByIndex(nDim
) );
1694 uno::Reference
<container::XNamed
> xDim( xIntDim
, uno::UNO_QUERY
);
1695 uno::Reference
<beans::XPropertySet
> xDimProp( xDim
, uno::UNO_QUERY
);
1696 uno::Reference
<sheet::XHierarchiesSupplier
> xDimSupp( xDim
, uno::UNO_QUERY
);
1697 sal_Bool bDataLayout
= ScUnoHelpFunctions::GetBoolProperty( xDimProp
,
1698 OUString(SC_UNO_DP_ISDATALAYOUT
) );
1699 sal_Int32 nOrient
= ScUnoHelpFunctions::GetEnumProperty(
1700 xDimProp
, OUString(SC_UNO_DP_ORIENTATION
),
1701 sheet::DataPilotFieldOrientation_HIDDEN
);
1704 if ( nOrient
== sheet::DataPilotFieldOrientation_DATA
)
1706 OUString aSourceName
;
1707 OUString aGivenName
;
1708 ScDPOutput::GetDataDimensionNames( aSourceName
, aGivenName
, xIntDim
);
1709 aDataNames
.push_back( aSourceName
);
1710 aGivenNames
.push_back( aGivenName
);
1712 else if ( nOrient
!= sheet::DataPilotFieldOrientation_HIDDEN
)
1714 // get level names, as in ScDPOutput
1716 uno::Reference
<container::XIndexAccess
> xHiers
= new ScNameToIndexAccess( xDimSupp
->getHierarchies() );
1717 sal_Int32 nHierarchy
= ScUnoHelpFunctions::GetLongProperty( xDimProp
,
1718 OUString(SC_UNO_DP_USEDHIERARCHY
) );
1719 if ( nHierarchy
>= xHiers
->getCount() )
1722 uno::Reference
<uno::XInterface
> xHier
= ScUnoHelpFunctions::AnyToInterface(
1723 xHiers
->getByIndex(nHierarchy
) );
1724 uno::Reference
<sheet::XLevelsSupplier
> xHierSupp( xHier
, uno::UNO_QUERY
);
1725 if ( xHierSupp
.is() )
1727 uno::Reference
<container::XIndexAccess
> xLevels
= new ScNameToIndexAccess( xHierSupp
->getLevels() );
1728 sal_Int32 nLevCount
= xLevels
->getCount();
1729 for (sal_Int32 nLev
=0; nLev
<nLevCount
; nLev
++)
1731 uno::Reference
<uno::XInterface
> xLevel
= ScUnoHelpFunctions::AnyToInterface(
1732 xLevels
->getByIndex(nLev
) );
1733 uno::Reference
<container::XNamed
> xLevNam( xLevel
, uno::UNO_QUERY
);
1734 uno::Reference
<sheet::XMembersSupplier
> xLevSupp( xLevel
, uno::UNO_QUERY
);
1735 if ( xLevNam
.is() && xLevSupp
.is() )
1737 uno::Reference
<container::XNameAccess
> xMembers
= xLevSupp
->getMembers();
1739 OUString
aFieldName( xLevNam
->getName() );
1740 uno::Sequence
<OUString
> aMemberNames( xMembers
->getElementNames() );
1742 aFieldNames
.push_back( aFieldName
);
1743 aFieldValues
.push_back( aMemberNames
);
1752 // compare and build filters
1755 SCSIZE nDataFields
= aDataNames
.size();
1756 SCSIZE nFieldCount
= aFieldNames
.size();
1757 OSL_ENSURE( aGivenNames
.size() == nDataFields
&& aFieldValues
.size() == nFieldCount
, "wrong count" );
1759 bool bError
= false;
1760 bool bHasData
= false;
1761 OUString
aRemaining(comphelper::string::strip(rFilterList
, ' '));
1762 while (!aRemaining
.isEmpty() && !bError
)
1766 // look for data field name
1768 for ( SCSIZE nDataPos
=0; nDataPos
<nDataFields
&& !bUsed
; nDataPos
++ )
1771 sal_Int32 nMatched
= 0;
1772 if (isAtStart(aRemaining
, aDataNames
[nDataPos
], nMatched
, false, NULL
))
1773 aFound
= aDataNames
[nDataPos
];
1774 else if (isAtStart(aRemaining
, aGivenNames
[nDataPos
], nMatched
, false, NULL
))
1775 aFound
= aGivenNames
[nDataPos
];
1777 if (!aFound
.isEmpty())
1779 rDataFieldName
= aFound
;
1780 aRemaining
= aRemaining
.copy(nMatched
);
1786 // look for field name
1788 OUString aSpecField
;
1789 bool bHasFieldName
= false;
1792 sal_Int32 nMatched
= 0;
1793 for ( SCSIZE nField
=0; nField
<nFieldCount
&& !bHasFieldName
; nField
++ )
1795 if (isAtStart(aRemaining
, aFieldNames
[nField
], nMatched
, true, NULL
))
1797 aSpecField
= aFieldNames
[nField
];
1798 aRemaining
= aRemaining
.copy(nMatched
);
1799 aRemaining
= comphelper::string::stripStart(aRemaining
, ' ');
1801 // field name has to be followed by item name in brackets
1802 if (!aRemaining
.isEmpty() && aRemaining
[0] == '[')
1804 bHasFieldName
= true;
1805 // bUsed remains false - still need the item
1816 // look for field item
1820 bool bItemFound
= false;
1821 sal_Int32 nMatched
= 0;
1822 OUString aFoundName
;
1823 OUString aFoundValue
;
1824 sheet::GeneralFunction eFunc
= sheet::GeneralFunction_NONE
;
1825 sheet::GeneralFunction eFoundFunc
= sheet::GeneralFunction_NONE
;
1827 for ( SCSIZE nField
=0; nField
<nFieldCount
; nField
++ )
1829 // If a field name is given, look in that field only, otherwise in all fields.
1830 // aSpecField is initialized from aFieldNames array, so exact comparison can be used.
1831 if ( !bHasFieldName
|| aFieldNames
[nField
] == aSpecField
)
1833 const uno::Sequence
<OUString
>& rItems
= aFieldValues
[nField
];
1834 sal_Int32 nItemCount
= rItems
.getLength();
1835 const OUString
* pItemArr
= rItems
.getConstArray();
1836 for ( sal_Int32 nItem
=0; nItem
<nItemCount
; nItem
++ )
1838 if ( isAtStart( aRemaining
, pItemArr
[nItem
], nMatched
, false, &eFunc
) )
1841 bError
= true; // duplicate (also across fields)
1844 aFoundName
= aFieldNames
[nField
];
1845 aFoundValue
= pItemArr
[nItem
];
1855 if ( bItemFound
&& !bError
)
1857 sheet::DataPilotFieldFilter aField
;
1858 aField
.FieldName
= aFoundName
;
1859 aField
.MatchValue
= aFoundValue
;
1860 rFilters
.push_back(aField
);
1861 rFilterFuncs
.push_back(eFoundFunc
);
1862 aRemaining
= aRemaining
.copy(nMatched
);
1869 // remove any number of spaces between entries
1870 aRemaining
= comphelper::string::stripStart(aRemaining
, ' ');
1873 if ( !bError
&& !bHasData
&& aDataNames
.size() == 1 )
1875 // if there's only one data field, its name need not be specified
1876 rDataFieldName
= aDataNames
[0];
1880 return bHasData
&& !bError
;
1883 void ScDPObject::ToggleDetails(const DataPilotTableHeaderData
& rElemDesc
, ScDPObject
* pDestObj
)
1885 CreateObjects(); // create xSource if not already done
1887 // find dimension name
1889 uno::Reference
<container::XNamed
> xDim
;
1890 uno::Reference
<container::XNameAccess
> xDimsName
= xSource
->getDimensions();
1891 uno::Reference
<container::XIndexAccess
> xIntDims
= new ScNameToIndexAccess( xDimsName
);
1892 long nIntCount
= xIntDims
->getCount();
1893 if ( rElemDesc
.Dimension
< nIntCount
)
1895 uno::Reference
<uno::XInterface
> xIntDim
= ScUnoHelpFunctions::AnyToInterface(
1896 xIntDims
->getByIndex(rElemDesc
.Dimension
) );
1897 xDim
= uno::Reference
<container::XNamed
>( xIntDim
, uno::UNO_QUERY
);
1899 OSL_ENSURE( xDim
.is(), "dimension not found" );
1900 if ( !xDim
.is() ) return;
1901 OUString aDimName
= xDim
->getName();
1903 uno::Reference
<beans::XPropertySet
> xDimProp( xDim
, uno::UNO_QUERY
);
1904 sal_Bool bDataLayout
= ScUnoHelpFunctions::GetBoolProperty( xDimProp
,
1905 OUString(SC_UNO_DP_ISDATALAYOUT
) );
1908 // the elements of the data layout dimension can't be found by their names
1909 // -> don't change anything
1915 long nHierCount
= 0;
1916 uno::Reference
<container::XIndexAccess
> xHiers
;
1917 uno::Reference
<sheet::XHierarchiesSupplier
> xHierSupp( xDim
, uno::UNO_QUERY
);
1918 if ( xHierSupp
.is() )
1920 uno::Reference
<container::XNameAccess
> xHiersName
= xHierSupp
->getHierarchies();
1921 xHiers
= new ScNameToIndexAccess( xHiersName
);
1922 nHierCount
= xHiers
->getCount();
1924 uno::Reference
<uno::XInterface
> xHier
;
1925 if ( rElemDesc
.Hierarchy
< nHierCount
)
1926 xHier
= ScUnoHelpFunctions::AnyToInterface( xHiers
->getByIndex(rElemDesc
.Hierarchy
) );
1927 OSL_ENSURE( xHier
.is(), "hierarchy not found" );
1928 if ( !xHier
.is() ) return;
1931 uno::Reference
<container::XIndexAccess
> xLevels
;
1932 uno::Reference
<sheet::XLevelsSupplier
> xLevSupp( xHier
, uno::UNO_QUERY
);
1933 if ( xLevSupp
.is() )
1935 uno::Reference
<container::XNameAccess
> xLevsName
= xLevSupp
->getLevels();
1936 xLevels
= new ScNameToIndexAccess( xLevsName
);
1937 nLevCount
= xLevels
->getCount();
1939 uno::Reference
<uno::XInterface
> xLevel
;
1940 if ( rElemDesc
.Level
< nLevCount
)
1941 xLevel
= ScUnoHelpFunctions::AnyToInterface( xLevels
->getByIndex(rElemDesc
.Level
) );
1942 OSL_ENSURE( xLevel
.is(), "level not found" );
1943 if ( !xLevel
.is() ) return;
1945 uno::Reference
<container::XNameAccess
> xMembers
;
1946 uno::Reference
<sheet::XMembersSupplier
> xMbrSupp( xLevel
, uno::UNO_QUERY
);
1947 if ( xMbrSupp
.is() )
1948 xMembers
= xMbrSupp
->getMembers();
1950 sal_Bool bFound
= false;
1951 sal_Bool bShowDetails
= sal_True
;
1953 if ( xMembers
.is() )
1955 if ( xMembers
->hasByName(rElemDesc
.MemberName
) )
1957 uno::Reference
<uno::XInterface
> xMemberInt
= ScUnoHelpFunctions::AnyToInterface(
1958 xMembers
->getByName(rElemDesc
.MemberName
) );
1959 uno::Reference
<beans::XPropertySet
> xMbrProp( xMemberInt
, uno::UNO_QUERY
);
1960 if ( xMbrProp
.is() )
1962 bShowDetails
= ScUnoHelpFunctions::GetBoolProperty( xMbrProp
,
1963 OUString(SC_UNO_DP_SHOWDETAILS
) );
1964 //! don't set bFound if property is unknown?
1970 OSL_ENSURE( bFound
, "member not found" );
1973 //! use Hierarchy and Level in SaveData !!!!
1975 // modify pDestObj if set, this object otherwise
1976 ScDPSaveData
* pModifyData
= pDestObj
? ( pDestObj
->pSaveData
) : pSaveData
;
1977 OSL_ENSURE( pModifyData
, "no data?" );
1980 const OUString aName
= rElemDesc
.MemberName
;
1981 pModifyData
->GetDimensionByName(aDimName
)->
1982 GetMemberByName(aName
)->SetShowDetails( !bShowDetails
); // toggle
1985 pDestObj
->InvalidateData(); // re-init source from SaveData
1987 InvalidateData(); // re-init source from SaveData
1991 static sal_uInt16
lcl_FirstSubTotal( const uno::Reference
<beans::XPropertySet
>& xDimProp
) // PIVOT_FUNC mask
1993 uno::Reference
<sheet::XHierarchiesSupplier
> xDimSupp( xDimProp
, uno::UNO_QUERY
);
1994 if ( xDimProp
.is() && xDimSupp
.is() )
1996 uno::Reference
<container::XIndexAccess
> xHiers
= new ScNameToIndexAccess( xDimSupp
->getHierarchies() );
1997 long nHierarchy
= ScUnoHelpFunctions::GetLongProperty( xDimProp
,
1998 OUString(SC_UNO_DP_USEDHIERARCHY
) );
1999 if ( nHierarchy
>= xHiers
->getCount() )
2002 uno::Reference
<uno::XInterface
> xHier
= ScUnoHelpFunctions::AnyToInterface(
2003 xHiers
->getByIndex(nHierarchy
) );
2004 uno::Reference
<sheet::XLevelsSupplier
> xHierSupp( xHier
, uno::UNO_QUERY
);
2005 if ( xHierSupp
.is() )
2007 uno::Reference
<container::XIndexAccess
> xLevels
= new ScNameToIndexAccess( xHierSupp
->getLevels() );
2008 uno::Reference
<uno::XInterface
> xLevel
=
2009 ScUnoHelpFunctions::AnyToInterface( xLevels
->getByIndex( 0 ) );
2010 uno::Reference
<beans::XPropertySet
> xLevProp( xLevel
, uno::UNO_QUERY
);
2011 if ( xLevProp
.is() )
2016 aSubAny
= xLevProp
->getPropertyValue(
2017 OUString(SC_UNO_DP_SUBTOTAL
) );
2019 catch(uno::Exception
&)
2022 uno::Sequence
<sheet::GeneralFunction
> aSeq
;
2023 if ( aSubAny
>>= aSeq
)
2025 sal_uInt16 nMask
= 0;
2026 const sheet::GeneralFunction
* pArray
= aSeq
.getConstArray();
2027 long nCount
= aSeq
.getLength();
2028 for (long i
=0; i
<nCount
; i
++)
2029 nMask
|= ScDataPilotConversion::FunctionBit(pArray
[i
]);
2036 OSL_FAIL("FirstSubTotal: NULL");
2042 class FindByColumn
: public std::unary_function
<ScPivotField
, bool>
2047 FindByColumn(SCsCOL nCol
, sal_uInt16 nMask
) : mnCol(nCol
), mnMask(nMask
) {}
2048 bool operator() (const ScPivotField
& r
) const
2050 return r
.nCol
== mnCol
&& r
.nFuncMask
== mnMask
;
2056 void lcl_FillOldFields( ScPivotFieldVector
& rFields
,
2057 const uno::Reference
<sheet::XDimensionsSupplier
>& xSource
,
2058 sal_uInt16 nOrient
, bool bAddData
)
2060 ScPivotFieldVector aFields
;
2062 bool bDataFound
= false;
2064 //! merge multiple occurrences (data field with different functions)
2065 //! force data field in one dimension
2069 uno::Reference
<container::XNameAccess
> xDimsName
= xSource
->getDimensions();
2070 uno::Reference
<container::XIndexAccess
> xDims
= new ScNameToIndexAccess( xDimsName
);
2071 long nDimCount
= xDims
->getCount();
2072 for (long nDim
= 0; nDim
< nDimCount
; ++nDim
)
2074 // Get dimension object.
2075 uno::Reference
<uno::XInterface
> xIntDim
=
2076 ScUnoHelpFunctions::AnyToInterface( xDims
->getByIndex(nDim
) );
2078 // dimension properties
2079 uno::Reference
<beans::XPropertySet
> xDimProp( xIntDim
, uno::UNO_QUERY
);
2081 // dimension orientation, hidden by default.
2082 long nDimOrient
= ScUnoHelpFunctions::GetEnumProperty(
2083 xDimProp
, OUString(SC_UNO_DP_ORIENTATION
),
2084 sheet::DataPilotFieldOrientation_HIDDEN
);
2086 if ( xDimProp
.is() && nDimOrient
== nOrient
)
2088 // Let's take this dimension.
2091 sal_uInt16 nMask
= 0;
2092 if ( nOrient
== sheet::DataPilotFieldOrientation_DATA
)
2094 sheet::GeneralFunction eFunc
= (sheet::GeneralFunction
)ScUnoHelpFunctions::GetEnumProperty(
2095 xDimProp
, OUString(SC_UNO_DP_FUNCTION
),
2096 sheet::GeneralFunction_NONE
);
2097 if ( eFunc
== sheet::GeneralFunction_AUTO
)
2099 //! test for numeric data
2100 eFunc
= sheet::GeneralFunction_SUM
;
2102 nMask
= ScDataPilotConversion::FunctionBit(eFunc
);
2105 nMask
= lcl_FirstSubTotal( xDimProp
); // from first hierarchy
2107 // is this data layout dimension?
2108 bool bDataLayout
= ScUnoHelpFunctions::GetBoolProperty(
2109 xDimProp
, OUString(SC_UNO_DP_ISDATALAYOUT
));
2111 // is this dimension cloned?
2112 long nDupSource
= -1;
2115 uno::Any aOrigAny
= xDimProp
->getPropertyValue(
2116 OUString(SC_UNO_DP_ORIGINAL_POS
));
2118 if (aOrigAny
>>= nTmp
)
2119 nDupSource
= static_cast<sal_Int32
>(nTmp
);
2121 catch(uno::Exception
&)
2125 sal_uInt8 nDupCount
= 0;
2126 if (nDupSource
>= 0)
2128 // this dimension is cloned.
2130 SCsCOL nCompCol
; // ID of the original dimension.
2132 nCompCol
= PIVOT_DATA_FIELD
;
2134 nCompCol
= static_cast<SCsCOL
>(nDupSource
); //! seek source column from name
2136 ScPivotFieldVector::iterator it
= std::find_if(aFields
.begin(), aFields
.end(), FindByColumn(nCompCol
, nMask
));
2137 if (it
!= aFields
.end())
2138 nDupCount
= it
->mnDupCount
+ 1;
2141 aFields
.push_back(ScPivotField());
2142 ScPivotField
& rField
= aFields
.back();
2145 rField
.nCol
= PIVOT_DATA_FIELD
;
2150 rField
.mnOriginalDim
= nDupSource
;
2151 rField
.nCol
= static_cast<SCCOL
>(nDim
); //! seek source column from name
2154 rField
.nFuncMask
= nMask
;
2155 rField
.mnDupCount
= nDupCount
;
2156 long nPos
= ScUnoHelpFunctions::GetLongProperty(
2157 xDimProp
, OUString(SC_UNO_DP_POSITION
));
2158 aPos
.push_back(nPos
);
2162 if (nOrient
== sheet::DataPilotFieldOrientation_DATA
)
2163 xDimProp
->getPropertyValue(OUString(SC_UNO_DP_REFVALUE
))
2164 >>= rField
.maFieldRef
;
2166 catch (uno::Exception
&)
2172 // sort by getPosition() value
2174 size_t nOutCount
= aFields
.size();
2177 for (size_t i
= 0; i
< nOutCount
- 1; ++i
)
2179 for (size_t j
= 0; j
+ i
< nOutCount
- 1; ++j
)
2181 if ( aPos
[j
+1] < aPos
[j
] )
2183 std::swap( aPos
[j
], aPos
[j
+1] );
2184 std::swap( aFields
[j
], aFields
[j
+1] );
2190 if (bAddData
&& !bDataFound
)
2191 aFields
.push_back(ScPivotField(PIVOT_DATA_FIELD
, 0));
2193 rFields
.swap(aFields
);
2196 bool ScDPObject::FillOldParam(ScPivotParam
& rParam
) const
2198 ((ScDPObject
*)this)->CreateObjects(); // xSource is needed for field numbers
2203 rParam
.nCol
= aOutRange
.aStart
.Col();
2204 rParam
.nRow
= aOutRange
.aStart
.Row();
2205 rParam
.nTab
= aOutRange
.aStart
.Tab();
2206 // ppLabelArr / nLabels is not changed
2208 bool bAddData
= ( lcl_GetDataGetOrientation( xSource
) == sheet::DataPilotFieldOrientation_HIDDEN
);
2210 rParam
.maPageFields
, xSource
, sheet::DataPilotFieldOrientation_PAGE
, false);
2212 rParam
.maColFields
, xSource
, sheet::DataPilotFieldOrientation_COLUMN
, bAddData
);
2214 rParam
.maRowFields
, xSource
, sheet::DataPilotFieldOrientation_ROW
, false);
2216 rParam
.maDataFields
, xSource
, sheet::DataPilotFieldOrientation_DATA
, false);
2218 uno::Reference
<beans::XPropertySet
> xProp( xSource
, uno::UNO_QUERY
);
2223 rParam
.bMakeTotalCol
= ScUnoHelpFunctions::GetBoolProperty( xProp
,
2224 OUString(SC_UNO_DP_COLGRAND
), true );
2225 rParam
.bMakeTotalRow
= ScUnoHelpFunctions::GetBoolProperty( xProp
,
2226 OUString(SC_UNO_DP_ROWGRAND
), true );
2228 // following properties may be missing for external sources
2229 rParam
.bIgnoreEmptyRows
= ScUnoHelpFunctions::GetBoolProperty( xProp
,
2230 OUString(SC_UNO_DP_IGNOREEMPTY
) );
2231 rParam
.bDetectCategories
= ScUnoHelpFunctions::GetBoolProperty( xProp
,
2232 OUString(SC_UNO_DP_REPEATEMPTY
) );
2234 catch(uno::Exception
&)
2242 static void lcl_FillLabelData( ScDPLabelData
& rData
, const uno::Reference
< beans::XPropertySet
>& xDimProp
)
2244 uno::Reference
<sheet::XHierarchiesSupplier
> xDimSupp( xDimProp
, uno::UNO_QUERY
);
2245 if (!xDimProp
.is() || !xDimSupp
.is())
2248 uno::Reference
<container::XIndexAccess
> xHiers
= new ScNameToIndexAccess( xDimSupp
->getHierarchies() );
2249 long nHierarchy
= ScUnoHelpFunctions::GetLongProperty(
2250 xDimProp
, OUString(SC_UNO_DP_USEDHIERARCHY
));
2251 if ( nHierarchy
>= xHiers
->getCount() )
2253 rData
.mnUsedHier
= nHierarchy
;
2255 uno::Reference
<uno::XInterface
> xHier
=
2256 ScUnoHelpFunctions::AnyToInterface(xHiers
->getByIndex(nHierarchy
));
2258 uno::Reference
<sheet::XLevelsSupplier
> xHierSupp( xHier
, uno::UNO_QUERY
);
2259 if (!xHierSupp
.is())
2262 uno::Reference
<container::XIndexAccess
> xLevels
=
2263 new ScNameToIndexAccess( xHierSupp
->getLevels() );
2265 uno::Reference
<uno::XInterface
> xLevel
=
2266 ScUnoHelpFunctions::AnyToInterface( xLevels
->getByIndex(0) );
2267 uno::Reference
<beans::XPropertySet
> xLevProp( xLevel
, uno::UNO_QUERY
);
2271 rData
.mbShowAll
= ScUnoHelpFunctions::GetBoolProperty(
2272 xLevProp
, OUString(SC_UNO_DP_SHOWEMPTY
));
2276 xLevProp
->getPropertyValue( OUString( SC_UNO_DP_SORTING
) )
2277 >>= rData
.maSortInfo
;
2278 xLevProp
->getPropertyValue( OUString( SC_UNO_DP_LAYOUT
) )
2279 >>= rData
.maLayoutInfo
;
2280 xLevProp
->getPropertyValue( OUString( SC_UNO_DP_AUTOSHOW
) )
2281 >>= rData
.maShowInfo
;
2283 catch(uno::Exception
&)
2288 bool ScDPObject::FillLabelDataForDimension(
2289 const uno::Reference
<container::XIndexAccess
>& xDims
, sal_Int32 nDim
, ScDPLabelData
& rLabelData
)
2291 uno::Reference
<uno::XInterface
> xIntDim
=
2292 ScUnoHelpFunctions::AnyToInterface( xDims
->getByIndex(nDim
) );
2293 uno::Reference
<container::XNamed
> xDimName( xIntDim
, uno::UNO_QUERY
);
2294 uno::Reference
<beans::XPropertySet
> xDimProp( xIntDim
, uno::UNO_QUERY
);
2296 if (!xDimName
.is() || !xDimProp
.is())
2299 bool bData
= ScUnoHelpFunctions::GetBoolProperty(
2300 xDimProp
, OUString(SC_UNO_DP_ISDATALAYOUT
));
2301 //! error checking -- is "IsDataLayoutDimension" property required??
2303 sal_Int32 nOrigPos
= -1;
2304 OUString aFieldName
;
2307 aFieldName
= xDimName
->getName();
2308 uno::Any aOrigAny
= xDimProp
->getPropertyValue(
2309 OUString(SC_UNO_DP_ORIGINAL_POS
));
2310 aOrigAny
>>= nOrigPos
;
2312 catch(uno::Exception
&)
2316 OUString aLayoutName
= ScUnoHelpFunctions::GetStringProperty(
2317 xDimProp
, OUString(SC_UNO_DP_LAYOUTNAME
), OUString());
2319 OUString aSubtotalName
= ScUnoHelpFunctions::GetStringProperty(
2320 xDimProp
, OUString(SC_UNO_DP_FIELD_SUBTOTALNAME
), OUString());
2322 bool bIsValue
= true; //! check
2324 // Name from the UNO dimension object may have trailing '*'s in which
2325 // case it's a duplicate dimension. Convert that to a duplicate index.
2327 sal_uInt8 nDupCount
= ScDPUtil::getDuplicateIndex(aFieldName
);
2328 aFieldName
= ScDPUtil::getSourceDimensionName(aFieldName
);
2330 rLabelData
.maName
= aFieldName
;
2331 rLabelData
.mnCol
= static_cast<SCCOL
>(nDim
);
2332 rLabelData
.mnDupCount
= nDupCount
;
2333 rLabelData
.mbDataLayout
= bData
;
2334 rLabelData
.mbIsValue
= bIsValue
;
2338 rLabelData
.mnOriginalDim
= static_cast<long>(nOrigPos
);
2339 rLabelData
.maLayoutName
= aLayoutName
;
2340 rLabelData
.maSubtotalName
= aSubtotalName
;
2342 // This is a duplicated dimension. Use the original dimension index.
2344 GetHierarchies(nDim
, rLabelData
.maHiers
);
2345 GetMembers(nDim
, GetUsedHierarchy(nDim
), rLabelData
.maMembers
);
2346 lcl_FillLabelData(rLabelData
, xDimProp
);
2347 rLabelData
.mnFlags
= ScUnoHelpFunctions::GetLongProperty(
2348 xDimProp
, OUString(SC_UNO_DP_FLAGS
), 0);
2353 bool ScDPObject::FillLabelData(sal_Int32 nDim
, ScDPLabelData
& rLabels
)
2359 uno::Reference
<container::XNameAccess
> xDimsName
= xSource
->getDimensions();
2360 uno::Reference
<container::XIndexAccess
> xDims
= new ScNameToIndexAccess( xDimsName
);
2361 sal_Int32 nDimCount
= xDims
->getCount();
2362 if (nDimCount
<= 0 || nDim
>= nDimCount
)
2365 return FillLabelDataForDimension(xDims
, nDim
, rLabels
);
2368 bool ScDPObject::FillLabelData(ScPivotParam
& rParam
)
2370 rParam
.maLabelArray
.clear();
2376 uno::Reference
<container::XNameAccess
> xDimsName
= xSource
->getDimensions();
2377 uno::Reference
<container::XIndexAccess
> xDims
= new ScNameToIndexAccess( xDimsName
);
2378 sal_Int32 nDimCount
= xDims
->getCount();
2382 for (sal_Int32 nDim
= 0; nDim
< nDimCount
; ++nDim
)
2384 std::auto_ptr
<ScDPLabelData
> pNewLabel(new ScDPLabelData
);
2385 FillLabelDataForDimension(xDims
, nDim
, *pNewLabel
);
2386 rParam
.maLabelArray
.push_back(pNewLabel
);
2392 bool ScDPObject::GetHierarchiesNA( sal_Int32 nDim
, uno::Reference
< container::XNameAccess
>& xHiers
)
2395 uno::Reference
<container::XNameAccess
> xDimsName( GetSource()->getDimensions() );
2396 uno::Reference
<container::XIndexAccess
> xIntDims(new ScNameToIndexAccess( xDimsName
));
2399 uno::Reference
<sheet::XHierarchiesSupplier
> xHierSup(xIntDims
->getByIndex( nDim
), uno::UNO_QUERY
);
2402 xHiers
.set( xHierSup
->getHierarchies() );
2409 bool ScDPObject::GetHierarchies( sal_Int32 nDim
, uno::Sequence
< OUString
>& rHiers
)
2412 uno::Reference
< container::XNameAccess
> xHiersNA
;
2413 if( GetHierarchiesNA( nDim
, xHiersNA
) )
2415 rHiers
= xHiersNA
->getElementNames();
2421 sal_Int32
ScDPObject::GetUsedHierarchy( sal_Int32 nDim
)
2423 sal_Int32 nHier
= 0;
2424 uno::Reference
<container::XNameAccess
> xDimsName( GetSource()->getDimensions() );
2425 uno::Reference
<container::XIndexAccess
> xIntDims(new ScNameToIndexAccess( xDimsName
));
2426 uno::Reference
<beans::XPropertySet
> xDim(xIntDims
->getByIndex( nDim
), uno::UNO_QUERY
);
2428 nHier
= ScUnoHelpFunctions::GetLongProperty( xDim
, OUString( SC_UNO_DP_USEDHIERARCHY
) );
2432 bool ScDPObject::GetMembersNA( sal_Int32 nDim
, uno::Reference
< container::XNameAccess
>& xMembers
)
2434 return GetMembersNA( nDim
, GetUsedHierarchy( nDim
), xMembers
);
2437 bool ScDPObject::GetMembersNA( sal_Int32 nDim
, sal_Int32 nHier
, uno::Reference
< container::XNameAccess
>& xMembers
)
2440 uno::Reference
<container::XNameAccess
> xDimsName( GetSource()->getDimensions() );
2441 uno::Reference
<container::XIndexAccess
> xIntDims(new ScNameToIndexAccess( xDimsName
));
2442 uno::Reference
<beans::XPropertySet
> xDim(xIntDims
->getByIndex( nDim
), uno::UNO_QUERY
);
2445 uno::Reference
<sheet::XHierarchiesSupplier
> xHierSup(xDim
, uno::UNO_QUERY
);
2448 uno::Reference
<container::XIndexAccess
> xHiers(new ScNameToIndexAccess(xHierSup
->getHierarchies()));
2449 uno::Reference
<sheet::XLevelsSupplier
> xLevSupp( xHiers
->getByIndex(nHier
), uno::UNO_QUERY
);
2450 if ( xLevSupp
.is() )
2452 uno::Reference
<container::XIndexAccess
> xLevels(new ScNameToIndexAccess( xLevSupp
->getLevels()));
2455 sal_Int32 nLevCount
= xLevels
->getCount();
2458 uno::Reference
<sheet::XMembersSupplier
> xMembSupp( xLevels
->getByIndex(0), uno::UNO_QUERY
);
2459 if ( xMembSupp
.is() )
2461 xMembers
.set(xMembSupp
->getMembers());
2472 //------------------------------------------------------------------------
2473 // convert old pivot tables into new datapilot tables
2477 OUString
lcl_GetDimName( const uno::Reference
<sheet::XDimensionsSupplier
>& xSource
, long nDim
)
2482 uno::Reference
<container::XNameAccess
> xDimsName
= xSource
->getDimensions();
2483 uno::Reference
<container::XIndexAccess
> xDims
= new ScNameToIndexAccess( xDimsName
);
2484 long nDimCount
= xDims
->getCount();
2485 if ( nDim
< nDimCount
)
2487 uno::Reference
<uno::XInterface
> xIntDim
=
2488 ScUnoHelpFunctions::AnyToInterface( xDims
->getByIndex(nDim
) );
2489 uno::Reference
<container::XNamed
> xDimName( xIntDim
, uno::UNO_QUERY
);
2494 aName
= xDimName
->getName();
2496 catch(uno::Exception
&)
2505 bool hasFieldColumn(const vector
<ScPivotField
>* pRefFields
, SCCOL nCol
)
2510 vector
<ScPivotField
>::const_iterator itr
= pRefFields
->begin(), itrEnd
= pRefFields
->end();
2511 for (; itr
!= itrEnd
; ++itr
)
2513 if (itr
->nCol
== nCol
)
2514 // This array of fields contains the specified column.
2520 class FindByOriginalDim
: public std::unary_function
<ScPivotField
, bool>
2524 FindByOriginalDim(long nDim
) : mnDim(nDim
) {}
2525 bool operator() (const ScPivotField
& r
) const
2527 return mnDim
== r
.getOriginalDim();
2533 void ScDPObject::ConvertOrientation(
2534 ScDPSaveData
& rSaveData
, const ScPivotFieldVector
& rFields
, sal_uInt16 nOrient
,
2535 const Reference
<XDimensionsSupplier
>& xSource
,
2536 const ScDPLabelDataVector
& rLabels
,
2537 const ScPivotFieldVector
* pRefColFields
,
2538 const ScPivotFieldVector
* pRefRowFields
,
2539 const ScPivotFieldVector
* pRefPageFields
)
2541 ScPivotFieldVector::const_iterator itr
, itrBeg
= rFields
.begin(), itrEnd
= rFields
.end();
2542 for (itr
= itrBeg
; itr
!= itrEnd
; ++itr
)
2544 const ScPivotField
& rField
= *itr
;
2546 long nCol
= rField
.getOriginalDim();
2547 sal_uInt16 nFuncs
= rField
.nFuncMask
;
2548 const sheet::DataPilotFieldReference
& rFieldRef
= rField
.maFieldRef
;
2550 ScDPSaveDimension
* pDim
= NULL
;
2551 if ( nCol
== PIVOT_DATA_FIELD
)
2552 pDim
= rSaveData
.GetDataLayoutDimension();
2555 OUString aDocStr
= lcl_GetDimName( xSource
, nCol
); // cols must start at 0
2556 if (!aDocStr
.isEmpty())
2557 pDim
= rSaveData
.GetDimensionByName(aDocStr
);
2565 if ( nOrient
== sheet::DataPilotFieldOrientation_DATA
) // set summary function
2567 // generate an individual entry for each function
2570 // if a dimension is used for column/row/page and data,
2571 // use duplicated dimensions for all data occurrences
2572 if (hasFieldColumn(pRefColFields
, nCol
))
2575 if (bFirst
&& hasFieldColumn(pRefRowFields
, nCol
))
2578 if (bFirst
&& hasFieldColumn(pRefPageFields
, nCol
))
2583 // if set via api, a data column may occur several times
2584 // (if the function hasn't been changed yet) -> also look for duplicate data column
2585 bFirst
= std::find_if(itrBeg
, itr
, FindByOriginalDim(nCol
)) == itr
;
2588 sheet::GeneralFunction eFunc
= ScDataPilotConversion::FirstFunc(rField
.nFuncMask
);
2590 pDim
= rSaveData
.DuplicateDimension(pDim
->GetName());
2591 pDim
->SetOrientation(nOrient
);
2592 pDim
->SetFunction(sal::static_int_cast
<sal_uInt16
>(eFunc
));
2594 if( rFieldRef
.ReferenceType
== sheet::DataPilotFieldReferenceType::NONE
)
2595 pDim
->SetReferenceValue(0);
2597 pDim
->SetReferenceValue(&rFieldRef
);
2599 else // set SubTotals
2601 pDim
->SetOrientation( nOrient
);
2603 sal_uInt16 nFuncArray
[16];
2604 sal_uInt16 nFuncCount
= 0;
2605 sal_uInt16 nMask
= 1;
2606 for (sal_uInt16 nBit
=0; nBit
<16; nBit
++)
2608 if ( nFuncs
& nMask
)
2609 nFuncArray
[nFuncCount
++] = sal::static_int_cast
<sal_uInt16
>(ScDataPilotConversion::FirstFunc( nMask
));
2612 pDim
->SetSubTotals( nFuncCount
, nFuncArray
);
2614 // ShowEmpty was implicit in old tables,
2615 // must be set for data layout dimension (not accessible in dialog)
2616 if ( nCol
== PIVOT_DATA_FIELD
)
2617 pDim
->SetShowEmpty( true );
2620 size_t nDimIndex
= rField
.nCol
;
2621 pDim
->RemoveLayoutName();
2622 pDim
->RemoveSubtotalName();
2623 if (nDimIndex
< rLabels
.size())
2625 const ScDPLabelData
& rLabel
= rLabels
[nDimIndex
];
2626 if (!rLabel
.maLayoutName
.isEmpty())
2627 pDim
->SetLayoutName(rLabel
.maLayoutName
);
2628 if (!rLabel
.maSubtotalName
.isEmpty())
2629 pDim
->SetSubtotalName(rLabel
.maSubtotalName
);
2634 bool ScDPObject::IsOrientationAllowed( sal_uInt16 nOrient
, sal_Int32 nDimFlags
)
2636 bool bAllowed
= true;
2639 case sheet::DataPilotFieldOrientation_PAGE
:
2640 bAllowed
= ( nDimFlags
& sheet::DimensionFlags::NO_PAGE_ORIENTATION
) == 0;
2642 case sheet::DataPilotFieldOrientation_COLUMN
:
2643 bAllowed
= ( nDimFlags
& sheet::DimensionFlags::NO_COLUMN_ORIENTATION
) == 0;
2645 case sheet::DataPilotFieldOrientation_ROW
:
2646 bAllowed
= ( nDimFlags
& sheet::DimensionFlags::NO_ROW_ORIENTATION
) == 0;
2648 case sheet::DataPilotFieldOrientation_DATA
:
2649 bAllowed
= ( nDimFlags
& sheet::DimensionFlags::NO_DATA_ORIENTATION
) == 0;
2653 // allowed to remove from previous orientation
2659 // -----------------------------------------------------------------------
2661 bool ScDPObject::HasRegisteredSources()
2663 bool bFound
= false;
2665 uno::Reference
<lang::XMultiServiceFactory
> xManager
= comphelper::getProcessServiceFactory();
2666 uno::Reference
<container::XContentEnumerationAccess
> xEnAc( xManager
, uno::UNO_QUERY
);
2669 uno::Reference
<container::XEnumeration
> xEnum
= xEnAc
->createContentEnumeration(
2670 OUString( SCDPSOURCE_SERVICE
) );
2671 if ( xEnum
.is() && xEnum
->hasMoreElements() )
2678 uno::Sequence
<OUString
> ScDPObject::GetRegisteredSources()
2680 uno::Sequence
<OUString
> aSeq(0);
2682 // use implementation names...
2684 uno::Reference
<lang::XMultiServiceFactory
> xManager
= comphelper::getProcessServiceFactory();
2685 uno::Reference
<container::XContentEnumerationAccess
> xEnAc( xManager
, uno::UNO_QUERY
);
2688 uno::Reference
<container::XEnumeration
> xEnum
= xEnAc
->createContentEnumeration(
2689 OUString( SCDPSOURCE_SERVICE
) );
2693 while ( xEnum
->hasMoreElements() )
2695 uno::Any aAddInAny
= xEnum
->nextElement();
2696 // if ( aAddInAny.getReflection()->getTypeClass() == TypeClass_INTERFACE )
2698 uno::Reference
<uno::XInterface
> xIntFac
;
2699 aAddInAny
>>= xIntFac
;
2702 uno::Reference
<lang::XServiceInfo
> xInfo( xIntFac
, uno::UNO_QUERY
);
2705 OUString sName
= xInfo
->getImplementationName();
2707 aSeq
.realloc( nCount
+1 );
2708 aSeq
.getArray()[nCount
] = sName
;
2720 uno::Reference
<sheet::XDimensionsSupplier
> ScDPObject::CreateSource( const ScDPServiceDesc
& rDesc
)
2722 OUString aImplName
= rDesc
.aServiceName
;
2723 uno::Reference
<sheet::XDimensionsSupplier
> xRet
= NULL
;
2725 uno::Reference
<lang::XMultiServiceFactory
> xManager
= comphelper::getProcessServiceFactory();
2726 uno::Reference
<container::XContentEnumerationAccess
> xEnAc(xManager
, uno::UNO_QUERY
);
2730 uno::Reference
<container::XEnumeration
> xEnum
=
2731 xEnAc
->createContentEnumeration(OUString(SCDPSOURCE_SERVICE
));
2735 while (xEnum
->hasMoreElements() && !xRet
.is())
2737 uno::Any aAddInAny
= xEnum
->nextElement();
2738 uno::Reference
<uno::XInterface
> xIntFac
;
2739 aAddInAny
>>= xIntFac
;
2743 uno::Reference
<lang::XServiceInfo
> xInfo(xIntFac
, uno::UNO_QUERY
);
2744 if (!xInfo
.is() || xInfo
->getImplementationName() != aImplName
)
2749 // #i113160# try XSingleComponentFactory in addition to (old) XSingleServiceFactory,
2750 // passing the context to the component (see ScUnoAddInCollection::Initialize)
2752 uno::Reference
<uno::XInterface
> xInterface
;
2753 uno::Reference
<uno::XComponentContext
> xCtx(
2754 comphelper::getComponentContext(xManager
));
2755 uno::Reference
<lang::XSingleComponentFactory
> xCFac( xIntFac
, uno::UNO_QUERY
);
2757 xInterface
= xCFac
->createInstanceWithContext(xCtx
);
2759 if (!xInterface
.is())
2761 uno::Reference
<lang::XSingleServiceFactory
> xFac( xIntFac
, uno::UNO_QUERY
);
2763 xInterface
= xFac
->createInstance();
2766 uno::Reference
<lang::XInitialization
> xInit( xInterface
, uno::UNO_QUERY
);
2770 uno::Sequence
<uno::Any
> aSeq(4);
2771 uno::Any
* pArray
= aSeq
.getArray();
2772 pArray
[0] <<= OUString( rDesc
.aParSource
);
2773 pArray
[1] <<= OUString( rDesc
.aParName
);
2774 pArray
[2] <<= OUString( rDesc
.aParUser
);
2775 pArray
[3] <<= OUString( rDesc
.aParPass
);
2776 xInit
->initialize( aSeq
);
2778 xRet
= uno::Reference
<sheet::XDimensionsSupplier
>( xInterface
, uno::UNO_QUERY
);
2780 catch(uno::Exception
&)
2788 #if DEBUG_PIVOT_TABLE
2789 void ScDPObject::DumpCache() const
2794 const ScDPCache
* pCache
= mpTableData
->GetCacheTable().getCache();
2802 ScDPCollection::SheetCaches::SheetCaches(ScDocument
* pDoc
) : mpDoc(pDoc
) {}
2806 struct FindInvalidRange
: public std::unary_function
<ScRange
, bool>
2808 bool operator() (const ScRange
& r
) const
2810 return !r
.IsValid();
2814 void setGroupItemsToCache( ScDPCache
& rCache
, const std::set
<ScDPObject
*>& rRefs
)
2816 // Go through all referencing pivot tables, and re-fill the group dimension info.
2817 std::set
<ScDPObject
*>::const_iterator itRef
= rRefs
.begin(), itRefEnd
= rRefs
.end();
2818 for (; itRef
!= itRefEnd
; ++itRef
)
2820 const ScDPObject
* pObj
= *itRef
;
2821 const ScDPSaveData
* pSave
= pObj
->GetSaveData();
2825 const ScDPDimensionSaveData
* pGroupDims
= pSave
->GetExistingDimensionData();
2829 pGroupDims
->WriteToCache(rCache
);
2835 bool ScDPCollection::SheetCaches::hasCache(const ScRange
& rRange
) const
2837 RangeIndexType::const_iterator it
= std::find(maRanges
.begin(), maRanges
.end(), rRange
);
2838 if (it
== maRanges
.end())
2842 size_t nIndex
= std::distance(maRanges
.begin(), it
);
2843 CachesType::const_iterator itCache
= maCaches
.find(nIndex
);
2844 return itCache
!= maCaches
.end();
2847 const ScDPCache
* ScDPCollection::SheetCaches::getCache(const ScRange
& rRange
, const ScDPDimensionSaveData
* pDimData
)
2849 RangeIndexType::iterator it
= std::find(maRanges
.begin(), maRanges
.end(), rRange
);
2850 if (it
!= maRanges
.end())
2853 size_t nIndex
= std::distance(maRanges
.begin(), it
);
2854 CachesType::iterator itCache
= maCaches
.find(nIndex
);
2855 if (itCache
== maCaches
.end())
2857 OSL_FAIL("Cache pool and index pool out-of-sync !!!");
2861 return itCache
->second
;
2864 // Not cached. Create a new cache.
2865 SAL_WNODEPRECATED_DECLARATIONS_PUSH
2866 ::std::auto_ptr
<ScDPCache
> pCache(new ScDPCache(mpDoc
));
2867 SAL_WNODEPRECATED_DECLARATIONS_POP
2868 pCache
->InitFromDoc(mpDoc
, rRange
);
2870 pDimData
->WriteToCache(*pCache
);
2872 // Get the smallest available range index.
2873 it
= std::find_if(maRanges
.begin(), maRanges
.end(), FindInvalidRange());
2875 size_t nIndex
= maRanges
.size();
2876 if (it
== maRanges
.end())
2878 // All range indices are valid. Append a new index.
2879 maRanges
.push_back(rRange
);
2883 // Slot with invalid range. Re-use this slot.
2885 nIndex
= std::distance(maRanges
.begin(), it
);
2888 const ScDPCache
* p
= pCache
.get();
2889 maCaches
.insert(nIndex
, pCache
);
2893 ScDPCache
* ScDPCollection::SheetCaches::getExistingCache(const ScRange
& rRange
)
2895 RangeIndexType::iterator it
= std::find(maRanges
.begin(), maRanges
.end(), rRange
);
2896 if (it
== maRanges
.end())
2901 size_t nIndex
= std::distance(maRanges
.begin(), it
);
2902 CachesType::iterator itCache
= maCaches
.find(nIndex
);
2903 if (itCache
== maCaches
.end())
2905 OSL_FAIL("Cache pool and index pool out-of-sync !!!");
2909 return itCache
->second
;
2912 size_t ScDPCollection::SheetCaches::size() const
2914 return maCaches
.size();
2917 void ScDPCollection::SheetCaches::updateReference(
2918 UpdateRefMode eMode
, const ScRange
& r
, SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
)
2920 if (maRanges
.empty())
2924 RangeIndexType::iterator it
= maRanges
.begin(), itEnd
= maRanges
.end();
2925 for (; it
!= itEnd
; ++it
)
2927 const ScRange
& rKeyRange
= *it
;
2928 SCCOL nCol1
= rKeyRange
.aStart
.Col();
2929 SCROW nRow1
= rKeyRange
.aStart
.Row();
2930 SCTAB nTab1
= rKeyRange
.aStart
.Tab();
2931 SCCOL nCol2
= rKeyRange
.aEnd
.Col();
2932 SCROW nRow2
= rKeyRange
.aEnd
.Row();
2933 SCTAB nTab2
= rKeyRange
.aEnd
.Tab();
2935 ScRefUpdateRes eRes
= ScRefUpdate::Update(
2937 r
.aStart
.Col(), r
.aStart
.Row(), r
.aStart
.Tab(),
2938 r
.aEnd
.Col(), r
.aEnd
.Row(), r
.aEnd
.Tab(), nDx
, nDy
, nDz
,
2939 nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
2941 if (eRes
!= UR_NOTHING
)
2944 ScRange
aNew(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
2950 void ScDPCollection::SheetCaches::updateCache(const ScRange
& rRange
, std::set
<ScDPObject
*>& rRefs
)
2952 RangeIndexType::iterator it
= std::find(maRanges
.begin(), maRanges
.end(), rRange
);
2953 if (it
== maRanges
.end())
2955 // Not cached. Nothing to do.
2960 size_t nIndex
= std::distance(maRanges
.begin(), it
);
2961 CachesType::iterator itCache
= maCaches
.find(nIndex
);
2962 if (itCache
== maCaches
.end())
2964 OSL_FAIL("Cache pool and index pool out-of-sync !!!");
2969 ScDPCache
& rCache
= *itCache
->second
;
2971 // Update the cache with new cell values. This will clear all group dimension info.
2972 rCache
.InitFromDoc(mpDoc
, rRange
);
2974 std::set
<ScDPObject
*> aRefs(rCache
.GetAllReferences());
2977 // Make sure to re-populate the group dimension info.
2978 setGroupItemsToCache(rCache
, rRefs
);
2981 bool ScDPCollection::SheetCaches::remove(const ScDPCache
* p
)
2983 CachesType::iterator it
= maCaches
.begin(), itEnd
= maCaches
.end();
2984 for (; it
!= itEnd
; ++it
)
2986 if (it
->second
== p
)
2988 size_t idx
= it
->first
;
2990 maRanges
[idx
].SetInvalid();
2997 ScDPCollection::NameCaches::NameCaches(ScDocument
* pDoc
) : mpDoc(pDoc
) {}
2999 bool ScDPCollection::NameCaches::hasCache(const OUString
& rName
) const
3001 return maCaches
.count(rName
) != 0;
3004 const ScDPCache
* ScDPCollection::NameCaches::getCache(
3005 const OUString
& rName
, const ScRange
& rRange
, const ScDPDimensionSaveData
* pDimData
)
3007 CachesType::const_iterator itr
= maCaches
.find(rName
);
3008 if (itr
!= maCaches
.end())
3012 SAL_WNODEPRECATED_DECLARATIONS_PUSH
3013 ::std::auto_ptr
<ScDPCache
> pCache(new ScDPCache(mpDoc
));
3014 SAL_WNODEPRECATED_DECLARATIONS_POP
3015 pCache
->InitFromDoc(mpDoc
, rRange
);
3017 pDimData
->WriteToCache(*pCache
);
3019 const ScDPCache
* p
= pCache
.get();
3020 maCaches
.insert(rName
, pCache
);
3024 ScDPCache
* ScDPCollection::NameCaches::getExistingCache(const OUString
& rName
)
3026 CachesType::iterator itr
= maCaches
.find(rName
);
3027 return itr
!= maCaches
.end() ? itr
->second
: NULL
;
3030 size_t ScDPCollection::NameCaches::size() const
3032 return maCaches
.size();
3035 void ScDPCollection::NameCaches::updateCache(
3036 const OUString
& rName
, const ScRange
& rRange
, std::set
<ScDPObject
*>& rRefs
)
3038 CachesType::iterator itr
= maCaches
.find(rName
);
3039 if (itr
== maCaches
.end())
3045 ScDPCache
& rCache
= *itr
->second
;
3046 // Update the cache with new cell values. This will clear all group dimension info.
3047 rCache
.InitFromDoc(mpDoc
, rRange
);
3049 std::set
<ScDPObject
*> aRefs(rCache
.GetAllReferences());
3052 // Make sure to re-populate the group dimension info.
3053 setGroupItemsToCache(rCache
, rRefs
);
3056 bool ScDPCollection::NameCaches::remove(const ScDPCache
* p
)
3058 CachesType::iterator it
= maCaches
.begin(), itEnd
= maCaches
.end();
3059 for (; it
!= itEnd
; ++it
)
3061 if (it
->second
== p
)
3070 ScDPCollection::DBType::DBType(sal_Int32 nSdbType
, const OUString
& rDBName
, const OUString
& rCommand
) :
3071 mnSdbType(nSdbType
), maDBName(rDBName
), maCommand(rCommand
) {}
3073 bool ScDPCollection::DBType::less::operator() (const DBType
& left
, const DBType
& right
) const
3075 return left
< right
;
3078 ScDPCollection::DBCaches::DBCaches(ScDocument
* pDoc
) : mpDoc(pDoc
) {}
3080 bool ScDPCollection::DBCaches::hasCache(sal_Int32 nSdbType
, const OUString
& rDBName
, const OUString
& rCommand
) const
3082 DBType
aType(nSdbType
, rDBName
, rCommand
);
3083 CachesType::const_iterator itr
= maCaches
.find(aType
);
3084 return itr
!= maCaches
.end();
3087 const ScDPCache
* ScDPCollection::DBCaches::getCache(
3088 sal_Int32 nSdbType
, const OUString
& rDBName
, const OUString
& rCommand
,
3089 const ScDPDimensionSaveData
* pDimData
)
3091 DBType
aType(nSdbType
, rDBName
, rCommand
);
3092 CachesType::const_iterator itr
= maCaches
.find(aType
);
3093 if (itr
!= maCaches
.end())
3097 uno::Reference
<sdbc::XRowSet
> xRowSet
= createRowSet(nSdbType
, rDBName
, rCommand
);
3101 SAL_WNODEPRECATED_DECLARATIONS_PUSH
3102 ::std::auto_ptr
<ScDPCache
> pCache(new ScDPCache(mpDoc
));
3103 SAL_WNODEPRECATED_DECLARATIONS_POP
3104 SvNumberFormatter
aFormat( comphelper::getProcessComponentContext(), ScGlobal::eLnge
);
3105 DBConnector
aDB(*pCache
, xRowSet
, *aFormat
.GetNullDate());
3109 if (!pCache
->InitFromDataBase(aDB
))
3111 // initialization failed.
3112 comphelper::disposeComponent(xRowSet
);
3117 pDimData
->WriteToCache(*pCache
);
3119 ::comphelper::disposeComponent(xRowSet
);
3120 const ScDPCache
* p
= pCache
.get();
3121 maCaches
.insert(aType
, pCache
);
3125 ScDPCache
* ScDPCollection::DBCaches::getExistingCache(
3126 sal_Int32 nSdbType
, const OUString
& rDBName
, const OUString
& rCommand
)
3128 DBType
aType(nSdbType
, rDBName
, rCommand
);
3129 CachesType::iterator itr
= maCaches
.find(aType
);
3130 return itr
!= maCaches
.end() ? itr
->second
: NULL
;
3133 uno::Reference
<sdbc::XRowSet
> ScDPCollection::DBCaches::createRowSet(
3134 sal_Int32 nSdbType
, const OUString
& rDBName
, const OUString
& rCommand
)
3136 uno::Reference
<sdbc::XRowSet
> xRowSet
;
3139 xRowSet
= uno::Reference
<sdbc::XRowSet
>(
3140 comphelper::getProcessServiceFactory()->createInstance(
3141 OUString(SC_SERVICE_ROWSET
)),
3144 uno::Reference
<beans::XPropertySet
> xRowProp(xRowSet
, UNO_QUERY
);
3145 OSL_ENSURE( xRowProp
.is(), "can't get RowSet" );
3153 // set source parameters
3157 xRowProp
->setPropertyValue(
3158 OUString(SC_DBPROP_DATASOURCENAME
), aAny
);
3161 xRowProp
->setPropertyValue(
3162 OUString(SC_DBPROP_COMMAND
), aAny
);
3165 xRowProp
->setPropertyValue(
3166 OUString(SC_DBPROP_COMMANDTYPE
), aAny
);
3168 uno::Reference
<sdb::XCompletedExecution
> xExecute( xRowSet
, uno::UNO_QUERY
);
3169 if ( xExecute
.is() )
3171 uno::Reference
<task::XInteractionHandler
> xHandler(
3172 task::InteractionHandler::createWithParent(comphelper::getProcessComponentContext(), 0),
3173 uno::UNO_QUERY_THROW
);
3174 xExecute
->executeWithCompletion( xHandler
);
3181 catch ( const sdbc::SQLException
& rError
)
3183 //! store error message
3184 InfoBox
aInfoBox( 0, OUString(rError
.Message
) );
3187 catch ( uno::Exception
& )
3189 OSL_FAIL("Unexpected exception in database");
3196 void ScDPCollection::DBCaches::updateCache(
3197 sal_Int32 nSdbType
, const OUString
& rDBName
, const OUString
& rCommand
,
3198 std::set
<ScDPObject
*>& rRefs
)
3200 DBType
aType(nSdbType
, rDBName
, rCommand
);
3201 CachesType::iterator it
= maCaches
.find(aType
);
3202 if (it
== maCaches
.end())
3209 ScDPCache
& rCache
= *it
->second
;
3211 uno::Reference
<sdbc::XRowSet
> xRowSet
= createRowSet(nSdbType
, rDBName
, rCommand
);
3218 SvNumberFormatter
aFormat( comphelper::getProcessComponentContext(), ScGlobal::eLnge
);
3219 DBConnector
aDB(rCache
, xRowSet
, *aFormat
.GetNullDate());
3223 if (!rCache
.InitFromDataBase(aDB
))
3225 // initialization failed.
3227 comphelper::disposeComponent(xRowSet
);
3231 comphelper::disposeComponent(xRowSet
);
3232 std::set
<ScDPObject
*> aRefs(rCache
.GetAllReferences());
3235 // Make sure to re-populate the group dimension info.
3236 setGroupItemsToCache(rCache
, rRefs
);
3239 bool ScDPCollection::DBCaches::remove(const ScDPCache
* p
)
3241 CachesType::iterator it
= maCaches
.begin(), itEnd
= maCaches
.end();
3242 for (; it
!= itEnd
; ++it
)
3244 if (it
->second
== p
)
3253 ScDPCollection::ScDPCollection(ScDocument
* pDocument
) :
3255 maSheetCaches(pDocument
),
3256 maNameCaches(pDocument
),
3257 maDBCaches(pDocument
)
3261 ScDPCollection::ScDPCollection(const ScDPCollection
& r
) :
3263 maSheetCaches(r
.mpDoc
),
3264 maNameCaches(r
.mpDoc
),
3269 ScDPCollection::~ScDPCollection()
3277 * Unary predicate to match DP objects by the table ID.
3279 class MatchByTable
: public unary_function
<ScDPObject
, bool>
3283 MatchByTable(SCTAB nTab
) : mnTab(nTab
) {}
3285 bool operator() (const ScDPObject
& rObj
) const
3287 return rObj
.GetOutRange().aStart
.Tab() == mnTab
;
3293 sal_uLong
ScDPCollection::ReloadCache(ScDPObject
* pDPObj
, std::set
<ScDPObject
*>& rRefs
)
3296 return STR_ERR_DATAPILOTSOURCE
;
3298 if (pDPObj
->IsSheetData())
3300 // data source is internal sheet.
3301 const ScSheetSourceDesc
* pDesc
= pDPObj
->GetSheetDesc();
3303 return STR_ERR_DATAPILOTSOURCE
;
3305 sal_uLong nErrId
= pDesc
->CheckSourceRange();
3309 if (pDesc
->HasRangeName())
3311 // cache by named range
3312 ScDPCollection::NameCaches
& rCaches
= GetNameCaches();
3313 if (rCaches
.hasCache(pDesc
->GetRangeName()))
3314 rCaches
.updateCache(pDesc
->GetRangeName(), pDesc
->GetSourceRange(), rRefs
);
3317 // Not cached yet. Collect all tables that use this named
3318 // range as data source.
3319 GetAllTables(pDesc
->GetRangeName(), rRefs
);
3324 // cache by cell range
3325 ScDPCollection::SheetCaches
& rCaches
= GetSheetCaches();
3326 if (rCaches
.hasCache(pDesc
->GetSourceRange()))
3327 rCaches
.updateCache(pDesc
->GetSourceRange(), rRefs
);
3330 // Not cached yet. Collect all tables that use this range as
3332 GetAllTables(pDesc
->GetSourceRange(), rRefs
);
3336 else if (pDPObj
->IsImportData())
3338 // data source is external database.
3339 const ScImportSourceDesc
* pDesc
= pDPObj
->GetImportSourceDesc();
3341 return STR_ERR_DATAPILOTSOURCE
;
3343 ScDPCollection::DBCaches
& rCaches
= GetDBCaches();
3344 if (rCaches
.hasCache(pDesc
->GetCommandType(), pDesc
->aDBName
, pDesc
->aObject
))
3345 rCaches
.updateCache(
3346 pDesc
->GetCommandType(), pDesc
->aDBName
, pDesc
->aObject
, rRefs
);
3349 // Not cached yet. Collect all tables that use this range as
3351 GetAllTables(pDesc
->GetCommandType(), pDesc
->aDBName
, pDesc
->aObject
, rRefs
);
3357 bool ScDPCollection::ReloadGroupsInCache(ScDPObject
* pDPObj
, std::set
<ScDPObject
*>& rRefs
)
3362 const ScDPSaveData
* pSaveData
= pDPObj
->GetSaveData();
3366 // Note: Unlike reloading cache, when modifying the group dimensions the
3367 // cache may not have all its references when this method is called.
3368 // Therefore, we need to always call GetAllTables to get its correct
3369 // references even when the cache exists. This may become a non-issue
3370 // if/when we implement loading and saving of pivot caches.
3372 ScDPCache
* pCache
= NULL
;
3374 if (pDPObj
->IsSheetData())
3376 // data source is internal sheet.
3377 const ScSheetSourceDesc
* pDesc
= pDPObj
->GetSheetDesc();
3381 if (pDesc
->HasRangeName())
3383 // cache by named range
3384 ScDPCollection::NameCaches
& rCaches
= GetNameCaches();
3385 if (rCaches
.hasCache(pDesc
->GetRangeName()))
3386 pCache
= rCaches
.getExistingCache(pDesc
->GetRangeName());
3389 // Not cached yet. Cache the source dimensions. Groups will
3391 pCache
= const_cast<ScDPCache
*>(
3392 rCaches
.getCache(pDesc
->GetRangeName(), pDesc
->GetSourceRange(), NULL
));
3394 GetAllTables(pDesc
->GetRangeName(), rRefs
);
3398 // cache by cell range
3399 ScDPCollection::SheetCaches
& rCaches
= GetSheetCaches();
3400 if (rCaches
.hasCache(pDesc
->GetSourceRange()))
3401 pCache
= rCaches
.getExistingCache(pDesc
->GetSourceRange());
3404 // Not cached yet. Cache the source dimensions. Groups will
3406 pCache
= const_cast<ScDPCache
*>(
3407 rCaches
.getCache(pDesc
->GetSourceRange(), NULL
));
3409 GetAllTables(pDesc
->GetSourceRange(), rRefs
);
3412 else if (pDPObj
->IsImportData())
3414 // data source is external database.
3415 const ScImportSourceDesc
* pDesc
= pDPObj
->GetImportSourceDesc();
3419 ScDPCollection::DBCaches
& rCaches
= GetDBCaches();
3420 if (rCaches
.hasCache(pDesc
->GetCommandType(), pDesc
->aDBName
, pDesc
->aObject
))
3421 pCache
= rCaches
.getExistingCache(
3422 pDesc
->GetCommandType(), pDesc
->aDBName
, pDesc
->aObject
);
3425 // Not cached yet. Cache the source dimensions. Groups will
3427 pCache
= const_cast<ScDPCache
*>(
3428 rCaches
.getCache(pDesc
->GetCommandType(), pDesc
->aDBName
, pDesc
->aObject
, NULL
));
3430 GetAllTables(pDesc
->GetCommandType(), pDesc
->aDBName
, pDesc
->aObject
, rRefs
);
3436 // Clear the existing group data from the cache, and rebuild it from the
3438 pCache
->ClearGroupFields();
3439 const ScDPDimensionSaveData
* pDimData
= pSaveData
->GetExistingDimensionData();
3441 pDimData
->WriteToCache(*pCache
);
3445 void ScDPCollection::DeleteOnTab( SCTAB nTab
)
3447 maTables
.erase_if(MatchByTable(nTab
));
3450 void ScDPCollection::UpdateReference( UpdateRefMode eUpdateRefMode
,
3451 const ScRange
& r
, SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
)
3453 TablesType::iterator itr
= maTables
.begin(), itrEnd
= maTables
.end();
3454 for (; itr
!= itrEnd
; ++itr
)
3455 itr
->UpdateReference(eUpdateRefMode
, r
, nDx
, nDy
, nDz
);
3457 // Update the source ranges of the caches.
3458 maSheetCaches
.updateReference(eUpdateRefMode
, r
, nDx
, nDy
, nDz
);
3461 void ScDPCollection::CopyToTab( SCTAB nOld
, SCTAB nNew
)
3464 TablesType::const_iterator it
= maTables
.begin(), itEnd
= maTables
.end();
3465 for (; it
!= itEnd
; ++it
)
3467 const ScDPObject
& rObj
= *it
;
3468 ScRange aOutRange
= rObj
.GetOutRange();
3469 if (aOutRange
.aStart
.Tab() != nOld
)
3472 ScAddress
& s
= aOutRange
.aStart
;
3473 ScAddress
& e
= aOutRange
.aEnd
;
3476 std::auto_ptr
<ScDPObject
> pNew(new ScDPObject(rObj
));
3477 pNew
->SetOutRange(aOutRange
);
3478 mpDoc
->ApplyFlagsTab(s
.Col(), s
.Row(), e
.Col(), e
.Row(), s
.Tab(), SC_MF_DP_TABLE
);
3479 aAdded
.push_back(pNew
);
3482 maTables
.transfer(maTables
.end(), aAdded
.begin(), aAdded
.end(), aAdded
);
3485 bool ScDPCollection::RefsEqual( const ScDPCollection
& r
) const
3487 if (maTables
.size() != r
.maTables
.size())
3490 TablesType::const_iterator itr
= maTables
.begin(), itr2
= r
.maTables
.begin(), itrEnd
= maTables
.end();
3491 for (; itr
!= itrEnd
; ++itr
, ++itr2
)
3492 if (!itr
->RefsEqual(*itr2
))
3498 void ScDPCollection::WriteRefsTo( ScDPCollection
& r
) const
3500 if ( maTables
.size() == r
.maTables
.size() )
3502 //! assert equal names?
3503 TablesType::const_iterator itr
= maTables
.begin(), itrEnd
= maTables
.end();
3504 TablesType::iterator itr2
= r
.maTables
.begin();
3505 for (; itr
!= itrEnd
; ++itr
, ++itr2
)
3506 itr
->WriteRefsTo(*itr2
);
3510 // #i8180# If data pilot tables were deleted with their sheet,
3511 // this collection contains extra entries that must be restored.
3512 // Matching objects are found by their names.
3513 size_t nSrcSize
= maTables
.size();
3514 size_t nDestSize
= r
.maTables
.size();
3515 OSL_ENSURE( nSrcSize
>= nDestSize
, "WriteRefsTo: missing entries in document" );
3516 for (size_t nSrcPos
= 0; nSrcPos
< nSrcSize
; ++nSrcPos
)
3518 const ScDPObject
& rSrcObj
= maTables
[nSrcPos
];
3519 const OUString
& aName
= rSrcObj
.GetName();
3520 bool bFound
= false;
3521 for (size_t nDestPos
= 0; nDestPos
< nDestSize
&& !bFound
; ++nDestPos
)
3523 ScDPObject
& rDestObj
= r
.maTables
[nDestPos
];
3524 if (rDestObj
.GetName() == aName
)
3526 rSrcObj
.WriteRefsTo(rDestObj
); // found object, copy refs
3533 // none found, re-insert deleted object (see ScUndoDataPilot::Undo)
3535 ScDPObject
* pDestObj
= new ScDPObject(rSrcObj
);
3536 r
.InsertNewTable(pDestObj
);
3539 OSL_ENSURE( maTables
.size() == r
.maTables
.size(), "WriteRefsTo: couldn't restore all entries" );
3543 size_t ScDPCollection::GetCount() const
3545 return maTables
.size();
3548 ScDPObject
* ScDPCollection::operator [](size_t nIndex
)
3550 return &maTables
[nIndex
];
3553 const ScDPObject
* ScDPCollection::operator [](size_t nIndex
) const
3555 return &maTables
[nIndex
];
3558 const ScDPObject
* ScDPCollection::GetByName(const OUString
& rName
) const
3560 TablesType::const_iterator itr
= maTables
.begin(), itrEnd
= maTables
.end();
3561 for (; itr
!= itrEnd
; ++itr
)
3562 if (itr
->GetName() == rName
)
3568 OUString
ScDPCollection::CreateNewName( sal_uInt16 nMin
) const
3570 OUString
aBase("DataPilot");
3572 size_t n
= maTables
.size();
3573 for (size_t nAdd
= 0; nAdd
<= n
; ++nAdd
) // nCount+1 tries
3575 OUStringBuffer aBuf
;
3577 aBuf
.append(static_cast<sal_Int32
>(nMin
+ nAdd
));
3578 OUString aNewName
= aBuf
.makeStringAndClear();
3579 bool bFound
= false;
3580 TablesType::const_iterator itr
= maTables
.begin(), itrEnd
= maTables
.end();
3581 for (; itr
!= itrEnd
; ++itr
)
3583 if (itr
->GetName() == aNewName
)
3590 return aNewName
; // found unused Name
3592 return OUString(); // should not happen
3595 void ScDPCollection::FreeTable(ScDPObject
* pDPObj
)
3597 const ScRange
& rOutRange
= pDPObj
->GetOutRange();
3598 const ScAddress
& s
= rOutRange
.aStart
;
3599 const ScAddress
& e
= rOutRange
.aEnd
;
3600 mpDoc
->RemoveFlagsTab(s
.Col(), s
.Row(), e
.Col(), e
.Row(), s
.Tab(), SC_MF_DP_TABLE
);
3601 TablesType::iterator itr
= maTables
.begin(), itrEnd
= maTables
.end();
3602 for (; itr
!= itrEnd
; ++itr
)
3604 ScDPObject
* p
= &(*itr
);
3607 maTables
.erase(itr
);
3613 bool ScDPCollection::InsertNewTable(ScDPObject
* pDPObj
)
3615 const ScRange
& rOutRange
= pDPObj
->GetOutRange();
3616 const ScAddress
& s
= rOutRange
.aStart
;
3617 const ScAddress
& e
= rOutRange
.aEnd
;
3618 mpDoc
->ApplyFlagsTab(s
.Col(), s
.Row(), e
.Col(), e
.Row(), s
.Tab(), SC_MF_DP_TABLE
);
3620 maTables
.push_back(pDPObj
);
3624 ScDPCollection::SheetCaches
& ScDPCollection::GetSheetCaches()
3626 return maSheetCaches
;
3629 ScDPCollection::NameCaches
& ScDPCollection::GetNameCaches()
3631 return maNameCaches
;
3634 ScDPCollection::DBCaches
& ScDPCollection::GetDBCaches()
3639 ScRangeList
ScDPCollection::GetAllTableRanges( SCTAB nTab
) const
3641 return std::for_each(maTables
.begin(), maTables
.end(), AccumulateOutputRanges(nTab
)).getRanges();
3644 bool ScDPCollection::IntersectsTableByColumns( SCCOL nCol1
, SCCOL nCol2
, SCROW nRow
, SCTAB nTab
) const
3646 return std::find_if(
3647 maTables
.begin(), maTables
.end(), FindIntersetingTableByColumns(nCol1
, nCol2
, nRow
, nTab
)) != maTables
.end();
3650 bool ScDPCollection::IntersectsTableByRows( SCCOL nCol
, SCROW nRow1
, SCROW nRow2
, SCTAB nTab
) const
3652 return std::find_if(
3653 maTables
.begin(), maTables
.end(), FindIntersectingTableByRows(nCol
, nRow1
, nRow2
, nTab
)) != maTables
.end();
3656 bool ScDPCollection::HasTable( const ScRange
& rRange
) const
3658 return std::find_if(
3659 maTables
.begin(), maTables
.end(), FindIntersectingTable(rRange
)) != maTables
.end();
3662 #if DEBUG_PIVOT_TABLE
3666 struct DumpTable
: std::unary_function
<ScDPObject
, void>
3668 void operator() (const ScDPObject
& rObj
) const
3670 cout
<< "-- '" << rObj
.GetName() << "'" << endl
;
3671 ScDPSaveData
* pSaveData
= rObj
.GetSaveData();
3677 cout
<< endl
; // blank line
3683 void ScDPCollection::DumpTables() const
3685 std::for_each(maTables
.begin(), maTables
.end(), DumpTable());
3690 void ScDPCollection::RemoveCache(const ScDPCache
* pCache
)
3692 if (maSheetCaches
.remove(pCache
))
3693 // sheet cache removed.
3696 if (maNameCaches
.remove(pCache
))
3697 // named range cache removed.
3700 if (maDBCaches
.remove(pCache
))
3701 // database cache removed.
3705 void ScDPCollection::GetAllTables(const ScRange
& rSrcRange
, std::set
<ScDPObject
*>& rRefs
) const
3707 std::set
<ScDPObject
*> aRefs
;
3708 TablesType::const_iterator it
= maTables
.begin(), itEnd
= maTables
.end();
3709 for (; it
!= itEnd
; ++it
)
3711 const ScDPObject
& rObj
= *it
;
3712 if (!rObj
.IsSheetData())
3713 // Source is not a sheet range.
3716 const ScSheetSourceDesc
* pDesc
= rObj
.GetSheetDesc();
3720 if (pDesc
->HasRangeName())
3721 // This table has a range name as its source.
3724 if (pDesc
->GetSourceRange() != rSrcRange
)
3725 // Different source range.
3728 aRefs
.insert(const_cast<ScDPObject
*>(&rObj
));
3734 void ScDPCollection::GetAllTables(const OUString
& rSrcName
, std::set
<ScDPObject
*>& rRefs
) const
3736 std::set
<ScDPObject
*> aRefs
;
3737 TablesType::const_iterator it
= maTables
.begin(), itEnd
= maTables
.end();
3738 for (; it
!= itEnd
; ++it
)
3740 const ScDPObject
& rObj
= *it
;
3741 if (!rObj
.IsSheetData())
3742 // Source is not a sheet range.
3745 const ScSheetSourceDesc
* pDesc
= rObj
.GetSheetDesc();
3749 if (!pDesc
->HasRangeName())
3750 // This table probably has a sheet range as its source.
3753 if (pDesc
->GetRangeName() != rSrcName
)
3754 // Different source name.
3757 aRefs
.insert(const_cast<ScDPObject
*>(&rObj
));
3763 void ScDPCollection::GetAllTables(
3764 sal_Int32 nSdbType
, const OUString
& rDBName
, const OUString
& rCommand
,
3765 std::set
<ScDPObject
*>& rRefs
) const
3767 std::set
<ScDPObject
*> aRefs
;
3768 TablesType::const_iterator it
= maTables
.begin(), itEnd
= maTables
.end();
3769 for (; it
!= itEnd
; ++it
)
3771 const ScDPObject
& rObj
= *it
;
3772 if (!rObj
.IsImportData())
3773 // Source data is not a database.
3776 const ScImportSourceDesc
* pDesc
= rObj
.GetImportSourceDesc();
3780 if (!pDesc
->aDBName
.equals(rDBName
) || !pDesc
->aObject
.equals(rCommand
) || pDesc
->GetCommandType() != nSdbType
)
3781 // Different database source.
3784 aRefs
.insert(const_cast<ScDPObject
*>(&rObj
));
3790 bool operator<(const ScDPCollection::DBType
& left
, const ScDPCollection::DBType
& right
)
3792 if (left
.mnSdbType
!= right
.mnSdbType
)
3793 return left
.mnSdbType
< right
.mnSdbType
;
3795 if (!left
.maDBName
.equals(right
.maDBName
))
3796 return left
.maDBName
< right
.maDBName
;
3798 return left
.maCommand
< right
.maCommand
;
3801 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */