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