xref: /aoo41x/main/sc/source/core/data/dpobject.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 
32 
33 // INCLUDE ---------------------------------------------------------------
34 
35 #include "dpobject.hxx"
36 #include "dptabsrc.hxx"
37 #include "dpsave.hxx"
38 #include "dpdimsave.hxx"
39 #include "dpoutput.hxx"
40 #include "dpshttab.hxx"
41 #include "dpsdbtab.hxx"
42 #include "dpgroup.hxx"
43 #include "document.hxx"
44 #include "rechead.hxx"
45 #include "pivot.hxx"		// PIVOT_DATA_FIELD
46 #include "dapiuno.hxx"		// ScDataPilotConversion
47 #include "miscuno.hxx"
48 #include "scerrors.hxx"
49 #include "refupdat.hxx"
50 #include "scresid.hxx"
51 #include "sc.hrc"
52 #include "attrib.hxx"
53 #include "scitems.hxx"
54 #include "unonames.hxx"
55 // Wang Xu Ming -- 2009-8-17
56 // DataPilot Migration - Cache&&Performance
57 #include "dpglobal.hxx"
58 #include "globstr.hrc"
59 // End Comments
60 #include <com/sun/star/beans/XPropertySet.hpp>
61 #include <com/sun/star/sheet/GeneralFunction.hpp>
62 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
63 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
64 #include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
65 #include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
66 #include <com/sun/star/sheet/DataPilotTablePositionData.hpp>
67 #include <com/sun/star/sheet/DataPilotTablePositionType.hpp>
68 #include <com/sun/star/sheet/DimensionFlags.hpp>
69 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
70 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
71 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
72 #include <com/sun/star/lang/XInitialization.hpp>
73 #include <com/sun/star/container/XContentEnumerationAccess.hpp>
74 #include <com/sun/star/sheet/XDrillDownDataSupplier.hpp>
75 
76 #include <comphelper/processfactory.hxx>
77 #include <tools/debug.hxx>
78 #include <tools/diagnose_ex.h>
79 #include <svl/zforlist.hxx>		// IsNumberFormat
80 
81 #include <vector>
82 #include <stdio.h>
83 
84 using namespace com::sun::star;
85 using ::std::vector;
86 using ::boost::shared_ptr;
87 using ::com::sun::star::uno::Sequence;
88 using ::com::sun::star::uno::Reference;
89 using ::com::sun::star::uno::UNO_QUERY;
90 using ::com::sun::star::uno::Any;
91 using ::com::sun::star::uno::Exception;
92 using ::com::sun::star::lang::XComponent;
93 using ::com::sun::star::sheet::DataPilotTableHeaderData;
94 using ::com::sun::star::sheet::DataPilotTablePositionData;
95 using ::com::sun::star::beans::XPropertySet;
96 using ::rtl::OUString;
97 
98 
99 // -----------------------------------------------------------------------
100 
101 #define SCDPSOURCE_SERVICE	"com.sun.star.sheet.DataPilotSource"
102 
103 // -----------------------------------------------------------------------
104 
105 // incompatible versions of data pilot files
106 #define SC_DP_VERSION_CURRENT	6
107 
108 // type of source data
109 #define SC_DP_SOURCE_SHEET		0
110 #define SC_DP_SOURCE_DATABASE	1
111 #define SC_DP_SOURCE_SERVICE	2
112 
113 // -----------------------------------------------------------------------
114 
115 //!	move to a header file
116 #define DP_PROP_COLUMNGRAND			"ColumnGrand"
117 #define DP_PROP_FUNCTION			"Function"
118 #define DP_PROP_IGNOREEMPTY			"IgnoreEmptyRows"
119 #define DP_PROP_ISDATALAYOUT		"IsDataLayoutDimension"
120 //#define DP_PROP_ISVISIBLE			"IsVisible"
121 #define DP_PROP_ORIENTATION			"Orientation"
122 #define DP_PROP_ORIGINAL			"Original"
123 #define DP_PROP_POSITION			"Position"
124 #define DP_PROP_REPEATIFEMPTY		"RepeatIfEmpty"
125 #define DP_PROP_ROWGRAND			"RowGrand"
126 #define DP_PROP_SHOWDETAILS			"ShowDetails"
127 #define DP_PROP_SHOWEMPTY			"ShowEmpty"
128 #define DP_PROP_SUBTOTALS			"SubTotals"
129 #define DP_PROP_USEDHIERARCHY		"UsedHierarchy"
130 
131 // -----------------------------------------------------------------------
132 
133 sal_uInt16 lcl_GetDataGetOrientation( const uno::Reference<sheet::XDimensionsSupplier>& xSource )
134 {
135 	long nRet = sheet::DataPilotFieldOrientation_HIDDEN;
136 	if ( xSource.is() )
137 	{
138 		uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
139 		uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
140 		long nIntCount = xIntDims->getCount();
141 		sal_Bool bFound = sal_False;
142 		for (long nIntDim=0; nIntDim<nIntCount && !bFound; nIntDim++)
143 		{
144 			uno::Reference<uno::XInterface> xIntDim =
145 				ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nIntDim) );
146 			uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
147 			if ( xDimProp.is() )
148 			{
149 				bFound = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
150 					rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
151 				//!	error checking -- is "IsDataLayoutDimension" property required??
152 				if (bFound)
153 					nRet = ScUnoHelpFunctions::GetEnumProperty(
154 							xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION),
155 							sheet::DataPilotFieldOrientation_HIDDEN );
156 			}
157 		}
158 	}
159     return static_cast< sal_uInt16 >( nRet );
160 }
161 
162 // -----------------------------------------------------------------------
163 
164 ScDPObject::ScDPObject( ScDocument* pD ) :
165 	pDoc( pD ),
166 	pSaveData( NULL ),
167 	pSheetDesc( NULL ),
168 	pImpDesc( NULL ),
169 	pServDesc( NULL ),
170     mpTableData(static_cast<ScDPTableData*>(NULL)),
171 	pOutput( NULL ),
172 	bSettingsChanged( sal_False ),
173 	bAlive( sal_False ),
174 	bAllowMove( sal_False ),
175 	nHeaderRows( 0 ),
176     mbHeaderLayout(false),
177 	bRefresh( sal_False ), // Wang Xu Ming - DataPilot migration
178     mnCacheId( -1 ), // Wang Xu Ming - DataPilot migration
179     mbCreatingTableData( false )
180 {
181 }
182 
183 ScDPObject::ScDPObject(const ScDPObject& r) :
184     ScDataObject(),
185 	pDoc( r.pDoc ),
186 	pSaveData( NULL ),
187 	aTableName( r.aTableName ),
188 	aTableTag( r.aTableTag ),
189 	aOutRange( r.aOutRange ),
190 	pSheetDesc( NULL ),
191 	pImpDesc( NULL ),
192 	pServDesc( NULL ),
193     mpTableData(static_cast<ScDPTableData*>(NULL)),
194 	pOutput( NULL ),
195 	bSettingsChanged( sal_False ),
196 	bAlive( sal_False ),
197 	bAllowMove( sal_False ),
198 	nHeaderRows( r.nHeaderRows ),
199     mbHeaderLayout( r.mbHeaderLayout ),
200 	bRefresh( r.bRefresh ), // Wang Xu Ming - DataPilot migration
201     mnCacheId ( r.mnCacheId ), // Wang Xu Ming - DataPilot migration
202     mbCreatingTableData( false )
203 {
204 	if (r.pSaveData)
205 		pSaveData = new ScDPSaveData(*r.pSaveData);
206 	if (r.pSheetDesc)
207 		pSheetDesc = new ScSheetSourceDesc(*r.pSheetDesc);
208 	if (r.pImpDesc)
209 		pImpDesc = new ScImportSourceDesc(*r.pImpDesc);
210 	if (r.pServDesc)
211 		pServDesc = new ScDPServiceDesc(*r.pServDesc);
212 	// xSource (and pOutput) is not copied
213 }
214 
215 ScDPObject::~ScDPObject()
216 {
217 	delete pOutput;
218 	delete pSaveData;
219 	delete pSheetDesc;
220 	delete pImpDesc;
221 	delete pServDesc;
222 	mnCacheId = -1; // Wang Xu Ming - DataPilot migration
223     InvalidateSource();
224 }
225 
226 ScDataObject* ScDPObject::Clone() const
227 {
228 	return new ScDPObject(*this);
229 }
230 
231 void ScDPObject::SetAlive(sal_Bool bSet)
232 {
233 	bAlive = bSet;
234 }
235 
236 void ScDPObject::SetAllowMove(sal_Bool bSet)
237 {
238 	bAllowMove = bSet;
239 }
240 
241 void ScDPObject::SetSaveData(const ScDPSaveData& rData)
242 {
243     if ( pSaveData != &rData )      // API implementation modifies the original SaveData object
244     {
245         delete pSaveData;
246         pSaveData = new ScDPSaveData( rData );
247         // Wang Xu Ming -- 2009-8-17
248         // DataPilot Migration - Cache&&Performance
249         if ( rData.GetCacheId() >= 0 )
250             mnCacheId = rData.GetCacheId();
251         else if ( mnCacheId >= 0 )
252             pSaveData->SetCacheId( mnCacheId );
253         // End Comments
254     }
255 
256 	InvalidateData();		// re-init source from SaveData
257 }
258 
259 void ScDPObject::SetHeaderLayout (bool bUseGrid)
260 {
261     mbHeaderLayout = bUseGrid;
262 }
263 
264 bool ScDPObject::GetHeaderLayout() const
265 {
266     return mbHeaderLayout;
267 }
268 
269 void ScDPObject::SetOutRange(const ScRange& rRange)
270 {
271 	aOutRange = rRange;
272 
273 	if ( pOutput )
274 		pOutput->SetPosition( rRange.aStart );
275 }
276 
277 void ScDPObject::SetSheetDesc(const ScSheetSourceDesc& rDesc, bool bFromRefUpdate)
278 {
279 	if ( pSheetDesc && rDesc == *pSheetDesc )
280 		return;				// nothing to do
281 
282 	DELETEZ( pImpDesc );
283 	DELETEZ( pServDesc );
284 
285     delete pSheetDesc;
286 	pSheetDesc = new ScSheetSourceDesc(rDesc);
287 
288 	//	make valid QueryParam
289 
290 	pSheetDesc->aQueryParam.nCol1 = pSheetDesc->aSourceRange.aStart.Col();
291 	pSheetDesc->aQueryParam.nRow1 = pSheetDesc->aSourceRange.aStart.Row();
292 	pSheetDesc->aQueryParam.nCol2 = pSheetDesc->aSourceRange.aEnd.Col();
293 	pSheetDesc->aQueryParam.nRow2 = pSheetDesc->aSourceRange.aEnd.Row();;
294 	pSheetDesc->aQueryParam.bHasHeader = sal_True;
295 
296 	InvalidateSource();		// new source must be created
297     if (!bFromRefUpdate)
298         SetCacheId( -1 );   // #i116504# don't use the same cache ID for a different range (except reference update)
299 }
300 
301 void ScDPObject::SetImportDesc(const ScImportSourceDesc& rDesc)
302 {
303 	if ( pImpDesc && rDesc == *pImpDesc )
304 		return;				// nothing to do
305 
306 	DELETEZ( pSheetDesc );
307 	DELETEZ( pServDesc );
308 
309 	delete pImpDesc;
310 	pImpDesc = new ScImportSourceDesc(rDesc);
311 
312 	InvalidateSource();		// new source must be created
313     SetCacheId( -1 );
314 }
315 
316 void ScDPObject::SetServiceData(const ScDPServiceDesc& rDesc)
317 {
318 	if ( pServDesc && rDesc == *pServDesc )
319 		return;				// nothing to do
320 
321 	DELETEZ( pSheetDesc );
322 	DELETEZ( pImpDesc );
323 
324 	delete pServDesc;
325 	pServDesc = new ScDPServiceDesc(rDesc);
326 
327 	InvalidateSource();		// new source must be created
328 }
329 
330 void ScDPObject::WriteSourceDataTo( ScDPObject& rDest ) const
331 {
332 	if ( pSheetDesc )
333 		rDest.SetSheetDesc( *pSheetDesc );
334 	else if ( pImpDesc )
335 		rDest.SetImportDesc( *pImpDesc );
336 	else if ( pServDesc )
337 		rDest.SetServiceData( *pServDesc );
338 
339 	//	name/tag are not source data, but needed along with source data
340 
341 	rDest.aTableName = aTableName;
342 	rDest.aTableTag  = aTableTag;
343 }
344 
345 void ScDPObject::WriteTempDataTo( ScDPObject& rDest ) const
346 {
347 	rDest.nHeaderRows = nHeaderRows;
348 }
349 
350 sal_Bool ScDPObject::IsSheetData() const
351 {
352 	return ( pSheetDesc != NULL );
353 }
354 
355 void ScDPObject::SetName(const String& rNew)
356 {
357 	aTableName = rNew;
358 }
359 
360 void ScDPObject::SetTag(const String& rNew)
361 {
362 	aTableTag = rNew;
363 }
364 
365 bool ScDPObject::IsDataDescriptionCell(const ScAddress& rPos)
366 {
367     if (!pSaveData)
368         return false;
369 
370     long nDataDimCount = pSaveData->GetDataDimensionCount();
371     if (nDataDimCount != 1)
372         // There has to be exactly one data dimension for the description to
373         // appear at top-left corner.
374         return false;
375 
376     CreateOutput();
377     ScRange aTabRange = pOutput->GetOutputRange(sheet::DataPilotOutputRangeType::TABLE);
378     return (rPos == aTabRange.aStart);
379 }
380 
381 uno::Reference<sheet::XDimensionsSupplier> ScDPObject::GetSource()
382 {
383 	CreateObjects();
384 	return xSource;
385 }
386 
387 void ScDPObject::CreateOutput()
388 {
389 	CreateObjects();
390 	if (!pOutput)
391 	{
392         sal_Bool bFilterButton = IsSheetData() && pSaveData && pSaveData->GetFilterButton();
393         pOutput = new ScDPOutput( pDoc, xSource, aOutRange.aStart, bFilterButton );
394         pOutput->SetHeaderLayout ( mbHeaderLayout );
395 
396 		long nOldRows = nHeaderRows;
397 		nHeaderRows = pOutput->GetHeaderRows();
398 
399 		if ( bAllowMove && nHeaderRows != nOldRows )
400 		{
401 			long nDiff = nOldRows - nHeaderRows;
402 			if ( nOldRows == 0 )
403 				--nDiff;
404 			if ( nHeaderRows == 0 )
405 				++nDiff;
406 
407 			long nNewRow = aOutRange.aStart.Row() + nDiff;
408 			if ( nNewRow < 0 )
409 				nNewRow = 0;
410 
411 			ScAddress aStart( aOutRange.aStart );
412             aStart.SetRow(nNewRow);
413 			pOutput->SetPosition( aStart );
414 
415 			//!	modify aOutRange?
416 
417 			bAllowMove = sal_False;		// use only once
418 		}
419 	}
420 }
421 
422 ScDPTableData* ScDPObject::GetTableData()
423 {
424     if (!mpTableData && !mbCreatingTableData)
425     {
426         // #i117239# While filling the cache, mpTableData is still null.
427         // Prevent nested calls from GetPivotData and similar functions.
428         mbCreatingTableData = true;
429 
430         shared_ptr<ScDPTableData> pData;
431         if ( pImpDesc )
432         {
433             // database data
434             pData.reset(new ScDatabaseDPData(pDoc, *pImpDesc, GetCacheId()));
435         }
436         else
437         {
438             // cell data
439             if (!pSheetDesc)
440             {
441                 DBG_ERROR("no source descriptor");
442                 pSheetDesc = new ScSheetSourceDesc;     // dummy defaults
443             }
444             // Wang Xu Ming -- 2009-8-17
445             // DataPilot Migration - Cache&&Performance
446             pData.reset(new ScSheetDPData(pDoc, *pSheetDesc, GetCacheId()));
447             // End Comments
448         }
449 
450         // grouping (for cell or database data)
451         if ( pSaveData && pSaveData->GetExistingDimensionData() )
452         {
453             shared_ptr<ScDPGroupTableData> pGroupData(new ScDPGroupTableData(pData, pDoc));
454             pSaveData->GetExistingDimensionData()->WriteToData(*pGroupData);
455             pData = pGroupData;
456         }
457 
458         // Wang Xu Ming -- 2009-8-17
459         // DataPilot Migration - Cache&&Performance
460         if ( pData )
461            SetCacheId( pData->GetCacheId());        // resets mpTableData
462         // End Comments
463 
464         mpTableData = pData;                        // after SetCacheId
465 
466         mbCreatingTableData = false;
467     }
468 
469     return mpTableData.get();
470 }
471 
472 void ScDPObject::CreateObjects()
473 {
474     // if groups are involved, create a new source with the ScDPGroupTableData
475     if ( bSettingsChanged && pSaveData && pSaveData->GetExistingDimensionData() )
476         InvalidateSource();
477 
478     if (!xSource.is())
479     {
480         //!	cache DPSource and/or Output?
481 
482         DBG_ASSERT( bAlive, "CreateObjects on non-inserted DPObject" );
483 
484         DELETEZ( pOutput );		// not valid when xSource is changed
485 
486         if ( pServDesc )
487         {
488             xSource = CreateSource( *pServDesc );
489         }
490 
491         if ( !xSource.is() )    // database or sheet data, or error in CreateSource
492 		{
493 			DBG_ASSERT( !pServDesc, "DPSource could not be created" );
494             ScDPTableData* pData = GetTableData();
495 
496             if ( pData )    // nested GetTableData calls may return NULL
497             {
498                 ScDPSource* pSource = new ScDPSource( pData );
499                 xSource = pSource;
500 
501                 if ( pSaveData && bRefresh )
502                 {
503                     pSaveData->Refresh( xSource );
504                     bRefresh = sal_False;
505                 }
506             }
507 		}
508         if ( xSource.is() && pSaveData )
509             pSaveData->WriteToSource( xSource );
510     }
511     else if (bSettingsChanged)
512     {
513         DELETEZ( pOutput );		// not valid when xSource is changed
514 
515         uno::Reference<util::XRefreshable> xRef( xSource, uno::UNO_QUERY );
516         if (xRef.is())
517         {
518             try
519             {
520                 xRef->refresh();
521             }
522             catch(uno::Exception&)
523             {
524                 DBG_ERROR("exception in refresh");
525             }
526         }
527 
528         if (pSaveData)
529             pSaveData->WriteToSource( xSource );
530     }
531 	bSettingsChanged = sal_False;
532 }
533 
534 void ScDPObject::InvalidateData()
535 {
536 	bSettingsChanged = sal_True;
537 }
538 
539 void ScDPObject::InvalidateSource()
540 {
541     Reference< XComponent > xObjectComp( xSource, UNO_QUERY );
542     if ( xObjectComp.is() )
543     {
544         try
545         {
546             xObjectComp->dispose();
547         }
548         catch( const Exception& )
549         {
550             DBG_UNHANDLED_EXCEPTION();
551         }
552     }
553     xSource = NULL;
554     mpTableData.reset();
555 }
556 
557 ScRange ScDPObject::GetNewOutputRange( sal_Bool& rOverflow )
558 {
559 	CreateOutput();				// create xSource and pOutput if not already done
560 
561 	rOverflow = pOutput->HasError();		// range overflow or exception from source
562 	if ( rOverflow )
563 		return ScRange( aOutRange.aStart );
564 	else
565 	{
566 		//	don't store the result in aOutRange, because nothing has been output yet
567 		return pOutput->GetOutputRange();
568 	}
569 }
570 
571 void ScDPObject::Output( const ScAddress& rPos )
572 {
573 	//	clear old output area
574 	pDoc->DeleteAreaTab( aOutRange.aStart.Col(), aOutRange.aStart.Row(),
575 						 aOutRange.aEnd.Col(),   aOutRange.aEnd.Row(),
576 						 aOutRange.aStart.Tab(), IDF_ALL );
577 	pDoc->RemoveFlagsTab( aOutRange.aStart.Col(), aOutRange.aStart.Row(),
578 						  aOutRange.aEnd.Col(),   aOutRange.aEnd.Row(),
579 						  aOutRange.aStart.Tab(), SC_MF_AUTO );
580 
581 	CreateOutput();				// create xSource and pOutput if not already done
582 
583     pOutput->SetPosition( rPos );
584 
585 	pOutput->Output();
586 
587 	//	aOutRange is always the range that was last output to the document
588 	aOutRange = pOutput->GetOutputRange();
589     const ScAddress& s = aOutRange.aStart;
590     const ScAddress& e = aOutRange.aEnd;
591     pDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
592 }
593 
594 const ScRange ScDPObject::GetOutputRangeByType( sal_Int32 nType )
595 {
596     CreateOutput();
597 
598     if (pOutput->HasError())
599         return ScRange(aOutRange.aStart);
600 
601     return pOutput->GetOutputRange(nType);
602 }
603 
604 sal_Bool lcl_HasButton( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
605 {
606 	return ((const ScMergeFlagAttr*)pDoc->GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG ))->HasButton();
607 }
608 
609 void ScDPObject::RefreshAfterLoad()
610 {
611 	// apply drop-down attribute, initialize nHeaderRows, without accessing the source
612 	// (button attribute must be present)
613 
614 	// simple test: block of button cells at the top, followed by an empty cell
615 
616 	SCCOL nFirstCol = aOutRange.aStart.Col();
617 	SCROW nFirstRow = aOutRange.aStart.Row();
618 	SCTAB nTab = aOutRange.aStart.Tab();
619 
620 	SCROW nInitial = 0;
621 	SCROW nOutRows = aOutRange.aEnd.Row() + 1 - aOutRange.aStart.Row();
622 	while ( nInitial + 1 < nOutRows && lcl_HasButton( pDoc, nFirstCol, nFirstRow + nInitial, nTab ) )
623 		++nInitial;
624 
625 	if ( nInitial + 1 < nOutRows &&
626 		pDoc->IsBlockEmpty( nTab, nFirstCol, nFirstRow + nInitial, nFirstCol, nFirstRow + nInitial ) &&
627 		aOutRange.aEnd.Col() > nFirstCol )
628 	{
629 		sal_Bool bFilterButton = IsSheetData();			// when available, filter button setting must be checked here
630 
631 		SCROW nSkip = bFilterButton ? 1 : 0;
632 		for (SCROW nPos=nSkip; nPos<nInitial; nPos++)
633 			pDoc->ApplyAttr( nFirstCol + 1, nFirstRow + nPos, nTab, ScMergeFlagAttr(SC_MF_AUTO) );
634 
635 		nHeaderRows = nInitial;
636 	}
637 	else
638 		nHeaderRows = 0;		// nothing found, no drop-down lists
639 }
640 
641 void ScDPObject::BuildAllDimensionMembers()
642 {
643     if (!pSaveData)
644         return;
645 
646     // #i111857# don't always create empty mpTableData for external service.
647     // #163781# Initialize all members from xSource instead.
648     if (pServDesc)
649     {
650         pSaveData->BuildAllDimensionMembersFromSource( this );
651         return;
652     }
653 
654     pSaveData->BuildAllDimensionMembers(GetTableData());
655 }
656 
657 bool ScDPObject::GetMemberNames( sal_Int32 nDim, Sequence<OUString>& rNames )
658 {
659     vector<ScDPLabelData::Member> aMembers;
660     if (!GetMembers(nDim, GetUsedHierarchy(nDim), aMembers))
661         return false;
662 
663     size_t n = aMembers.size();
664     rNames.realloc(n);
665     for (size_t i = 0; i < n; ++i)
666         rNames[i] = aMembers[i].maName;
667 
668     return true;
669 }
670 
671 bool ScDPObject::GetMembers( sal_Int32 nDim, sal_Int32 nHier, vector<ScDPLabelData::Member>& rMembers )
672 {
673     Reference< container::XNameAccess > xMembersNA;
674     if (!GetMembersNA( nDim, nHier, xMembersNA ))
675         return false;
676 
677     Reference<container::XIndexAccess> xMembersIA( new ScNameToIndexAccess(xMembersNA) );
678     sal_Int32 nCount = xMembersIA->getCount();
679     vector<ScDPLabelData::Member> aMembers;
680     aMembers.reserve(nCount);
681 
682     for (sal_Int32 i = 0; i < nCount; ++i)
683     {
684         Reference<container::XNamed> xMember(xMembersIA->getByIndex(i), UNO_QUERY);
685         ScDPLabelData::Member aMem;
686 
687         if (xMember.is())
688             aMem.maName = xMember->getName();
689 
690         Reference<beans::XPropertySet> xMemProp(xMember, UNO_QUERY);
691         if (xMemProp.is())
692         {
693             aMem.mbVisible     = ScUnoHelpFunctions::GetBoolProperty(xMemProp, OUString::createFromAscii(SC_UNO_ISVISIBL));
694             aMem.mbShowDetails = ScUnoHelpFunctions::GetBoolProperty(xMemProp, OUString::createFromAscii(SC_UNO_SHOWDETA));
695 
696             aMem.maLayoutName = ScUnoHelpFunctions::GetStringProperty(
697                 xMemProp, OUString::createFromAscii(SC_UNO_LAYOUTNAME), OUString());
698         }
699 
700         aMembers.push_back(aMem);
701     }
702     rMembers.swap(aMembers);
703     return true;
704 }
705 
706 void ScDPObject::UpdateReference( UpdateRefMode eUpdateRefMode,
707 									 const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
708 {
709 	// Output area
710 
711 	SCCOL nCol1 = aOutRange.aStart.Col();
712 	SCROW nRow1 = aOutRange.aStart.Row();
713 	SCTAB nTab1 = aOutRange.aStart.Tab();
714 	SCCOL nCol2 = aOutRange.aEnd.Col();
715 	SCROW nRow2 = aOutRange.aEnd.Row();
716 	SCTAB nTab2 = aOutRange.aEnd.Tab();
717 
718 	ScRefUpdateRes eRes =
719 		ScRefUpdate::Update( pDoc, eUpdateRefMode,
720 			rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
721 			rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz,
722 			nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
723 	if ( eRes != UR_NOTHING )
724 		SetOutRange( ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ) );
725 
726 	// sheet source data
727 
728 	if ( pSheetDesc )
729 	{
730 		nCol1 = pSheetDesc->aSourceRange.aStart.Col();
731 		nRow1 = pSheetDesc->aSourceRange.aStart.Row();
732 		nTab1 = pSheetDesc->aSourceRange.aStart.Tab();
733 		nCol2 = pSheetDesc->aSourceRange.aEnd.Col();
734 		nRow2 = pSheetDesc->aSourceRange.aEnd.Row();
735 		nTab2 = pSheetDesc->aSourceRange.aEnd.Tab();
736 
737 		eRes = ScRefUpdate::Update( pDoc, eUpdateRefMode,
738 				rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
739 				rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz,
740 				nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
741 		if ( eRes != UR_NOTHING )
742 		{
743 			ScSheetSourceDesc aNewDesc;
744 			aNewDesc.aSourceRange = ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
745 
746 			SCsCOL nDiffX = nCol1 - (SCsCOL) pSheetDesc->aSourceRange.aStart.Col();
747 			SCsROW nDiffY = nRow1 - (SCsROW) pSheetDesc->aSourceRange.aStart.Row();
748 
749 			aNewDesc.aQueryParam = pSheetDesc->aQueryParam;
750             aNewDesc.aQueryParam.nCol1 = sal::static_int_cast<SCCOL>( aNewDesc.aQueryParam.nCol1 + nDiffX );
751             aNewDesc.aQueryParam.nCol2 = sal::static_int_cast<SCCOL>( aNewDesc.aQueryParam.nCol2 + nDiffX );
752 			aNewDesc.aQueryParam.nRow1 += nDiffY;	//! used?
753 			aNewDesc.aQueryParam.nRow2 += nDiffY;	//! used?
754 			SCSIZE nEC = aNewDesc.aQueryParam.GetEntryCount();
755 			for (SCSIZE i=0; i<nEC; i++)
756 				if (aNewDesc.aQueryParam.GetEntry(i).bDoQuery)
757 					aNewDesc.aQueryParam.GetEntry(i).nField += nDiffX;
758 
759             SetSheetDesc( aNewDesc, true );     // allocates new pSheetDesc
760 		}
761 	}
762 }
763 
764 sal_Bool ScDPObject::RefsEqual( const ScDPObject& r ) const
765 {
766 	if ( aOutRange != r.aOutRange )
767 		return sal_False;
768 
769 	if ( pSheetDesc && r.pSheetDesc )
770 	{
771 		if ( pSheetDesc->aSourceRange != r.pSheetDesc->aSourceRange )
772 			return sal_False;
773 	}
774 	else if ( pSheetDesc || r.pSheetDesc )
775 	{
776 		DBG_ERROR("RefsEqual: SheetDesc set at only one object");
777 		return sal_False;
778 	}
779 
780 	return sal_True;
781 }
782 
783 void ScDPObject::WriteRefsTo( ScDPObject& r ) const
784 {
785 	r.SetOutRange( aOutRange );
786 	if ( pSheetDesc )
787         r.SetSheetDesc( *pSheetDesc, true );
788 }
789 
790 void ScDPObject::GetPositionData(const ScAddress& rPos, DataPilotTablePositionData& rPosData)
791 {
792     CreateOutput();
793     pOutput->GetPositionData(rPos, rPosData);
794 }
795 
796 bool ScDPObject::GetDataFieldPositionData(
797     const ScAddress& rPos, Sequence<sheet::DataPilotFieldFilter>& rFilters)
798 {
799     CreateOutput();
800 
801     vector<sheet::DataPilotFieldFilter> aFilters;
802     if (!pOutput->GetDataResultPositionData(aFilters, rPos))
803         return false;
804 
805     sal_Int32 n = static_cast<sal_Int32>(aFilters.size());
806     rFilters.realloc(n);
807     for (sal_Int32 i = 0; i < n; ++i)
808         rFilters[i] = aFilters[i];
809 
810     return true;
811 }
812 
813 void ScDPObject::GetDrillDownData(const ScAddress& rPos, Sequence< Sequence<Any> >& rTableData)
814 {
815     CreateOutput();
816 
817     Reference<sheet::XDrillDownDataSupplier> xDrillDownData(xSource, UNO_QUERY);
818     if (!xDrillDownData.is())
819         return;
820 
821     Sequence<sheet::DataPilotFieldFilter> filters;
822     if (!GetDataFieldPositionData(rPos, filters))
823         return;
824 
825     rTableData = xDrillDownData->getDrillDownData(filters);
826 }
827 
828 bool ScDPObject::IsDimNameInUse(const OUString& rName) const
829 {
830     if (!xSource.is())
831         return false;
832 
833     Reference<container::XNameAccess> xDims = xSource->getDimensions();
834     Sequence<OUString> aDimNames = xDims->getElementNames();
835     sal_Int32 n = aDimNames.getLength();
836     for (sal_Int32 i = 0; i < n; ++i)
837     {
838         const OUString& rDimName = aDimNames[i];
839         if (rDimName.equalsIgnoreAsciiCase(rName))
840             return true;
841 
842         Reference<beans::XPropertySet> xPropSet(xDims->getByName(rDimName), UNO_QUERY);
843         if (!xPropSet.is())
844             continue;
845 
846         OUString aLayoutName = ScUnoHelpFunctions::GetStringProperty(
847             xPropSet, OUString::createFromAscii(SC_UNO_LAYOUTNAME), OUString());
848         if (aLayoutName.equalsIgnoreAsciiCase(rName))
849             return true;
850     }
851     return false;
852 }
853 
854 String ScDPObject::GetDimName( long nDim, sal_Bool& rIsDataLayout, sal_Int32* pFlags )
855 {
856 	rIsDataLayout = sal_False;
857 	String aRet;
858 
859 	if ( xSource.is() )
860 	{
861 		uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
862 		uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
863 		long nDimCount = xDims->getCount();
864 		if ( nDim < nDimCount )
865 		{
866 			uno::Reference<uno::XInterface> xIntDim =
867 				ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
868 			uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
869 			uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
870 			if ( xDimName.is() && xDimProp.is() )
871 			{
872 				sal_Bool bData = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
873 								rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
874 				//!	error checking -- is "IsDataLayoutDimension" property required??
875 
876 				rtl::OUString aName;
877 				try
878 				{
879 					aName = xDimName->getName();
880 				}
881 				catch(uno::Exception&)
882 				{
883 				}
884 				if ( bData )
885 					rIsDataLayout = sal_True;
886 				else
887 					aRet = String( aName );
888 
889                 if (pFlags)
890                     *pFlags = ScUnoHelpFunctions::GetLongProperty( xDimProp,
891                                 rtl::OUString::createFromAscii(SC_UNO_FLAGS), 0 );
892 			}
893 		}
894 	}
895 
896 	return aRet;
897 }
898 
899 sal_Bool ScDPObject::IsDuplicated( long nDim )
900 {
901     sal_Bool bDuplicated = sal_False;
902     if ( xSource.is() )
903     {
904         uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
905         uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
906         long nDimCount = xDims->getCount();
907         if ( nDim < nDimCount )
908         {
909             uno::Reference<uno::XInterface> xIntDim =
910                 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
911             uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
912             if ( xDimProp.is() )
913             {
914                 try
915                 {
916                     uno::Any aOrigAny = xDimProp->getPropertyValue(
917                                 rtl::OUString::createFromAscii(DP_PROP_ORIGINAL) );
918                     uno::Reference<uno::XInterface> xIntOrig;
919                     if ( (aOrigAny >>= xIntOrig) && xIntOrig.is() )
920                         bDuplicated = sal_True;
921                 }
922                 catch(uno::Exception&)
923                 {
924                 }
925             }
926         }
927     }
928     return bDuplicated;
929 }
930 
931 long ScDPObject::GetDimCount()
932 {
933     long nRet = 0;
934     if ( xSource.is() )
935     {
936         try
937         {
938             uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
939             if ( xDimsName.is() )
940                 nRet = xDimsName->getElementNames().getLength();
941         }
942         catch(uno::Exception&)
943         {
944         }
945     }
946     return nRet;
947 }
948 
949 void ScDPObject::FillPageList( TypedScStrCollection& rStrings, long nField )
950 {
951 	//!	merge members access with ToggleDetails?
952 
953 	//!	convert field index to dimension index?
954 
955 	DBG_ASSERT( xSource.is(), "no source" );
956 	if ( !xSource.is() ) return;
957 
958 	uno::Reference<container::XNamed> xDim;
959 	uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
960 	uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
961 	long nIntCount = xIntDims->getCount();
962 	if ( nField < nIntCount )
963 	{
964 		uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface(
965 									xIntDims->getByIndex(nField) );
966 		xDim = uno::Reference<container::XNamed>( xIntDim, uno::UNO_QUERY );
967 	}
968 	DBG_ASSERT( xDim.is(), "dimension not found" );
969 	if ( !xDim.is() ) return;
970 
971 	uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
972 	long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
973 							rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
974 	long nLevel = 0;
975 
976 	long nHierCount = 0;
977 	uno::Reference<container::XIndexAccess> xHiers;
978 	uno::Reference<sheet::XHierarchiesSupplier> xHierSupp( xDim, uno::UNO_QUERY );
979 	if ( xHierSupp.is() )
980 	{
981 		uno::Reference<container::XNameAccess> xHiersName = xHierSupp->getHierarchies();
982 		xHiers = new ScNameToIndexAccess( xHiersName );
983 		nHierCount = xHiers->getCount();
984 	}
985 	uno::Reference<uno::XInterface> xHier;
986 	if ( nHierarchy < nHierCount )
987 		xHier = ScUnoHelpFunctions::AnyToInterface( xHiers->getByIndex(nHierarchy) );
988 	DBG_ASSERT( xHier.is(), "hierarchy not found" );
989 	if ( !xHier.is() ) return;
990 
991 	long nLevCount = 0;
992 	uno::Reference<container::XIndexAccess> xLevels;
993 	uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHier, uno::UNO_QUERY );
994 	if ( xLevSupp.is() )
995 	{
996 		uno::Reference<container::XNameAccess> xLevsName = xLevSupp->getLevels();
997 		xLevels = new ScNameToIndexAccess( xLevsName );
998 		nLevCount = xLevels->getCount();
999 	}
1000 	uno::Reference<uno::XInterface> xLevel;
1001 	if ( nLevel < nLevCount )
1002 		xLevel = ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex(nLevel) );
1003 	DBG_ASSERT( xLevel.is(), "level not found" );
1004 	if ( !xLevel.is() ) return;
1005 
1006 	uno::Reference<container::XNameAccess> xMembers;
1007 	uno::Reference<sheet::XMembersSupplier> xMbrSupp( xLevel, uno::UNO_QUERY );
1008 	if ( xMbrSupp.is() )
1009 		xMembers = xMbrSupp->getMembers();
1010 	DBG_ASSERT( xMembers.is(), "members not found" );
1011 	if ( !xMembers.is() ) return;
1012 
1013 	uno::Sequence<rtl::OUString> aNames = xMembers->getElementNames();
1014 	long nNameCount = aNames.getLength();
1015 	const rtl::OUString* pNameArr = aNames.getConstArray();
1016 	for (long nPos = 0; nPos < nNameCount; ++nPos)
1017 	{
1018         // Make sure to insert only visible members.
1019         Reference<XPropertySet> xPropSet(xMembers->getByName(pNameArr[nPos]), UNO_QUERY);
1020         sal_Bool bVisible = false;
1021         if (xPropSet.is())
1022         {
1023             Any any = xPropSet->getPropertyValue(OUString::createFromAscii(SC_UNO_ISVISIBL));
1024             any >>= bVisible;
1025         }
1026 
1027         if (bVisible)
1028         {
1029             // use the order from getElementNames
1030             TypedStrData* pData = new TypedStrData( pNameArr[nPos] );
1031             if ( !rStrings.AtInsert( rStrings.GetCount(), pData ) )
1032                 delete pData;
1033         }
1034     }
1035 
1036 	//	add "-all-" entry to the top (unsorted)
1037 	TypedStrData* pAllData = new TypedStrData( String( ScResId( SCSTR_ALL ) ) );	//! separate string? (also output)
1038 	if ( !rStrings.AtInsert( 0, pAllData ) )
1039 		delete pAllData;
1040 }
1041 
1042 void ScDPObject::GetHeaderPositionData(const ScAddress& rPos, DataPilotTableHeaderData& rData)
1043 {
1044     using namespace ::com::sun::star::sheet::DataPilotTablePositionType;
1045 
1046 	CreateOutput();				// create xSource and pOutput if not already done
1047 
1048     // Reset member values to invalid state.
1049     rData.Dimension = rData.Hierarchy = rData.Level = -1;
1050     rData.Flags = 0;
1051 
1052     DataPilotTablePositionData aPosData;
1053     pOutput->GetPositionData(rPos, aPosData);
1054     const sal_Int32 nPosType = aPosData.PositionType;
1055     if (nPosType == COLUMN_HEADER || nPosType == ROW_HEADER)
1056         aPosData.PositionData >>= rData;
1057 }
1058 
1059 // Returns sal_True on success and stores the result in rTarget
1060 sal_Bool ScDPObject::GetPivotData( ScDPGetPivotDataField& rTarget,
1061                                const std::vector< ScDPGetPivotDataField >& rFilters )
1062 {
1063     // #i117239# Exit with an error if called from creating the cache for this object
1064     // (don't create an empty pOutput object)
1065     if (mbCreatingTableData)
1066         return sal_False;
1067 
1068     CreateOutput();             // create xSource and pOutput if not already done
1069 
1070     return pOutput->GetPivotData( rTarget, rFilters );
1071 }
1072 
1073 sal_Bool ScDPObject::IsFilterButton( const ScAddress& rPos )
1074 {
1075 	CreateOutput();				// create xSource and pOutput if not already done
1076 
1077 	return pOutput->IsFilterButton( rPos );
1078 }
1079 
1080 long ScDPObject::GetHeaderDim( const ScAddress& rPos, sal_uInt16& rOrient )
1081 {
1082 	CreateOutput();				// create xSource and pOutput if not already done
1083 
1084 	return pOutput->GetHeaderDim( rPos, rOrient );
1085 }
1086 
1087 sal_Bool ScDPObject::GetHeaderDrag( const ScAddress& rPos, sal_Bool bMouseLeft, sal_Bool bMouseTop, long nDragDim,
1088 								Rectangle& rPosRect, sal_uInt16& rOrient, long& rDimPos )
1089 {
1090 	CreateOutput();				// create xSource and pOutput if not already done
1091 
1092 	return pOutput->GetHeaderDrag( rPos, bMouseLeft, bMouseTop, nDragDim, rPosRect, rOrient, rDimPos );
1093 }
1094 
1095 void ScDPObject::GetMemberResultNames( ScStrCollection& rNames, long nDimension )
1096 {
1097     CreateOutput();             // create xSource and pOutput if not already done
1098 
1099     pOutput->GetMemberResultNames( rNames, nDimension );    // used only with table data -> level not needed
1100 }
1101 
1102 bool lcl_Dequote( const String& rSource, xub_StrLen nStartPos, xub_StrLen& rEndPos, String& rResult )
1103 {
1104     // nStartPos has to point to opening quote
1105 
1106     bool bRet = false;
1107     const sal_Unicode cQuote = '\'';
1108 
1109     if ( rSource.GetChar(nStartPos) == cQuote )
1110     {
1111         rtl::OUStringBuffer aBuffer;
1112         xub_StrLen nPos = nStartPos + 1;
1113         const xub_StrLen nLen = rSource.Len();
1114 
1115         while ( nPos < nLen )
1116         {
1117             const sal_Unicode cNext = rSource.GetChar(nPos);
1118             if ( cNext == cQuote )
1119             {
1120                 if ( nPos+1 < nLen && rSource.GetChar(nPos+1) == cQuote )
1121                 {
1122                     // double quote is used for an embedded quote
1123                     aBuffer.append( cNext );    // append one quote
1124                     ++nPos;                     // skip the next one
1125                 }
1126                 else
1127                 {
1128                     // end of quoted string
1129                     rResult = aBuffer.makeStringAndClear();
1130                     rEndPos = nPos + 1;         // behind closing quote
1131                     return true;
1132                 }
1133             }
1134             else
1135                 aBuffer.append( cNext );
1136 
1137             ++nPos;
1138         }
1139         // no closing quote before the end of the string -> error (bRet still false)
1140     }
1141 
1142     return bRet;
1143 }
1144 
1145 struct ScGetPivotDataFunctionEntry
1146 {
1147     const sal_Char*         pName;
1148     sheet::GeneralFunction  eFunc;
1149 };
1150 
1151 bool lcl_ParseFunction( const String& rList, xub_StrLen nStartPos, xub_StrLen& rEndPos, sheet::GeneralFunction& rFunc )
1152 {
1153     static const ScGetPivotDataFunctionEntry aFunctions[] =
1154     {
1155         // our names
1156         { "Sum",        sheet::GeneralFunction_SUM       },
1157         { "Count",      sheet::GeneralFunction_COUNT     },
1158         { "Average",    sheet::GeneralFunction_AVERAGE   },
1159         { "Max",        sheet::GeneralFunction_MAX       },
1160         { "Min",        sheet::GeneralFunction_MIN       },
1161         { "Product",    sheet::GeneralFunction_PRODUCT   },
1162         { "CountNums",  sheet::GeneralFunction_COUNTNUMS },
1163         { "StDev",      sheet::GeneralFunction_STDEV     },
1164         { "StDevp",     sheet::GeneralFunction_STDEVP    },
1165         { "Var",        sheet::GeneralFunction_VAR       },
1166         { "VarP",       sheet::GeneralFunction_VARP      },
1167         // compatibility names
1168         { "Count Nums", sheet::GeneralFunction_COUNTNUMS },
1169         { "StdDev",     sheet::GeneralFunction_STDEV     },
1170         { "StdDevp",    sheet::GeneralFunction_STDEVP    }
1171 	};
1172 
1173     const xub_StrLen nListLen = rList.Len();
1174     while ( nStartPos < nListLen && rList.GetChar(nStartPos) == ' ' )
1175         ++nStartPos;
1176 
1177     bool bParsed = false;
1178     bool bFound = false;
1179     String aFuncStr;
1180     xub_StrLen nFuncEnd = 0;
1181     if ( nStartPos < nListLen && rList.GetChar(nStartPos) == '\'' )
1182         bParsed = lcl_Dequote( rList, nStartPos, nFuncEnd, aFuncStr );
1183     else
1184     {
1185         nFuncEnd = rList.Search( static_cast<sal_Unicode>(']'), nStartPos );
1186         if ( nFuncEnd != STRING_NOTFOUND )
1187         {
1188             aFuncStr = rList.Copy( nStartPos, nFuncEnd - nStartPos );
1189             bParsed = true;
1190         }
1191     }
1192 
1193     if ( bParsed )
1194     {
1195         aFuncStr.EraseLeadingAndTrailingChars( ' ' );
1196 
1197         const sal_Int32 nFuncCount = sizeof(aFunctions) / sizeof(aFunctions[0]);
1198         for ( sal_Int32 nFunc=0; nFunc<nFuncCount && !bFound; nFunc++ )
1199         {
1200             if ( aFuncStr.EqualsIgnoreCaseAscii( aFunctions[nFunc].pName ) )
1201             {
1202                 rFunc = aFunctions[nFunc].eFunc;
1203                 bFound = true;
1204 
1205                 while ( nFuncEnd < nListLen && rList.GetChar(nFuncEnd) == ' ' )
1206                     ++nFuncEnd;
1207                 rEndPos = nFuncEnd;
1208             }
1209         }
1210     }
1211 
1212     return bFound;
1213 }
1214 
1215 bool lcl_IsAtStart( const String& rList, const String& rSearch, sal_Int32& rMatched,
1216                     bool bAllowBracket, sheet::GeneralFunction* pFunc )
1217 {
1218     sal_Int32 nMatchList = 0;
1219     sal_Int32 nMatchSearch = 0;
1220     sal_Unicode cFirst = rList.GetChar(0);
1221     if ( cFirst == '\'' || cFirst == '[' )
1222     {
1223         // quoted string or string in brackets must match completely
1224 
1225         String aDequoted;
1226         xub_StrLen nQuoteEnd = 0;
1227         bool bParsed = false;
1228 
1229         if ( cFirst == '\'' )
1230             bParsed = lcl_Dequote( rList, 0, nQuoteEnd, aDequoted );
1231         else if ( cFirst == '[' )
1232         {
1233             // skip spaces after the opening bracket
1234 
1235             xub_StrLen nStartPos = 1;
1236             const xub_StrLen nListLen = rList.Len();
1237             while ( nStartPos < nListLen && rList.GetChar(nStartPos) == ' ' )
1238                 ++nStartPos;
1239 
1240             if ( rList.GetChar(nStartPos) == '\'' )         // quoted within the brackets?
1241             {
1242                 if ( lcl_Dequote( rList, nStartPos, nQuoteEnd, aDequoted ) )
1243                 {
1244                     // after the quoted string, there must be the closing bracket, optionally preceded by spaces,
1245                     // and/or a function name
1246                     while ( nQuoteEnd < nListLen && rList.GetChar(nQuoteEnd) == ' ' )
1247                         ++nQuoteEnd;
1248 
1249                     // semicolon separates function name
1250                     if ( nQuoteEnd < nListLen && rList.GetChar(nQuoteEnd) == ';' && pFunc )
1251                     {
1252                         xub_StrLen nFuncEnd = 0;
1253                         if ( lcl_ParseFunction( rList, nQuoteEnd + 1, nFuncEnd, *pFunc ) )
1254                             nQuoteEnd = nFuncEnd;
1255                     }
1256                     if ( nQuoteEnd < nListLen && rList.GetChar(nQuoteEnd) == ']' )
1257                     {
1258                         ++nQuoteEnd;        // include the closing bracket for the matched length
1259                         bParsed = true;
1260                     }
1261                 }
1262             }
1263             else
1264             {
1265                 // implicit quoting to the closing bracket
1266 
1267                 xub_StrLen nClosePos = rList.Search( static_cast<sal_Unicode>(']'), nStartPos );
1268                 if ( nClosePos != STRING_NOTFOUND )
1269                 {
1270                     xub_StrLen nNameEnd = nClosePos;
1271                     xub_StrLen nSemiPos = rList.Search( static_cast<sal_Unicode>(';'), nStartPos );
1272                     if ( nSemiPos != STRING_NOTFOUND && nSemiPos < nClosePos && pFunc )
1273                     {
1274                         xub_StrLen nFuncEnd = 0;
1275                         if ( lcl_ParseFunction( rList, nSemiPos + 1, nFuncEnd, *pFunc ) )
1276                             nNameEnd = nSemiPos;
1277                     }
1278 
1279                     aDequoted = rList.Copy( nStartPos, nNameEnd - nStartPos );
1280                     aDequoted.EraseTrailingChars( ' ' );        // spaces before the closing bracket or semicolon
1281                     nQuoteEnd = nClosePos + 1;
1282                     bParsed = true;
1283                 }
1284             }
1285         }
1286 
1287         if ( bParsed && ScGlobal::GetpTransliteration()->isEqual( aDequoted, rSearch ) )
1288         {
1289             nMatchList = nQuoteEnd;             // match count in the list string, including quotes
1290             nMatchSearch = rSearch.Len();
1291         }
1292     }
1293     else
1294     {
1295         // otherwise look for search string at the start of rList
1296         ScGlobal::GetpTransliteration()->equals( rList, 0, rList.Len(), nMatchList,
1297                                             rSearch, 0, rSearch.Len(), nMatchSearch );
1298     }
1299 
1300     if ( nMatchSearch == rSearch.Len() )
1301     {
1302         // search string is at start of rList - look for following space or end of string
1303 
1304         bool bValid = false;
1305         if ( sal::static_int_cast<xub_StrLen>(nMatchList) >= rList.Len() )
1306             bValid = true;
1307         else
1308         {
1309             sal_Unicode cNext = rList.GetChar(sal::static_int_cast<xub_StrLen>(nMatchList));
1310             if ( cNext == ' ' || ( bAllowBracket && cNext == '[' ) )
1311                 bValid = true;
1312         }
1313 
1314         if ( bValid )
1315         {
1316             rMatched = nMatchList;
1317             return true;
1318         }
1319     }
1320 
1321     return false;
1322 }
1323 
1324 sal_Bool ScDPObject::ParseFilters( ScDPGetPivotDataField& rTarget,
1325                                std::vector< ScDPGetPivotDataField >& rFilters,
1326                                const String& rFilterList )
1327 {
1328     // parse the string rFilterList into parameters for GetPivotData
1329 
1330     CreateObjects();            // create xSource if not already done
1331 
1332     std::vector<String> aDataNames;     // data fields (source name)
1333     std::vector<String> aGivenNames;    // data fields (compound name)
1334     std::vector<String> aFieldNames;    // column/row/data fields
1335     std::vector< uno::Sequence<rtl::OUString> > aFieldValues;
1336 
1337     //
1338     // get all the field and item names
1339     //
1340 
1341     uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1342     uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
1343     sal_Int32 nDimCount = xIntDims->getCount();
1344     for ( sal_Int32 nDim = 0; nDim<nDimCount; nDim++ )
1345     {
1346         uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nDim) );
1347         uno::Reference<container::XNamed> xDim( xIntDim, uno::UNO_QUERY );
1348         uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
1349         uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDim, uno::UNO_QUERY );
1350         sal_Bool bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1351                             rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
1352         sal_Int32 nOrient = ScUnoHelpFunctions::GetEnumProperty(
1353                             xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION),
1354                             sheet::DataPilotFieldOrientation_HIDDEN );
1355         if ( !bDataLayout )
1356         {
1357             if ( nOrient == sheet::DataPilotFieldOrientation_DATA )
1358             {
1359                 String aSourceName;
1360                 String aGivenName;
1361                 ScDPOutput::GetDataDimensionNames( aSourceName, aGivenName, xIntDim );
1362                 aDataNames.push_back( aSourceName );
1363                 aGivenNames.push_back( aGivenName );
1364             }
1365             else if ( nOrient != sheet::DataPilotFieldOrientation_HIDDEN )
1366             {
1367                 // get level names, as in ScDPOutput
1368 
1369                 uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
1370                 sal_Int32 nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
1371                                                     rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
1372                 if ( nHierarchy >= xHiers->getCount() )
1373                     nHierarchy = 0;
1374 
1375                 uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
1376                                                     xHiers->getByIndex(nHierarchy) );
1377                 uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
1378                 if ( xHierSupp.is() )
1379                 {
1380                     uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
1381                     sal_Int32 nLevCount = xLevels->getCount();
1382                     for (sal_Int32 nLev=0; nLev<nLevCount; nLev++)
1383                     {
1384                         uno::Reference<uno::XInterface> xLevel = ScUnoHelpFunctions::AnyToInterface(
1385                                                             xLevels->getByIndex(nLev) );
1386                         uno::Reference<container::XNamed> xLevNam( xLevel, uno::UNO_QUERY );
1387                         uno::Reference<sheet::XMembersSupplier> xLevSupp( xLevel, uno::UNO_QUERY );
1388                         if ( xLevNam.is() && xLevSupp.is() )
1389                         {
1390                             uno::Reference<container::XNameAccess> xMembers = xLevSupp->getMembers();
1391 
1392                             String aFieldName( xLevNam->getName() );
1393                             uno::Sequence<rtl::OUString> aMemberNames( xMembers->getElementNames() );
1394 
1395                             aFieldNames.push_back( aFieldName );
1396                             aFieldValues.push_back( aMemberNames );
1397                         }
1398                     }
1399                 }
1400             }
1401         }
1402     }
1403 
1404     //
1405     // compare and build filters
1406     //
1407 
1408     SCSIZE nDataFields = aDataNames.size();
1409     SCSIZE nFieldCount = aFieldNames.size();
1410     DBG_ASSERT( aGivenNames.size() == nDataFields && aFieldValues.size() == nFieldCount, "wrong count" );
1411 
1412     bool bError = false;
1413     bool bHasData = false;
1414     String aRemaining( rFilterList );
1415     aRemaining.EraseLeadingAndTrailingChars( ' ' );
1416     while ( aRemaining.Len() && !bError )
1417     {
1418         bool bUsed = false;
1419 
1420         // look for data field name
1421 
1422         for ( SCSIZE nDataPos=0; nDataPos<nDataFields && !bUsed; nDataPos++ )
1423         {
1424             String aFound;
1425             sal_Int32 nMatched = 0;
1426             if ( lcl_IsAtStart( aRemaining, aDataNames[nDataPos], nMatched, false, NULL ) )
1427                 aFound = aDataNames[nDataPos];
1428             else if ( lcl_IsAtStart( aRemaining, aGivenNames[nDataPos], nMatched, false, NULL ) )
1429                 aFound = aGivenNames[nDataPos];
1430 
1431             if ( aFound.Len() )
1432             {
1433                 rTarget.maFieldName = aFound;
1434                 aRemaining.Erase( 0, sal::static_int_cast<xub_StrLen>(nMatched) );
1435                 bHasData = true;
1436                 bUsed = true;
1437             }
1438         }
1439 
1440         // look for field name
1441 
1442         String aSpecField;
1443         bool bHasFieldName = false;
1444         if ( !bUsed )
1445         {
1446             sal_Int32 nMatched = 0;
1447             for ( SCSIZE nField=0; nField<nFieldCount && !bHasFieldName; nField++ )
1448             {
1449                 if ( lcl_IsAtStart( aRemaining, aFieldNames[nField], nMatched, true, NULL ) )
1450                 {
1451                     aSpecField = aFieldNames[nField];
1452                     aRemaining.Erase( 0, sal::static_int_cast<xub_StrLen>(nMatched) );
1453                     aRemaining.EraseLeadingChars( ' ' );
1454 
1455                     // field name has to be followed by item name in brackets
1456                     if ( aRemaining.GetChar(0) == '[' )
1457                     {
1458                         bHasFieldName = true;
1459                         // bUsed remains false - still need the item
1460                     }
1461                     else
1462                     {
1463                         bUsed = true;
1464                         bError = true;
1465                     }
1466                 }
1467             }
1468         }
1469 
1470         // look for field item
1471 
1472         if ( !bUsed )
1473         {
1474             bool bItemFound = false;
1475             sal_Int32 nMatched = 0;
1476             String aFoundName;
1477             String aFoundValue;
1478             sheet::GeneralFunction eFunc = sheet::GeneralFunction_NONE;
1479             sheet::GeneralFunction eFoundFunc = sheet::GeneralFunction_NONE;
1480 
1481             for ( SCSIZE nField=0; nField<nFieldCount; nField++ )
1482             {
1483                 // If a field name is given, look in that field only, otherwise in all fields.
1484                 // aSpecField is initialized from aFieldNames array, so exact comparison can be used.
1485                 if ( !bHasFieldName || aFieldNames[nField] == aSpecField )
1486                 {
1487                     const uno::Sequence<rtl::OUString>& rItems = aFieldValues[nField];
1488                     sal_Int32 nItemCount = rItems.getLength();
1489                     const rtl::OUString* pItemArr = rItems.getConstArray();
1490                     for ( sal_Int32 nItem=0; nItem<nItemCount; nItem++ )
1491                     {
1492                         if ( lcl_IsAtStart( aRemaining, pItemArr[nItem], nMatched, false, &eFunc ) )
1493                         {
1494                             if ( bItemFound )
1495                                 bError = true;      // duplicate (also across fields)
1496                             else
1497                             {
1498                                 aFoundName = aFieldNames[nField];
1499                                 aFoundValue = pItemArr[nItem];
1500                                 eFoundFunc = eFunc;
1501                                 bItemFound = true;
1502                                 bUsed = true;
1503                             }
1504                         }
1505                     }
1506                 }
1507             }
1508 
1509             if ( bItemFound && !bError )
1510             {
1511                 ScDPGetPivotDataField aField;
1512                 aField.maFieldName = aFoundName;
1513                 aField.meFunction = eFoundFunc;
1514                 aField.mbValIsStr = true;
1515                 aField.maValStr = aFoundValue;
1516                 aField.mnValNum = 0.0;
1517                 rFilters.push_back( aField );
1518 
1519                 aRemaining.Erase( 0, sal::static_int_cast<xub_StrLen>(nMatched) );
1520             }
1521         }
1522 
1523         if ( !bUsed )
1524             bError = true;
1525 
1526         aRemaining.EraseLeadingChars( ' ' );        // remove any number of spaces between entries
1527     }
1528 
1529     if ( !bError && !bHasData && aDataNames.size() == 1 )
1530     {
1531         // if there's only one data field, its name need not be specified
1532         rTarget.maFieldName = aDataNames[0];
1533         bHasData = true;
1534     }
1535 
1536     return bHasData && !bError;
1537 }
1538 
1539 void ScDPObject::ToggleDetails(const DataPilotTableHeaderData& rElemDesc, ScDPObject* pDestObj)
1540 {
1541 	CreateObjects();			// create xSource if not already done
1542 
1543 	//	find dimension name
1544 
1545 	uno::Reference<container::XNamed> xDim;
1546 	uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1547 	uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
1548 	long nIntCount = xIntDims->getCount();
1549 	if ( rElemDesc.Dimension < nIntCount )
1550 	{
1551 		uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface(
1552 									xIntDims->getByIndex(rElemDesc.Dimension) );
1553 		xDim = uno::Reference<container::XNamed>( xIntDim, uno::UNO_QUERY );
1554 	}
1555 	DBG_ASSERT( xDim.is(), "dimension not found" );
1556 	if ( !xDim.is() ) return;
1557 	String aDimName = xDim->getName();
1558 
1559 	uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
1560 	sal_Bool bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1561 						rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
1562 	if (bDataLayout)
1563 	{
1564 		//	the elements of the data layout dimension can't be found by their names
1565 		//	-> don't change anything
1566 		return;
1567 	}
1568 
1569 	//	query old state
1570 
1571 	long nHierCount = 0;
1572 	uno::Reference<container::XIndexAccess> xHiers;
1573 	uno::Reference<sheet::XHierarchiesSupplier> xHierSupp( xDim, uno::UNO_QUERY );
1574 	if ( xHierSupp.is() )
1575 	{
1576 		uno::Reference<container::XNameAccess> xHiersName = xHierSupp->getHierarchies();
1577 		xHiers = new ScNameToIndexAccess( xHiersName );
1578 		nHierCount = xHiers->getCount();
1579 	}
1580 	uno::Reference<uno::XInterface> xHier;
1581 	if ( rElemDesc.Hierarchy < nHierCount )
1582 		xHier = ScUnoHelpFunctions::AnyToInterface( xHiers->getByIndex(rElemDesc.Hierarchy) );
1583 	DBG_ASSERT( xHier.is(), "hierarchy not found" );
1584 	if ( !xHier.is() ) return;
1585 
1586 	long nLevCount = 0;
1587 	uno::Reference<container::XIndexAccess> xLevels;
1588 	uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHier, uno::UNO_QUERY );
1589 	if ( xLevSupp.is() )
1590 	{
1591 		uno::Reference<container::XNameAccess> xLevsName = xLevSupp->getLevels();
1592 		xLevels = new ScNameToIndexAccess( xLevsName );
1593 		nLevCount = xLevels->getCount();
1594 	}
1595 	uno::Reference<uno::XInterface> xLevel;
1596 	if ( rElemDesc.Level < nLevCount )
1597 		xLevel = ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex(rElemDesc.Level) );
1598 	DBG_ASSERT( xLevel.is(), "level not found" );
1599 	if ( !xLevel.is() ) return;
1600 
1601 	uno::Reference<container::XNameAccess> xMembers;
1602 	uno::Reference<sheet::XMembersSupplier> xMbrSupp( xLevel, uno::UNO_QUERY );
1603 	if ( xMbrSupp.is() )
1604 		xMembers = xMbrSupp->getMembers();
1605 
1606 	sal_Bool bFound = sal_False;
1607 	sal_Bool bShowDetails = sal_True;
1608 
1609 	if ( xMembers.is() )
1610 	{
1611 		if ( xMembers->hasByName(rElemDesc.MemberName) )
1612 		{
1613 			uno::Reference<uno::XInterface> xMemberInt = ScUnoHelpFunctions::AnyToInterface(
1614 											xMembers->getByName(rElemDesc.MemberName) );
1615 			uno::Reference<beans::XPropertySet> xMbrProp( xMemberInt, uno::UNO_QUERY );
1616 			if ( xMbrProp.is() )
1617 			{
1618 				bShowDetails = ScUnoHelpFunctions::GetBoolProperty( xMbrProp,
1619 									rtl::OUString::createFromAscii(DP_PROP_SHOWDETAILS) );
1620 				//! don't set bFound if property is unknown?
1621 				bFound = sal_True;
1622 			}
1623 		}
1624 	}
1625 
1626 	DBG_ASSERT( bFound, "member not found" );
1627 
1628 	//!	use Hierarchy and Level in SaveData !!!!
1629 
1630 	//	modify pDestObj if set, this object otherwise
1631 	ScDPSaveData* pModifyData = pDestObj ? ( pDestObj->pSaveData ) : pSaveData;
1632 	DBG_ASSERT( pModifyData, "no data?" );
1633 	if ( pModifyData )
1634 	{
1635         const String aName = rElemDesc.MemberName;
1636 		pModifyData->GetDimensionByName(aDimName)->
1637 			GetMemberByName(aName)->SetShowDetails( !bShowDetails );	// toggle
1638 
1639 		if ( pDestObj )
1640 			pDestObj->InvalidateData();		// re-init source from SaveData
1641 		else
1642 			InvalidateData();				// re-init source from SaveData
1643 	}
1644 }
1645 
1646 long lcl_FindName( const rtl::OUString& rString, const uno::Reference<container::XNameAccess>& xCollection )
1647 {
1648 	if ( xCollection.is() )
1649 	{
1650 		uno::Sequence<rtl::OUString> aSeq = xCollection->getElementNames();
1651 		long nCount = aSeq.getLength();
1652 		const rtl::OUString* pArr = aSeq.getConstArray();
1653 		for (long nPos=0; nPos<nCount; nPos++)
1654 			if ( pArr[nPos] == rString )
1655 				return nPos;
1656 	}
1657 	return -1;		// not found
1658 }
1659 
1660 sal_uInt16 lcl_FirstSubTotal( const uno::Reference<beans::XPropertySet>& xDimProp )		// PIVOT_FUNC mask
1661 {
1662 	uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDimProp, uno::UNO_QUERY );
1663 	if ( xDimProp.is() && xDimSupp.is() )
1664 	{
1665 		uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
1666 		long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
1667 								rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
1668 		if ( nHierarchy >= xHiers->getCount() )
1669 			nHierarchy = 0;
1670 
1671 		uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
1672 									xHiers->getByIndex(nHierarchy) );
1673 		uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
1674 		if ( xHierSupp.is() )
1675 		{
1676 			uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
1677 			uno::Reference<uno::XInterface> xLevel =
1678 				ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex( 0 ) );
1679 			uno::Reference<beans::XPropertySet> xLevProp( xLevel, uno::UNO_QUERY );
1680 			if ( xLevProp.is() )
1681 			{
1682 				uno::Any aSubAny;
1683 				try
1684 				{
1685 					aSubAny = xLevProp->getPropertyValue(
1686 							rtl::OUString::createFromAscii(DP_PROP_SUBTOTALS) );
1687 				}
1688 				catch(uno::Exception&)
1689 				{
1690 				}
1691 				uno::Sequence<sheet::GeneralFunction> aSeq;
1692 				if ( aSubAny >>= aSeq )
1693 				{
1694 					sal_uInt16 nMask = 0;
1695 					const sheet::GeneralFunction* pArray = aSeq.getConstArray();
1696 					long nCount = aSeq.getLength();
1697 					for (long i=0; i<nCount; i++)
1698 						nMask |= ScDataPilotConversion::FunctionBit(pArray[i]);
1699 					return nMask;
1700 				}
1701 			}
1702 		}
1703 	}
1704 
1705 	DBG_ERROR("FirstSubTotal: NULL");
1706 	return 0;
1707 }
1708 
1709 sal_uInt16 lcl_CountBits( sal_uInt16 nBits )
1710 {
1711 	if (!nBits) return 0;
1712 
1713 	sal_uInt16 nCount = 0;
1714 	sal_uInt16 nMask = 1;
1715 	for (sal_uInt16 i=0; i<16; i++)
1716 	{
1717 		if ( nBits & nMask )
1718 			++nCount;
1719 		nMask <<= 1;
1720 	}
1721 	return nCount;
1722 }
1723 
1724 void lcl_FillOldFields( ScPivotFieldVector& rFields,
1725 							const uno::Reference<sheet::XDimensionsSupplier>& xSource,
1726 							sal_uInt16 nOrient, SCCOL nColAdd, bool bAddData )
1727 {
1728 	bool bDataFound = false;
1729 	rFields.clear();
1730 
1731 	//!	merge multiple occurences (data field with different functions)
1732 	//!	force data field in one dimension
1733 
1734     std::vector< long > aPos;
1735 
1736 	uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1737 	uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
1738 	long nDimCount = xDims->getCount();
1739     for (long nDim=0; nDim < nDimCount; nDim++)
1740 	{
1741 		uno::Reference<uno::XInterface> xIntDim =
1742 			ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
1743 		uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
1744 		long nDimOrient = ScUnoHelpFunctions::GetEnumProperty(
1745 							xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION),
1746 							sheet::DataPilotFieldOrientation_HIDDEN );
1747 		if ( xDimProp.is() && nDimOrient == nOrient )
1748 		{
1749 			sal_uInt16 nMask = 0;
1750 			if ( nOrient == sheet::DataPilotFieldOrientation_DATA )
1751 			{
1752 				sheet::GeneralFunction eFunc = (sheet::GeneralFunction)ScUnoHelpFunctions::GetEnumProperty(
1753 											xDimProp, rtl::OUString::createFromAscii(DP_PROP_FUNCTION),
1754 											sheet::GeneralFunction_NONE );
1755 				if ( eFunc == sheet::GeneralFunction_AUTO )
1756 				{
1757 					//!	test for numeric data
1758 					eFunc = sheet::GeneralFunction_SUM;
1759 				}
1760 				nMask = ScDataPilotConversion::FunctionBit(eFunc);
1761 			}
1762 			else
1763 				nMask = lcl_FirstSubTotal( xDimProp );		// from first hierarchy
1764 
1765 			sal_Bool bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1766 									rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
1767 			uno::Any aOrigAny;
1768 			try
1769 			{
1770 				aOrigAny = xDimProp->getPropertyValue(
1771 								rtl::OUString::createFromAscii(DP_PROP_ORIGINAL) );
1772 			}
1773 			catch(uno::Exception&)
1774 			{
1775 			}
1776 
1777 			long nDupSource = -1;
1778 			uno::Reference<uno::XInterface> xIntOrig = ScUnoHelpFunctions::AnyToInterface( aOrigAny );
1779 			if ( xIntOrig.is() )
1780 			{
1781 				uno::Reference<container::XNamed> xNameOrig( xIntOrig, uno::UNO_QUERY );
1782 				if ( xNameOrig.is() )
1783 					nDupSource = lcl_FindName( xNameOrig->getName(), xDimsName );
1784 			}
1785 
1786 			bool bDupUsed = false;
1787 			if ( nDupSource >= 0 )
1788 			{
1789 				//	add function bit to previous entry
1790 
1791 				SCsCOL nCompCol;
1792 				if ( bDataLayout )
1793 					nCompCol = PIVOT_DATA_FIELD;
1794 				else
1795 					nCompCol = static_cast<SCsCOL>(nDupSource)+nColAdd;		//! seek source column from name
1796 
1797 				for (ScPivotFieldVector::iterator aIt = rFields.begin(), aEnd = rFields.end(); (aIt != aEnd) && !bDupUsed; ++aIt)
1798 					if ( aIt->nCol == nCompCol )
1799 					{
1800 						//	add to previous column only if new bits aren't already set there
1801 						if ( ( aIt->nFuncMask & nMask ) == 0 )
1802 						{
1803 							aIt->nFuncMask |= nMask;
1804 							aIt->nFuncCount = lcl_CountBits( aIt->nFuncMask );
1805 							bDupUsed = true;
1806 						}
1807 					}
1808 			}
1809 
1810 			if ( !bDupUsed )		// also for duplicated dim if original has different orientation
1811 			{
1812                 rFields.resize( rFields.size() + 1 );
1813                 ScPivotField& rField = rFields.back();
1814 
1815 				if ( bDataLayout )
1816 				{
1817 					rField.nCol = PIVOT_DATA_FIELD;
1818 					bDataFound = true;
1819 				}
1820 				else if ( nDupSource >= 0 )		// if source was not found (different orientation)
1821 					rField.nCol = static_cast<SCsCOL>(nDupSource)+nColAdd;		//! seek from name
1822 				else
1823 					rField.nCol = static_cast<SCsCOL>(nDim)+nColAdd;	//! seek source column from name
1824 
1825 				rField.nFuncMask = nMask;
1826 				rField.nFuncCount = lcl_CountBits( nMask );
1827 
1828                 aPos.push_back( ScUnoHelpFunctions::GetLongProperty( xDimProp,
1829 									rtl::OUString::createFromAscii(DP_PROP_POSITION) ) );
1830 
1831                 try
1832                 {
1833                     if( nOrient == sheet::DataPilotFieldOrientation_DATA )
1834                         xDimProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_REFVALUE ) ) )
1835                             >>= rFields.back().maFieldRef;
1836                 }
1837                 catch( uno::Exception& )
1838                 {
1839                 }
1840 			}
1841 		}
1842 	}
1843 
1844 	//	sort by getPosition() value
1845     size_t nSize = aPos.size();
1846 	for (size_t i=0; i+1<nSize; i++)
1847 	{
1848 		for (size_t j=0; j+i+1<nSize; j++)
1849             if ( aPos[j+1] < aPos[j] )
1850 			{
1851                 std::swap( aPos[j], aPos[j+1] );
1852                 std::swap( rFields[j], rFields[j+1] );
1853 			}
1854 	}
1855 
1856 	if ( bAddData && !bDataFound )
1857 	{
1858         rFields.resize( rFields.size() + 1 );
1859         ScPivotField& rField = rFields.back();
1860 		rField.nCol = PIVOT_DATA_FIELD;
1861 		rField.nFuncMask = 0;
1862 		rField.nFuncCount = 0;
1863 	}
1864 }
1865 
1866 sal_Bool ScDPObject::FillOldParam(ScPivotParam& rParam) const
1867 {
1868 	((ScDPObject*)this)->CreateObjects();		// xSource is needed for field numbers
1869 
1870 	rParam.nCol = aOutRange.aStart.Col();
1871 	rParam.nRow = aOutRange.aStart.Row();
1872 	rParam.nTab = aOutRange.aStart.Tab();
1873 	// ppLabelArr / nLabels is not changed
1874 
1875 	SCCOL nColAdd = 0;
1876 	bool bAddData = ( lcl_GetDataGetOrientation( xSource ) == sheet::DataPilotFieldOrientation_HIDDEN );
1877     lcl_FillOldFields( rParam.maPageArr, xSource, sheet::DataPilotFieldOrientation_PAGE,   nColAdd, false );
1878 	lcl_FillOldFields( rParam.maColArr,  xSource, sheet::DataPilotFieldOrientation_COLUMN, nColAdd, bAddData );
1879 	lcl_FillOldFields( rParam.maRowArr,  xSource, sheet::DataPilotFieldOrientation_ROW,    nColAdd, false );
1880 	lcl_FillOldFields( rParam.maDataArr, xSource, sheet::DataPilotFieldOrientation_DATA,   nColAdd, false );
1881 
1882 	uno::Reference<beans::XPropertySet> xProp( xSource, uno::UNO_QUERY );
1883 	if (xProp.is())
1884 	{
1885 		try
1886 		{
1887 			rParam.bMakeTotalCol = ScUnoHelpFunctions::GetBoolProperty( xProp,
1888 						rtl::OUString::createFromAscii(DP_PROP_COLUMNGRAND), sal_True );
1889 			rParam.bMakeTotalRow = ScUnoHelpFunctions::GetBoolProperty( xProp,
1890 						rtl::OUString::createFromAscii(DP_PROP_ROWGRAND), sal_True );
1891 
1892 			// following properties may be missing for external sources
1893 			rParam.bIgnoreEmptyRows = ScUnoHelpFunctions::GetBoolProperty( xProp,
1894 						rtl::OUString::createFromAscii(DP_PROP_IGNOREEMPTY) );
1895 			rParam.bDetectCategories = ScUnoHelpFunctions::GetBoolProperty( xProp,
1896 						rtl::OUString::createFromAscii(DP_PROP_REPEATIFEMPTY) );
1897 		}
1898 		catch(uno::Exception&)
1899 		{
1900 			// no error
1901 		}
1902 	}
1903 	return sal_True;
1904 }
1905 
1906 void lcl_FillLabelData( ScDPLabelData& rData, const uno::Reference< beans::XPropertySet >& xDimProp )
1907 {
1908 	uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDimProp, uno::UNO_QUERY );
1909 	if ( xDimProp.is() && xDimSupp.is() )
1910 	{
1911 		uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
1912 		long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
1913 								rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
1914 		if ( nHierarchy >= xHiers->getCount() )
1915 			nHierarchy = 0;
1916         rData.mnUsedHier = nHierarchy;
1917 
1918 		uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
1919 									xHiers->getByIndex(nHierarchy) );
1920 
1921 		uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
1922 		if ( xHierSupp.is() )
1923 		{
1924 			uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
1925 			uno::Reference<uno::XInterface> xLevel =
1926 				ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex( 0 ) );
1927 			uno::Reference<beans::XPropertySet> xLevProp( xLevel, uno::UNO_QUERY );
1928 			if ( xLevProp.is() )
1929             {
1930                 rData.mbShowAll = ScUnoHelpFunctions::GetBoolProperty( xLevProp,
1931 									rtl::OUString::createFromAscii(DP_PROP_SHOWEMPTY) );
1932 
1933                 try
1934                 {
1935                     xLevProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_SORTING ) ) )
1936                         >>= rData.maSortInfo;
1937                     xLevProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_LAYOUT ) ) )
1938                         >>= rData.maLayoutInfo;
1939                     xLevProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_AUTOSHOW ) ) )
1940                         >>= rData.maShowInfo;
1941                 }
1942                 catch(uno::Exception&)
1943                 {
1944                 }
1945             }
1946 		}
1947 	}
1948 }
1949 
1950 sal_Bool ScDPObject::FillLabelData(ScPivotParam& rParam)
1951 {
1952     rParam.maLabelArray.clear();
1953 
1954 	((ScDPObject*)this)->CreateObjects();
1955 
1956 	uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1957 	uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
1958 	long nDimCount = xDims->getCount();
1959 	if ( nDimCount > MAX_LABELS )
1960 		nDimCount = MAX_LABELS;
1961 	if (!nDimCount)
1962 		return sal_False;
1963 
1964 	for (long nDim=0; nDim < nDimCount; nDim++)
1965 	{
1966 		String aFieldName;
1967 		uno::Reference<uno::XInterface> xIntDim =
1968 			ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
1969 		uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
1970 		uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
1971 
1972 		if ( xDimName.is() && xDimProp.is() )
1973 		{
1974 			sal_Bool bDuplicated = sal_False;
1975 			sal_Bool bData = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1976 							rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
1977 			//!	error checking -- is "IsDataLayoutDimension" property required??
1978 
1979 			try
1980 			{
1981 				aFieldName = String( xDimName->getName() );
1982 
1983 				uno::Any aOrigAny = xDimProp->getPropertyValue(
1984 							rtl::OUString::createFromAscii(DP_PROP_ORIGINAL) );
1985 				uno::Reference<uno::XInterface> xIntOrig;
1986 				if ( (aOrigAny >>= xIntOrig) && xIntOrig.is() )
1987 					bDuplicated = sal_True;
1988 			}
1989 			catch(uno::Exception&)
1990 			{
1991 			}
1992 
1993             OUString aLayoutName = ScUnoHelpFunctions::GetStringProperty(
1994                 xDimProp, OUString::createFromAscii(SC_UNO_LAYOUTNAME), OUString());
1995 
1996 			if ( aFieldName.Len() && !bData && !bDuplicated )
1997 			{
1998                 SCsCOL nCol = static_cast< SCsCOL >( nDim );           //! ???
1999                 bool bIsValue = true;                               //! check
2000 
2001                 ScDPLabelData aNewLabel(aFieldName, nCol, bIsValue);
2002                 aNewLabel.maLayoutName = aLayoutName;
2003                 GetHierarchies(nDim, aNewLabel.maHiers);
2004                 GetMembers(nDim, GetUsedHierarchy(nDim), aNewLabel.maMembers);
2005                 lcl_FillLabelData(aNewLabel, xDimProp);
2006                 aNewLabel.mnFlags = ScUnoHelpFunctions::GetLongProperty( xDimProp,
2007                                         rtl::OUString::createFromAscii(SC_UNO_FLAGS), 0 );
2008                 rParam.maLabelArray.push_back(aNewLabel);
2009 			}
2010 		}
2011 	}
2012 
2013 	return sal_True;
2014 }
2015 
2016 sal_Bool ScDPObject::GetHierarchiesNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xHiers )
2017 {
2018     sal_Bool bRet = sal_False;
2019     uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
2020     uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
2021     if( xIntDims.is() )
2022     {
2023         uno::Reference<sheet::XHierarchiesSupplier> xHierSup(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
2024         if (xHierSup.is())
2025         {
2026             xHiers.set( xHierSup->getHierarchies() );
2027             bRet = xHiers.is();
2028         }
2029     }
2030     return bRet;
2031 }
2032 
2033 sal_Bool ScDPObject::GetHierarchies( sal_Int32 nDim, uno::Sequence< rtl::OUString >& rHiers )
2034 {
2035     sal_Bool bRet = sal_False;
2036     uno::Reference< container::XNameAccess > xHiersNA;
2037     if( GetHierarchiesNA( nDim, xHiersNA ) )
2038     {
2039         rHiers = xHiersNA->getElementNames();
2040         bRet = sal_True;
2041     }
2042     return bRet;
2043 }
2044 
2045 sal_Int32 ScDPObject::GetUsedHierarchy( sal_Int32 nDim )
2046 {
2047     sal_Int32 nHier = 0;
2048     uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
2049     uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
2050     uno::Reference<beans::XPropertySet> xDim(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
2051     if (xDim.is())
2052         nHier = ScUnoHelpFunctions::GetLongProperty( xDim, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( SC_UNO_USEDHIER ) ) );
2053     return nHier;
2054 }
2055 
2056 sal_Bool ScDPObject::GetMembersNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xMembers )
2057 {
2058     return GetMembersNA( nDim, GetUsedHierarchy( nDim ), xMembers );
2059 }
2060 
2061 sal_Bool ScDPObject::GetMembersNA( sal_Int32 nDim, sal_Int32 nHier, uno::Reference< container::XNameAccess >& xMembers )
2062 {
2063     sal_Bool bRet = sal_False;
2064     uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
2065     uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
2066     uno::Reference<beans::XPropertySet> xDim(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
2067     if (xDim.is())
2068     {
2069         uno::Reference<sheet::XHierarchiesSupplier> xHierSup(xDim, uno::UNO_QUERY);
2070         if (xHierSup.is())
2071         {
2072             uno::Reference<container::XIndexAccess> xHiers(new ScNameToIndexAccess(xHierSup->getHierarchies()));
2073             uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHiers->getByIndex(nHier), uno::UNO_QUERY );
2074             if ( xLevSupp.is() )
2075             {
2076                 uno::Reference<container::XIndexAccess> xLevels(new ScNameToIndexAccess( xLevSupp->getLevels()));
2077                 if (xLevels.is())
2078                 {
2079                     sal_Int32 nLevCount = xLevels->getCount();
2080                     if (nLevCount > 0)
2081                     {
2082                         uno::Reference<sheet::XMembersSupplier> xMembSupp( xLevels->getByIndex(0), uno::UNO_QUERY );
2083                         if ( xMembSupp.is() )
2084                         {
2085                             xMembers.set(xMembSupp->getMembers());
2086                             bRet = sal_True;
2087                         }
2088                     }
2089                 }
2090             }
2091         }
2092     }
2093     return bRet;
2094 }
2095 
2096 //------------------------------------------------------------------------
2097 //	convert old pivot tables into new datapilot tables
2098 
2099 String lcl_GetDimName( const uno::Reference<sheet::XDimensionsSupplier>& xSource, long nDim )
2100 {
2101 	rtl::OUString aName;
2102 	if ( xSource.is() )
2103 	{
2104 		uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
2105 		uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
2106 		long nDimCount = xDims->getCount();
2107 		if ( nDim < nDimCount )
2108 		{
2109 			uno::Reference<uno::XInterface> xIntDim =
2110 				ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
2111 			uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
2112 			if (xDimName.is())
2113 			{
2114 				try
2115 				{
2116 					aName = xDimName->getName();
2117 				}
2118 				catch(uno::Exception&)
2119 				{
2120 				}
2121 			}
2122 		}
2123 	}
2124 	return aName;
2125 }
2126 
2127 // static
2128 void ScDPObject::ConvertOrientation( ScDPSaveData& rSaveData,
2129 							const ScPivotFieldVector& rFields, sal_uInt16 nOrient,
2130 							ScDocument* pDoc, SCROW nRow, SCTAB nTab,
2131 							const uno::Reference<sheet::XDimensionsSupplier>& xSource,
2132 							bool bOldDefaults,
2133 							const ScPivotFieldVector* pRefColFields,
2134                             const ScPivotFieldVector* pRefRowFields,
2135                             const ScPivotFieldVector* pRefPageFields )
2136 {
2137 	//	pDoc or xSource must be set
2138 	DBG_ASSERT( pDoc || xSource.is(), "missing string source" );
2139 
2140 	String aDocStr;
2141 	ScDPSaveDimension* pDim;
2142 
2143 	for (ScPivotFieldVector::const_iterator aIt = rFields.begin(), aEnd = rFields.end(); aIt != aEnd; ++aIt)
2144 	{
2145 		SCCOL nCol = aIt->nCol;
2146 		sal_uInt16 nFuncs = aIt->nFuncMask;
2147         const sheet::DataPilotFieldReference& rFieldRef = aIt->maFieldRef;
2148 
2149 		if ( nCol == PIVOT_DATA_FIELD )
2150 			pDim = rSaveData.GetDataLayoutDimension();
2151 		else
2152 		{
2153 			if ( pDoc )
2154 				pDoc->GetString( nCol, nRow, nTab, aDocStr );
2155 			else
2156 				aDocStr = lcl_GetDimName( xSource, nCol );	// cols must start at 0
2157 
2158 			if ( aDocStr.Len() )
2159 				pDim = rSaveData.GetDimensionByName(aDocStr);
2160 			else
2161 				pDim = NULL;
2162 		}
2163 
2164 		if ( pDim )
2165 		{
2166 			if ( nOrient == sheet::DataPilotFieldOrientation_DATA )		// set summary function
2167 			{
2168 				//	generate an individual entry for each function
2169 				bool bFirst = true;
2170 
2171                 //  if a dimension is used for column/row/page and data,
2172 				//	use duplicated dimensions for all data occurrences
2173 				if (pRefColFields)
2174                     for (ScPivotFieldVector::const_iterator aRefIt = pRefColFields->begin(), aRefEnd = pRefColFields->end(); bFirst && (aRefIt != aRefEnd); ++aRefIt)
2175 						if (aRefIt->nCol == nCol)
2176 							bFirst = false;
2177 				if (pRefRowFields)
2178                     for (ScPivotFieldVector::const_iterator aRefIt = pRefRowFields->begin(), aRefEnd = pRefRowFields->end(); bFirst && (aRefIt != aRefEnd); ++aRefIt)
2179 						if (aRefIt->nCol == nCol)
2180 							bFirst = false;
2181                 if (pRefPageFields)
2182                     for (ScPivotFieldVector::const_iterator aRefIt = pRefPageFields->begin(), aRefEnd = pRefPageFields->end(); bFirst && (aRefIt != aRefEnd); ++aRefIt)
2183 						if (aRefIt->nCol == nCol)
2184 							bFirst = false;
2185 
2186 				//	if set via api, a data column may occur several times
2187 				//	(if the function hasn't been changed yet) -> also look for duplicate data column
2188                 for (ScPivotFieldVector::const_iterator aRefIt = rFields.begin(); bFirst && (aRefIt != aIt); ++aRefIt)
2189 					if (aRefIt->nCol == nCol)
2190 						bFirst = false;
2191 
2192 				sal_uInt16 nMask = 1;
2193 				for (sal_uInt16 nBit=0; nBit<16; nBit++)
2194 				{
2195 					if ( nFuncs & nMask )
2196 					{
2197 						sheet::GeneralFunction eFunc = ScDataPilotConversion::FirstFunc( nMask );
2198                         ScDPSaveDimension* pCurrDim = bFirst ? pDim : rSaveData.DuplicateDimension(pDim->GetName());
2199                         pCurrDim->SetOrientation( nOrient );
2200                         pCurrDim->SetFunction( sal::static_int_cast<sal_uInt16>(eFunc) );
2201 
2202                         if( rFieldRef.ReferenceType == sheet::DataPilotFieldReferenceType::NONE )
2203                             pCurrDim->SetReferenceValue( 0 );
2204                         else
2205                             pCurrDim->SetReferenceValue( &rFieldRef );
2206 
2207                         bFirst = false;
2208 					}
2209 					nMask *= 2;
2210 				}
2211 			}
2212 			else											// set SubTotals
2213 			{
2214 				pDim->SetOrientation( nOrient );
2215 
2216 				sal_uInt16 nFuncArray[16];
2217 				sal_uInt16 nFuncCount = 0;
2218 				sal_uInt16 nMask = 1;
2219 				for (sal_uInt16 nBit=0; nBit<16; nBit++)
2220 				{
2221 					if ( nFuncs & nMask )
2222                         nFuncArray[nFuncCount++] = sal::static_int_cast<sal_uInt16>(ScDataPilotConversion::FirstFunc( nMask ));
2223 					nMask *= 2;
2224 				}
2225 				pDim->SetSubTotals( nFuncCount, nFuncArray );
2226 
2227 				//	ShowEmpty was implicit in old tables,
2228 				//	must be set for data layout dimension (not accessible in dialog)
2229 				if ( bOldDefaults || nCol == PIVOT_DATA_FIELD )
2230 					pDim->SetShowEmpty( sal_True );
2231 			}
2232 		}
2233 	}
2234 }
2235 
2236 // static
2237 bool ScDPObject::IsOrientationAllowed( sal_uInt16 nOrient, sal_Int32 nDimFlags )
2238 {
2239     bool bAllowed = true;
2240     switch (nOrient)
2241     {
2242         case sheet::DataPilotFieldOrientation_PAGE:
2243             bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_PAGE_ORIENTATION ) == 0;
2244             break;
2245         case sheet::DataPilotFieldOrientation_COLUMN:
2246             bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_COLUMN_ORIENTATION ) == 0;
2247             break;
2248         case sheet::DataPilotFieldOrientation_ROW:
2249             bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_ROW_ORIENTATION ) == 0;
2250             break;
2251         case sheet::DataPilotFieldOrientation_DATA:
2252             bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_DATA_ORIENTATION ) == 0;
2253             break;
2254         default:
2255             {
2256                 // allowed to remove from previous orientation
2257             }
2258     }
2259     return bAllowed;
2260 }
2261 
2262 // -----------------------------------------------------------------------
2263 
2264 //	static
2265 sal_Bool ScDPObject::HasRegisteredSources()
2266 {
2267 	sal_Bool bFound = sal_False;
2268 
2269 	uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
2270 	uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
2271 	if ( xEnAc.is() )
2272 	{
2273 		uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
2274 										rtl::OUString::createFromAscii( SCDPSOURCE_SERVICE ) );
2275 		if ( xEnum.is() && xEnum->hasMoreElements() )
2276 			bFound = sal_True;
2277 	}
2278 
2279 	return bFound;
2280 }
2281 
2282 //	static
2283 uno::Sequence<rtl::OUString> ScDPObject::GetRegisteredSources()
2284 {
2285 	long nCount = 0;
2286 	uno::Sequence<rtl::OUString> aSeq(0);
2287 
2288 	//	use implementation names...
2289 
2290 	uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
2291 	uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
2292 	if ( xEnAc.is() )
2293 	{
2294 		uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
2295 										rtl::OUString::createFromAscii( SCDPSOURCE_SERVICE ) );
2296 		if ( xEnum.is() )
2297 		{
2298 			while ( xEnum->hasMoreElements() )
2299 			{
2300 				uno::Any aAddInAny = xEnum->nextElement();
2301 //				if ( aAddInAny.getReflection()->getTypeClass() == TypeClass_INTERFACE )
2302 				{
2303 					uno::Reference<uno::XInterface> xIntFac;
2304 					aAddInAny >>= xIntFac;
2305 					if ( xIntFac.is() )
2306 					{
2307 						uno::Reference<lang::XServiceInfo> xInfo( xIntFac, uno::UNO_QUERY );
2308 						if ( xInfo.is() )
2309 						{
2310 							rtl::OUString sName = xInfo->getImplementationName();
2311 
2312 							aSeq.realloc( nCount+1 );
2313 							aSeq.getArray()[nCount] = sName;
2314 							++nCount;
2315 						}
2316 					}
2317 				}
2318 			}
2319 		}
2320 	}
2321 
2322 	return aSeq;
2323 }
2324 
2325 // use getContext from addincol.cxx
2326 uno::Reference<uno::XComponentContext> getContext(uno::Reference<lang::XMultiServiceFactory> xMSF);
2327 
2328 //	static
2329 uno::Reference<sheet::XDimensionsSupplier> ScDPObject::CreateSource( const ScDPServiceDesc& rDesc )
2330 {
2331 	rtl::OUString aImplName = rDesc.aServiceName;
2332 	uno::Reference<sheet::XDimensionsSupplier> xRet = NULL;
2333 
2334 	uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
2335 	uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
2336 	if ( xEnAc.is() )
2337 	{
2338 		uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
2339 										rtl::OUString::createFromAscii( SCDPSOURCE_SERVICE ) );
2340 		if ( xEnum.is() )
2341 		{
2342 			while ( xEnum->hasMoreElements() && !xRet.is() )
2343 			{
2344 				uno::Any aAddInAny = xEnum->nextElement();
2345 //				if ( aAddInAny.getReflection()->getTypeClass() == TypeClass_INTERFACE )
2346 				{
2347 					uno::Reference<uno::XInterface> xIntFac;
2348 					aAddInAny >>= xIntFac;
2349 					if ( xIntFac.is() )
2350 					{
2351 						uno::Reference<lang::XServiceInfo> xInfo( xIntFac, uno::UNO_QUERY );
2352 						if ( xInfo.is() && xInfo->getImplementationName() == aImplName )
2353 						{
2354 							try
2355 							{
2356                                 // #i113160# try XSingleComponentFactory in addition to (old) XSingleServiceFactory,
2357                                 // passing the context to the component (see ScUnoAddInCollection::Initialize)
2358 
2359                                 uno::Reference<uno::XInterface> xInterface;
2360                                 uno::Reference<uno::XComponentContext> xCtx = getContext(xManager);
2361                                 uno::Reference<lang::XSingleComponentFactory> xCFac( xIntFac, uno::UNO_QUERY );
2362                                 if (xCtx.is() && xCFac.is())
2363                                     xInterface = xCFac->createInstanceWithContext(xCtx);
2364 
2365                                 if (!xInterface.is())
2366                                 {
2367                                     uno::Reference<lang::XSingleServiceFactory> xFac( xIntFac, uno::UNO_QUERY );
2368                                     if ( xFac.is() )
2369                                         xInterface = xFac->createInstance();
2370                                 }
2371 
2372 								uno::Reference<lang::XInitialization> xInit( xInterface, uno::UNO_QUERY );
2373 								if (xInit.is())
2374 								{
2375 									//	initialize
2376 									uno::Sequence<uno::Any> aSeq(4);
2377 									uno::Any* pArray = aSeq.getArray();
2378 									pArray[0] <<= rtl::OUString( rDesc.aParSource );
2379 									pArray[1] <<= rtl::OUString( rDesc.aParName );
2380 									pArray[2] <<= rtl::OUString( rDesc.aParUser );
2381 									pArray[3] <<= rtl::OUString( rDesc.aParPass );
2382 									xInit->initialize( aSeq );
2383 								}
2384 								xRet = uno::Reference<sheet::XDimensionsSupplier>( xInterface, uno::UNO_QUERY );
2385 							}
2386 							catch(uno::Exception&)
2387 							{
2388 							}
2389 						}
2390 					}
2391 				}
2392 			}
2393 		}
2394 	}
2395 
2396 	return xRet;
2397 }
2398 
2399 // ----------------------------------------------------------------------------
2400 
2401 ScDPCollection::ScDPCollection(ScDocument* pDocument) :
2402 	pDoc( pDocument )
2403 {
2404 }
2405 
2406 ScDPCollection::ScDPCollection(const ScDPCollection& r) :
2407 	ScCollection(r),
2408     pDoc(r.pDoc)
2409 {
2410 }
2411 
2412 ScDPCollection::~ScDPCollection()
2413 {
2414 }
2415 
2416 ScDataObject* ScDPCollection::Clone() const
2417 {
2418 	return new ScDPCollection(*this);
2419 }
2420 
2421 void ScDPCollection::DeleteOnTab( SCTAB nTab )
2422 {
2423     sal_uInt16 nPos = 0;
2424     while ( nPos < nCount )
2425     {
2426         // look for output positions on the deleted sheet
2427         if ( static_cast<const ScDPObject*>(At(nPos))->GetOutRange().aStart.Tab() == nTab )
2428             AtFree(nPos);
2429         else
2430             ++nPos;
2431     }
2432 }
2433 
2434 void ScDPCollection::UpdateReference( UpdateRefMode eUpdateRefMode,
2435 										 const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
2436 {
2437 	for (sal_uInt16 i=0; i<nCount; i++)
2438 		((ScDPObject*)At(i))->UpdateReference( eUpdateRefMode, r, nDx, nDy, nDz );
2439 }
2440 
2441 sal_Bool ScDPCollection::RefsEqual( const ScDPCollection& r ) const
2442 {
2443 	if ( nCount != r.nCount )
2444 		return sal_False;
2445 
2446 	for (sal_uInt16 i=0; i<nCount; i++)
2447 		if ( ! ((const ScDPObject*)At(i))->RefsEqual( *((const ScDPObject*)r.At(i)) ) )
2448 			return sal_False;
2449 
2450 	return sal_True;	// all equal
2451 }
2452 
2453 void ScDPCollection::WriteRefsTo( ScDPCollection& r ) const
2454 {
2455 	if ( nCount == r.nCount )
2456 	{
2457 		//!	assert equal names?
2458 		for (sal_uInt16 i=0; i<nCount; i++)
2459 			((const ScDPObject*)At(i))->WriteRefsTo( *((ScDPObject*)r.At(i)) );
2460 	}
2461 	else
2462     {
2463         // #i8180# If data pilot tables were deleted with their sheet,
2464         // this collection contains extra entries that must be restored.
2465         // Matching objects are found by their names.
2466 
2467         DBG_ASSERT( nCount >= r.nCount, "WriteRefsTo: missing entries in document" );
2468         for (sal_uInt16 nSourcePos=0; nSourcePos<nCount; nSourcePos++)
2469         {
2470             const ScDPObject* pSourceObj = static_cast<const ScDPObject*>(At(nSourcePos));
2471             String aName = pSourceObj->GetName();
2472             bool bFound = false;
2473             for (sal_uInt16 nDestPos=0; nDestPos<r.nCount && !bFound; nDestPos++)
2474             {
2475                 ScDPObject* pDestObj = static_cast<ScDPObject*>(r.At(nDestPos));
2476                 if ( pDestObj->GetName() == aName )
2477                 {
2478                     pSourceObj->WriteRefsTo( *pDestObj );     // found object, copy refs
2479                     bFound = true;
2480                 }
2481             }
2482             if ( !bFound )
2483             {
2484                 // none found, re-insert deleted object (see ScUndoDataPilot::Undo)
2485 
2486                 ScDPObject* pDestObj = new ScDPObject( *pSourceObj );
2487                 pDestObj->SetAlive(sal_True);
2488                 if ( !r.InsertNewTable(pDestObj) )
2489                 {
2490                     DBG_ERROR("cannot insert DPObject");
2491                     DELETEZ( pDestObj );
2492                 }
2493             }
2494         }
2495         DBG_ASSERT( nCount == r.nCount, "WriteRefsTo: couldn't restore all entries" );
2496     }
2497 }
2498 
2499 ScDPObject* ScDPCollection::GetByName(const String& rName) const
2500 {
2501     for (sal_uInt16 i=0; i<nCount; i++)
2502         if (static_cast<const ScDPObject*>(pItems[i])->GetName() == rName)
2503             return static_cast<ScDPObject*>(pItems[i]);
2504     return NULL;
2505 }
2506 
2507 String ScDPCollection::CreateNewName( sal_uInt16 nMin ) const
2508 {
2509 	String aBase( RTL_CONSTASCII_USTRINGPARAM( "Pivot" ) );
2510 	//!	from Resource?
2511 
2512 	for (sal_uInt16 nAdd=0; nAdd<=nCount; nAdd++)	//	nCount+1 tries
2513 	{
2514 		String aNewName = aBase;
2515 		aNewName += String::CreateFromInt32( nMin + nAdd );
2516 		sal_Bool bFound = sal_False;
2517 		for (sal_uInt16 i=0; i<nCount && !bFound; i++)
2518 			if (((const ScDPObject*)pItems[i])->GetName() == aNewName)
2519 				bFound = sal_True;
2520 		if (!bFound)
2521 			return aNewName;			// found unused Name
2522 	}
2523 	return String();					// should not happen
2524 }
2525 
2526 
2527 
2528 // Wang Xu Ming -- 2009-8-17
2529 // DataPilot Migration - Cache&&Performance
2530 long ScDPObject::GetCacheId() const
2531 {
2532     if ( GetSaveData() )
2533         return GetSaveData()->GetCacheId();
2534     else
2535         return mnCacheId;
2536 }
2537 sal_uLong ScDPObject::RefreshCache()
2538 {
2539     if ( pServDesc )
2540     {
2541         // cache table isn't used for external service - do nothing, no error
2542         return 0;
2543     }
2544 
2545     CreateObjects();
2546     sal_uLong nErrId = 0;
2547     if ( pSheetDesc)
2548         nErrId =  pSheetDesc->CheckValidate( pDoc );
2549     if ( nErrId == 0 )
2550     {
2551         long nOldId = GetCacheId();
2552         long nNewId = pDoc->GetNewDPObjectCacheId();
2553         if ( nOldId >= 0 )
2554             pDoc->RemoveDPObjectCache( nOldId );
2555 
2556         ScDPTableDataCache* pCache  = NULL;
2557         if ( pSheetDesc )
2558             pCache = pSheetDesc->CreateCache( pDoc, nNewId );
2559         else if ( pImpDesc )
2560             pCache = pImpDesc->CreateCache( pDoc, nNewId );
2561 
2562         if ( pCache == NULL )
2563         {
2564             //cache failed
2565             DBG_ASSERT( pCache , " pCache == NULL" );
2566             return STR_ERR_DATAPILOTSOURCE;
2567         }
2568 
2569         nNewId = pCache->GetId();
2570 
2571         bRefresh = sal_True;
2572         ScDPCollection* pDPCollection = pDoc->GetDPCollection();
2573         sal_uInt16 nCount = pDPCollection->GetCount();
2574         for (sal_uInt16 i=0; i<nCount; i++)
2575         { //set new cache id
2576             if ( (*pDPCollection)[i]->GetCacheId() == nOldId  )
2577             {
2578                 (*pDPCollection)[i]->SetCacheId( nNewId );
2579                 (*pDPCollection)[i]->SetRefresh();
2580 
2581             }
2582         }
2583         DBG_ASSERT( GetCacheId() >= 0, " GetCacheId() >= 0 " );
2584     }
2585     return nErrId;
2586 }
2587 void ScDPObject::SetCacheId( long nCacheId )
2588 {
2589     if ( GetCacheId() != nCacheId )
2590     {
2591         InvalidateSource();
2592         if ( GetSaveData() )
2593             GetSaveData()->SetCacheId( nCacheId );
2594 
2595         mnCacheId = nCacheId;
2596     }
2597 }
2598 const ScDPTableDataCache* ScDPObject::GetCache() const
2599 {
2600     return pDoc->GetDPObjectCache( GetCacheId() );
2601 }
2602 // End Comments
2603 
2604 void ScDPCollection::FreeTable(ScDPObject* pDPObj)
2605 {
2606     const ScRange& rOutRange = pDPObj->GetOutRange();
2607     const ScAddress& s = rOutRange.aStart;
2608     const ScAddress& e = rOutRange.aEnd;
2609     pDoc->RemoveFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
2610     Free(pDPObj);
2611 }
2612 
2613 bool ScDPCollection::InsertNewTable(ScDPObject* pDPObj)
2614 {
2615     bool bSuccess = Insert(pDPObj);
2616     if (bSuccess)
2617     {
2618         const ScRange& rOutRange = pDPObj->GetOutRange();
2619         const ScAddress& s = rOutRange.aStart;
2620         const ScAddress& e = rOutRange.aEnd;
2621         pDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
2622     }
2623     return bSuccess;
2624 }
2625 
2626 bool ScDPCollection::HasDPTable(SCCOL nCol, SCROW nRow, SCTAB nTab) const
2627 {
2628     const ScMergeFlagAttr* pMergeAttr = static_cast<const ScMergeFlagAttr*>(
2629             pDoc->GetAttr(nCol, nRow, nTab, ATTR_MERGE_FLAG));
2630 
2631     if (!pMergeAttr)
2632         return false;
2633 
2634     return pMergeAttr->HasDPTable();
2635 }
2636 
2637 
2638