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