re-enabled user-defined numeric fields for dBase export
[LibreOffice.git] / sc / source / core / data / dpobject.cxx
blob3ade4cff5c8f4f37d02d07989f73921653d3e9ea
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" // PIVOT_DATA_FIELD
31 #include "dapiuno.hxx" // ScDataPilotConversion
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> // IsNumberFormat
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 String 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 String 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 if (pDimData)
2862 pDimData->WriteToCache(*itCache->second);
2864 return itCache->second;
2867 // Not cached. Create a new cache.
2868 SAL_WNODEPRECATED_DECLARATIONS_PUSH
2869 ::std::auto_ptr<ScDPCache> pCache(new ScDPCache(mpDoc));
2870 SAL_WNODEPRECATED_DECLARATIONS_POP
2871 pCache->InitFromDoc(mpDoc, rRange);
2872 if (pDimData)
2873 pDimData->WriteToCache(*pCache);
2875 // Get the smallest available range index.
2876 it = std::find_if(maRanges.begin(), maRanges.end(), FindInvalidRange());
2878 size_t nIndex = maRanges.size();
2879 if (it == maRanges.end())
2881 // All range indices are valid. Append a new index.
2882 maRanges.push_back(rRange);
2884 else
2886 // Slot with invalid range. Re-use this slot.
2887 *it = rRange;
2888 nIndex = std::distance(maRanges.begin(), it);
2891 const ScDPCache* p = pCache.get();
2892 maCaches.insert(nIndex, pCache);
2893 return p;
2896 ScDPCache* ScDPCollection::SheetCaches::getExistingCache(const ScRange& rRange)
2898 RangeIndexType::iterator it = std::find(maRanges.begin(), maRanges.end(), rRange);
2899 if (it == maRanges.end())
2900 // Not cached.
2901 return NULL;
2903 // Already cached.
2904 size_t nIndex = std::distance(maRanges.begin(), it);
2905 CachesType::iterator itCache = maCaches.find(nIndex);
2906 if (itCache == maCaches.end())
2908 OSL_FAIL("Cache pool and index pool out-of-sync !!!");
2909 return NULL;
2912 return itCache->second;
2915 size_t ScDPCollection::SheetCaches::size() const
2917 return maCaches.size();
2920 void ScDPCollection::SheetCaches::updateReference(
2921 UpdateRefMode eMode, const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz)
2923 if (maRanges.empty())
2924 // No caches.
2925 return;
2927 RangeIndexType::iterator it = maRanges.begin(), itEnd = maRanges.end();
2928 for (; it != itEnd; ++it)
2930 const ScRange& rKeyRange = *it;
2931 SCCOL nCol1 = rKeyRange.aStart.Col();
2932 SCROW nRow1 = rKeyRange.aStart.Row();
2933 SCTAB nTab1 = rKeyRange.aStart.Tab();
2934 SCCOL nCol2 = rKeyRange.aEnd.Col();
2935 SCROW nRow2 = rKeyRange.aEnd.Row();
2936 SCTAB nTab2 = rKeyRange.aEnd.Tab();
2938 ScRefUpdateRes eRes = ScRefUpdate::Update(
2939 mpDoc, eMode,
2940 r.aStart.Col(), r.aStart.Row(), r.aStart.Tab(),
2941 r.aEnd.Col(), r.aEnd.Row(), r.aEnd.Tab(), nDx, nDy, nDz,
2942 nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
2944 if (eRes != UR_NOTHING)
2946 // range updated.
2947 ScRange aNew(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
2948 *it = aNew;
2953 void ScDPCollection::SheetCaches::updateCache(const ScRange& rRange, std::set<ScDPObject*>& rRefs)
2955 RangeIndexType::iterator it = std::find(maRanges.begin(), maRanges.end(), rRange);
2956 if (it == maRanges.end())
2958 // Not cached. Nothing to do.
2959 rRefs.clear();
2960 return;
2963 size_t nIndex = std::distance(maRanges.begin(), it);
2964 CachesType::iterator itCache = maCaches.find(nIndex);
2965 if (itCache == maCaches.end())
2967 OSL_FAIL("Cache pool and index pool out-of-sync !!!");
2968 rRefs.clear();
2969 return;
2972 ScDPCache& rCache = *itCache->second;
2974 // Update the cache with new cell values. This will clear all group dimension info.
2975 rCache.InitFromDoc(mpDoc, rRange);
2977 std::set<ScDPObject*> aRefs(rCache.GetAllReferences());
2978 rRefs.swap(aRefs);
2980 // Make sure to re-populate the group dimension info.
2981 setGroupItemsToCache(rCache, rRefs);
2984 bool ScDPCollection::SheetCaches::remove(const ScDPCache* p)
2986 CachesType::iterator it = maCaches.begin(), itEnd = maCaches.end();
2987 for (; it != itEnd; ++it)
2989 if (it->second == p)
2991 size_t idx = it->first;
2992 maCaches.erase(it);
2993 maRanges[idx].SetInvalid();
2994 return true;
2997 return false;
3000 ScDPCollection::NameCaches::NameCaches(ScDocument* pDoc) : mpDoc(pDoc) {}
3002 bool ScDPCollection::NameCaches::hasCache(const OUString& rName) const
3004 return maCaches.count(rName) != 0;
3007 const ScDPCache* ScDPCollection::NameCaches::getCache(
3008 const OUString& rName, const ScRange& rRange, const ScDPDimensionSaveData* pDimData)
3010 CachesType::const_iterator itr = maCaches.find(rName);
3011 if (itr != maCaches.end())
3012 // already cached.
3013 return itr->second;
3015 SAL_WNODEPRECATED_DECLARATIONS_PUSH
3016 ::std::auto_ptr<ScDPCache> pCache(new ScDPCache(mpDoc));
3017 SAL_WNODEPRECATED_DECLARATIONS_POP
3018 pCache->InitFromDoc(mpDoc, rRange);
3019 if (pDimData)
3020 pDimData->WriteToCache(*pCache);
3022 const ScDPCache* p = pCache.get();
3023 maCaches.insert(rName, pCache);
3024 return p;
3027 ScDPCache* ScDPCollection::NameCaches::getExistingCache(const OUString& rName)
3029 CachesType::iterator itr = maCaches.find(rName);
3030 return itr != maCaches.end() ? itr->second : NULL;
3033 size_t ScDPCollection::NameCaches::size() const
3035 return maCaches.size();
3038 void ScDPCollection::NameCaches::updateCache(
3039 const OUString& rName, const ScRange& rRange, std::set<ScDPObject*>& rRefs)
3041 CachesType::iterator itr = maCaches.find(rName);
3042 if (itr == maCaches.end())
3044 rRefs.clear();
3045 return;
3048 ScDPCache& rCache = *itr->second;
3049 // Update the cache with new cell values. This will clear all group dimension info.
3050 rCache.InitFromDoc(mpDoc, rRange);
3052 std::set<ScDPObject*> aRefs(rCache.GetAllReferences());
3053 rRefs.swap(aRefs);
3055 // Make sure to re-populate the group dimension info.
3056 setGroupItemsToCache(rCache, rRefs);
3059 bool ScDPCollection::NameCaches::remove(const ScDPCache* p)
3061 CachesType::iterator it = maCaches.begin(), itEnd = maCaches.end();
3062 for (; it != itEnd; ++it)
3064 if (it->second == p)
3066 maCaches.erase(it);
3067 return true;
3070 return false;
3073 ScDPCollection::DBType::DBType(sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand) :
3074 mnSdbType(nSdbType), maDBName(rDBName), maCommand(rCommand) {}
3076 bool ScDPCollection::DBType::less::operator() (const DBType& left, const DBType& right) const
3078 return left < right;
3081 ScDPCollection::DBCaches::DBCaches(ScDocument* pDoc) : mpDoc(pDoc) {}
3083 bool ScDPCollection::DBCaches::hasCache(sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand) const
3085 DBType aType(nSdbType, rDBName, rCommand);
3086 CachesType::const_iterator itr = maCaches.find(aType);
3087 return itr != maCaches.end();
3090 const ScDPCache* ScDPCollection::DBCaches::getCache(
3091 sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand,
3092 const ScDPDimensionSaveData* pDimData)
3094 DBType aType(nSdbType, rDBName, rCommand);
3095 CachesType::const_iterator itr = maCaches.find(aType);
3096 if (itr != maCaches.end())
3097 // already cached.
3098 return itr->second;
3100 uno::Reference<sdbc::XRowSet> xRowSet = createRowSet(nSdbType, rDBName, rCommand);
3101 if (!xRowSet.is())
3102 return NULL;
3104 SAL_WNODEPRECATED_DECLARATIONS_PUSH
3105 ::std::auto_ptr<ScDPCache> pCache(new ScDPCache(mpDoc));
3106 SAL_WNODEPRECATED_DECLARATIONS_POP
3107 SvNumberFormatter aFormat( comphelper::getComponentContext(mpDoc->GetServiceManager()), ScGlobal::eLnge);
3108 DBConnector aDB(*pCache, xRowSet, *aFormat.GetNullDate());
3109 if (!aDB.isValid())
3110 return NULL;
3112 if (!pCache->InitFromDataBase(aDB))
3114 // initialization failed.
3115 comphelper::disposeComponent(xRowSet);
3116 return NULL;
3119 if (pDimData)
3120 pDimData->WriteToCache(*pCache);
3122 ::comphelper::disposeComponent(xRowSet);
3123 const ScDPCache* p = pCache.get();
3124 maCaches.insert(aType, pCache);
3125 return p;
3128 ScDPCache* ScDPCollection::DBCaches::getExistingCache(
3129 sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand)
3131 DBType aType(nSdbType, rDBName, rCommand);
3132 CachesType::iterator itr = maCaches.find(aType);
3133 return itr != maCaches.end() ? itr->second : NULL;
3136 uno::Reference<sdbc::XRowSet> ScDPCollection::DBCaches::createRowSet(
3137 sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand)
3139 uno::Reference<sdbc::XRowSet> xRowSet;
3142 xRowSet = uno::Reference<sdbc::XRowSet>(
3143 comphelper::getProcessServiceFactory()->createInstance(
3144 OUString(SC_SERVICE_ROWSET)),
3145 UNO_QUERY);
3147 uno::Reference<beans::XPropertySet> xRowProp(xRowSet, UNO_QUERY);
3148 OSL_ENSURE( xRowProp.is(), "can't get RowSet" );
3149 if (!xRowProp.is())
3151 xRowSet.set(NULL);
3152 return xRowSet;
3156 // set source parameters
3158 uno::Any aAny;
3159 aAny <<= rDBName;
3160 xRowProp->setPropertyValue(
3161 OUString(SC_DBPROP_DATASOURCENAME), aAny );
3163 aAny <<= rCommand;
3164 xRowProp->setPropertyValue(
3165 OUString(SC_DBPROP_COMMAND), aAny );
3167 aAny <<= nSdbType;
3168 xRowProp->setPropertyValue(
3169 OUString(SC_DBPROP_COMMANDTYPE), aAny );
3171 uno::Reference<sdb::XCompletedExecution> xExecute( xRowSet, uno::UNO_QUERY );
3172 if ( xExecute.is() )
3174 uno::Reference<task::XInteractionHandler> xHandler(
3175 task::InteractionHandler::createWithParent(comphelper::getProcessComponentContext(), 0),
3176 uno::UNO_QUERY_THROW);
3177 xExecute->executeWithCompletion( xHandler );
3179 else
3180 xRowSet->execute();
3182 return xRowSet;
3184 catch ( const sdbc::SQLException& rError )
3186 //! store error message
3187 InfoBox aInfoBox( 0, String(rError.Message) );
3188 aInfoBox.Execute();
3190 catch ( uno::Exception& )
3192 OSL_FAIL("Unexpected exception in database");
3195 xRowSet.set(NULL);
3196 return xRowSet;
3199 void ScDPCollection::DBCaches::updateCache(
3200 sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand,
3201 std::set<ScDPObject*>& rRefs)
3203 DBType aType(nSdbType, rDBName, rCommand);
3204 CachesType::iterator it = maCaches.find(aType);
3205 if (it == maCaches.end())
3207 // not cached.
3208 rRefs.clear();
3209 return;
3212 ScDPCache& rCache = *it->second;
3214 uno::Reference<sdbc::XRowSet> xRowSet = createRowSet(nSdbType, rDBName, rCommand);
3215 if (!xRowSet.is())
3217 rRefs.clear();
3218 return;
3221 SvNumberFormatter aFormat( comphelper::getComponentContext(mpDoc->GetServiceManager()), ScGlobal::eLnge);
3222 DBConnector aDB(rCache, xRowSet, *aFormat.GetNullDate());
3223 if (!aDB.isValid())
3224 return;
3226 if (!rCache.InitFromDataBase(aDB))
3228 // initialization failed.
3229 rRefs.clear();
3230 comphelper::disposeComponent(xRowSet);
3231 return;
3234 comphelper::disposeComponent(xRowSet);
3235 std::set<ScDPObject*> aRefs(rCache.GetAllReferences());
3236 aRefs.swap(rRefs);
3238 // Make sure to re-populate the group dimension info.
3239 setGroupItemsToCache(rCache, rRefs);
3242 bool ScDPCollection::DBCaches::remove(const ScDPCache* p)
3244 CachesType::iterator it = maCaches.begin(), itEnd = maCaches.end();
3245 for (; it != itEnd; ++it)
3247 if (it->second == p)
3249 maCaches.erase(it);
3250 return true;
3253 return false;
3256 ScDPCollection::ScDPCollection(ScDocument* pDocument) :
3257 mpDoc( pDocument ),
3258 maSheetCaches(pDocument),
3259 maNameCaches(pDocument),
3260 maDBCaches(pDocument)
3264 ScDPCollection::ScDPCollection(const ScDPCollection& r) :
3265 mpDoc(r.mpDoc),
3266 maSheetCaches(r.mpDoc),
3267 maNameCaches(r.mpDoc),
3268 maDBCaches(r.mpDoc)
3272 ScDPCollection::~ScDPCollection()
3274 maTables.clear();
3277 namespace {
3280 * Unary predicate to match DP objects by the table ID.
3282 class MatchByTable : public unary_function<ScDPObject, bool>
3284 SCTAB mnTab;
3285 public:
3286 MatchByTable(SCTAB nTab) : mnTab(nTab) {}
3288 bool operator() (const ScDPObject& rObj) const
3290 return rObj.GetOutRange().aStart.Tab() == mnTab;
3296 sal_uLong ScDPCollection::ReloadCache(ScDPObject* pDPObj, std::set<ScDPObject*>& rRefs)
3298 if (!pDPObj)
3299 return STR_ERR_DATAPILOTSOURCE;
3301 if (pDPObj->IsSheetData())
3303 // data source is internal sheet.
3304 const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc();
3305 if (!pDesc)
3306 return STR_ERR_DATAPILOTSOURCE;
3308 sal_uLong nErrId = pDesc->CheckSourceRange();
3309 if (nErrId)
3310 return nErrId;
3312 if (pDesc->HasRangeName())
3314 // cache by named range
3315 ScDPCollection::NameCaches& rCaches = GetNameCaches();
3316 if (rCaches.hasCache(pDesc->GetRangeName()))
3317 rCaches.updateCache(pDesc->GetRangeName(), pDesc->GetSourceRange(), rRefs);
3318 else
3320 // Not cached yet. Collect all tables that use this named
3321 // range as data source.
3322 GetAllTables(pDesc->GetRangeName(), rRefs);
3325 else
3327 // cache by cell range
3328 ScDPCollection::SheetCaches& rCaches = GetSheetCaches();
3329 if (rCaches.hasCache(pDesc->GetSourceRange()))
3330 rCaches.updateCache(pDesc->GetSourceRange(), rRefs);
3331 else
3333 // Not cached yet. Collect all tables that use this range as
3334 // data source.
3335 GetAllTables(pDesc->GetSourceRange(), rRefs);
3339 else if (pDPObj->IsImportData())
3341 // data source is external database.
3342 const ScImportSourceDesc* pDesc = pDPObj->GetImportSourceDesc();
3343 if (!pDesc)
3344 return STR_ERR_DATAPILOTSOURCE;
3346 ScDPCollection::DBCaches& rCaches = GetDBCaches();
3347 if (rCaches.hasCache(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject))
3348 rCaches.updateCache(
3349 pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, rRefs);
3350 else
3352 // Not cached yet. Collect all tables that use this range as
3353 // data source.
3354 GetAllTables(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, rRefs);
3357 return 0;
3360 bool ScDPCollection::ReloadGroupsInCache(ScDPObject* pDPObj, std::set<ScDPObject*>& rRefs)
3362 if (!pDPObj)
3363 return false;
3365 const ScDPSaveData* pSaveData = pDPObj->GetSaveData();
3366 if (!pSaveData)
3367 return false;
3369 // Note: Unlike reloading cache, when modifying the group dimensions the
3370 // cache may not have all its references when this method is called.
3371 // Therefore, we need to always call GetAllTables to get its correct
3372 // references even when the cache exists. This may become a non-issue
3373 // if/when we implement loading and saving of pivot caches.
3375 ScDPCache* pCache = NULL;
3377 if (pDPObj->IsSheetData())
3379 // data source is internal sheet.
3380 const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc();
3381 if (!pDesc)
3382 return false;
3384 if (pDesc->HasRangeName())
3386 // cache by named range
3387 ScDPCollection::NameCaches& rCaches = GetNameCaches();
3388 if (rCaches.hasCache(pDesc->GetRangeName()))
3389 pCache = rCaches.getExistingCache(pDesc->GetRangeName());
3390 else
3392 // Not cached yet. Cache the source dimensions. Groups will
3393 // be added below.
3394 pCache = const_cast<ScDPCache*>(
3395 rCaches.getCache(pDesc->GetRangeName(), pDesc->GetSourceRange(), NULL));
3397 GetAllTables(pDesc->GetRangeName(), rRefs);
3399 else
3401 // cache by cell range
3402 ScDPCollection::SheetCaches& rCaches = GetSheetCaches();
3403 if (rCaches.hasCache(pDesc->GetSourceRange()))
3404 pCache = rCaches.getExistingCache(pDesc->GetSourceRange());
3405 else
3407 // Not cached yet. Cache the source dimensions. Groups will
3408 // be added below.
3409 pCache = const_cast<ScDPCache*>(
3410 rCaches.getCache(pDesc->GetSourceRange(), NULL));
3412 GetAllTables(pDesc->GetSourceRange(), rRefs);
3415 else if (pDPObj->IsImportData())
3417 // data source is external database.
3418 const ScImportSourceDesc* pDesc = pDPObj->GetImportSourceDesc();
3419 if (!pDesc)
3420 return false;
3422 ScDPCollection::DBCaches& rCaches = GetDBCaches();
3423 if (rCaches.hasCache(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject))
3424 pCache = rCaches.getExistingCache(
3425 pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject);
3426 else
3428 // Not cached yet. Cache the source dimensions. Groups will
3429 // be added below.
3430 pCache = const_cast<ScDPCache*>(
3431 rCaches.getCache(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, NULL));
3433 GetAllTables(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, rRefs);
3436 if (!pCache)
3437 return false;
3439 // Clear the existing group data from the cache, and rebuild it from the
3440 // dimension data.
3441 pCache->ClearGroupFields();
3442 const ScDPDimensionSaveData* pDimData = pSaveData->GetExistingDimensionData();
3443 if (pDimData)
3444 pDimData->WriteToCache(*pCache);
3445 return true;
3448 void ScDPCollection::DeleteOnTab( SCTAB nTab )
3450 maTables.erase_if(MatchByTable(nTab));
3453 void ScDPCollection::UpdateReference( UpdateRefMode eUpdateRefMode,
3454 const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
3456 TablesType::iterator itr = maTables.begin(), itrEnd = maTables.end();
3457 for (; itr != itrEnd; ++itr)
3458 itr->UpdateReference(eUpdateRefMode, r, nDx, nDy, nDz);
3460 // Update the source ranges of the caches.
3461 maSheetCaches.updateReference(eUpdateRefMode, r, nDx, nDy, nDz);
3464 void ScDPCollection::CopyToTab( SCTAB nOld, SCTAB nNew )
3466 TablesType aAdded;
3467 TablesType::const_iterator it = maTables.begin(), itEnd = maTables.end();
3468 for (; it != itEnd; ++it)
3470 const ScDPObject& rObj = *it;
3471 ScRange aOutRange = rObj.GetOutRange();
3472 if (aOutRange.aStart.Tab() != nOld)
3473 continue;
3475 ScAddress& s = aOutRange.aStart;
3476 ScAddress& e = aOutRange.aEnd;
3477 s.SetTab(nNew);
3478 e.SetTab(nNew);
3479 std::auto_ptr<ScDPObject> pNew(new ScDPObject(rObj));
3480 pNew->SetOutRange(aOutRange);
3481 mpDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
3482 aAdded.push_back(pNew);
3485 maTables.transfer(maTables.end(), aAdded.begin(), aAdded.end(), aAdded);
3488 bool ScDPCollection::RefsEqual( const ScDPCollection& r ) const
3490 if (maTables.size() != r.maTables.size())
3491 return false;
3493 TablesType::const_iterator itr = maTables.begin(), itr2 = r.maTables.begin(), itrEnd = maTables.end();
3494 for (; itr != itrEnd; ++itr, ++itr2)
3495 if (!itr->RefsEqual(*itr2))
3496 return false;
3498 return true;
3501 void ScDPCollection::WriteRefsTo( ScDPCollection& r ) const
3503 if ( maTables.size() == r.maTables.size() )
3505 //! assert equal names?
3506 TablesType::const_iterator itr = maTables.begin(), itrEnd = maTables.end();
3507 TablesType::iterator itr2 = r.maTables.begin();
3508 for (; itr != itrEnd; ++itr, ++itr2)
3509 itr->WriteRefsTo(*itr2);
3511 else
3513 // #i8180# If data pilot tables were deleted with their sheet,
3514 // this collection contains extra entries that must be restored.
3515 // Matching objects are found by their names.
3516 size_t nSrcSize = maTables.size();
3517 size_t nDestSize = r.maTables.size();
3518 OSL_ENSURE( nSrcSize >= nDestSize, "WriteRefsTo: missing entries in document" );
3519 for (size_t nSrcPos = 0; nSrcPos < nSrcSize; ++nSrcPos)
3521 const ScDPObject& rSrcObj = maTables[nSrcPos];
3522 const OUString& aName = rSrcObj.GetName();
3523 bool bFound = false;
3524 for (size_t nDestPos = 0; nDestPos < nDestSize && !bFound; ++nDestPos)
3526 ScDPObject& rDestObj = r.maTables[nDestPos];
3527 if (rDestObj.GetName() == aName)
3529 rSrcObj.WriteRefsTo(rDestObj); // found object, copy refs
3530 bFound = true;
3534 if (!bFound)
3536 // none found, re-insert deleted object (see ScUndoDataPilot::Undo)
3538 ScDPObject* pDestObj = new ScDPObject(rSrcObj);
3539 r.InsertNewTable(pDestObj);
3542 OSL_ENSURE( maTables.size() == r.maTables.size(), "WriteRefsTo: couldn't restore all entries" );
3546 size_t ScDPCollection::GetCount() const
3548 return maTables.size();
3551 ScDPObject* ScDPCollection::operator [](size_t nIndex)
3553 return &maTables[nIndex];
3556 const ScDPObject* ScDPCollection::operator [](size_t nIndex) const
3558 return &maTables[nIndex];
3561 const ScDPObject* ScDPCollection::GetByName(const OUString& rName) const
3563 TablesType::const_iterator itr = maTables.begin(), itrEnd = maTables.end();
3564 for (; itr != itrEnd; ++itr)
3565 if (itr->GetName() == rName)
3566 return &(*itr);
3568 return NULL;
3571 OUString ScDPCollection::CreateNewName( sal_uInt16 nMin ) const
3573 OUString aBase("DataPilot");
3575 size_t n = maTables.size();
3576 for (size_t nAdd = 0; nAdd <= n; ++nAdd) // nCount+1 tries
3578 OUStringBuffer aBuf;
3579 aBuf.append(aBase);
3580 aBuf.append(static_cast<sal_Int32>(nMin + nAdd));
3581 OUString aNewName = aBuf.makeStringAndClear();
3582 bool bFound = false;
3583 TablesType::const_iterator itr = maTables.begin(), itrEnd = maTables.end();
3584 for (; itr != itrEnd; ++itr)
3586 if (itr->GetName() == aNewName)
3588 bFound = true;
3589 break;
3592 if (!bFound)
3593 return aNewName; // found unused Name
3595 return OUString(); // should not happen
3598 void ScDPCollection::FreeTable(ScDPObject* pDPObj)
3600 const ScRange& rOutRange = pDPObj->GetOutRange();
3601 const ScAddress& s = rOutRange.aStart;
3602 const ScAddress& e = rOutRange.aEnd;
3603 mpDoc->RemoveFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
3604 TablesType::iterator itr = maTables.begin(), itrEnd = maTables.end();
3605 for (; itr != itrEnd; ++itr)
3607 ScDPObject* p = &(*itr);
3608 if (p == pDPObj)
3610 maTables.erase(itr);
3611 break;
3616 bool ScDPCollection::InsertNewTable(ScDPObject* pDPObj)
3618 const ScRange& rOutRange = pDPObj->GetOutRange();
3619 const ScAddress& s = rOutRange.aStart;
3620 const ScAddress& e = rOutRange.aEnd;
3621 mpDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
3623 maTables.push_back(pDPObj);
3624 return true;
3627 ScDPCollection::SheetCaches& ScDPCollection::GetSheetCaches()
3629 return maSheetCaches;
3632 ScDPCollection::NameCaches& ScDPCollection::GetNameCaches()
3634 return maNameCaches;
3637 ScDPCollection::DBCaches& ScDPCollection::GetDBCaches()
3639 return maDBCaches;
3642 ScRangeList ScDPCollection::GetAllTableRanges( SCTAB nTab ) const
3644 return std::for_each(maTables.begin(), maTables.end(), AccumulateOutputRanges(nTab)).getRanges();
3647 bool ScDPCollection::IntersectsTableByColumns( SCCOL nCol1, SCCOL nCol2, SCROW nRow, SCTAB nTab ) const
3649 return std::find_if(
3650 maTables.begin(), maTables.end(), FindIntersetingTableByColumns(nCol1, nCol2, nRow, nTab)) != maTables.end();
3653 bool ScDPCollection::IntersectsTableByRows( SCCOL nCol, SCROW nRow1, SCROW nRow2, SCTAB nTab ) const
3655 return std::find_if(
3656 maTables.begin(), maTables.end(), FindIntersectingTableByRows(nCol, nRow1, nRow2, nTab)) != maTables.end();
3659 bool ScDPCollection::HasTable( const ScRange& rRange ) const
3661 return std::find_if(
3662 maTables.begin(), maTables.end(), FindIntersectingTable(rRange)) != maTables.end();
3665 void ScDPCollection::RemoveCache(const ScDPCache* pCache)
3667 if (maSheetCaches.remove(pCache))
3668 // sheet cache removed.
3669 return;
3671 if (maNameCaches.remove(pCache))
3672 // named range cache removed.
3673 return;
3675 if (maDBCaches.remove(pCache))
3676 // database cache removed.
3677 return;
3680 void ScDPCollection::GetAllTables(const ScRange& rSrcRange, std::set<ScDPObject*>& rRefs) const
3682 std::set<ScDPObject*> aRefs;
3683 TablesType::const_iterator it = maTables.begin(), itEnd = maTables.end();
3684 for (; it != itEnd; ++it)
3686 const ScDPObject& rObj = *it;
3687 if (!rObj.IsSheetData())
3688 // Source is not a sheet range.
3689 continue;
3691 const ScSheetSourceDesc* pDesc = rObj.GetSheetDesc();
3692 if (!pDesc)
3693 continue;
3695 if (pDesc->HasRangeName())
3696 // This table has a range name as its source.
3697 continue;
3699 if (pDesc->GetSourceRange() != rSrcRange)
3700 // Different source range.
3701 continue;
3703 aRefs.insert(const_cast<ScDPObject*>(&rObj));
3706 rRefs.swap(aRefs);
3709 void ScDPCollection::GetAllTables(const OUString& rSrcName, std::set<ScDPObject*>& rRefs) const
3711 std::set<ScDPObject*> aRefs;
3712 TablesType::const_iterator it = maTables.begin(), itEnd = maTables.end();
3713 for (; it != itEnd; ++it)
3715 const ScDPObject& rObj = *it;
3716 if (!rObj.IsSheetData())
3717 // Source is not a sheet range.
3718 continue;
3720 const ScSheetSourceDesc* pDesc = rObj.GetSheetDesc();
3721 if (!pDesc)
3722 continue;
3724 if (!pDesc->HasRangeName())
3725 // This table probably has a sheet range as its source.
3726 continue;
3728 if (pDesc->GetRangeName() != rSrcName)
3729 // Different source name.
3730 continue;
3732 aRefs.insert(const_cast<ScDPObject*>(&rObj));
3735 rRefs.swap(aRefs);
3738 void ScDPCollection::GetAllTables(
3739 sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand,
3740 std::set<ScDPObject*>& rRefs) const
3742 std::set<ScDPObject*> aRefs;
3743 TablesType::const_iterator it = maTables.begin(), itEnd = maTables.end();
3744 for (; it != itEnd; ++it)
3746 const ScDPObject& rObj = *it;
3747 if (!rObj.IsImportData())
3748 // Source data is not a database.
3749 continue;
3751 const ScImportSourceDesc* pDesc = rObj.GetImportSourceDesc();
3752 if (!pDesc)
3753 continue;
3755 if (!pDesc->aDBName.equals(rDBName) || !pDesc->aObject.equals(rCommand) || pDesc->GetCommandType() != nSdbType)
3756 // Different database source.
3757 continue;
3759 aRefs.insert(const_cast<ScDPObject*>(&rObj));
3762 rRefs.swap(aRefs);
3765 bool operator<(const ScDPCollection::DBType& left, const ScDPCollection::DBType& right)
3767 if (left.mnSdbType != right.mnSdbType)
3768 return left.mnSdbType < right.mnSdbType;
3770 if (!left.maDBName.equals(right.maDBName))
3771 return left.maDBName < right.maDBName;
3773 return left.maCommand < right.maCommand;
3776 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */