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