Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / core / data / dpobject.cxx
blobbde315618e1815722cdabcda499d49393505e77a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "dpobject.hxx"
21 #include "dptabsrc.hxx"
22 #include "dpsave.hxx"
23 #include "dpdimsave.hxx"
24 #include "dpoutput.hxx"
25 #include "dpshttab.hxx"
26 #include "dpsdbtab.hxx"
27 #include "dpgroup.hxx"
28 #include "document.hxx"
29 #include "rechead.hxx"
30 #include "pivot.hxx"
31 #include "dapiuno.hxx"
32 #include "miscuno.hxx"
33 #include "scerrors.hxx"
34 #include "refupdat.hxx"
35 #include "scresid.hxx"
36 #include "sc.hrc"
37 #include "attrib.hxx"
38 #include "scitems.hxx"
39 #include "unonames.hxx"
40 #include "dpglobal.hxx"
41 #include "globstr.hrc"
42 #include "queryentry.hxx"
43 #include "dputil.hxx"
45 #include <com/sun/star/beans/XPropertySet.hpp>
46 #include <com/sun/star/sdb/XCompletedExecution.hpp>
47 #include <com/sun/star/sdbc/DataType.hpp>
48 #include <com/sun/star/sdbc/XResultSetMetaData.hpp>
49 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
50 #include <com/sun/star/sdbc/XRow.hpp>
51 #include <com/sun/star/sdbc/XRowSet.hpp>
52 #include <com/sun/star/sheet/GeneralFunction.hpp>
53 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
54 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
55 #include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
56 #include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
57 #include <com/sun/star/sheet/DataPilotTablePositionData.hpp>
58 #include <com/sun/star/sheet/DataPilotTablePositionType.hpp>
59 #include <com/sun/star/sheet/DimensionFlags.hpp>
60 #include <com/sun/star/task/InteractionHandler.hpp>
61 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
62 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
63 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
64 #include <com/sun/star/lang/XInitialization.hpp>
65 #include <com/sun/star/container/XContentEnumerationAccess.hpp>
66 #include <com/sun/star/sheet/XDrillDownDataSupplier.hpp>
68 #include <comphelper/processfactory.hxx>
69 #include <comphelper/string.hxx>
70 #include <comphelper/types.hxx>
71 #include <sal/macros.h>
72 #include <tools/debug.hxx>
73 #include <tools/diagnose_ex.h>
74 #include <svl/zforlist.hxx>
75 #include <vcl/msgbox.hxx>
77 #include <vector>
78 #include <memory>
80 #include <boost/unordered_map.hpp>
82 using namespace com::sun::star;
83 using ::std::vector;
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"
107 namespace {
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
116 ScDPCache& mrCache;
118 uno::Reference<sdbc::XRowSet> mxRowSet;
119 uno::Reference<sdbc::XRow> mxRow;
120 uno::Reference<sdbc::XResultSetMetaData> mxMetaData;
121 Date maNullDate;
123 public:
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();
132 virtual bool next();
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);
140 if (xMetaSupp.is())
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);
183 double fValue = 0.0;
184 switch (nType)
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);
192 break;
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);
207 break;
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);
216 break;
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);
228 break;
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);
241 break;
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:
250 default:
251 rData.SetString(mrCache.InternString(mxRow->getString(nCol+1)));
254 catch (uno::Exception&)
256 rData.SetEmpty();
262 sal_uInt16 lcl_GetDataGetOrientation( const uno::Reference<sheet::XDimensionsSupplier>& xSource )
264 long nRet = sheet::DataPilotFieldOrientation_HIDDEN;
265 if ( xSource.is() )
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 );
276 if ( xDimProp.is() )
278 bFound = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
279 OUString(SC_UNO_DP_ISDATALAYOUT) );
280 //! error checking -- is "IsDataLayoutDimension" property required??
281 if (bFound)
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 ),
295 aParSource( rSrc ),
296 aParName( rNam ),
297 aParUser( rUser ),
298 aParPass( rPass ) {}
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 ) :
310 pDoc( pD ),
311 pSaveData( NULL ),
312 pSheetDesc( NULL ),
313 pImpDesc( NULL ),
314 pServDesc( NULL ),
315 mpTableData(static_cast<ScDPTableData*>(NULL)),
316 pOutput( NULL ),
317 mnAutoFormatIndex( 65535 ),
318 nHeaderRows( 0 ),
319 mbHeaderLayout(false),
320 bAllowMove(false),
321 bSettingsChanged(false),
322 mbEnableGetPivotData(true)
326 ScDPObject::ScDPObject(const ScDPObject& r) :
327 pDoc( r.pDoc ),
328 pSaveData( NULL ),
329 aTableName( r.aTableName ),
330 aTableTag( r.aTableTag ),
331 aOutRange( r.aOutRange ),
332 pSheetDesc( NULL ),
333 pImpDesc( NULL ),
334 pServDesc( NULL ),
335 mpTableData(static_cast<ScDPTableData*>(NULL)),
336 pOutput( NULL ),
337 mnAutoFormatIndex( r.mnAutoFormatIndex ),
338 nHeaderRows( r.nHeaderRows ),
339 mbHeaderLayout( r.mbHeaderLayout ),
340 bAllowMove(false),
341 bSettingsChanged(false),
342 mbEnableGetPivotData(r.mbEnableGetPivotData)
344 if (r.pSaveData)
345 pSaveData = new ScDPSaveData(*r.pSaveData);
346 if (r.pSheetDesc)
347 pSheetDesc = new ScSheetSourceDesc(*r.pSheetDesc);
348 if (r.pImpDesc)
349 pImpDesc = new ScImportSourceDesc(*r.pImpDesc);
350 if (r.pServDesc)
351 pServDesc = new ScDPServiceDesc(*r.pServDesc);
352 // xSource (and pOutput) is not copied
355 ScDPObject::~ScDPObject()
357 Clear();
360 ScDPObject& ScDPObject::operator= (const ScDPObject& r)
362 Clear();
364 pDoc = r.pDoc;
365 aTableName = r.aTableName;
366 aTableTag = r.aTableTag;
367 aOutRange = r.aOutRange;
368 mnAutoFormatIndex = r.mnAutoFormatIndex;
369 nHeaderRows = r.nHeaderRows;
370 mbHeaderLayout = r.mbHeaderLayout;
371 bAllowMove = false;
372 bSettingsChanged = false;
373 mbEnableGetPivotData = r.mbEnableGetPivotData;
375 if (r.pSaveData)
376 pSaveData = new ScDPSaveData(*r.pSaveData);
377 if (r.pSheetDesc)
378 pSheetDesc = new ScSheetSourceDesc(*r.pSheetDesc);
379 if (r.pImpDesc)
380 pImpDesc = new ScImportSourceDesc(*r.pImpDesc);
381 if (r.pServDesc)
382 pServDesc = new ScDPServiceDesc(*r.pServDesc);
384 return *this;
387 void ScDPObject::EnableGetPivotData(bool b)
389 mbEnableGetPivotData = b;
392 void ScDPObject::SetAllowMove(bool bSet)
394 bAllowMove = bSet;
397 void ScDPObject::SetSaveData(const ScDPSaveData& rData)
399 if ( pSaveData != &rData ) // API implementation modifies the original SaveData object
401 delete pSaveData;
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)
420 aOutRange = rRange;
422 if ( pOutput )
423 pOutput->SetPosition( rRange.aStart );
426 void ScDPObject::SetSheetDesc(const ScSheetSourceDesc& rDesc, bool /*bFromRefUpdate*/)
428 if ( pSheetDesc && rDesc == *pSheetDesc )
429 return; // nothing to do
431 DELETEZ( pImpDesc );
432 DELETEZ( pServDesc );
434 delete pSheetDesc;
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 );
459 delete pImpDesc;
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 );
471 DELETEZ( pImpDesc );
473 delete pServDesc;
474 pServDesc = new ScDPServiceDesc(rDesc);
476 ClearTableData(); // new source must be created
479 void ScDPObject::WriteSourceDataTo( ScDPObject& rDest ) const
481 if ( pSheetDesc )
482 rDest.SetSheetDesc( *pSheetDesc );
483 else if ( pImpDesc )
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)
506 aTableName = rNew;
509 void ScDPObject::SetTag(const OUString& rNew)
511 aTableTag = rNew;
514 bool ScDPObject::IsDataDescriptionCell(const ScAddress& rPos)
516 if (!pSaveData)
517 return false;
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.
523 return false;
525 CreateOutput();
526 ScRange aTabRange = pOutput->GetOutputRange(sheet::DataPilotOutputRangeType::TABLE);
527 return (rPos == aTabRange.aStart);
530 uno::Reference<sheet::XDimensionsSupplier> ScDPObject::GetSource()
532 CreateObjects();
533 return xSource;
536 void ScDPObject::CreateOutput()
538 CreateObjects();
539 if (!pOutput)
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;
551 if ( nOldRows == 0 )
552 --nDiff;
553 if ( nHeaderRows == 0 )
554 ++nDiff;
556 long nNewRow = aOutRange.aStart.Row() + nDiff;
557 if ( nNewRow < 0 )
558 nNewRow = 0;
560 ScAddress aStart( aOutRange.aStart );
561 aStart.SetRow(nNewRow);
562 pOutput->SetPosition( aStart );
564 //! modify aOutRange?
566 bAllowMove = false; // use only once
571 namespace {
573 class DisableGetPivotData
575 ScDPObject& mrDPObj;
576 bool mbOldState;
577 public:
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>
591 ScRange maRange;
592 public:
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>
603 SCCOL mnCol1;
604 SCCOL mnCol2;
605 SCROW mnRow;
606 SCTAB mnTab;
607 public:
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.
616 return false;
618 if (rRange.aEnd.Row() < mnRow)
619 // This table is above the row. It's safe.
620 return false;
622 if (mnCol1 <= rRange.aStart.Col() && rRange.aEnd.Col() <= mnCol2)
623 // This table is fully enclosed in this column range.
624 return false;
626 if (rRange.aEnd.Col() < mnCol1 || mnCol2 < rRange.aStart.Col())
627 // This table is entirely outside this column range.
628 return false;
630 // This table must be intersected by this column range.
631 return true;
635 class FindIntersectingTableByRows : std::unary_function<ScDPObject, bool>
637 SCCOL mnCol;
638 SCROW mnRow1;
639 SCROW mnRow2;
640 SCTAB mnTab;
641 public:
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.
650 return false;
652 if (rRange.aEnd.Col() < mnCol)
653 // This table is to the left of the column. It's safe.
654 return false;
656 if (mnRow1 <= rRange.aStart.Row() && rRange.aEnd.Row() <= mnRow2)
657 // This table is fully enclosed in this row range.
658 return false;
660 if (rRange.aEnd.Row() < mnRow1 || mnRow2 < rRange.aStart.Row())
661 // This table is entirely outside this row range.
662 return false;
664 // This table must be intersected by this row range.
665 return true;
669 class AccumulateOutputRanges : std::unary_function<ScDPObject, void>
671 ScRangeList maRanges;
672 SCTAB mnTab;
673 public:
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.
682 return;
684 maRanges.Join(rRange);
687 ScRangeList getRanges() const { return maRanges; }
692 ScDPTableData* ScDPObject::GetTableData()
694 if (!mpTableData)
696 shared_ptr<ScDPTableData> pData;
697 const ScDPDimensionSaveData* pDimData = pSaveData ? pSaveData->GetExistingDimensionData() : NULL;
699 if ( pImpDesc )
701 // database data
702 const ScDPCache* pCache = pImpDesc->CreateCache(pDimData);
703 if (pCache)
705 pCache->AddReference(this);
706 pData.reset(new ScDatabaseDPData(pDoc, *pCache));
709 else
711 // cell data
712 if (!pSheetDesc)
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
721 // range.
722 DisableGetPivotData aSwitch(*this, mbEnableGetPivotData);
723 const ScDPCache* pCache = pSheetDesc->CreateCache(pDimData);
724 if (pCache)
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);
737 pData = pGroupData;
740 mpTableData = pData; // after SetCacheId
743 return mpTableData.get();
746 void ScDPObject::CreateObjects()
748 if (!xSource.is())
750 DELETEZ( pOutput ); // not valid when xSource is changed
752 if ( pServDesc )
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();
761 if (pData)
763 if (pSaveData)
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 );
770 xSource = pSource;
774 if (pSaveData)
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 );
782 if (xRef.is())
786 xRef->refresh();
788 catch(uno::Exception&)
790 OSL_FAIL("exception in refresh");
794 if (pSaveData)
795 pSaveData->WriteToSource( xSource );
797 bSettingsChanged = false;
800 void ScDPObject::InvalidateData()
802 bSettingsChanged = true;
805 void ScDPObject::Clear()
807 delete pOutput;
808 delete pSaveData;
809 delete pSheetDesc;
810 delete pImpDesc;
811 delete pServDesc;
812 pOutput = NULL;
813 pSaveData = NULL;
814 pSheetDesc = NULL;
815 pImpDesc = NULL;
816 pServDesc = NULL;
817 ClearTableData();
820 void ScDPObject::ClearTableData()
822 ClearSource();
824 if (mpTableData)
825 mpTableData->GetCacheTable().getCache()->RemoveReference(this);
826 mpTableData.reset();
829 void ScDPObject::ReloadGroupTableData()
831 ClearSource();
833 if (!mpTableData)
834 // Table data not built yet. No need to reload the group data.
835 return;
837 if (!pSaveData)
838 // How could it not have the save data... but whatever.
839 return;
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());
847 if (pData)
849 // Replace the existing group table data with the source data.
850 shared_ptr<ScDPTableData> pSource = pData->GetSourceTableData();
851 mpTableData = pSource;
853 return;
856 ScDPGroupTableData* pData = dynamic_cast<ScDPGroupTableData*>(mpTableData.get());
857 if (pData)
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;
866 else
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();
891 xSource = NULL;
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
899 if ( rOverflow )
900 return ScRange( aOutRange.aStart );
901 else
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 );
922 pOutput->Output();
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 )
933 CreateOutput();
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();
957 SCROW nInitial = 0;
958 SCROW nOutRows = aOutRange.aEnd.Row() + 1 - aOutRange.aStart.Row();
959 while ( nInitial + 1 < nOutRows && lcl_HasButton( pDoc, nFirstCol, nFirstRow + nInitial, nTab ) )
960 ++nInitial;
962 if ( nInitial + 1 < nOutRows &&
963 pDoc->IsBlockEmpty( nTab, nFirstCol, nFirstRow + nInitial, nFirstCol, nFirstRow + nInitial ) &&
964 aOutRange.aEnd.Col() > nFirstCol )
966 nHeaderRows = nInitial;
968 else
969 nHeaderRows = 0; // nothing found, no drop-down lists
972 void ScDPObject::BuildAllDimensionMembers()
974 if (!pSaveData)
975 return;
977 // #i111857# don't always create empty mpTableData for external service.
978 if (pServDesc)
979 return;
981 pSaveData->BuildAllDimensionMembers(GetTableData());
984 bool ScDPObject::SyncAllDimensionMembers()
986 if (!pSaveData)
987 return false;
989 // #i111857# don't always create empty mpTableData for external service.
990 // Ideally, xSource should be used instead of mpTableData.
991 if (pServDesc)
992 return false;
994 ScDPTableData* pData = GetTableData();
995 if (!pData)
996 // No table data exists. This can happen when refreshing from an
997 // external source which doesn't exist.
998 return false;
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);
1004 return true;
1007 bool ScDPObject::GetMemberNames( sal_Int32 nDim, Sequence<OUString>& rNames )
1009 vector<ScDPLabelData::Member> aMembers;
1010 if (!GetMembers(nDim, GetUsedHierarchy(nDim), aMembers))
1011 return false;
1013 size_t n = aMembers.size();
1014 rNames.realloc(n);
1015 for (size_t i = 0; i < n; ++i)
1016 rNames[i] = aMembers[i].maName;
1018 return true;
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 ))
1025 return false;
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;
1037 if (xMember.is())
1038 aMem.maName = xMember->getName();
1040 Reference<beans::XPropertySet> xMemProp(xMember, UNO_QUERY);
1041 if (xMemProp.is())
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);
1053 return true;
1056 void ScDPObject::UpdateReference( UpdateRefMode eUpdateRefMode,
1057 const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
1059 // Output area
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
1078 if ( pSheetDesc )
1080 const OUString& rRangeName = pSheetDesc->GetRangeName();
1081 if (!rRangeName.isEmpty())
1082 // Source range is a named range. No need to update.
1083 return;
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 )
1121 return false;
1123 if ( pSheetDesc && r.pSheetDesc )
1125 if ( pSheetDesc->GetSourceRange() != r.pSheetDesc->GetSourceRange() )
1126 return false;
1128 else if ( pSheetDesc || r.pSheetDesc )
1130 OSL_FAIL("RefsEqual: SheetDesc set at only one object");
1131 return false;
1134 return true;
1137 void ScDPObject::WriteRefsTo( ScDPObject& r ) const
1139 r.SetOutRange( aOutRange );
1140 if ( pSheetDesc )
1141 r.SetSheetDesc( *pSheetDesc, true );
1144 void ScDPObject::GetPositionData(const ScAddress& rPos, DataPilotTablePositionData& rPosData)
1146 CreateOutput();
1147 pOutput->GetPositionData(rPos, rPosData);
1150 bool ScDPObject::GetDataFieldPositionData(
1151 const ScAddress& rPos, Sequence<sheet::DataPilotFieldFilter>& rFilters)
1153 CreateOutput();
1155 vector<sheet::DataPilotFieldFilter> aFilters;
1156 if (!pOutput->GetDataResultPositionData(aFilters, rPos))
1157 return false;
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];
1164 return true;
1167 void ScDPObject::GetDrillDownData(const ScAddress& rPos, Sequence< Sequence<Any> >& rTableData)
1169 CreateOutput();
1171 Reference<sheet::XDrillDownDataSupplier> xDrillDownData(xSource, UNO_QUERY);
1172 if (!xDrillDownData.is())
1173 return;
1175 Sequence<sheet::DataPilotFieldFilter> filters;
1176 if (!GetDataFieldPositionData(rPos, filters))
1177 return;
1179 rTableData = xDrillDownData->getDrillDownData(filters);
1182 bool ScDPObject::IsDimNameInUse(const OUString& rName) const
1184 if (!xSource.is())
1185 return false;
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))
1194 return true;
1196 Reference<beans::XPropertySet> xPropSet(xDims->getByName(rDimName), UNO_QUERY);
1197 if (!xPropSet.is())
1198 continue;
1200 OUString aLayoutName = ScUnoHelpFunctions::GetStringProperty(
1201 xPropSet, OUString(SC_UNO_DP_LAYOUTNAME), OUString());
1202 if (aLayoutName.equalsIgnoreAsciiCase(rName))
1203 return true;
1205 return false;
1208 OUString ScDPObject::GetDimName( long nDim, bool& rIsDataLayout, sal_Int32* pFlags )
1210 rIsDataLayout = false;
1211 OUString aRet;
1213 if ( xSource.is() )
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??
1230 OUString aName;
1233 aName = xDimName->getName();
1235 catch(uno::Exception&)
1238 if ( bData )
1239 rIsDataLayout = true;
1240 else
1241 aRet = aName;
1243 if (pFlags)
1244 *pFlags = ScUnoHelpFunctions::GetLongProperty( xDimProp,
1245 OUString(SC_UNO_DP_FLAGS), 0 );
1250 return aRet;
1253 bool ScDPObject::IsDuplicated( long nDim )
1255 bool bDuplicated = false;
1256 if ( xSource.is() )
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() )
1274 bDuplicated = true;
1276 catch(uno::Exception&)
1282 return bDuplicated;
1285 long ScDPObject::GetDimCount()
1287 long nRet = 0;
1288 if ( xSource.is() )
1292 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1293 if ( xDimsName.is() )
1294 nRet = xDimsName->getElementNames().getLength();
1296 catch(uno::Exception&)
1300 return nRet;
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;
1311 rData.Flags = 0;
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;
1320 namespace {
1322 class FindByName : std::unary_function<const ScDPSaveDimension*, bool>
1324 OUString maName; // must be all uppercase.
1325 public:
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)
1332 return true;
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))
1339 return true;
1341 return maName == ScGlobal::pCharClass->uppercase(aSrcName);
1345 class LessByDimOrder : std::binary_function<sheet::DataPilotFieldFilter, sheet::DataPilotFieldFilter, bool>
1347 const ScDPSaveData::DimOrderType& mrDimOrder;
1349 public:
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)
1372 double fRet;
1373 rtl::math::setNan(&fRet);
1374 if (!mbEnableGetPivotData)
1375 return fRet;
1377 CreateObjects();
1379 std::vector<const ScDPSaveDimension*> aDataDims;
1380 pSaveData->GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_DATA, aDataDims);
1381 if (aDataDims.empty())
1382 return fRet;
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())
1389 return fRet;
1391 size_t nDataIndex = std::distance(aDataDims.begin(), it);
1393 uno::Reference<sheet::XDataPilotResults> xDPResults(xSource, uno::UNO_QUERY);
1394 if (!xDPResults.is())
1395 return fRet;
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())
1408 return fRet;
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
1442 namespace {
1444 bool dequote( const OUString& rSource, sal_Int32 nStartPos, sal_Int32& rEndPos, OUString& rResult )
1446 // nStartPos has to point to opening quote
1448 bool bRet = false;
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
1468 else
1470 // end of quoted string
1471 rResult = aBuffer.makeStringAndClear();
1472 rEndPos = nPos + 1; // behind closing quote
1473 return true;
1476 else
1477 aBuffer.append( cNext );
1479 ++nPos;
1481 // no closing quote before the end of the string -> error (bRet still false)
1484 return bRet;
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[] =
1497 // our names
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] == ' ')
1517 ++nStartPos;
1519 bool bParsed = false;
1520 bool bFound = false;
1521 OUString aFuncStr;
1522 sal_Int32 nFuncEnd = 0;
1523 if (nStartPos < nListLen && rList[nStartPos] == '\'')
1524 bParsed = dequote( rList, nStartPos, nFuncEnd, aFuncStr );
1525 else
1527 nFuncEnd = rList.indexOf(']', nStartPos);
1528 if (nFuncEnd >= 0)
1530 aFuncStr = rList.copy(nStartPos, nFuncEnd - nStartPos);
1531 bParsed = true;
1535 if ( bParsed )
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;
1545 bFound = true;
1547 while (nFuncEnd < nListLen && rList[nFuncEnd] == ' ')
1548 ++nFuncEnd;
1549 rEndPos = nFuncEnd;
1554 return bFound;
1557 bool isAtStart(
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
1568 OUString aDequoted;
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] == ' ')
1581 ++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] == ' ')
1590 ++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
1602 bParsed = true;
1606 else
1608 // implicit quoting to the closing bracket
1610 sal_Int32 nClosePos = rList.indexOf(']', nStartPos);
1611 if (nClosePos >= 0)
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;
1626 bParsed = true;
1631 if ( bParsed && ScGlobal::GetpTransliteration()->isEqual( aDequoted, rSearch ) )
1633 nMatchList = nQuoteEnd; // match count in the list string, including quotes
1634 nMatchSearch = rSearch.getLength();
1637 else
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() )
1650 bValid = true;
1651 else
1653 sal_Unicode cNext = rList[nMatchList];
1654 if ( cNext == ' ' || ( bAllowBracket && cNext == '[' ) )
1655 bValid = true;
1658 if ( bValid )
1660 rMatched = nMatchList;
1661 return true;
1665 return false;
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 );
1702 if ( !bDataLayout )
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() )
1720 nHierarchy = 0;
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)
1764 bool bUsed = false;
1766 // look for data field name
1768 for ( SCSIZE nDataPos=0; nDataPos<nDataFields && !bUsed; nDataPos++ )
1770 OUString aFound;
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);
1781 bHasData = true;
1782 bUsed = true;
1786 // look for field name
1788 OUString aSpecField;
1789 bool bHasFieldName = false;
1790 if ( !bUsed )
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
1807 else
1809 bUsed = true;
1810 bError = true;
1816 // look for field item
1818 if ( !bUsed )
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 ) )
1840 if ( bItemFound )
1841 bError = true; // duplicate (also across fields)
1842 else
1844 aFoundName = aFieldNames[nField];
1845 aFoundValue = pItemArr[nItem];
1846 eFoundFunc = eFunc;
1847 bItemFound = true;
1848 bUsed = true;
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);
1866 if ( !bUsed )
1867 bError = true;
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];
1877 bHasData = true;
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) );
1906 if (bDataLayout)
1908 // the elements of the data layout dimension can't be found by their names
1909 // -> don't change anything
1910 return;
1913 // query old state
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;
1930 long nLevCount = 0;
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?
1965 bFound = sal_True;
1970 OSL_ENSURE( bFound, "member not found" );
1971 (void)bFound;
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?" );
1978 if ( pModifyData )
1980 const OUString aName = rElemDesc.MemberName;
1981 pModifyData->GetDimensionByName(aDimName)->
1982 GetMemberByName(aName)->SetShowDetails( !bShowDetails ); // toggle
1984 if ( pDestObj )
1985 pDestObj->InvalidateData(); // re-init source from SaveData
1986 else
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() )
2000 nHierarchy = 0;
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() )
2013 uno::Any aSubAny;
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]);
2030 return nMask;
2036 OSL_FAIL("FirstSubTotal: NULL");
2037 return 0;
2040 namespace {
2042 class FindByColumn : public std::unary_function<ScPivotField, bool>
2044 SCsCOL mnCol;
2045 sal_uInt16 mnMask;
2046 public:
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
2067 vector<long> aPos;
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.
2090 // function mask.
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);
2104 else
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));
2117 sal_Int32 nTmp = 0;
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.
2131 if ( bDataLayout )
2132 nCompCol = PIVOT_DATA_FIELD;
2133 else
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();
2143 if (bDataLayout)
2145 rField.nCol = PIVOT_DATA_FIELD;
2146 bDataFound = true;
2148 else
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();
2175 if (nOutCount >= 1)
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
2200 if (!xSource.is())
2201 return false;
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 );
2209 lcl_FillOldFields(
2210 rParam.maPageFields, xSource, sheet::DataPilotFieldOrientation_PAGE, false);
2211 lcl_FillOldFields(
2212 rParam.maColFields, xSource, sheet::DataPilotFieldOrientation_COLUMN, bAddData);
2213 lcl_FillOldFields(
2214 rParam.maRowFields, xSource, sheet::DataPilotFieldOrientation_ROW, false);
2215 lcl_FillOldFields(
2216 rParam.maDataFields, xSource, sheet::DataPilotFieldOrientation_DATA, false);
2218 uno::Reference<beans::XPropertySet> xProp( xSource, uno::UNO_QUERY );
2219 if (xProp.is())
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&)
2236 // no error
2239 return true;
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())
2246 return;
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() )
2252 nHierarchy = 0;
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())
2260 return;
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 );
2268 if (!xLevProp.is())
2269 return;
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())
2297 return false;
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;
2336 if (!bData)
2338 rLabelData.mnOriginalDim = static_cast<long>(nOrigPos);
2339 rLabelData.maLayoutName = aLayoutName;
2340 rLabelData.maSubtotalName = aSubtotalName;
2341 if (nOrigPos >= 0)
2342 // This is a duplicated dimension. Use the original dimension index.
2343 nDim = nOrigPos;
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);
2350 return true;
2353 bool ScDPObject::FillLabelData(sal_Int32 nDim, ScDPLabelData& rLabels)
2355 CreateObjects();
2356 if (!xSource.is())
2357 return false;
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)
2363 return false;
2365 return FillLabelDataForDimension(xDims, nDim, rLabels);
2368 bool ScDPObject::FillLabelData(ScPivotParam& rParam)
2370 rParam.maLabelArray.clear();
2372 CreateObjects();
2373 if (!xSource.is())
2374 return false;
2376 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
2377 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
2378 sal_Int32 nDimCount = xDims->getCount();
2379 if (nDimCount <= 0)
2380 return false;
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);
2389 return true;
2392 bool ScDPObject::GetHierarchiesNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xHiers )
2394 bool bRet = false;
2395 uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
2396 uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
2397 if( xIntDims.is() )
2399 uno::Reference<sheet::XHierarchiesSupplier> xHierSup(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
2400 if (xHierSup.is())
2402 xHiers.set( xHierSup->getHierarchies() );
2403 bRet = xHiers.is();
2406 return bRet;
2409 bool ScDPObject::GetHierarchies( sal_Int32 nDim, uno::Sequence< OUString >& rHiers )
2411 bool bRet = false;
2412 uno::Reference< container::XNameAccess > xHiersNA;
2413 if( GetHierarchiesNA( nDim, xHiersNA ) )
2415 rHiers = xHiersNA->getElementNames();
2416 bRet = true;
2418 return bRet;
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);
2427 if (xDim.is())
2428 nHier = ScUnoHelpFunctions::GetLongProperty( xDim, OUString( SC_UNO_DP_USEDHIERARCHY ) );
2429 return nHier;
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 )
2439 bool bRet = false;
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);
2443 if (xDim.is())
2445 uno::Reference<sheet::XHierarchiesSupplier> xHierSup(xDim, uno::UNO_QUERY);
2446 if (xHierSup.is())
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()));
2453 if (xLevels.is())
2455 sal_Int32 nLevCount = xLevels->getCount();
2456 if (nLevCount > 0)
2458 uno::Reference<sheet::XMembersSupplier> xMembSupp( xLevels->getByIndex(0), uno::UNO_QUERY );
2459 if ( xMembSupp.is() )
2461 xMembers.set(xMembSupp->getMembers());
2462 bRet = true;
2469 return bRet;
2472 //------------------------------------------------------------------------
2473 // convert old pivot tables into new datapilot tables
2475 namespace {
2477 OUString lcl_GetDimName( const uno::Reference<sheet::XDimensionsSupplier>& xSource, long nDim )
2479 OUString aName;
2480 if ( xSource.is() )
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 );
2490 if (xDimName.is())
2494 aName = xDimName->getName();
2496 catch(uno::Exception&)
2502 return aName;
2505 bool hasFieldColumn(const vector<ScPivotField>* pRefFields, SCCOL nCol)
2507 if (!pRefFields)
2508 return false;
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.
2515 return true;
2517 return false;
2520 class FindByOriginalDim : public std::unary_function<ScPivotField, bool>
2522 long mnDim;
2523 public:
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();
2553 else
2555 OUString aDocStr = lcl_GetDimName( xSource, nCol ); // cols must start at 0
2556 if (!aDocStr.isEmpty())
2557 pDim = rSaveData.GetDimensionByName(aDocStr);
2558 else
2559 pDim = NULL;
2562 if (!pDim)
2563 continue;
2565 if ( nOrient == sheet::DataPilotFieldOrientation_DATA ) // set summary function
2567 // generate an individual entry for each function
2568 bool bFirst = true;
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))
2573 bFirst = false;
2575 if (bFirst && hasFieldColumn(pRefRowFields, nCol))
2576 bFirst = false;
2578 if (bFirst && hasFieldColumn(pRefPageFields, nCol))
2579 bFirst = false;
2581 if (bFirst)
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);
2589 if (!bFirst)
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);
2596 else
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 ));
2610 nMask *= 2;
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;
2637 switch (nOrient)
2639 case sheet::DataPilotFieldOrientation_PAGE:
2640 bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_PAGE_ORIENTATION ) == 0;
2641 break;
2642 case sheet::DataPilotFieldOrientation_COLUMN:
2643 bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_COLUMN_ORIENTATION ) == 0;
2644 break;
2645 case sheet::DataPilotFieldOrientation_ROW:
2646 bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_ROW_ORIENTATION ) == 0;
2647 break;
2648 case sheet::DataPilotFieldOrientation_DATA:
2649 bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_DATA_ORIENTATION ) == 0;
2650 break;
2651 default:
2653 // allowed to remove from previous orientation
2656 return bAllowed;
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 );
2667 if ( xEnAc.is() )
2669 uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
2670 OUString( SCDPSOURCE_SERVICE ) );
2671 if ( xEnum.is() && xEnum->hasMoreElements() )
2672 bFound = true;
2675 return bFound;
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 );
2686 if ( xEnAc.is() )
2688 uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
2689 OUString( SCDPSOURCE_SERVICE ) );
2690 if ( xEnum.is() )
2692 long nCount = 0;
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;
2700 if ( xIntFac.is() )
2702 uno::Reference<lang::XServiceInfo> xInfo( xIntFac, uno::UNO_QUERY );
2703 if ( xInfo.is() )
2705 OUString sName = xInfo->getImplementationName();
2707 aSeq.realloc( nCount+1 );
2708 aSeq.getArray()[nCount] = sName;
2709 ++nCount;
2717 return aSeq;
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);
2727 if (!xEnAc.is())
2728 return xRet;
2730 uno::Reference<container::XEnumeration> xEnum =
2731 xEnAc->createContentEnumeration(OUString(SCDPSOURCE_SERVICE));
2732 if (!xEnum.is())
2733 return xRet;
2735 while (xEnum->hasMoreElements() && !xRet.is())
2737 uno::Any aAddInAny = xEnum->nextElement();
2738 uno::Reference<uno::XInterface> xIntFac;
2739 aAddInAny >>= xIntFac;
2740 if (!xIntFac.is())
2741 continue;
2743 uno::Reference<lang::XServiceInfo> xInfo(xIntFac, uno::UNO_QUERY);
2744 if (!xInfo.is() || xInfo->getImplementationName() != aImplName)
2745 continue;
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 );
2756 if (xCFac.is())
2757 xInterface = xCFac->createInstanceWithContext(xCtx);
2759 if (!xInterface.is())
2761 uno::Reference<lang::XSingleServiceFactory> xFac( xIntFac, uno::UNO_QUERY );
2762 if ( xFac.is() )
2763 xInterface = xFac->createInstance();
2766 uno::Reference<lang::XInitialization> xInit( xInterface, uno::UNO_QUERY );
2767 if (xInit.is())
2769 // initialize
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&)
2785 return xRet;
2788 #if DEBUG_PIVOT_TABLE
2789 void ScDPObject::DumpCache() const
2791 if (!mpTableData)
2792 return;
2794 const ScDPCache* pCache = mpTableData->GetCacheTable().getCache();
2795 if (!pCache)
2796 return;
2798 pCache->Dump();
2800 #endif
2802 ScDPCollection::SheetCaches::SheetCaches(ScDocument* pDoc) : mpDoc(pDoc) {}
2804 namespace {
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();
2822 if (!pSave)
2823 continue;
2825 const ScDPDimensionSaveData* pGroupDims = pSave->GetExistingDimensionData();
2826 if (!pGroupDims)
2827 continue;
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())
2839 return false;
2841 // Already cached.
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())
2852 // Already cached.
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 !!!");
2858 return NULL;
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);
2869 if (pDimData)
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);
2881 else
2883 // Slot with invalid range. Re-use this slot.
2884 *it = rRange;
2885 nIndex = std::distance(maRanges.begin(), it);
2888 const ScDPCache* p = pCache.get();
2889 maCaches.insert(nIndex, pCache);
2890 return p;
2893 ScDPCache* ScDPCollection::SheetCaches::getExistingCache(const ScRange& rRange)
2895 RangeIndexType::iterator it = std::find(maRanges.begin(), maRanges.end(), rRange);
2896 if (it == maRanges.end())
2897 // Not cached.
2898 return NULL;
2900 // Already cached.
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 !!!");
2906 return NULL;
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())
2921 // No caches.
2922 return;
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(
2936 mpDoc, eMode,
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)
2943 // range updated.
2944 ScRange aNew(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
2945 *it = aNew;
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.
2956 rRefs.clear();
2957 return;
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 !!!");
2965 rRefs.clear();
2966 return;
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());
2975 rRefs.swap(aRefs);
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;
2989 maCaches.erase(it);
2990 maRanges[idx].SetInvalid();
2991 return true;
2994 return false;
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())
3009 // already cached.
3010 return itr->second;
3012 SAL_WNODEPRECATED_DECLARATIONS_PUSH
3013 ::std::auto_ptr<ScDPCache> pCache(new ScDPCache(mpDoc));
3014 SAL_WNODEPRECATED_DECLARATIONS_POP
3015 pCache->InitFromDoc(mpDoc, rRange);
3016 if (pDimData)
3017 pDimData->WriteToCache(*pCache);
3019 const ScDPCache* p = pCache.get();
3020 maCaches.insert(rName, pCache);
3021 return p;
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())
3041 rRefs.clear();
3042 return;
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());
3050 rRefs.swap(aRefs);
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)
3063 maCaches.erase(it);
3064 return true;
3067 return false;
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())
3094 // already cached.
3095 return itr->second;
3097 uno::Reference<sdbc::XRowSet> xRowSet = createRowSet(nSdbType, rDBName, rCommand);
3098 if (!xRowSet.is())
3099 return NULL;
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());
3106 if (!aDB.isValid())
3107 return NULL;
3109 if (!pCache->InitFromDataBase(aDB))
3111 // initialization failed.
3112 comphelper::disposeComponent(xRowSet);
3113 return NULL;
3116 if (pDimData)
3117 pDimData->WriteToCache(*pCache);
3119 ::comphelper::disposeComponent(xRowSet);
3120 const ScDPCache* p = pCache.get();
3121 maCaches.insert(aType, pCache);
3122 return p;
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)),
3142 UNO_QUERY);
3144 uno::Reference<beans::XPropertySet> xRowProp(xRowSet, UNO_QUERY);
3145 OSL_ENSURE( xRowProp.is(), "can't get RowSet" );
3146 if (!xRowProp.is())
3148 xRowSet.set(NULL);
3149 return xRowSet;
3153 // set source parameters
3155 uno::Any aAny;
3156 aAny <<= rDBName;
3157 xRowProp->setPropertyValue(
3158 OUString(SC_DBPROP_DATASOURCENAME), aAny );
3160 aAny <<= rCommand;
3161 xRowProp->setPropertyValue(
3162 OUString(SC_DBPROP_COMMAND), aAny );
3164 aAny <<= nSdbType;
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 );
3176 else
3177 xRowSet->execute();
3179 return xRowSet;
3181 catch ( const sdbc::SQLException& rError )
3183 //! store error message
3184 InfoBox aInfoBox( 0, OUString(rError.Message) );
3185 aInfoBox.Execute();
3187 catch ( uno::Exception& )
3189 OSL_FAIL("Unexpected exception in database");
3192 xRowSet.set(NULL);
3193 return xRowSet;
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())
3204 // not cached.
3205 rRefs.clear();
3206 return;
3209 ScDPCache& rCache = *it->second;
3211 uno::Reference<sdbc::XRowSet> xRowSet = createRowSet(nSdbType, rDBName, rCommand);
3212 if (!xRowSet.is())
3214 rRefs.clear();
3215 return;
3218 SvNumberFormatter aFormat( comphelper::getProcessComponentContext(), ScGlobal::eLnge);
3219 DBConnector aDB(rCache, xRowSet, *aFormat.GetNullDate());
3220 if (!aDB.isValid())
3221 return;
3223 if (!rCache.InitFromDataBase(aDB))
3225 // initialization failed.
3226 rRefs.clear();
3227 comphelper::disposeComponent(xRowSet);
3228 return;
3231 comphelper::disposeComponent(xRowSet);
3232 std::set<ScDPObject*> aRefs(rCache.GetAllReferences());
3233 aRefs.swap(rRefs);
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)
3246 maCaches.erase(it);
3247 return true;
3250 return false;
3253 ScDPCollection::ScDPCollection(ScDocument* pDocument) :
3254 mpDoc( pDocument ),
3255 maSheetCaches(pDocument),
3256 maNameCaches(pDocument),
3257 maDBCaches(pDocument)
3261 ScDPCollection::ScDPCollection(const ScDPCollection& r) :
3262 mpDoc(r.mpDoc),
3263 maSheetCaches(r.mpDoc),
3264 maNameCaches(r.mpDoc),
3265 maDBCaches(r.mpDoc)
3269 ScDPCollection::~ScDPCollection()
3271 maTables.clear();
3274 namespace {
3277 * Unary predicate to match DP objects by the table ID.
3279 class MatchByTable : public unary_function<ScDPObject, bool>
3281 SCTAB mnTab;
3282 public:
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)
3295 if (!pDPObj)
3296 return STR_ERR_DATAPILOTSOURCE;
3298 if (pDPObj->IsSheetData())
3300 // data source is internal sheet.
3301 const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc();
3302 if (!pDesc)
3303 return STR_ERR_DATAPILOTSOURCE;
3305 sal_uLong nErrId = pDesc->CheckSourceRange();
3306 if (nErrId)
3307 return nErrId;
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);
3315 else
3317 // Not cached yet. Collect all tables that use this named
3318 // range as data source.
3319 GetAllTables(pDesc->GetRangeName(), rRefs);
3322 else
3324 // cache by cell range
3325 ScDPCollection::SheetCaches& rCaches = GetSheetCaches();
3326 if (rCaches.hasCache(pDesc->GetSourceRange()))
3327 rCaches.updateCache(pDesc->GetSourceRange(), rRefs);
3328 else
3330 // Not cached yet. Collect all tables that use this range as
3331 // data source.
3332 GetAllTables(pDesc->GetSourceRange(), rRefs);
3336 else if (pDPObj->IsImportData())
3338 // data source is external database.
3339 const ScImportSourceDesc* pDesc = pDPObj->GetImportSourceDesc();
3340 if (!pDesc)
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);
3347 else
3349 // Not cached yet. Collect all tables that use this range as
3350 // data source.
3351 GetAllTables(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, rRefs);
3354 return 0;
3357 bool ScDPCollection::ReloadGroupsInCache(ScDPObject* pDPObj, std::set<ScDPObject*>& rRefs)
3359 if (!pDPObj)
3360 return false;
3362 const ScDPSaveData* pSaveData = pDPObj->GetSaveData();
3363 if (!pSaveData)
3364 return false;
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();
3378 if (!pDesc)
3379 return false;
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());
3387 else
3389 // Not cached yet. Cache the source dimensions. Groups will
3390 // be added below.
3391 pCache = const_cast<ScDPCache*>(
3392 rCaches.getCache(pDesc->GetRangeName(), pDesc->GetSourceRange(), NULL));
3394 GetAllTables(pDesc->GetRangeName(), rRefs);
3396 else
3398 // cache by cell range
3399 ScDPCollection::SheetCaches& rCaches = GetSheetCaches();
3400 if (rCaches.hasCache(pDesc->GetSourceRange()))
3401 pCache = rCaches.getExistingCache(pDesc->GetSourceRange());
3402 else
3404 // Not cached yet. Cache the source dimensions. Groups will
3405 // be added below.
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();
3416 if (!pDesc)
3417 return false;
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);
3423 else
3425 // Not cached yet. Cache the source dimensions. Groups will
3426 // be added below.
3427 pCache = const_cast<ScDPCache*>(
3428 rCaches.getCache(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, NULL));
3430 GetAllTables(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, rRefs);
3433 if (!pCache)
3434 return false;
3436 // Clear the existing group data from the cache, and rebuild it from the
3437 // dimension data.
3438 pCache->ClearGroupFields();
3439 const ScDPDimensionSaveData* pDimData = pSaveData->GetExistingDimensionData();
3440 if (pDimData)
3441 pDimData->WriteToCache(*pCache);
3442 return true;
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 )
3463 TablesType aAdded;
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)
3470 continue;
3472 ScAddress& s = aOutRange.aStart;
3473 ScAddress& e = aOutRange.aEnd;
3474 s.SetTab(nNew);
3475 e.SetTab(nNew);
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())
3488 return false;
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))
3493 return false;
3495 return true;
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);
3508 else
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
3527 bFound = true;
3531 if (!bFound)
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)
3563 return &(*itr);
3565 return NULL;
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;
3576 aBuf.append(aBase);
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)
3585 bFound = true;
3586 break;
3589 if (!bFound)
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);
3605 if (p == pDPObj)
3607 maTables.erase(itr);
3608 break;
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);
3621 return true;
3624 ScDPCollection::SheetCaches& ScDPCollection::GetSheetCaches()
3626 return maSheetCaches;
3629 ScDPCollection::NameCaches& ScDPCollection::GetNameCaches()
3631 return maNameCaches;
3634 ScDPCollection::DBCaches& ScDPCollection::GetDBCaches()
3636 return maDBCaches;
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
3664 namespace {
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();
3672 if (!pSaveData)
3673 return;
3675 pSaveData->Dump();
3677 cout << endl; // blank line
3683 void ScDPCollection::DumpTables() const
3685 std::for_each(maTables.begin(), maTables.end(), DumpTable());
3688 #endif
3690 void ScDPCollection::RemoveCache(const ScDPCache* pCache)
3692 if (maSheetCaches.remove(pCache))
3693 // sheet cache removed.
3694 return;
3696 if (maNameCaches.remove(pCache))
3697 // named range cache removed.
3698 return;
3700 if (maDBCaches.remove(pCache))
3701 // database cache removed.
3702 return;
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.
3714 continue;
3716 const ScSheetSourceDesc* pDesc = rObj.GetSheetDesc();
3717 if (!pDesc)
3718 continue;
3720 if (pDesc->HasRangeName())
3721 // This table has a range name as its source.
3722 continue;
3724 if (pDesc->GetSourceRange() != rSrcRange)
3725 // Different source range.
3726 continue;
3728 aRefs.insert(const_cast<ScDPObject*>(&rObj));
3731 rRefs.swap(aRefs);
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.
3743 continue;
3745 const ScSheetSourceDesc* pDesc = rObj.GetSheetDesc();
3746 if (!pDesc)
3747 continue;
3749 if (!pDesc->HasRangeName())
3750 // This table probably has a sheet range as its source.
3751 continue;
3753 if (pDesc->GetRangeName() != rSrcName)
3754 // Different source name.
3755 continue;
3757 aRefs.insert(const_cast<ScDPObject*>(&rObj));
3760 rRefs.swap(aRefs);
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.
3774 continue;
3776 const ScImportSourceDesc* pDesc = rObj.GetImportSourceDesc();
3777 if (!pDesc)
3778 continue;
3780 if (!pDesc->aDBName.equals(rDBName) || !pDesc->aObject.equals(rCommand) || pDesc->GetCommandType() != nSdbType)
3781 // Different database source.
3782 continue;
3784 aRefs.insert(const_cast<ScDPObject*>(&rObj));
3787 rRefs.swap(aRefs);
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: */