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