Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "dpobject.hxx"
21 : #include "dptabsrc.hxx"
22 : #include "dpsave.hxx"
23 : #include "dpdimsave.hxx"
24 : #include "dpoutput.hxx"
25 : #include "dpshttab.hxx"
26 : #include "dpsdbtab.hxx"
27 : #include "dpgroup.hxx"
28 : #include "document.hxx"
29 : #include "rechead.hxx"
30 : #include "pivot.hxx"
31 : #include "dapiuno.hxx"
32 : #include "miscuno.hxx"
33 : #include "scerrors.hxx"
34 : #include "refupdat.hxx"
35 : #include "scresid.hxx"
36 : #include "sc.hrc"
37 : #include "attrib.hxx"
38 : #include "scitems.hxx"
39 : #include "unonames.hxx"
40 : #include "dpglobal.hxx"
41 : #include "globstr.hrc"
42 : #include "queryentry.hxx"
43 : #include "dputil.hxx"
44 :
45 : #include <com/sun/star/beans/XPropertySet.hpp>
46 : #include <com/sun/star/sdb/XCompletedExecution.hpp>
47 : #include <com/sun/star/sdbc/DataType.hpp>
48 : #include <com/sun/star/sdbc/XResultSetMetaData.hpp>
49 : #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
50 : #include <com/sun/star/sdbc/XRow.hpp>
51 : #include <com/sun/star/sdbc/XRowSet.hpp>
52 : #include <com/sun/star/sheet/GeneralFunction.hpp>
53 : #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
54 : #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
55 : #include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
56 : #include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
57 : #include <com/sun/star/sheet/DataPilotTablePositionData.hpp>
58 : #include <com/sun/star/sheet/DataPilotTablePositionType.hpp>
59 : #include <com/sun/star/sheet/DimensionFlags.hpp>
60 : #include <com/sun/star/task/InteractionHandler.hpp>
61 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
62 : #include <com/sun/star/lang/XSingleServiceFactory.hpp>
63 : #include <com/sun/star/lang/XSingleComponentFactory.hpp>
64 : #include <com/sun/star/lang/XInitialization.hpp>
65 : #include <com/sun/star/container/XContentEnumerationAccess.hpp>
66 : #include <com/sun/star/sheet/XDrillDownDataSupplier.hpp>
67 :
68 : #include <comphelper/processfactory.hxx>
69 : #include <comphelper/string.hxx>
70 : #include <comphelper/types.hxx>
71 : #include <o3tl/ptr_container.hxx>
72 : #include <sal/macros.h>
73 : #include <tools/debug.hxx>
74 : #include <tools/diagnose_ex.h>
75 : #include <svl/zforlist.hxx>
76 : #include <vcl/msgbox.hxx>
77 :
78 : #include <utility>
79 : #include <vector>
80 : #include <memory>
81 :
82 : #include <boost/unordered_map.hpp>
83 :
84 : using namespace com::sun::star;
85 : using ::std::vector;
86 : using ::std::unary_function;
87 : using ::boost::shared_ptr;
88 : using ::com::sun::star::uno::Sequence;
89 : using ::com::sun::star::uno::Reference;
90 : using ::com::sun::star::uno::UNO_QUERY;
91 : using ::com::sun::star::uno::Any;
92 : using ::com::sun::star::uno::Exception;
93 : using ::com::sun::star::lang::XComponent;
94 : using ::com::sun::star::sheet::DataPilotTableHeaderData;
95 : using ::com::sun::star::sheet::DataPilotTablePositionData;
96 : using ::com::sun::star::sheet::XDimensionsSupplier;
97 : using ::com::sun::star::beans::XPropertySet;
98 :
99 : #define SC_SERVICE_ROWSET "com.sun.star.sdb.RowSet"
100 :
101 : #define SC_DBPROP_DATASOURCENAME "DataSourceName"
102 : #define SC_DBPROP_COMMAND "Command"
103 : #define SC_DBPROP_COMMANDTYPE "CommandType"
104 :
105 : #define SCDPSOURCE_SERVICE "com.sun.star.sheet.DataPilotSource"
106 :
107 : namespace {
108 :
109 : /**
110 : * Database connection implementation for UNO database API. Note that in
111 : * the UNO database API, column index is 1-based, whereas the interface
112 : * requires that column index be 0-based.
113 : */
114 0 : class DBConnector : public ScDPCache::DBConnector
115 : {
116 : ScDPCache& mrCache;
117 :
118 : uno::Reference<sdbc::XRowSet> mxRowSet;
119 : uno::Reference<sdbc::XRow> mxRow;
120 : uno::Reference<sdbc::XResultSetMetaData> mxMetaData;
121 : Date maNullDate;
122 :
123 : public:
124 : DBConnector(ScDPCache& rCache, const uno::Reference<sdbc::XRowSet>& xRowSet, const Date& rNullDate);
125 :
126 : bool isValid() const;
127 :
128 : virtual void getValue(long nCol, ScDPItemData &rData, short& rNumType) const SAL_OVERRIDE;
129 : virtual OUString getColumnLabel(long nCol) const SAL_OVERRIDE;
130 : virtual long getColumnCount() const SAL_OVERRIDE;
131 : virtual bool first() SAL_OVERRIDE;
132 : virtual bool next() SAL_OVERRIDE;
133 : virtual void finish() SAL_OVERRIDE;
134 : };
135 :
136 0 : DBConnector::DBConnector(ScDPCache& rCache, const uno::Reference<sdbc::XRowSet>& xRowSet, const Date& rNullDate) :
137 0 : mrCache(rCache), mxRowSet(xRowSet), maNullDate(rNullDate)
138 : {
139 0 : Reference<sdbc::XResultSetMetaDataSupplier> xMetaSupp(mxRowSet, UNO_QUERY);
140 0 : if (xMetaSupp.is())
141 0 : mxMetaData = xMetaSupp->getMetaData();
142 :
143 0 : mxRow.set(mxRowSet, UNO_QUERY);
144 0 : }
145 :
146 0 : bool DBConnector::isValid() const
147 : {
148 0 : return mxRowSet.is() && mxRow.is() && mxMetaData.is();
149 : }
150 :
151 0 : bool DBConnector::first()
152 : {
153 0 : return mxRowSet->first();
154 : }
155 :
156 0 : bool DBConnector::next()
157 : {
158 0 : return mxRowSet->next();
159 : }
160 :
161 0 : void DBConnector::finish()
162 : {
163 0 : mxRowSet->beforeFirst();
164 0 : }
165 :
166 0 : long DBConnector::getColumnCount() const
167 : {
168 0 : return mxMetaData->getColumnCount();
169 : }
170 :
171 0 : OUString DBConnector::getColumnLabel(long nCol) const
172 : {
173 0 : return mxMetaData->getColumnLabel(nCol+1);
174 : }
175 :
176 0 : void DBConnector::getValue(long nCol, ScDPItemData &rData, short& rNumType) const
177 : {
178 0 : rNumType = NUMBERFORMAT_NUMBER;
179 0 : sal_Int32 nType = mxMetaData->getColumnType(nCol+1);
180 :
181 : try
182 : {
183 0 : double fValue = 0.0;
184 0 : switch (nType)
185 : {
186 : case sdbc::DataType::BIT:
187 : case sdbc::DataType::BOOLEAN:
188 : {
189 0 : rNumType = NUMBERFORMAT_LOGICAL;
190 0 : fValue = mxRow->getBoolean(nCol+1) ? 1 : 0;
191 0 : rData.SetValue(fValue);
192 0 : break;
193 : }
194 : case sdbc::DataType::TINYINT:
195 : case sdbc::DataType::SMALLINT:
196 : case sdbc::DataType::INTEGER:
197 : case sdbc::DataType::BIGINT:
198 : case sdbc::DataType::FLOAT:
199 : case sdbc::DataType::REAL:
200 : case sdbc::DataType::DOUBLE:
201 : case sdbc::DataType::NUMERIC:
202 : case sdbc::DataType::DECIMAL:
203 : {
204 : //! do the conversion here?
205 0 : fValue = mxRow->getDouble(nCol+1);
206 0 : rData.SetValue(fValue);
207 0 : break;
208 : }
209 : case sdbc::DataType::DATE:
210 : {
211 0 : rNumType = NUMBERFORMAT_DATE;
212 :
213 0 : util::Date aDate = mxRow->getDate(nCol+1);
214 0 : fValue = Date(aDate.Day, aDate.Month, aDate.Year) - maNullDate;
215 0 : rData.SetValue(fValue);
216 0 : break;
217 : }
218 : case sdbc::DataType::TIME:
219 : {
220 0 : rNumType = NUMBERFORMAT_TIME;
221 :
222 0 : util::Time aTime = mxRow->getTime(nCol+1);
223 0 : fValue = aTime.Hours / static_cast<double>(::tools::Time::hourPerDay) +
224 0 : aTime.Minutes / static_cast<double>(::tools::Time::minutePerDay) +
225 0 : aTime.Seconds / static_cast<double>(::tools::Time::secondPerDay) +
226 0 : aTime.NanoSeconds / static_cast<double>(::tools::Time::nanoSecPerDay);
227 0 : rData.SetValue(fValue);
228 0 : break;
229 : }
230 : case sdbc::DataType::TIMESTAMP:
231 : {
232 0 : rNumType = NUMBERFORMAT_DATETIME;
233 :
234 0 : util::DateTime aStamp = mxRow->getTimestamp(nCol+1);
235 0 : fValue = ( Date( aStamp.Day, aStamp.Month, aStamp.Year ) - maNullDate ) +
236 0 : aStamp.Hours / static_cast<double>(::tools::Time::hourPerDay) +
237 0 : aStamp.Minutes / static_cast<double>(::tools::Time::minutePerDay) +
238 0 : aStamp.Seconds / static_cast<double>(::tools::Time::secondPerDay) +
239 0 : aStamp.NanoSeconds / static_cast<double>(::tools::Time::nanoSecPerDay);
240 0 : rData.SetValue(fValue);
241 0 : break;
242 : }
243 : case sdbc::DataType::CHAR:
244 : case sdbc::DataType::VARCHAR:
245 : case sdbc::DataType::LONGVARCHAR:
246 : case sdbc::DataType::SQLNULL:
247 : case sdbc::DataType::BINARY:
248 : case sdbc::DataType::VARBINARY:
249 : case sdbc::DataType::LONGVARBINARY:
250 : default:
251 0 : rData.SetString(mrCache.InternString(mxRow->getString(nCol+1)));
252 : }
253 : }
254 0 : catch (uno::Exception&)
255 : {
256 0 : rData.SetEmpty();
257 : }
258 0 : }
259 :
260 : }
261 :
262 0 : sal_uInt16 lcl_GetDataGetOrientation( const uno::Reference<sheet::XDimensionsSupplier>& xSource )
263 : {
264 0 : long nRet = sheet::DataPilotFieldOrientation_HIDDEN;
265 0 : if ( xSource.is() )
266 : {
267 0 : uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
268 0 : uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
269 0 : long nIntCount = xIntDims->getCount();
270 0 : bool bFound = false;
271 0 : for (long nIntDim=0; nIntDim<nIntCount && !bFound; nIntDim++)
272 : {
273 : uno::Reference<uno::XInterface> xIntDim =
274 0 : ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nIntDim) );
275 0 : uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
276 0 : if ( xDimProp.is() )
277 : {
278 : bFound = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
279 0 : OUString(SC_UNO_DP_ISDATALAYOUT) );
280 : //! error checking -- is "IsDataLayoutDimension" property required??
281 0 : if (bFound)
282 : nRet = ScUnoHelpFunctions::GetEnumProperty(
283 : xDimProp, OUString(SC_UNO_DP_ORIENTATION),
284 0 : sheet::DataPilotFieldOrientation_HIDDEN );
285 : }
286 0 : }
287 : }
288 0 : return static_cast< sal_uInt16 >( nRet );
289 : }
290 :
291 0 : ScDPServiceDesc::ScDPServiceDesc(
292 : const OUString& rServ, const OUString& rSrc, const OUString& rNam,
293 : const OUString& rUser, const OUString& rPass ) :
294 : aServiceName( rServ ),
295 : aParSource( rSrc ),
296 : aParName( rNam ),
297 : aParUser( rUser ),
298 0 : aParPass( rPass ) {}
299 :
300 0 : bool ScDPServiceDesc::operator== ( const ScDPServiceDesc& rOther ) const
301 : {
302 0 : return aServiceName == rOther.aServiceName &&
303 0 : aParSource == rOther.aParSource &&
304 0 : aParName == rOther.aParName &&
305 0 : aParUser == rOther.aParUser &&
306 0 : aParPass == rOther.aParPass;
307 : }
308 :
309 96 : ScDPObject::ScDPObject( ScDocument* pD ) :
310 : pDoc( pD ),
311 : pSaveData( NULL ),
312 : pSheetDesc( NULL ),
313 : pImpDesc( NULL ),
314 : pServDesc( NULL ),
315 : mpTableData(static_cast<ScDPTableData*>(NULL)),
316 : pOutput( NULL ),
317 : mnAutoFormatIndex( 65535 ),
318 : nHeaderRows( 0 ),
319 : mbHeaderLayout(false),
320 : bAllowMove(false),
321 : bSettingsChanged(false),
322 96 : mbEnableGetPivotData(true)
323 : {
324 96 : }
325 :
326 226 : ScDPObject::ScDPObject(const ScDPObject& r) :
327 : pDoc( r.pDoc ),
328 : pSaveData( NULL ),
329 : aTableName( r.aTableName ),
330 : aTableTag( r.aTableTag ),
331 : aOutRange( r.aOutRange ),
332 : pSheetDesc( NULL ),
333 : pImpDesc( NULL ),
334 : pServDesc( NULL ),
335 : mpTableData(static_cast<ScDPTableData*>(NULL)),
336 : pOutput( NULL ),
337 : mnAutoFormatIndex( r.mnAutoFormatIndex ),
338 : nHeaderRows( r.nHeaderRows ),
339 : mbHeaderLayout( r.mbHeaderLayout ),
340 : bAllowMove(false),
341 : bSettingsChanged(false),
342 226 : mbEnableGetPivotData(r.mbEnableGetPivotData)
343 : {
344 226 : if (r.pSaveData)
345 226 : pSaveData = new ScDPSaveData(*r.pSaveData);
346 226 : if (r.pSheetDesc)
347 226 : pSheetDesc = new ScSheetSourceDesc(*r.pSheetDesc);
348 226 : if (r.pImpDesc)
349 0 : pImpDesc = new ScImportSourceDesc(*r.pImpDesc);
350 226 : if (r.pServDesc)
351 0 : pServDesc = new ScDPServiceDesc(*r.pServDesc);
352 : // xSource (and pOutput) is not copied
353 226 : }
354 :
355 636 : ScDPObject::~ScDPObject()
356 : {
357 318 : Clear();
358 318 : }
359 :
360 0 : ScDPObject& ScDPObject::operator= (const ScDPObject& r)
361 : {
362 0 : Clear();
363 :
364 0 : pDoc = r.pDoc;
365 0 : aTableName = r.aTableName;
366 0 : aTableTag = r.aTableTag;
367 0 : aOutRange = r.aOutRange;
368 0 : mnAutoFormatIndex = r.mnAutoFormatIndex;
369 0 : nHeaderRows = r.nHeaderRows;
370 0 : mbHeaderLayout = r.mbHeaderLayout;
371 0 : bAllowMove = false;
372 0 : bSettingsChanged = false;
373 0 : mbEnableGetPivotData = r.mbEnableGetPivotData;
374 :
375 0 : if (r.pSaveData)
376 0 : pSaveData = new ScDPSaveData(*r.pSaveData);
377 0 : if (r.pSheetDesc)
378 0 : pSheetDesc = new ScSheetSourceDesc(*r.pSheetDesc);
379 0 : if (r.pImpDesc)
380 0 : pImpDesc = new ScImportSourceDesc(*r.pImpDesc);
381 0 : if (r.pServDesc)
382 0 : pServDesc = new ScDPServiceDesc(*r.pServDesc);
383 :
384 0 : return *this;
385 : }
386 :
387 372 : void ScDPObject::EnableGetPivotData(bool b)
388 : {
389 372 : mbEnableGetPivotData = b;
390 372 : }
391 :
392 58 : void ScDPObject::SetAllowMove(bool bSet)
393 : {
394 58 : bAllowMove = bSet;
395 58 : }
396 :
397 166 : void ScDPObject::SetSaveData(const ScDPSaveData& rData)
398 : {
399 166 : if ( pSaveData != &rData ) // API implementation modifies the original SaveData object
400 : {
401 152 : delete pSaveData;
402 152 : pSaveData = new ScDPSaveData( rData );
403 : }
404 :
405 166 : InvalidateData(); // re-init source from SaveData
406 166 : }
407 :
408 16 : void ScDPObject::SetHeaderLayout (bool bUseGrid)
409 : {
410 16 : mbHeaderLayout = bUseGrid;
411 16 : }
412 :
413 228 : void ScDPObject::SetOutRange(const ScRange& rRange)
414 : {
415 228 : aOutRange = rRange;
416 :
417 228 : if ( pOutput )
418 132 : pOutput->SetPosition( rRange.aStart );
419 228 : }
420 :
421 3321 : const ScRange& ScDPObject::GetOutRange() const
422 : {
423 3321 : return aOutRange;
424 : }
425 :
426 146 : void ScDPObject::SetSheetDesc(const ScSheetSourceDesc& rDesc, bool /*bFromRefUpdate*/)
427 : {
428 146 : if ( pSheetDesc && rDesc == *pSheetDesc )
429 146 : return; // nothing to do
430 :
431 146 : DELETEZ( pImpDesc );
432 146 : DELETEZ( pServDesc );
433 :
434 146 : delete pSheetDesc;
435 146 : pSheetDesc = new ScSheetSourceDesc(rDesc);
436 :
437 : // make valid QueryParam
438 :
439 146 : const ScRange& rSrcRange = pSheetDesc->GetSourceRange();
440 146 : ScQueryParam aParam = pSheetDesc->GetQueryParam();
441 146 : aParam.nCol1 = rSrcRange.aStart.Col();
442 146 : aParam.nRow1 = rSrcRange.aStart.Row();
443 146 : aParam.nCol2 = rSrcRange.aEnd.Col();
444 146 : aParam.nRow2 = rSrcRange.aEnd.Row();
445 146 : aParam.bHasHeader = true;
446 146 : pSheetDesc->SetQueryParam(aParam);
447 :
448 146 : ClearTableData(); // new source must be created
449 : }
450 :
451 0 : void ScDPObject::SetImportDesc(const ScImportSourceDesc& rDesc)
452 : {
453 0 : if ( pImpDesc && rDesc == *pImpDesc )
454 0 : return; // nothing to do
455 :
456 0 : DELETEZ( pSheetDesc );
457 0 : DELETEZ( pServDesc );
458 :
459 0 : delete pImpDesc;
460 0 : pImpDesc = new ScImportSourceDesc(rDesc);
461 :
462 0 : ClearTableData(); // new source must be created
463 : }
464 :
465 0 : void ScDPObject::SetServiceData(const ScDPServiceDesc& rDesc)
466 : {
467 0 : if ( pServDesc && rDesc == *pServDesc )
468 0 : return; // nothing to do
469 :
470 0 : DELETEZ( pSheetDesc );
471 0 : DELETEZ( pImpDesc );
472 :
473 0 : delete pServDesc;
474 0 : pServDesc = new ScDPServiceDesc(rDesc);
475 :
476 0 : ClearTableData(); // new source must be created
477 : }
478 :
479 0 : void ScDPObject::WriteSourceDataTo( ScDPObject& rDest ) const
480 : {
481 0 : if ( pSheetDesc )
482 0 : rDest.SetSheetDesc( *pSheetDesc );
483 0 : else if ( pImpDesc )
484 0 : rDest.SetImportDesc( *pImpDesc );
485 0 : else if ( pServDesc )
486 0 : rDest.SetServiceData( *pServDesc );
487 :
488 : // name/tag are not source data, but needed along with source data
489 :
490 0 : rDest.aTableName = aTableName;
491 0 : rDest.aTableTag = aTableTag;
492 0 : }
493 :
494 0 : void ScDPObject::WriteTempDataTo( ScDPObject& rDest ) const
495 : {
496 0 : rDest.nHeaderRows = nHeaderRows;
497 0 : }
498 :
499 280 : bool ScDPObject::IsSheetData() const
500 : {
501 280 : return ( pSheetDesc != NULL );
502 : }
503 :
504 102 : void ScDPObject::SetName(const OUString& rNew)
505 : {
506 102 : aTableName = rNew;
507 102 : }
508 :
509 68 : void ScDPObject::SetTag(const OUString& rNew)
510 : {
511 68 : aTableTag = rNew;
512 68 : }
513 :
514 0 : bool ScDPObject::IsDataDescriptionCell(const ScAddress& rPos)
515 : {
516 0 : if (!pSaveData)
517 0 : return false;
518 :
519 0 : long nDataDimCount = pSaveData->GetDataDimensionCount();
520 0 : if (nDataDimCount != 1)
521 : // There has to be exactly one data dimension for the description to
522 : // appear at top-left corner.
523 0 : return false;
524 :
525 0 : CreateOutput();
526 0 : ScRange aTabRange = pOutput->GetOutputRange(sheet::DataPilotOutputRangeType::TABLE);
527 0 : return (rPos == aTabRange.aStart);
528 : }
529 :
530 836 : uno::Reference<sheet::XDimensionsSupplier> ScDPObject::GetSource()
531 : {
532 836 : CreateObjects();
533 836 : return xSource;
534 : }
535 :
536 1364 : void ScDPObject::CreateOutput()
537 : {
538 1364 : CreateObjects();
539 1364 : if (!pOutput)
540 : {
541 174 : bool bFilterButton = IsSheetData() && pSaveData && pSaveData->GetFilterButton();
542 174 : pOutput = new ScDPOutput( pDoc, xSource, aOutRange.aStart, bFilterButton );
543 174 : pOutput->SetHeaderLayout ( mbHeaderLayout );
544 :
545 174 : long nOldRows = nHeaderRows;
546 174 : nHeaderRows = pOutput->GetHeaderRows();
547 :
548 174 : if ( bAllowMove && nHeaderRows != nOldRows )
549 : {
550 0 : long nDiff = nOldRows - nHeaderRows;
551 0 : if ( nOldRows == 0 )
552 0 : --nDiff;
553 0 : if ( nHeaderRows == 0 )
554 0 : ++nDiff;
555 :
556 0 : long nNewRow = aOutRange.aStart.Row() + nDiff;
557 0 : if ( nNewRow < 0 )
558 0 : nNewRow = 0;
559 :
560 0 : ScAddress aStart( aOutRange.aStart );
561 0 : aStart.SetRow(nNewRow);
562 0 : pOutput->SetPosition( aStart );
563 :
564 : //! modify aOutRange?
565 :
566 0 : bAllowMove = false; // use only once
567 : }
568 : }
569 1364 : }
570 :
571 : namespace {
572 :
573 : class DisableGetPivotData
574 : {
575 : ScDPObject& mrDPObj;
576 : bool mbOldState;
577 : public:
578 186 : DisableGetPivotData(ScDPObject& rObj, bool bOld) : mrDPObj(rObj), mbOldState(bOld)
579 : {
580 186 : mrDPObj.EnableGetPivotData(false);
581 186 : }
582 :
583 186 : ~DisableGetPivotData()
584 : {
585 186 : mrDPObj.EnableGetPivotData(mbOldState);
586 186 : }
587 : };
588 :
589 0 : class FindIntersectingTable : std::unary_function<ScDPObject, bool>
590 : {
591 : ScRange maRange;
592 : public:
593 0 : FindIntersectingTable(const ScRange& rRange) : maRange(rRange) {}
594 :
595 0 : bool operator() (const ScDPObject& rObj) const
596 : {
597 0 : return maRange.Intersects(rObj.GetOutRange());
598 : }
599 : };
600 :
601 : class FindIntersetingTableByColumns : std::unary_function<ScDPObject, bool>
602 : {
603 : SCCOL mnCol1;
604 : SCCOL mnCol2;
605 : SCROW mnRow;
606 : SCTAB mnTab;
607 : public:
608 0 : FindIntersetingTableByColumns(SCCOL nCol1, SCCOL nCol2, SCROW nRow, SCTAB nTab) :
609 0 : mnCol1(nCol1), mnCol2(nCol2), mnRow(nRow), mnTab(nTab) {}
610 :
611 0 : bool operator() (const ScDPObject& rObj) const
612 : {
613 0 : const ScRange& rRange = rObj.GetOutRange();
614 0 : if (mnTab != rRange.aStart.Tab())
615 : // Not on this sheet.
616 0 : return false;
617 :
618 0 : if (rRange.aEnd.Row() < mnRow)
619 : // This table is above the row. It's safe.
620 0 : return false;
621 :
622 0 : if (mnCol1 <= rRange.aStart.Col() && rRange.aEnd.Col() <= mnCol2)
623 : // This table is fully enclosed in this column range.
624 0 : return false;
625 :
626 0 : if (rRange.aEnd.Col() < mnCol1 || mnCol2 < rRange.aStart.Col())
627 : // This table is entirely outside this column range.
628 0 : return false;
629 :
630 : // This table must be intersected by this column range.
631 0 : return true;
632 : }
633 : };
634 :
635 : class FindIntersectingTableByRows : std::unary_function<ScDPObject, bool>
636 : {
637 : SCCOL mnCol;
638 : SCROW mnRow1;
639 : SCROW mnRow2;
640 : SCTAB mnTab;
641 : public:
642 0 : FindIntersectingTableByRows(SCCOL nCol, SCROW nRow1, SCROW nRow2, SCTAB nTab) :
643 0 : mnCol(nCol), mnRow1(nRow1), mnRow2(nRow2), mnTab(nTab) {}
644 :
645 0 : bool operator() (const ScDPObject& rObj) const
646 : {
647 0 : const ScRange& rRange = rObj.GetOutRange();
648 0 : if (mnTab != rRange.aStart.Tab())
649 : // Not on this sheet.
650 0 : return false;
651 :
652 0 : if (rRange.aEnd.Col() < mnCol)
653 : // This table is to the left of the column. It's safe.
654 0 : return false;
655 :
656 0 : if (mnRow1 <= rRange.aStart.Row() && rRange.aEnd.Row() <= mnRow2)
657 : // This table is fully enclosed in this row range.
658 0 : return false;
659 :
660 0 : if (rRange.aEnd.Row() < mnRow1 || mnRow2 < rRange.aStart.Row())
661 : // This table is entirely outside this row range.
662 0 : return false;
663 :
664 : // This table must be intersected by this row range.
665 0 : return true;
666 : }
667 : };
668 :
669 286 : class AccumulateOutputRanges : std::unary_function<ScDPObject, void>
670 : {
671 : ScRangeList maRanges;
672 : SCTAB mnTab;
673 : public:
674 143 : AccumulateOutputRanges(SCTAB nTab) : mnTab(nTab) {}
675 143 : AccumulateOutputRanges(const AccumulateOutputRanges& r) : maRanges(r.maRanges), mnTab(r.mnTab) {}
676 :
677 281 : void operator() (const ScDPObject& rObj)
678 : {
679 281 : const ScRange& rRange = rObj.GetOutRange();
680 281 : if (mnTab != rRange.aStart.Tab())
681 : // Not on this sheet.
682 429 : return;
683 :
684 133 : maRanges.Join(rRange);
685 : }
686 :
687 143 : ScRangeList getRanges() const { return maRanges; }
688 : };
689 :
690 : }
691 :
692 348 : ScDPTableData* ScDPObject::GetTableData()
693 : {
694 348 : if (!mpTableData)
695 : {
696 186 : shared_ptr<ScDPTableData> pData;
697 186 : const ScDPDimensionSaveData* pDimData = pSaveData ? pSaveData->GetExistingDimensionData() : NULL;
698 :
699 186 : if ( pImpDesc )
700 : {
701 : // database data
702 0 : const ScDPCache* pCache = pImpDesc->CreateCache(pDimData);
703 0 : if (pCache)
704 : {
705 0 : pCache->AddReference(this);
706 0 : pData.reset(new ScDatabaseDPData(pDoc, *pCache));
707 : }
708 : }
709 : else
710 : {
711 : // cell data
712 186 : if (!pSheetDesc)
713 : {
714 : OSL_FAIL("no source descriptor");
715 0 : pSheetDesc = new ScSheetSourceDesc(pDoc); // dummy defaults
716 : }
717 :
718 : {
719 : // Temporarily disable GETPIVOTDATA to avoid having
720 : // GETPIVOTDATA called onto itself from within the source
721 : // range.
722 186 : DisableGetPivotData aSwitch(*this, mbEnableGetPivotData);
723 186 : const ScDPCache* pCache = pSheetDesc->CreateCache(pDimData);
724 186 : if (pCache)
725 : {
726 186 : pCache->AddReference(this);
727 186 : pData.reset(new ScSheetDPData(pDoc, *pSheetDesc, *pCache));
728 186 : }
729 : }
730 : }
731 :
732 : // grouping (for cell or database data)
733 186 : if (pData && pDimData)
734 : {
735 8 : shared_ptr<ScDPGroupTableData> pGroupData(new ScDPGroupTableData(pData, pDoc));
736 8 : pDimData->WriteToData(*pGroupData);
737 8 : pData = pGroupData;
738 : }
739 :
740 186 : mpTableData = pData; // after SetCacheId
741 : }
742 :
743 348 : return mpTableData.get();
744 : }
745 :
746 2288 : void ScDPObject::CreateObjects()
747 : {
748 2288 : if (!xSource.is())
749 : {
750 238 : DELETEZ( pOutput ); // not valid when xSource is changed
751 :
752 238 : if ( pServDesc )
753 : {
754 0 : xSource = CreateSource( *pServDesc );
755 : }
756 :
757 238 : if ( !xSource.is() ) // database or sheet data, or error in CreateSource
758 : {
759 : OSL_ENSURE( !pServDesc, "DPSource could not be created" );
760 238 : ScDPTableData* pData = GetTableData();
761 238 : if (pData)
762 : {
763 238 : if (pSaveData)
764 : // Make sure to transfer these flags to the table data
765 : // since they may have changed.
766 238 : pData->SetEmptyFlags(pSaveData->GetIgnoreEmptyRows(), pSaveData->GetRepeatIfEmpty());
767 :
768 238 : pData->ReloadCacheTable();
769 238 : ScDPSource* pSource = new ScDPSource( pData );
770 238 : xSource = pSource;
771 : }
772 : }
773 :
774 238 : if (pSaveData)
775 238 : pSaveData->WriteToSource( xSource );
776 : }
777 2050 : else if (bSettingsChanged)
778 : {
779 18 : DELETEZ( pOutput ); // not valid when xSource is changed
780 :
781 18 : uno::Reference<util::XRefreshable> xRef( xSource, uno::UNO_QUERY );
782 18 : if (xRef.is())
783 : {
784 : try
785 : {
786 18 : xRef->refresh();
787 : }
788 0 : catch(uno::Exception&)
789 : {
790 : OSL_FAIL("exception in refresh");
791 : }
792 : }
793 :
794 18 : if (pSaveData)
795 18 : pSaveData->WriteToSource( xSource );
796 : }
797 2288 : bSettingsChanged = false;
798 2288 : }
799 :
800 310 : void ScDPObject::InvalidateData()
801 : {
802 310 : bSettingsChanged = true;
803 310 : }
804 :
805 318 : void ScDPObject::Clear()
806 : {
807 318 : delete pOutput;
808 318 : delete pSaveData;
809 318 : delete pSheetDesc;
810 318 : delete pImpDesc;
811 318 : delete pServDesc;
812 318 : pOutput = NULL;
813 318 : pSaveData = NULL;
814 318 : pSheetDesc = NULL;
815 318 : pImpDesc = NULL;
816 318 : pServDesc = NULL;
817 318 : ClearTableData();
818 318 : }
819 :
820 502 : void ScDPObject::ClearTableData()
821 : {
822 502 : ClearSource();
823 :
824 502 : if (mpTableData)
825 186 : mpTableData->GetCacheTable().getCache().RemoveReference(this);
826 502 : mpTableData.reset();
827 502 : }
828 :
829 114 : void ScDPObject::ReloadGroupTableData()
830 : {
831 114 : ClearSource();
832 :
833 114 : if (!mpTableData)
834 : // Table data not built yet. No need to reload the group data.
835 58 : return;
836 :
837 56 : if (!pSaveData)
838 : // How could it not have the save data... but whatever.
839 0 : return;
840 :
841 56 : const ScDPDimensionSaveData* pDimData = pSaveData->GetExistingDimensionData();
842 56 : if (!pDimData || !pDimData->HasGroupDimensions())
843 : {
844 : // No group dimensions exist. Check if it currently has group
845 : // dimensions, and if so, remove all of them.
846 42 : ScDPGroupTableData* pData = dynamic_cast<ScDPGroupTableData*>(mpTableData.get());
847 42 : if (pData)
848 : {
849 : // Replace the existing group table data with the source data.
850 2 : shared_ptr<ScDPTableData> pSource = pData->GetSourceTableData();
851 2 : mpTableData = pSource;
852 : }
853 42 : return;
854 : }
855 :
856 14 : ScDPGroupTableData* pData = dynamic_cast<ScDPGroupTableData*>(mpTableData.get());
857 14 : if (pData)
858 : {
859 : // This is already a group table data. Salvage the source data and
860 : // re-create a new group data.
861 4 : shared_ptr<ScDPTableData> pSource = pData->GetSourceTableData();
862 8 : shared_ptr<ScDPGroupTableData> pGroupData(new ScDPGroupTableData(pSource, pDoc));
863 4 : pDimData->WriteToData(*pGroupData);
864 8 : mpTableData = pGroupData;
865 : }
866 : else
867 : {
868 : // This is a source data. Create a group data based on it.
869 10 : shared_ptr<ScDPGroupTableData> pGroupData(new ScDPGroupTableData(mpTableData, pDoc));
870 10 : pDimData->WriteToData(*pGroupData);
871 10 : mpTableData = pGroupData;
872 : }
873 :
874 14 : bSettingsChanged = true;
875 : }
876 :
877 616 : void ScDPObject::ClearSource()
878 : {
879 616 : Reference< XComponent > xObjectComp( xSource, UNO_QUERY );
880 616 : if (xObjectComp.is())
881 : {
882 : try
883 : {
884 0 : xObjectComp->dispose();
885 : }
886 0 : catch( const Exception& )
887 : {
888 : DBG_UNHANDLED_EXCEPTION();
889 : }
890 : }
891 616 : xSource = NULL;
892 616 : }
893 :
894 168 : ScRange ScDPObject::GetNewOutputRange( bool& rOverflow )
895 : {
896 168 : CreateOutput(); // create xSource and pOutput if not already done
897 :
898 168 : rOverflow = pOutput->HasError(); // range overflow or exception from source
899 168 : if ( rOverflow )
900 0 : return ScRange( aOutRange.aStart );
901 : else
902 : {
903 : // don't store the result in aOutRange, because nothing has been output yet
904 168 : return pOutput->GetOutputRange();
905 : }
906 : }
907 :
908 172 : void ScDPObject::Output( const ScAddress& rPos )
909 : {
910 : // clear old output area
911 172 : pDoc->DeleteAreaTab( aOutRange.aStart.Col(), aOutRange.aStart.Row(),
912 172 : aOutRange.aEnd.Col(), aOutRange.aEnd.Row(),
913 516 : aOutRange.aStart.Tab(), IDF_ALL );
914 172 : pDoc->RemoveFlagsTab( aOutRange.aStart.Col(), aOutRange.aStart.Row(),
915 172 : aOutRange.aEnd.Col(), aOutRange.aEnd.Row(),
916 516 : aOutRange.aStart.Tab(), SC_MF_AUTO );
917 :
918 172 : CreateOutput(); // create xSource and pOutput if not already done
919 :
920 172 : pOutput->SetPosition( rPos );
921 :
922 172 : pOutput->Output();
923 :
924 : // aOutRange is always the range that was last output to the document
925 172 : aOutRange = pOutput->GetOutputRange();
926 172 : const ScAddress& s = aOutRange.aStart;
927 172 : const ScAddress& e = aOutRange.aEnd;
928 172 : pDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
929 172 : }
930 :
931 30 : ScRange ScDPObject::GetOutputRangeByType( sal_Int32 nType )
932 : {
933 30 : CreateOutput();
934 :
935 30 : if (pOutput->HasError())
936 0 : return ScRange(aOutRange.aStart);
937 :
938 30 : return pOutput->GetOutputRange(nType);
939 : }
940 :
941 8 : ScRange ScDPObject::GetOutputRangeByType( sal_Int32 nType ) const
942 : {
943 8 : if (!pOutput || pOutput->HasError())
944 0 : return ScRange(ScAddress::INITIALIZE_INVALID);
945 :
946 8 : return pOutput->GetOutputRange(nType);
947 : }
948 :
949 40 : static bool lcl_HasButton( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
950 : {
951 40 : return static_cast<const ScMergeFlagAttr*>(pDoc->GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG ))->HasPivotButton();
952 : }
953 :
954 14 : void ScDPObject::RefreshAfterLoad()
955 : {
956 : // apply drop-down attribute, initialize nHeaderRows, without accessing the source
957 : // (button attribute must be present)
958 :
959 : // simple test: block of button cells at the top, followed by an empty cell
960 :
961 14 : SCCOL nFirstCol = aOutRange.aStart.Col();
962 14 : SCROW nFirstRow = aOutRange.aStart.Row();
963 14 : SCTAB nTab = aOutRange.aStart.Tab();
964 :
965 14 : SCROW nInitial = 0;
966 14 : SCROW nOutRows = aOutRange.aEnd.Row() + 1 - aOutRange.aStart.Row();
967 54 : while ( nInitial + 1 < nOutRows && lcl_HasButton( pDoc, nFirstCol, nFirstRow + nInitial, nTab ) )
968 26 : ++nInitial;
969 :
970 42 : if ( nInitial + 1 < nOutRows &&
971 28 : pDoc->IsBlockEmpty( nTab, nFirstCol, nFirstRow + nInitial, nFirstCol, nFirstRow + nInitial ) &&
972 14 : aOutRange.aEnd.Col() > nFirstCol )
973 : {
974 12 : nHeaderRows = nInitial;
975 : }
976 : else
977 2 : nHeaderRows = 0; // nothing found, no drop-down lists
978 14 : }
979 :
980 8 : void ScDPObject::BuildAllDimensionMembers()
981 : {
982 8 : if (!pSaveData)
983 0 : return;
984 :
985 : // #i111857# don't always create empty mpTableData for external service.
986 8 : if (pServDesc)
987 0 : return;
988 :
989 8 : ScDPTableData* pTableData = GetTableData();
990 8 : if(pTableData)
991 8 : pSaveData->BuildAllDimensionMembers(pTableData);
992 : }
993 :
994 102 : bool ScDPObject::SyncAllDimensionMembers()
995 : {
996 102 : if (!pSaveData)
997 0 : return false;
998 :
999 : // #i111857# don't always create empty mpTableData for external service.
1000 : // Ideally, xSource should be used instead of mpTableData.
1001 102 : if (pServDesc)
1002 0 : return false;
1003 :
1004 102 : ScDPTableData* pData = GetTableData();
1005 102 : if (!pData)
1006 : // No table data exists. This can happen when refreshing from an
1007 : // external source which doesn't exist.
1008 0 : return false;
1009 :
1010 : // Refresh the cache wrapper since the cache may have changed.
1011 102 : pData->SetEmptyFlags(pSaveData->GetIgnoreEmptyRows(), pSaveData->GetRepeatIfEmpty());
1012 102 : pData->ReloadCacheTable();
1013 102 : pSaveData->SyncAllDimensionMembers(pData);
1014 102 : return true;
1015 : }
1016 :
1017 4 : bool ScDPObject::GetMemberNames( sal_Int32 nDim, Sequence<OUString>& rNames )
1018 : {
1019 4 : vector<ScDPLabelData::Member> aMembers;
1020 4 : if (!GetMembers(nDim, GetUsedHierarchy(nDim), aMembers))
1021 0 : return false;
1022 :
1023 4 : size_t n = aMembers.size();
1024 4 : rNames.realloc(n);
1025 24 : for (size_t i = 0; i < n; ++i)
1026 20 : rNames[i] = aMembers[i].maName;
1027 :
1028 4 : return true;
1029 : }
1030 :
1031 10 : bool ScDPObject::GetMembers( sal_Int32 nDim, sal_Int32 nHier, vector<ScDPLabelData::Member>& rMembers )
1032 : {
1033 10 : Reference< container::XNameAccess > xMembersNA;
1034 10 : if (!GetMembersNA( nDim, nHier, xMembersNA ))
1035 0 : return false;
1036 :
1037 20 : Reference<container::XIndexAccess> xMembersIA( new ScNameToIndexAccess(xMembersNA) );
1038 10 : sal_Int32 nCount = xMembersIA->getCount();
1039 20 : vector<ScDPLabelData::Member> aMembers;
1040 10 : aMembers.reserve(nCount);
1041 :
1042 74 : for (sal_Int32 i = 0; i < nCount; ++i)
1043 : {
1044 64 : Reference<container::XNamed> xMember(xMembersIA->getByIndex(i), UNO_QUERY);
1045 128 : ScDPLabelData::Member aMem;
1046 :
1047 64 : if (xMember.is())
1048 64 : aMem.maName = xMember->getName();
1049 :
1050 128 : Reference<beans::XPropertySet> xMemProp(xMember, UNO_QUERY);
1051 64 : if (xMemProp.is())
1052 : {
1053 64 : aMem.mbVisible = ScUnoHelpFunctions::GetBoolProperty(xMemProp, OUString(SC_UNO_DP_ISVISIBLE));
1054 64 : aMem.mbShowDetails = ScUnoHelpFunctions::GetBoolProperty(xMemProp, OUString(SC_UNO_DP_SHOWDETAILS));
1055 :
1056 128 : aMem.maLayoutName = ScUnoHelpFunctions::GetStringProperty(
1057 64 : xMemProp, OUString(SC_UNO_DP_LAYOUTNAME), OUString());
1058 : }
1059 :
1060 64 : aMembers.push_back(aMem);
1061 64 : }
1062 10 : rMembers.swap(aMembers);
1063 20 : return true;
1064 : }
1065 :
1066 132 : void ScDPObject::UpdateReference( UpdateRefMode eUpdateRefMode,
1067 : const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
1068 : {
1069 : // Output area
1070 :
1071 132 : SCCOL nCol1 = aOutRange.aStart.Col();
1072 132 : SCROW nRow1 = aOutRange.aStart.Row();
1073 132 : SCTAB nTab1 = aOutRange.aStart.Tab();
1074 132 : SCCOL nCol2 = aOutRange.aEnd.Col();
1075 132 : SCROW nRow2 = aOutRange.aEnd.Row();
1076 132 : SCTAB nTab2 = aOutRange.aEnd.Tab();
1077 :
1078 : ScRefUpdateRes eRes =
1079 : ScRefUpdate::Update( pDoc, eUpdateRefMode,
1080 264 : rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
1081 264 : rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz,
1082 660 : nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
1083 132 : if ( eRes != UR_NOTHING )
1084 132 : SetOutRange( ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ) );
1085 :
1086 : // sheet source data
1087 :
1088 132 : if ( pSheetDesc )
1089 : {
1090 132 : const OUString& rRangeName = pSheetDesc->GetRangeName();
1091 132 : if (!rRangeName.isEmpty())
1092 : // Source range is a named range. No need to update.
1093 4 : return;
1094 :
1095 130 : const ScRange& rSrcRange = pSheetDesc->GetSourceRange();
1096 130 : nCol1 = rSrcRange.aStart.Col();
1097 130 : nRow1 = rSrcRange.aStart.Row();
1098 130 : nTab1 = rSrcRange.aStart.Tab();
1099 130 : nCol2 = rSrcRange.aEnd.Col();
1100 130 : nRow2 = rSrcRange.aEnd.Row();
1101 130 : nTab2 = rSrcRange.aEnd.Tab();
1102 :
1103 : eRes = ScRefUpdate::Update( pDoc, eUpdateRefMode,
1104 260 : rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
1105 260 : rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz,
1106 650 : nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
1107 130 : if ( eRes != UR_NOTHING )
1108 : {
1109 130 : SCsCOL nDiffX = nCol1 - pSheetDesc->GetSourceRange().aStart.Col();
1110 130 : SCsROW nDiffY = nRow1 - pSheetDesc->GetSourceRange().aStart.Row();
1111 :
1112 130 : ScQueryParam aParam = pSheetDesc->GetQueryParam();
1113 130 : aParam.nCol1 = sal::static_int_cast<SCCOL>( aParam.nCol1 + nDiffX );
1114 130 : aParam.nCol2 = sal::static_int_cast<SCCOL>( aParam.nCol2 + nDiffX );
1115 130 : aParam.nRow1 += nDiffY; //! used?
1116 130 : aParam.nRow2 += nDiffY; //! used?
1117 130 : SCSIZE nEC = aParam.GetEntryCount();
1118 1170 : for (SCSIZE i=0; i<nEC; i++)
1119 1040 : if (aParam.GetEntry(i).bDoQuery)
1120 128 : aParam.GetEntry(i).nField += nDiffX;
1121 :
1122 130 : pSheetDesc->SetQueryParam(aParam);
1123 130 : pSheetDesc->SetSourceRange(ScRange(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2));
1124 : }
1125 : }
1126 : }
1127 :
1128 0 : bool ScDPObject::RefsEqual( const ScDPObject& r ) const
1129 : {
1130 0 : if ( aOutRange != r.aOutRange )
1131 0 : return false;
1132 :
1133 0 : if ( pSheetDesc && r.pSheetDesc )
1134 : {
1135 0 : if ( pSheetDesc->GetSourceRange() != r.pSheetDesc->GetSourceRange() )
1136 0 : return false;
1137 : }
1138 0 : else if ( pSheetDesc || r.pSheetDesc )
1139 : {
1140 : OSL_FAIL("RefsEqual: SheetDesc set at only one object");
1141 0 : return false;
1142 : }
1143 :
1144 0 : return true;
1145 : }
1146 :
1147 0 : void ScDPObject::WriteRefsTo( ScDPObject& r ) const
1148 : {
1149 0 : r.SetOutRange( aOutRange );
1150 0 : if ( pSheetDesc )
1151 0 : r.SetSheetDesc( *pSheetDesc, true );
1152 0 : }
1153 :
1154 532 : void ScDPObject::GetPositionData(const ScAddress& rPos, DataPilotTablePositionData& rPosData)
1155 : {
1156 532 : CreateOutput();
1157 532 : pOutput->GetPositionData(rPos, rPosData);
1158 532 : }
1159 :
1160 266 : bool ScDPObject::GetDataFieldPositionData(
1161 : const ScAddress& rPos, Sequence<sheet::DataPilotFieldFilter>& rFilters)
1162 : {
1163 266 : CreateOutput();
1164 :
1165 266 : vector<sheet::DataPilotFieldFilter> aFilters;
1166 266 : if (!pOutput->GetDataResultPositionData(aFilters, rPos))
1167 0 : return false;
1168 :
1169 266 : sal_Int32 n = static_cast<sal_Int32>(aFilters.size());
1170 266 : rFilters.realloc(n);
1171 1186 : for (sal_Int32 i = 0; i < n; ++i)
1172 920 : rFilters[i] = aFilters[i];
1173 :
1174 266 : return true;
1175 : }
1176 :
1177 194 : void ScDPObject::GetDrillDownData(const ScAddress& rPos, Sequence< Sequence<Any> >& rTableData)
1178 : {
1179 194 : CreateOutput();
1180 :
1181 194 : Reference<sheet::XDrillDownDataSupplier> xDrillDownData(xSource, UNO_QUERY);
1182 194 : if (!xDrillDownData.is())
1183 0 : return;
1184 :
1185 388 : Sequence<sheet::DataPilotFieldFilter> filters;
1186 194 : if (!GetDataFieldPositionData(rPos, filters))
1187 0 : return;
1188 :
1189 388 : rTableData = xDrillDownData->getDrillDownData(filters);
1190 : }
1191 :
1192 96 : bool ScDPObject::IsDimNameInUse(const OUString& rName) const
1193 : {
1194 96 : if (!xSource.is())
1195 4 : return false;
1196 :
1197 92 : Reference<container::XNameAccess> xDims = xSource->getDimensions();
1198 184 : Sequence<OUString> aDimNames = xDims->getElementNames();
1199 92 : sal_Int32 n = aDimNames.getLength();
1200 438 : for (sal_Int32 i = 0; i < n; ++i)
1201 : {
1202 424 : const OUString& rDimName = aDimNames[i];
1203 424 : if (rDimName.equalsIgnoreAsciiCase(rName))
1204 152 : return true;
1205 :
1206 350 : Reference<beans::XPropertySet> xPropSet(xDims->getByName(rDimName), UNO_QUERY);
1207 350 : if (!xPropSet.is())
1208 0 : continue;
1209 :
1210 : OUString aLayoutName = ScUnoHelpFunctions::GetStringProperty(
1211 696 : xPropSet, OUString(SC_UNO_DP_LAYOUTNAME), OUString());
1212 350 : if (aLayoutName.equalsIgnoreAsciiCase(rName))
1213 4 : return true;
1214 346 : }
1215 106 : return false;
1216 : }
1217 :
1218 120 : OUString ScDPObject::GetDimName( long nDim, bool& rIsDataLayout, sal_Int32* pFlags )
1219 : {
1220 120 : rIsDataLayout = false;
1221 120 : OUString aRet;
1222 :
1223 120 : if ( xSource.is() )
1224 : {
1225 120 : uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1226 240 : uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
1227 120 : long nDimCount = xDims->getCount();
1228 120 : if ( nDim < nDimCount )
1229 : {
1230 : uno::Reference<uno::XInterface> xIntDim =
1231 120 : ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
1232 240 : uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
1233 240 : uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
1234 120 : if ( xDimName.is() && xDimProp.is() )
1235 : {
1236 : bool bData = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1237 120 : OUString(SC_UNO_DP_ISDATALAYOUT) );
1238 : //! error checking -- is "IsDataLayoutDimension" property required??
1239 :
1240 120 : OUString aName;
1241 : try
1242 : {
1243 120 : aName = xDimName->getName();
1244 : }
1245 0 : catch(uno::Exception&)
1246 : {
1247 : }
1248 120 : if ( bData )
1249 0 : rIsDataLayout = true;
1250 : else
1251 120 : aRet = aName;
1252 :
1253 120 : if (pFlags)
1254 : *pFlags = ScUnoHelpFunctions::GetLongProperty( xDimProp,
1255 0 : OUString(SC_UNO_DP_FLAGS), 0 );
1256 120 : }
1257 120 : }
1258 : }
1259 :
1260 120 : return aRet;
1261 : }
1262 :
1263 0 : bool ScDPObject::IsDuplicated( long nDim )
1264 : {
1265 0 : bool bDuplicated = false;
1266 0 : if ( xSource.is() )
1267 : {
1268 0 : uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1269 0 : uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
1270 0 : long nDimCount = xDims->getCount();
1271 0 : if ( nDim < nDimCount )
1272 : {
1273 : uno::Reference<uno::XInterface> xIntDim =
1274 0 : ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
1275 0 : uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
1276 0 : if ( xDimProp.is() )
1277 : {
1278 : try
1279 : {
1280 0 : uno::Any aOrigAny = xDimProp->getPropertyValue(
1281 0 : OUString(SC_UNO_DP_ORIGINAL) );
1282 0 : uno::Reference<uno::XInterface> xIntOrig;
1283 0 : if ( (aOrigAny >>= xIntOrig) && xIntOrig.is() )
1284 0 : bDuplicated = true;
1285 : }
1286 0 : catch(uno::Exception&)
1287 : {
1288 : }
1289 0 : }
1290 0 : }
1291 : }
1292 0 : return bDuplicated;
1293 : }
1294 :
1295 120 : long ScDPObject::GetDimCount()
1296 : {
1297 120 : long nRet = 0;
1298 120 : if ( xSource.is() )
1299 : {
1300 : try
1301 : {
1302 120 : uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1303 120 : if ( xDimsName.is() )
1304 120 : nRet = xDimsName->getElementNames().getLength();
1305 : }
1306 0 : catch(uno::Exception&)
1307 : {
1308 : }
1309 : }
1310 120 : return nRet;
1311 : }
1312 :
1313 0 : void ScDPObject::GetHeaderPositionData(const ScAddress& rPos, DataPilotTableHeaderData& rData)
1314 : {
1315 : using namespace ::com::sun::star::sheet::DataPilotTablePositionType;
1316 :
1317 0 : CreateOutput(); // create xSource and pOutput if not already done
1318 :
1319 : // Reset member values to invalid state.
1320 0 : rData.Dimension = rData.Hierarchy = rData.Level = -1;
1321 0 : rData.Flags = 0;
1322 :
1323 0 : DataPilotTablePositionData aPosData;
1324 0 : pOutput->GetPositionData(rPos, aPosData);
1325 0 : const sal_Int32 nPosType = aPosData.PositionType;
1326 0 : if (nPosType == COLUMN_HEADER || nPosType == ROW_HEADER)
1327 0 : aPosData.PositionData >>= rData;
1328 0 : }
1329 :
1330 : namespace {
1331 :
1332 558 : class FindByName : std::unary_function<const ScDPSaveDimension*, bool>
1333 : {
1334 : OUString maName; // must be all uppercase.
1335 : public:
1336 62 : FindByName(const OUString& rName) : maName(rName) {}
1337 68 : bool operator() (const ScDPSaveDimension* pDim) const
1338 : {
1339 : // Layout name takes precedence.
1340 68 : const OUString* pLayoutName = pDim->GetLayoutName();
1341 68 : if (pLayoutName && ScGlobal::pCharClass->uppercase(*pLayoutName) == maName)
1342 4 : return true;
1343 :
1344 64 : sheet::GeneralFunction eGenFunc = static_cast<sheet::GeneralFunction>(pDim->GetFunction());
1345 64 : ScSubTotalFunc eFunc = ScDPUtil::toSubTotalFunc(eGenFunc);
1346 64 : OUString aSrcName = ScDPUtil::getSourceDimensionName(pDim->GetName());
1347 128 : OUString aFuncName = ScDPUtil::getDisplayedMeasureName(aSrcName, eFunc);
1348 64 : if (maName == ScGlobal::pCharClass->uppercase(aFuncName))
1349 12 : return true;
1350 :
1351 116 : return maName == ScGlobal::pCharClass->uppercase(aSrcName);
1352 : }
1353 : };
1354 :
1355 : class LessByDimOrder : std::binary_function<sheet::DataPilotFieldFilter, sheet::DataPilotFieldFilter, bool>
1356 : {
1357 : const ScDPSaveData::DimOrderType& mrDimOrder;
1358 :
1359 : public:
1360 62 : LessByDimOrder(const ScDPSaveData::DimOrderType& rDimOrder) : mrDimOrder(rDimOrder) {}
1361 :
1362 0 : bool operator() (const sheet::DataPilotFieldFilter& r1, const sheet::DataPilotFieldFilter& r2) const
1363 : {
1364 0 : size_t nRank1 = mrDimOrder.size();
1365 0 : size_t nRank2 = mrDimOrder.size();
1366 0 : ScDPSaveData::DimOrderType::const_iterator it1 = mrDimOrder.find(r1.FieldName);
1367 0 : if (it1 != mrDimOrder.end())
1368 0 : nRank1 = it1->second;
1369 :
1370 0 : ScDPSaveData::DimOrderType::const_iterator it2 = mrDimOrder.find(r2.FieldName);
1371 0 : if (it2 != mrDimOrder.end())
1372 0 : nRank2 = it2->second;
1373 :
1374 0 : return nRank1 < nRank2;
1375 : }
1376 : };
1377 :
1378 : }
1379 :
1380 62 : double ScDPObject::GetPivotData(const OUString& rDataFieldName, std::vector<sheet::DataPilotFieldFilter>& rFilters)
1381 : {
1382 : double fRet;
1383 62 : rtl::math::setNan(&fRet);
1384 62 : if (!mbEnableGetPivotData)
1385 0 : return fRet;
1386 :
1387 62 : CreateObjects();
1388 :
1389 62 : std::vector<const ScDPSaveDimension*> aDataDims;
1390 62 : pSaveData->GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_DATA, aDataDims);
1391 62 : if (aDataDims.empty())
1392 0 : return fRet;
1393 :
1394 : std::vector<const ScDPSaveDimension*>::iterator it = std::find_if(
1395 : aDataDims.begin(), aDataDims.end(),
1396 62 : FindByName(ScGlobal::pCharClass->uppercase(rDataFieldName)));
1397 :
1398 62 : if (it == aDataDims.end())
1399 0 : return fRet;
1400 :
1401 62 : size_t nDataIndex = std::distance(aDataDims.begin(), it);
1402 :
1403 124 : uno::Reference<sheet::XDataPilotResults> xDPResults(xSource, uno::UNO_QUERY);
1404 62 : if (!xDPResults.is())
1405 0 : return fRet;
1406 :
1407 : // Dimensions must be sorted in order of appearance, and row dimensions
1408 : // must come before column dimensions.
1409 62 : std::sort(rFilters.begin(), rFilters.end(), LessByDimOrder(pSaveData->GetDimensionSortOrder()));
1410 :
1411 62 : size_t n = rFilters.size();
1412 124 : uno::Sequence<sheet::DataPilotFieldFilter> aFilters(n);
1413 118 : for (size_t i = 0; i < n; ++i)
1414 56 : aFilters[i] = rFilters[i];
1415 :
1416 124 : uno::Sequence<double> aRes = xDPResults->getFilteredResults(aFilters);
1417 62 : if (static_cast<sal_Int32>(nDataIndex) >= aRes.getLength())
1418 0 : return fRet;
1419 :
1420 124 : return aRes[nDataIndex];
1421 : }
1422 :
1423 0 : bool ScDPObject::IsFilterButton( const ScAddress& rPos )
1424 : {
1425 0 : CreateOutput(); // create xSource and pOutput if not already done
1426 :
1427 0 : return pOutput->IsFilterButton( rPos );
1428 : }
1429 :
1430 2 : long ScDPObject::GetHeaderDim( const ScAddress& rPos, sal_uInt16& rOrient )
1431 : {
1432 2 : CreateOutput(); // create xSource and pOutput if not already done
1433 :
1434 2 : return pOutput->GetHeaderDim( rPos, rOrient );
1435 : }
1436 :
1437 0 : bool ScDPObject::GetHeaderDrag( const ScAddress& rPos, bool bMouseLeft, bool bMouseTop, long nDragDim,
1438 : Rectangle& rPosRect, sal_uInt16& rOrient, long& rDimPos )
1439 : {
1440 0 : CreateOutput(); // create xSource and pOutput if not already done
1441 :
1442 0 : return pOutput->GetHeaderDrag( rPos, bMouseLeft, bMouseTop, nDragDim, rPosRect, rOrient, rDimPos );
1443 : }
1444 :
1445 0 : void ScDPObject::GetMemberResultNames(ScDPUniqueStringSet& rNames, long nDimension)
1446 : {
1447 0 : CreateOutput(); // create xSource and pOutput if not already done
1448 :
1449 0 : pOutput->GetMemberResultNames(rNames, nDimension); // used only with table data -> level not needed
1450 0 : }
1451 :
1452 : namespace {
1453 :
1454 0 : bool dequote( const OUString& rSource, sal_Int32 nStartPos, sal_Int32& rEndPos, OUString& rResult )
1455 : {
1456 : // nStartPos has to point to opening quote
1457 :
1458 0 : bool bRet = false;
1459 0 : const sal_Unicode cQuote = '\'';
1460 :
1461 0 : if (rSource[nStartPos] == cQuote)
1462 : {
1463 0 : OUStringBuffer aBuffer;
1464 0 : sal_Int32 nPos = nStartPos + 1;
1465 0 : const sal_Int32 nLen = rSource.getLength();
1466 :
1467 0 : while ( nPos < nLen )
1468 : {
1469 0 : const sal_Unicode cNext = rSource[nPos];
1470 0 : if ( cNext == cQuote )
1471 : {
1472 0 : if (nPos+1 < nLen && rSource[nPos+1] == cQuote)
1473 : {
1474 : // double quote is used for an embedded quote
1475 0 : aBuffer.append( cNext ); // append one quote
1476 0 : ++nPos; // skip the next one
1477 : }
1478 : else
1479 : {
1480 : // end of quoted string
1481 0 : rResult = aBuffer.makeStringAndClear();
1482 0 : rEndPos = nPos + 1; // behind closing quote
1483 0 : return true;
1484 : }
1485 : }
1486 : else
1487 0 : aBuffer.append( cNext );
1488 :
1489 0 : ++nPos;
1490 0 : }
1491 : // no closing quote before the end of the string -> error (bRet still false)
1492 : }
1493 :
1494 0 : return bRet;
1495 : }
1496 :
1497 : struct ScGetPivotDataFunctionEntry
1498 : {
1499 : const sal_Char* pName;
1500 : sheet::GeneralFunction eFunc;
1501 : };
1502 :
1503 0 : bool parseFunction( const OUString& rList, sal_Int32 nStartPos, sal_Int32& rEndPos, sheet::GeneralFunction& rFunc )
1504 : {
1505 : static const ScGetPivotDataFunctionEntry aFunctions[] =
1506 : {
1507 : // our names
1508 : { "Sum", sheet::GeneralFunction_SUM },
1509 : { "Count", sheet::GeneralFunction_COUNT },
1510 : { "Average", sheet::GeneralFunction_AVERAGE },
1511 : { "Max", sheet::GeneralFunction_MAX },
1512 : { "Min", sheet::GeneralFunction_MIN },
1513 : { "Product", sheet::GeneralFunction_PRODUCT },
1514 : { "CountNums", sheet::GeneralFunction_COUNTNUMS },
1515 : { "StDev", sheet::GeneralFunction_STDEV },
1516 : { "StDevp", sheet::GeneralFunction_STDEVP },
1517 : { "Var", sheet::GeneralFunction_VAR },
1518 : { "VarP", sheet::GeneralFunction_VARP },
1519 : // compatibility names
1520 : { "Count Nums", sheet::GeneralFunction_COUNTNUMS },
1521 : { "StdDev", sheet::GeneralFunction_STDEV },
1522 : { "StdDevp", sheet::GeneralFunction_STDEVP }
1523 : };
1524 :
1525 0 : const sal_Int32 nListLen = rList.getLength();
1526 0 : while (nStartPos < nListLen && rList[nStartPos] == ' ')
1527 0 : ++nStartPos;
1528 :
1529 0 : bool bParsed = false;
1530 0 : bool bFound = false;
1531 0 : OUString aFuncStr;
1532 0 : sal_Int32 nFuncEnd = 0;
1533 0 : if (nStartPos < nListLen && rList[nStartPos] == '\'')
1534 0 : bParsed = dequote( rList, nStartPos, nFuncEnd, aFuncStr );
1535 : else
1536 : {
1537 0 : nFuncEnd = rList.indexOf(']', nStartPos);
1538 0 : if (nFuncEnd >= 0)
1539 : {
1540 0 : aFuncStr = rList.copy(nStartPos, nFuncEnd - nStartPos);
1541 0 : bParsed = true;
1542 : }
1543 : }
1544 :
1545 0 : if ( bParsed )
1546 : {
1547 0 : aFuncStr = comphelper::string::strip(aFuncStr, ' ');
1548 :
1549 0 : const sal_Int32 nFuncCount = sizeof(aFunctions) / sizeof(aFunctions[0]);
1550 0 : for ( sal_Int32 nFunc=0; nFunc<nFuncCount && !bFound; nFunc++ )
1551 : {
1552 0 : if (aFuncStr.equalsIgnoreAsciiCaseAscii(aFunctions[nFunc].pName))
1553 : {
1554 0 : rFunc = aFunctions[nFunc].eFunc;
1555 0 : bFound = true;
1556 :
1557 0 : while (nFuncEnd < nListLen && rList[nFuncEnd] == ' ')
1558 0 : ++nFuncEnd;
1559 0 : rEndPos = nFuncEnd;
1560 : }
1561 : }
1562 : }
1563 :
1564 0 : return bFound;
1565 : }
1566 :
1567 192 : bool isAtStart(
1568 : const OUString& rList, const OUString& rSearch, sal_Int32& rMatched,
1569 : bool bAllowBracket, sheet::GeneralFunction* pFunc )
1570 : {
1571 192 : sal_Int32 nMatchList = 0;
1572 192 : sal_Int32 nMatchSearch = 0;
1573 192 : sal_Unicode cFirst = rList[0];
1574 192 : if ( cFirst == '\'' || cFirst == '[' )
1575 : {
1576 : // quoted string or string in brackets must match completely
1577 :
1578 96 : OUString aDequoted;
1579 96 : sal_Int32 nQuoteEnd = 0;
1580 96 : bool bParsed = false;
1581 :
1582 96 : if ( cFirst == '\'' )
1583 0 : bParsed = dequote( rList, 0, nQuoteEnd, aDequoted );
1584 96 : else if ( cFirst == '[' )
1585 : {
1586 : // skip spaces after the opening bracket
1587 :
1588 96 : sal_Int32 nStartPos = 1;
1589 96 : const sal_Int32 nListLen = rList.getLength();
1590 192 : while (nStartPos < nListLen && rList[nStartPos] == ' ')
1591 0 : ++nStartPos;
1592 :
1593 96 : if (nStartPos < nListLen && rList[nStartPos] == '\'') // quoted within the brackets?
1594 : {
1595 0 : if ( dequote( rList, nStartPos, nQuoteEnd, aDequoted ) )
1596 : {
1597 : // after the quoted string, there must be the closing bracket, optionally preceded by spaces,
1598 : // and/or a function name
1599 0 : while (nQuoteEnd < nListLen && rList[nQuoteEnd] == ' ')
1600 0 : ++nQuoteEnd;
1601 :
1602 : // semicolon separates function name
1603 0 : if (nQuoteEnd < nListLen && rList[nQuoteEnd] == ';' && pFunc)
1604 : {
1605 0 : sal_Int32 nFuncEnd = 0;
1606 0 : if ( parseFunction( rList, nQuoteEnd + 1, nFuncEnd, *pFunc ) )
1607 0 : nQuoteEnd = nFuncEnd;
1608 : }
1609 0 : if (nQuoteEnd < nListLen && rList[nQuoteEnd] == ']')
1610 : {
1611 0 : ++nQuoteEnd; // include the closing bracket for the matched length
1612 0 : bParsed = true;
1613 : }
1614 : }
1615 : }
1616 : else
1617 : {
1618 : // implicit quoting to the closing bracket
1619 :
1620 96 : sal_Int32 nClosePos = rList.indexOf(']', nStartPos);
1621 96 : if (nClosePos >= 0)
1622 : {
1623 96 : sal_Int32 nNameEnd = nClosePos;
1624 96 : sal_Int32 nSemiPos = rList.indexOf(';', nStartPos);
1625 96 : if (nSemiPos >= 0 && nSemiPos < nClosePos && pFunc)
1626 : {
1627 0 : sal_Int32 nFuncEnd = 0;
1628 0 : if (parseFunction(rList, nSemiPos+1, nFuncEnd, *pFunc))
1629 0 : nNameEnd = nSemiPos;
1630 : }
1631 :
1632 96 : aDequoted = rList.copy(nStartPos, nNameEnd - nStartPos);
1633 : // spaces before the closing bracket or semicolon
1634 96 : aDequoted = comphelper::string::stripEnd(aDequoted, ' ');
1635 96 : nQuoteEnd = nClosePos + 1;
1636 96 : bParsed = true;
1637 : }
1638 : }
1639 : }
1640 :
1641 96 : if ( bParsed && ScGlobal::GetpTransliteration()->isEqual( aDequoted, rSearch ) )
1642 : {
1643 24 : nMatchList = nQuoteEnd; // match count in the list string, including quotes
1644 24 : nMatchSearch = rSearch.getLength();
1645 96 : }
1646 : }
1647 : else
1648 : {
1649 : // otherwise look for search string at the start of rList
1650 : ScGlobal::GetpTransliteration()->equals(
1651 96 : rList, 0, rList.getLength(), nMatchList, rSearch, 0, rSearch.getLength(), nMatchSearch);
1652 : }
1653 :
1654 192 : if (nMatchSearch == rSearch.getLength())
1655 : {
1656 : // search string is at start of rList - look for following space or end of string
1657 :
1658 48 : bool bValid = false;
1659 48 : if ( sal::static_int_cast<sal_Int32>(nMatchList) >= rList.getLength() )
1660 24 : bValid = true;
1661 : else
1662 : {
1663 24 : sal_Unicode cNext = rList[nMatchList];
1664 24 : if ( cNext == ' ' || ( bAllowBracket && cNext == '[' ) )
1665 24 : bValid = true;
1666 : }
1667 :
1668 48 : if ( bValid )
1669 : {
1670 48 : rMatched = nMatchList;
1671 48 : return true;
1672 : }
1673 : }
1674 :
1675 144 : return false;
1676 : }
1677 :
1678 : } // anonymous namespace
1679 :
1680 24 : bool ScDPObject::ParseFilters(
1681 : OUString& rDataFieldName,
1682 : std::vector<sheet::DataPilotFieldFilter>& rFilters,
1683 : std::vector<sheet::GeneralFunction>& rFilterFuncs, const OUString& rFilterList )
1684 : {
1685 : // parse the string rFilterList into parameters for GetPivotData
1686 :
1687 24 : CreateObjects(); // create xSource if not already done
1688 :
1689 24 : std::vector<OUString> aDataNames; // data fields (source name)
1690 48 : std::vector<OUString> aGivenNames; // data fields (compound name)
1691 48 : std::vector<OUString> aFieldNames; // column/row/data fields
1692 48 : std::vector< uno::Sequence<OUString> > aFieldValues;
1693 :
1694 : // get all the field and item names
1695 :
1696 48 : uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1697 48 : uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
1698 24 : sal_Int32 nDimCount = xIntDims->getCount();
1699 120 : for ( sal_Int32 nDim = 0; nDim<nDimCount; nDim++ )
1700 : {
1701 96 : uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nDim) );
1702 192 : uno::Reference<container::XNamed> xDim( xIntDim, uno::UNO_QUERY );
1703 192 : uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
1704 192 : uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDim, uno::UNO_QUERY );
1705 : bool bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1706 96 : OUString(SC_UNO_DP_ISDATALAYOUT) );
1707 : sal_Int32 nOrient = ScUnoHelpFunctions::GetEnumProperty(
1708 : xDimProp, OUString(SC_UNO_DP_ORIENTATION),
1709 96 : sheet::DataPilotFieldOrientation_HIDDEN );
1710 96 : if ( !bDataLayout )
1711 : {
1712 72 : if ( nOrient == sheet::DataPilotFieldOrientation_DATA )
1713 : {
1714 24 : OUString aSourceName;
1715 48 : OUString aGivenName;
1716 24 : ScDPOutput::GetDataDimensionNames( aSourceName, aGivenName, xIntDim );
1717 24 : aDataNames.push_back( aSourceName );
1718 48 : aGivenNames.push_back( aGivenName );
1719 : }
1720 48 : else if ( nOrient != sheet::DataPilotFieldOrientation_HIDDEN )
1721 : {
1722 : // get level names, as in ScDPOutput
1723 :
1724 48 : uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
1725 : sal_Int32 nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
1726 48 : OUString(SC_UNO_DP_USEDHIERARCHY) );
1727 48 : if ( nHierarchy >= xHiers->getCount() )
1728 0 : nHierarchy = 0;
1729 :
1730 : uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
1731 96 : xHiers->getByIndex(nHierarchy) );
1732 96 : uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
1733 48 : if ( xHierSupp.is() )
1734 : {
1735 48 : uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
1736 48 : sal_Int32 nLevCount = xLevels->getCount();
1737 96 : for (sal_Int32 nLev=0; nLev<nLevCount; nLev++)
1738 : {
1739 : uno::Reference<uno::XInterface> xLevel = ScUnoHelpFunctions::AnyToInterface(
1740 48 : xLevels->getByIndex(nLev) );
1741 96 : uno::Reference<container::XNamed> xLevNam( xLevel, uno::UNO_QUERY );
1742 96 : uno::Reference<sheet::XMembersSupplier> xLevSupp( xLevel, uno::UNO_QUERY );
1743 48 : if ( xLevNam.is() && xLevSupp.is() )
1744 : {
1745 48 : uno::Reference<container::XNameAccess> xMembers = xLevSupp->getMembers();
1746 :
1747 96 : OUString aFieldName( xLevNam->getName() );
1748 96 : uno::Sequence<OUString> aMemberNames( xMembers->getElementNames() );
1749 :
1750 48 : aFieldNames.push_back( aFieldName );
1751 96 : aFieldValues.push_back( aMemberNames );
1752 : }
1753 96 : }
1754 48 : }
1755 : }
1756 : }
1757 96 : }
1758 :
1759 : // compare and build filters
1760 :
1761 24 : SCSIZE nDataFields = aDataNames.size();
1762 24 : SCSIZE nFieldCount = aFieldNames.size();
1763 : OSL_ENSURE( aGivenNames.size() == nDataFields && aFieldValues.size() == nFieldCount, "wrong count" );
1764 :
1765 24 : bool bError = false;
1766 24 : bool bHasData = false;
1767 48 : OUString aRemaining(comphelper::string::strip(rFilterList, ' '));
1768 72 : while (!aRemaining.isEmpty() && !bError)
1769 : {
1770 24 : bool bUsed = false;
1771 :
1772 : // look for data field name
1773 :
1774 48 : for ( SCSIZE nDataPos=0; nDataPos<nDataFields && !bUsed; nDataPos++ )
1775 : {
1776 24 : OUString aFound;
1777 24 : sal_Int32 nMatched = 0;
1778 24 : if (isAtStart(aRemaining, aDataNames[nDataPos], nMatched, false, NULL))
1779 0 : aFound = aDataNames[nDataPos];
1780 24 : else if (isAtStart(aRemaining, aGivenNames[nDataPos], nMatched, false, NULL))
1781 0 : aFound = aGivenNames[nDataPos];
1782 :
1783 24 : if (!aFound.isEmpty())
1784 : {
1785 0 : rDataFieldName = aFound;
1786 0 : aRemaining = aRemaining.copy(nMatched);
1787 0 : bHasData = true;
1788 0 : bUsed = true;
1789 : }
1790 24 : }
1791 :
1792 : // look for field name
1793 :
1794 24 : OUString aSpecField;
1795 24 : bool bHasFieldName = false;
1796 24 : if ( !bUsed )
1797 : {
1798 24 : sal_Int32 nMatched = 0;
1799 72 : for ( SCSIZE nField=0; nField<nFieldCount && !bHasFieldName; nField++ )
1800 : {
1801 48 : if (isAtStart(aRemaining, aFieldNames[nField], nMatched, true, NULL))
1802 : {
1803 24 : aSpecField = aFieldNames[nField];
1804 24 : aRemaining = aRemaining.copy(nMatched);
1805 24 : aRemaining = comphelper::string::stripStart(aRemaining, ' ');
1806 :
1807 : // field name has to be followed by item name in brackets
1808 24 : if (aRemaining.startsWith("["))
1809 : {
1810 24 : bHasFieldName = true;
1811 : // bUsed remains false - still need the item
1812 : }
1813 : else
1814 : {
1815 0 : bUsed = true;
1816 0 : bError = true;
1817 : }
1818 : }
1819 : }
1820 : }
1821 :
1822 : // look for field item
1823 :
1824 24 : if ( !bUsed )
1825 : {
1826 24 : bool bItemFound = false;
1827 24 : sal_Int32 nMatched = 0;
1828 24 : OUString aFoundName;
1829 48 : OUString aFoundValue;
1830 24 : sheet::GeneralFunction eFunc = sheet::GeneralFunction_NONE;
1831 24 : sheet::GeneralFunction eFoundFunc = sheet::GeneralFunction_NONE;
1832 :
1833 72 : for ( SCSIZE nField=0; nField<nFieldCount; nField++ )
1834 : {
1835 : // If a field name is given, look in that field only, otherwise in all fields.
1836 : // aSpecField is initialized from aFieldNames array, so exact comparison can be used.
1837 48 : if ( !bHasFieldName || aFieldNames[nField] == aSpecField )
1838 : {
1839 24 : const uno::Sequence<OUString>& rItems = aFieldValues[nField];
1840 24 : sal_Int32 nItemCount = rItems.getLength();
1841 24 : const OUString* pItemArr = rItems.getConstArray();
1842 120 : for ( sal_Int32 nItem=0; nItem<nItemCount; nItem++ )
1843 : {
1844 96 : if ( isAtStart( aRemaining, pItemArr[nItem], nMatched, false, &eFunc ) )
1845 : {
1846 24 : if ( bItemFound )
1847 0 : bError = true; // duplicate (also across fields)
1848 : else
1849 : {
1850 24 : aFoundName = aFieldNames[nField];
1851 24 : aFoundValue = pItemArr[nItem];
1852 24 : eFoundFunc = eFunc;
1853 24 : bItemFound = true;
1854 24 : bUsed = true;
1855 : }
1856 : }
1857 : }
1858 : }
1859 : }
1860 :
1861 24 : if ( bItemFound && !bError )
1862 : {
1863 24 : sheet::DataPilotFieldFilter aField;
1864 24 : aField.FieldName = aFoundName;
1865 24 : aField.MatchValue = aFoundValue;
1866 24 : rFilters.push_back(aField);
1867 24 : rFilterFuncs.push_back(eFoundFunc);
1868 24 : aRemaining = aRemaining.copy(nMatched);
1869 24 : }
1870 : }
1871 :
1872 24 : if ( !bUsed )
1873 0 : bError = true;
1874 :
1875 : // remove any number of spaces between entries
1876 24 : aRemaining = comphelper::string::stripStart(aRemaining, ' ');
1877 24 : }
1878 :
1879 24 : if ( !bError && !bHasData && aDataNames.size() == 1 )
1880 : {
1881 : // if there's only one data field, its name need not be specified
1882 24 : rDataFieldName = aDataNames[0];
1883 24 : bHasData = true;
1884 : }
1885 :
1886 48 : return bHasData && !bError;
1887 : }
1888 :
1889 0 : void ScDPObject::ToggleDetails(const DataPilotTableHeaderData& rElemDesc, ScDPObject* pDestObj)
1890 : {
1891 0 : CreateObjects(); // create xSource if not already done
1892 :
1893 : // find dimension name
1894 :
1895 0 : uno::Reference<container::XNamed> xDim;
1896 0 : uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
1897 0 : uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
1898 0 : long nIntCount = xIntDims->getCount();
1899 0 : if ( rElemDesc.Dimension < nIntCount )
1900 : {
1901 : uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface(
1902 0 : xIntDims->getByIndex(rElemDesc.Dimension) );
1903 0 : xDim = uno::Reference<container::XNamed>( xIntDim, uno::UNO_QUERY );
1904 : }
1905 : OSL_ENSURE( xDim.is(), "dimension not found" );
1906 0 : if ( !xDim.is() ) return;
1907 0 : OUString aDimName = xDim->getName();
1908 :
1909 0 : uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
1910 : bool bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1911 0 : OUString(SC_UNO_DP_ISDATALAYOUT) );
1912 0 : if (bDataLayout)
1913 : {
1914 : // the elements of the data layout dimension can't be found by their names
1915 : // -> don't change anything
1916 0 : return;
1917 : }
1918 :
1919 : // query old state
1920 :
1921 0 : long nHierCount = 0;
1922 0 : uno::Reference<container::XIndexAccess> xHiers;
1923 0 : uno::Reference<sheet::XHierarchiesSupplier> xHierSupp( xDim, uno::UNO_QUERY );
1924 0 : if ( xHierSupp.is() )
1925 : {
1926 0 : uno::Reference<container::XNameAccess> xHiersName = xHierSupp->getHierarchies();
1927 0 : xHiers = new ScNameToIndexAccess( xHiersName );
1928 0 : nHierCount = xHiers->getCount();
1929 : }
1930 0 : uno::Reference<uno::XInterface> xHier;
1931 0 : if ( rElemDesc.Hierarchy < nHierCount )
1932 0 : xHier = ScUnoHelpFunctions::AnyToInterface( xHiers->getByIndex(rElemDesc.Hierarchy) );
1933 : OSL_ENSURE( xHier.is(), "hierarchy not found" );
1934 0 : if ( !xHier.is() ) return;
1935 :
1936 0 : long nLevCount = 0;
1937 0 : uno::Reference<container::XIndexAccess> xLevels;
1938 0 : uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHier, uno::UNO_QUERY );
1939 0 : if ( xLevSupp.is() )
1940 : {
1941 0 : uno::Reference<container::XNameAccess> xLevsName = xLevSupp->getLevels();
1942 0 : xLevels = new ScNameToIndexAccess( xLevsName );
1943 0 : nLevCount = xLevels->getCount();
1944 : }
1945 0 : uno::Reference<uno::XInterface> xLevel;
1946 0 : if ( rElemDesc.Level < nLevCount )
1947 0 : xLevel = ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex(rElemDesc.Level) );
1948 : OSL_ENSURE( xLevel.is(), "level not found" );
1949 0 : if ( !xLevel.is() ) return;
1950 :
1951 0 : uno::Reference<container::XNameAccess> xMembers;
1952 0 : uno::Reference<sheet::XMembersSupplier> xMbrSupp( xLevel, uno::UNO_QUERY );
1953 0 : if ( xMbrSupp.is() )
1954 0 : xMembers = xMbrSupp->getMembers();
1955 :
1956 0 : bool bFound = false;
1957 0 : bool bShowDetails = true;
1958 :
1959 0 : if ( xMembers.is() )
1960 : {
1961 0 : if ( xMembers->hasByName(rElemDesc.MemberName) )
1962 : {
1963 : uno::Reference<uno::XInterface> xMemberInt = ScUnoHelpFunctions::AnyToInterface(
1964 0 : xMembers->getByName(rElemDesc.MemberName) );
1965 0 : uno::Reference<beans::XPropertySet> xMbrProp( xMemberInt, uno::UNO_QUERY );
1966 0 : if ( xMbrProp.is() )
1967 : {
1968 : bShowDetails = ScUnoHelpFunctions::GetBoolProperty( xMbrProp,
1969 0 : OUString(SC_UNO_DP_SHOWDETAILS) );
1970 : //! don't set bFound if property is unknown?
1971 0 : bFound = true;
1972 0 : }
1973 : }
1974 : }
1975 :
1976 : OSL_ENSURE( bFound, "member not found" );
1977 : (void)bFound;
1978 :
1979 : //! use Hierarchy and Level in SaveData !!!!
1980 :
1981 : // modify pDestObj if set, this object otherwise
1982 0 : ScDPSaveData* pModifyData = pDestObj ? ( pDestObj->pSaveData ) : pSaveData;
1983 : OSL_ENSURE( pModifyData, "no data?" );
1984 0 : if ( pModifyData )
1985 : {
1986 0 : const OUString aName = rElemDesc.MemberName;
1987 : pModifyData->GetDimensionByName(aDimName)->
1988 0 : GetMemberByName(aName)->SetShowDetails( !bShowDetails ); // toggle
1989 :
1990 0 : if ( pDestObj )
1991 0 : pDestObj->InvalidateData(); // re-init source from SaveData
1992 : else
1993 0 : InvalidateData(); // re-init source from SaveData
1994 0 : }
1995 : }
1996 :
1997 0 : static sal_uInt16 lcl_FirstSubTotal( const uno::Reference<beans::XPropertySet>& xDimProp ) // PIVOT_FUNC mask
1998 : {
1999 0 : uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDimProp, uno::UNO_QUERY );
2000 0 : if ( xDimProp.is() && xDimSupp.is() )
2001 : {
2002 0 : uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
2003 : long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
2004 0 : OUString(SC_UNO_DP_USEDHIERARCHY) );
2005 0 : if ( nHierarchy >= xHiers->getCount() )
2006 0 : nHierarchy = 0;
2007 :
2008 : uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
2009 0 : xHiers->getByIndex(nHierarchy) );
2010 0 : uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
2011 0 : if ( xHierSupp.is() )
2012 : {
2013 0 : uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
2014 : uno::Reference<uno::XInterface> xLevel =
2015 0 : ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex( 0 ) );
2016 0 : uno::Reference<beans::XPropertySet> xLevProp( xLevel, uno::UNO_QUERY );
2017 0 : if ( xLevProp.is() )
2018 : {
2019 0 : uno::Any aSubAny;
2020 : try
2021 : {
2022 0 : aSubAny = xLevProp->getPropertyValue(
2023 0 : OUString(SC_UNO_DP_SUBTOTAL) );
2024 : }
2025 0 : catch(uno::Exception&)
2026 : {
2027 : }
2028 0 : uno::Sequence<sheet::GeneralFunction> aSeq;
2029 0 : if ( aSubAny >>= aSeq )
2030 : {
2031 0 : sal_uInt16 nMask = 0;
2032 0 : const sheet::GeneralFunction* pArray = aSeq.getConstArray();
2033 0 : long nCount = aSeq.getLength();
2034 0 : for (long i=0; i<nCount; i++)
2035 0 : nMask |= ScDataPilotConversion::FunctionBit(pArray[i]);
2036 0 : return nMask;
2037 0 : }
2038 0 : }
2039 0 : }
2040 : }
2041 :
2042 : OSL_FAIL("FirstSubTotal: NULL");
2043 0 : return 0;
2044 : }
2045 :
2046 : namespace {
2047 :
2048 : class FindByColumn : public std::unary_function<ScPivotField, bool>
2049 : {
2050 : SCsCOL mnCol;
2051 : sal_uInt16 mnMask;
2052 : public:
2053 0 : FindByColumn(SCsCOL nCol, sal_uInt16 nMask) : mnCol(nCol), mnMask(nMask) {}
2054 0 : bool operator() (const ScPivotField& r) const
2055 : {
2056 0 : return r.nCol == mnCol && r.nFuncMask == mnMask;
2057 : }
2058 : };
2059 :
2060 : }
2061 :
2062 0 : void lcl_FillOldFields( ScPivotFieldVector& rFields,
2063 : const uno::Reference<sheet::XDimensionsSupplier>& xSource,
2064 : sal_uInt16 nOrient, bool bAddData )
2065 : {
2066 0 : ScPivotFieldVector aFields;
2067 :
2068 0 : bool bDataFound = false;
2069 :
2070 : //! merge multiple occurrences (data field with different functions)
2071 : //! force data field in one dimension
2072 :
2073 0 : vector<long> aPos;
2074 :
2075 0 : uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
2076 0 : uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
2077 0 : long nDimCount = xDims->getCount();
2078 0 : for (long nDim = 0; nDim < nDimCount; ++nDim)
2079 : {
2080 : // Get dimension object.
2081 : uno::Reference<uno::XInterface> xIntDim =
2082 0 : ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
2083 :
2084 : // dimension properties
2085 0 : uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
2086 :
2087 : // dimension orientation, hidden by default.
2088 : long nDimOrient = ScUnoHelpFunctions::GetEnumProperty(
2089 : xDimProp, OUString(SC_UNO_DP_ORIENTATION),
2090 0 : sheet::DataPilotFieldOrientation_HIDDEN );
2091 :
2092 0 : if ( xDimProp.is() && nDimOrient == nOrient )
2093 : {
2094 : // Let's take this dimension.
2095 :
2096 : // function mask.
2097 0 : sal_uInt16 nMask = 0;
2098 0 : if ( nOrient == sheet::DataPilotFieldOrientation_DATA )
2099 : {
2100 : sheet::GeneralFunction eFunc = (sheet::GeneralFunction)ScUnoHelpFunctions::GetEnumProperty(
2101 : xDimProp, OUString(SC_UNO_DP_FUNCTION),
2102 0 : sheet::GeneralFunction_NONE );
2103 0 : if ( eFunc == sheet::GeneralFunction_AUTO )
2104 : {
2105 : //! test for numeric data
2106 0 : eFunc = sheet::GeneralFunction_SUM;
2107 : }
2108 0 : nMask = ScDataPilotConversion::FunctionBit(eFunc);
2109 : }
2110 : else
2111 0 : nMask = lcl_FirstSubTotal( xDimProp ); // from first hierarchy
2112 :
2113 : // is this data layout dimension?
2114 : bool bDataLayout = ScUnoHelpFunctions::GetBoolProperty(
2115 0 : xDimProp, OUString(SC_UNO_DP_ISDATALAYOUT));
2116 :
2117 : // is this dimension cloned?
2118 0 : long nDupSource = -1;
2119 : try
2120 : {
2121 0 : uno::Any aOrigAny = xDimProp->getPropertyValue(
2122 0 : OUString(SC_UNO_DP_ORIGINAL_POS));
2123 0 : sal_Int32 nTmp = 0;
2124 0 : if (aOrigAny >>= nTmp)
2125 0 : nDupSource = static_cast<sal_Int32>(nTmp);
2126 : }
2127 0 : catch(uno::Exception&)
2128 : {
2129 : }
2130 :
2131 0 : sal_uInt8 nDupCount = 0;
2132 0 : if (nDupSource >= 0)
2133 : {
2134 : // this dimension is cloned.
2135 :
2136 : SCsCOL nCompCol; // ID of the original dimension.
2137 0 : if ( bDataLayout )
2138 0 : nCompCol = PIVOT_DATA_FIELD;
2139 : else
2140 0 : nCompCol = static_cast<SCsCOL>(nDupSource); //! seek source column from name
2141 :
2142 0 : ScPivotFieldVector::iterator it = std::find_if(aFields.begin(), aFields.end(), FindByColumn(nCompCol, nMask));
2143 0 : if (it != aFields.end())
2144 0 : nDupCount = it->mnDupCount + 1;
2145 : }
2146 :
2147 0 : aFields.push_back(ScPivotField());
2148 0 : ScPivotField& rField = aFields.back();
2149 0 : if (bDataLayout)
2150 : {
2151 0 : rField.nCol = PIVOT_DATA_FIELD;
2152 0 : bDataFound = true;
2153 : }
2154 : else
2155 : {
2156 0 : rField.mnOriginalDim = nDupSource;
2157 0 : rField.nCol = static_cast<SCCOL>(nDim); //! seek source column from name
2158 : }
2159 :
2160 0 : rField.nFuncMask = nMask;
2161 0 : rField.mnDupCount = nDupCount;
2162 : long nPos = ScUnoHelpFunctions::GetLongProperty(
2163 0 : xDimProp, OUString(SC_UNO_DP_POSITION));
2164 0 : aPos.push_back(nPos);
2165 :
2166 : try
2167 : {
2168 0 : if (nOrient == sheet::DataPilotFieldOrientation_DATA)
2169 0 : xDimProp->getPropertyValue(OUString(SC_UNO_DP_REFVALUE))
2170 0 : >>= rField.maFieldRef;
2171 : }
2172 0 : catch (uno::Exception&)
2173 : {
2174 : }
2175 : }
2176 0 : }
2177 :
2178 : // sort by getPosition() value
2179 :
2180 0 : size_t nOutCount = aFields.size();
2181 0 : if (nOutCount >= 1)
2182 : {
2183 0 : for (size_t i = 0; i < nOutCount - 1; ++i)
2184 : {
2185 0 : for (size_t j = 0; j + i < nOutCount - 1; ++j)
2186 : {
2187 0 : if ( aPos[j+1] < aPos[j] )
2188 : {
2189 0 : std::swap( aPos[j], aPos[j+1] );
2190 0 : std::swap( aFields[j], aFields[j+1] );
2191 : }
2192 : }
2193 : }
2194 : }
2195 :
2196 0 : if (bAddData && !bDataFound)
2197 0 : aFields.push_back(ScPivotField(PIVOT_DATA_FIELD, 0));
2198 :
2199 0 : rFields.swap(aFields);
2200 0 : }
2201 :
2202 0 : bool ScDPObject::FillOldParam(ScPivotParam& rParam) const
2203 : {
2204 0 : ((ScDPObject*)this)->CreateObjects(); // xSource is needed for field numbers
2205 :
2206 0 : if (!xSource.is())
2207 0 : return false;
2208 :
2209 0 : rParam.nCol = aOutRange.aStart.Col();
2210 0 : rParam.nRow = aOutRange.aStart.Row();
2211 0 : rParam.nTab = aOutRange.aStart.Tab();
2212 : // ppLabelArr / nLabels is not changed
2213 :
2214 0 : bool bAddData = ( lcl_GetDataGetOrientation( xSource ) == sheet::DataPilotFieldOrientation_HIDDEN );
2215 : lcl_FillOldFields(
2216 0 : rParam.maPageFields, xSource, sheet::DataPilotFieldOrientation_PAGE, false);
2217 : lcl_FillOldFields(
2218 0 : rParam.maColFields, xSource, sheet::DataPilotFieldOrientation_COLUMN, bAddData);
2219 : lcl_FillOldFields(
2220 0 : rParam.maRowFields, xSource, sheet::DataPilotFieldOrientation_ROW, false);
2221 : lcl_FillOldFields(
2222 0 : rParam.maDataFields, xSource, sheet::DataPilotFieldOrientation_DATA, false);
2223 :
2224 0 : uno::Reference<beans::XPropertySet> xProp( xSource, uno::UNO_QUERY );
2225 0 : if (xProp.is())
2226 : {
2227 : try
2228 : {
2229 : rParam.bMakeTotalCol = ScUnoHelpFunctions::GetBoolProperty( xProp,
2230 0 : OUString(SC_UNO_DP_COLGRAND), true );
2231 : rParam.bMakeTotalRow = ScUnoHelpFunctions::GetBoolProperty( xProp,
2232 0 : OUString(SC_UNO_DP_ROWGRAND), true );
2233 :
2234 : // following properties may be missing for external sources
2235 : rParam.bIgnoreEmptyRows = ScUnoHelpFunctions::GetBoolProperty( xProp,
2236 0 : OUString(SC_UNO_DP_IGNOREEMPTY) );
2237 : rParam.bDetectCategories = ScUnoHelpFunctions::GetBoolProperty( xProp,
2238 0 : OUString(SC_UNO_DP_REPEATEMPTY) );
2239 : }
2240 0 : catch(uno::Exception&)
2241 : {
2242 : // no error
2243 : }
2244 : }
2245 0 : return true;
2246 : }
2247 :
2248 6 : static void lcl_FillLabelData( ScDPLabelData& rData, const uno::Reference< beans::XPropertySet >& xDimProp )
2249 : {
2250 6 : uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDimProp, uno::UNO_QUERY );
2251 6 : if (!xDimProp.is() || !xDimSupp.is())
2252 0 : return;
2253 :
2254 12 : uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
2255 : long nHierarchy = ScUnoHelpFunctions::GetLongProperty(
2256 6 : xDimProp, OUString(SC_UNO_DP_USEDHIERARCHY));
2257 6 : if ( nHierarchy >= xHiers->getCount() )
2258 0 : nHierarchy = 0;
2259 6 : rData.mnUsedHier = nHierarchy;
2260 :
2261 : uno::Reference<uno::XInterface> xHier =
2262 12 : ScUnoHelpFunctions::AnyToInterface(xHiers->getByIndex(nHierarchy));
2263 :
2264 12 : uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
2265 6 : if (!xHierSupp.is())
2266 0 : return;
2267 :
2268 : uno::Reference<container::XIndexAccess> xLevels =
2269 12 : new ScNameToIndexAccess( xHierSupp->getLevels() );
2270 :
2271 : uno::Reference<uno::XInterface> xLevel =
2272 12 : ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex(0) );
2273 12 : uno::Reference<beans::XPropertySet> xLevProp( xLevel, uno::UNO_QUERY );
2274 6 : if (!xLevProp.is())
2275 0 : return;
2276 :
2277 : rData.mbShowAll = ScUnoHelpFunctions::GetBoolProperty(
2278 6 : xLevProp, OUString(SC_UNO_DP_SHOWEMPTY));
2279 :
2280 : try
2281 : {
2282 6 : xLevProp->getPropertyValue( OUString( SC_UNO_DP_SORTING ) )
2283 12 : >>= rData.maSortInfo;
2284 6 : xLevProp->getPropertyValue( OUString( SC_UNO_DP_LAYOUT ) )
2285 12 : >>= rData.maLayoutInfo;
2286 6 : xLevProp->getPropertyValue( OUString( SC_UNO_DP_AUTOSHOW ) )
2287 12 : >>= rData.maShowInfo;
2288 : }
2289 0 : catch(uno::Exception&)
2290 : {
2291 6 : }
2292 : }
2293 :
2294 8 : bool ScDPObject::FillLabelDataForDimension(
2295 : const uno::Reference<container::XIndexAccess>& xDims, sal_Int32 nDim, ScDPLabelData& rLabelData)
2296 : {
2297 : uno::Reference<uno::XInterface> xIntDim =
2298 8 : ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
2299 16 : uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
2300 16 : uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
2301 :
2302 8 : if (!xDimName.is() || !xDimProp.is())
2303 0 : return false;
2304 :
2305 : bool bData = ScUnoHelpFunctions::GetBoolProperty(
2306 8 : xDimProp, OUString(SC_UNO_DP_ISDATALAYOUT));
2307 : //! error checking -- is "IsDataLayoutDimension" property required??
2308 :
2309 8 : sal_Int32 nOrigPos = -1;
2310 16 : OUString aFieldName;
2311 : try
2312 : {
2313 8 : aFieldName = xDimName->getName();
2314 8 : uno::Any aOrigAny = xDimProp->getPropertyValue(
2315 8 : OUString(SC_UNO_DP_ORIGINAL_POS));
2316 8 : aOrigAny >>= nOrigPos;
2317 : }
2318 0 : catch(uno::Exception&)
2319 : {
2320 : }
2321 :
2322 : OUString aLayoutName = ScUnoHelpFunctions::GetStringProperty(
2323 16 : xDimProp, OUString(SC_UNO_DP_LAYOUTNAME), OUString());
2324 :
2325 : OUString aSubtotalName = ScUnoHelpFunctions::GetStringProperty(
2326 16 : xDimProp, OUString(SC_UNO_DP_FIELD_SUBTOTALNAME), OUString());
2327 :
2328 8 : bool bIsValue = true; //! check
2329 :
2330 : // Name from the UNO dimension object may have trailing '*'s in which
2331 : // case it's a duplicate dimension. Convert that to a duplicate index.
2332 :
2333 8 : sal_uInt8 nDupCount = ScDPUtil::getDuplicateIndex(aFieldName);
2334 8 : aFieldName = ScDPUtil::getSourceDimensionName(aFieldName);
2335 :
2336 8 : rLabelData.maName = aFieldName;
2337 8 : rLabelData.mnCol = static_cast<SCCOL>(nDim);
2338 8 : rLabelData.mnDupCount = nDupCount;
2339 8 : rLabelData.mbDataLayout = bData;
2340 8 : rLabelData.mbIsValue = bIsValue;
2341 :
2342 8 : if (!bData)
2343 : {
2344 6 : rLabelData.mnOriginalDim = static_cast<long>(nOrigPos);
2345 6 : rLabelData.maLayoutName = aLayoutName;
2346 6 : rLabelData.maSubtotalName = aSubtotalName;
2347 6 : if (nOrigPos >= 0)
2348 : // This is a duplicated dimension. Use the original dimension index.
2349 2 : nDim = nOrigPos;
2350 6 : GetHierarchies(nDim, rLabelData.maHiers);
2351 6 : GetMembers(nDim, GetUsedHierarchy(nDim), rLabelData.maMembers);
2352 6 : lcl_FillLabelData(rLabelData, xDimProp);
2353 : rLabelData.mnFlags = ScUnoHelpFunctions::GetLongProperty(
2354 6 : xDimProp, OUString(SC_UNO_DP_FLAGS), 0);
2355 : }
2356 16 : return true;
2357 : }
2358 :
2359 0 : bool ScDPObject::FillLabelData(sal_Int32 nDim, ScDPLabelData& rLabels)
2360 : {
2361 0 : CreateObjects();
2362 0 : if (!xSource.is())
2363 0 : return false;
2364 :
2365 0 : uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
2366 0 : uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
2367 0 : sal_Int32 nDimCount = xDims->getCount();
2368 0 : if (nDimCount <= 0 || nDim >= nDimCount)
2369 0 : return false;
2370 :
2371 0 : return FillLabelDataForDimension(xDims, nDim, rLabels);
2372 : }
2373 :
2374 2 : bool ScDPObject::FillLabelData(ScPivotParam& rParam)
2375 : {
2376 2 : rParam.maLabelArray.clear();
2377 :
2378 2 : CreateObjects();
2379 2 : if (!xSource.is())
2380 0 : return false;
2381 :
2382 2 : uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
2383 4 : uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
2384 2 : sal_Int32 nDimCount = xDims->getCount();
2385 2 : if (nDimCount <= 0)
2386 0 : return false;
2387 :
2388 10 : for (sal_Int32 nDim = 0; nDim < nDimCount; ++nDim)
2389 : {
2390 8 : std::unique_ptr<ScDPLabelData> pNewLabel(new ScDPLabelData);
2391 8 : FillLabelDataForDimension(xDims, nDim, *pNewLabel);
2392 8 : o3tl::ptr_container::push_back(rParam.maLabelArray, std::move(pNewLabel));
2393 8 : }
2394 :
2395 4 : return true;
2396 : }
2397 :
2398 6 : bool ScDPObject::GetHierarchiesNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xHiers )
2399 : {
2400 6 : bool bRet = false;
2401 6 : uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
2402 12 : uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
2403 6 : if( xIntDims.is() )
2404 : {
2405 6 : uno::Reference<sheet::XHierarchiesSupplier> xHierSup(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
2406 6 : if (xHierSup.is())
2407 : {
2408 6 : xHiers.set( xHierSup->getHierarchies() );
2409 6 : bRet = xHiers.is();
2410 6 : }
2411 : }
2412 12 : return bRet;
2413 : }
2414 :
2415 6 : bool ScDPObject::GetHierarchies( sal_Int32 nDim, uno::Sequence< OUString >& rHiers )
2416 : {
2417 6 : bool bRet = false;
2418 6 : uno::Reference< container::XNameAccess > xHiersNA;
2419 6 : if( GetHierarchiesNA( nDim, xHiersNA ) )
2420 : {
2421 6 : rHiers = xHiersNA->getElementNames();
2422 6 : bRet = true;
2423 : }
2424 6 : return bRet;
2425 : }
2426 :
2427 126 : sal_Int32 ScDPObject::GetUsedHierarchy( sal_Int32 nDim )
2428 : {
2429 126 : sal_Int32 nHier = 0;
2430 126 : uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
2431 252 : uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
2432 252 : uno::Reference<beans::XPropertySet> xDim(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
2433 126 : if (xDim.is())
2434 126 : nHier = ScUnoHelpFunctions::GetLongProperty( xDim, OUString( SC_UNO_DP_USEDHIERARCHY ) );
2435 252 : return nHier;
2436 : }
2437 :
2438 116 : bool ScDPObject::GetMembersNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xMembers )
2439 : {
2440 116 : return GetMembersNA( nDim, GetUsedHierarchy( nDim ), xMembers );
2441 : }
2442 :
2443 126 : bool ScDPObject::GetMembersNA( sal_Int32 nDim, sal_Int32 nHier, uno::Reference< container::XNameAccess >& xMembers )
2444 : {
2445 126 : bool bRet = false;
2446 126 : uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
2447 252 : uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
2448 252 : uno::Reference<beans::XPropertySet> xDim(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
2449 126 : if (xDim.is())
2450 : {
2451 126 : uno::Reference<sheet::XHierarchiesSupplier> xHierSup(xDim, uno::UNO_QUERY);
2452 126 : if (xHierSup.is())
2453 : {
2454 126 : uno::Reference<container::XIndexAccess> xHiers(new ScNameToIndexAccess(xHierSup->getHierarchies()));
2455 252 : uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHiers->getByIndex(nHier), uno::UNO_QUERY );
2456 126 : if ( xLevSupp.is() )
2457 : {
2458 126 : uno::Reference<container::XIndexAccess> xLevels(new ScNameToIndexAccess( xLevSupp->getLevels()));
2459 126 : if (xLevels.is())
2460 : {
2461 126 : sal_Int32 nLevCount = xLevels->getCount();
2462 126 : if (nLevCount > 0)
2463 : {
2464 126 : uno::Reference<sheet::XMembersSupplier> xMembSupp( xLevels->getByIndex(0), uno::UNO_QUERY );
2465 126 : if ( xMembSupp.is() )
2466 : {
2467 126 : xMembers.set(xMembSupp->getMembers());
2468 126 : bRet = true;
2469 126 : }
2470 : }
2471 126 : }
2472 126 : }
2473 126 : }
2474 : }
2475 252 : return bRet;
2476 : }
2477 :
2478 : // convert old pivot tables into new datapilot tables
2479 :
2480 : namespace {
2481 :
2482 0 : OUString lcl_GetDimName( const uno::Reference<sheet::XDimensionsSupplier>& xSource, long nDim )
2483 : {
2484 0 : OUString aName;
2485 0 : if ( xSource.is() )
2486 : {
2487 0 : uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
2488 0 : uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
2489 0 : long nDimCount = xDims->getCount();
2490 0 : if ( nDim < nDimCount )
2491 : {
2492 : uno::Reference<uno::XInterface> xIntDim =
2493 0 : ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
2494 0 : uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
2495 0 : if (xDimName.is())
2496 : {
2497 : try
2498 : {
2499 0 : aName = xDimName->getName();
2500 : }
2501 0 : catch(uno::Exception&)
2502 : {
2503 : }
2504 0 : }
2505 0 : }
2506 : }
2507 0 : return aName;
2508 : }
2509 :
2510 0 : bool hasFieldColumn(const vector<ScPivotField>* pRefFields, SCCOL nCol)
2511 : {
2512 0 : if (!pRefFields)
2513 0 : return false;
2514 :
2515 0 : vector<ScPivotField>::const_iterator itr = pRefFields->begin(), itrEnd = pRefFields->end();
2516 0 : for (; itr != itrEnd; ++itr)
2517 : {
2518 0 : if (itr->nCol == nCol)
2519 : // This array of fields contains the specified column.
2520 0 : return true;
2521 : }
2522 0 : return false;
2523 : }
2524 :
2525 : class FindByOriginalDim : public std::unary_function<ScPivotField, bool>
2526 : {
2527 : long mnDim;
2528 : public:
2529 0 : FindByOriginalDim(long nDim) : mnDim(nDim) {}
2530 0 : bool operator() (const ScPivotField& r) const
2531 : {
2532 0 : return mnDim == r.getOriginalDim();
2533 : }
2534 : };
2535 :
2536 : }
2537 :
2538 0 : void ScDPObject::ConvertOrientation(
2539 : ScDPSaveData& rSaveData, const ScPivotFieldVector& rFields, sal_uInt16 nOrient,
2540 : const Reference<XDimensionsSupplier>& xSource,
2541 : const ScDPLabelDataVector& rLabels,
2542 : const ScPivotFieldVector* pRefColFields,
2543 : const ScPivotFieldVector* pRefRowFields,
2544 : const ScPivotFieldVector* pRefPageFields )
2545 : {
2546 0 : ScPivotFieldVector::const_iterator itr, itrBeg = rFields.begin(), itrEnd = rFields.end();
2547 0 : for (itr = itrBeg; itr != itrEnd; ++itr)
2548 : {
2549 0 : const ScPivotField& rField = *itr;
2550 :
2551 0 : long nCol = rField.getOriginalDim();
2552 0 : sal_uInt16 nFuncs = rField.nFuncMask;
2553 0 : const sheet::DataPilotFieldReference& rFieldRef = rField.maFieldRef;
2554 :
2555 0 : ScDPSaveDimension* pDim = NULL;
2556 0 : if ( nCol == PIVOT_DATA_FIELD )
2557 0 : pDim = rSaveData.GetDataLayoutDimension();
2558 : else
2559 : {
2560 0 : OUString aDocStr = lcl_GetDimName( xSource, nCol ); // cols must start at 0
2561 0 : if (!aDocStr.isEmpty())
2562 0 : pDim = rSaveData.GetDimensionByName(aDocStr);
2563 : else
2564 0 : pDim = NULL;
2565 : }
2566 :
2567 0 : if (!pDim)
2568 0 : continue;
2569 :
2570 0 : if ( nOrient == sheet::DataPilotFieldOrientation_DATA ) // set summary function
2571 : {
2572 : // generate an individual entry for each function
2573 0 : bool bFirst = true;
2574 :
2575 : // if a dimension is used for column/row/page and data,
2576 : // use duplicated dimensions for all data occurrences
2577 0 : if (hasFieldColumn(pRefColFields, nCol))
2578 0 : bFirst = false;
2579 :
2580 0 : if (bFirst && hasFieldColumn(pRefRowFields, nCol))
2581 0 : bFirst = false;
2582 :
2583 0 : if (bFirst && hasFieldColumn(pRefPageFields, nCol))
2584 0 : bFirst = false;
2585 :
2586 0 : if (bFirst)
2587 : {
2588 : // if set via api, a data column may occur several times
2589 : // (if the function hasn't been changed yet) -> also look for duplicate data column
2590 0 : bFirst = std::find_if(itrBeg, itr, FindByOriginalDim(nCol)) == itr;
2591 : }
2592 :
2593 0 : sheet::GeneralFunction eFunc = ScDataPilotConversion::FirstFunc(rField.nFuncMask);
2594 0 : if (!bFirst)
2595 0 : pDim = rSaveData.DuplicateDimension(pDim->GetName());
2596 0 : pDim->SetOrientation(nOrient);
2597 0 : pDim->SetFunction(sal::static_int_cast<sal_uInt16>(eFunc));
2598 :
2599 0 : if( rFieldRef.ReferenceType == sheet::DataPilotFieldReferenceType::NONE )
2600 0 : pDim->SetReferenceValue(0);
2601 : else
2602 0 : pDim->SetReferenceValue(&rFieldRef);
2603 : }
2604 : else // set SubTotals
2605 : {
2606 0 : pDim->SetOrientation( nOrient );
2607 :
2608 : sal_uInt16 nFuncArray[16];
2609 0 : sal_uInt16 nFuncCount = 0;
2610 0 : sal_uInt16 nMask = 1;
2611 0 : for (sal_uInt16 nBit=0; nBit<16; nBit++)
2612 : {
2613 0 : if ( nFuncs & nMask )
2614 0 : nFuncArray[nFuncCount++] = sal::static_int_cast<sal_uInt16>(ScDataPilotConversion::FirstFunc( nMask ));
2615 0 : nMask *= 2;
2616 : }
2617 0 : pDim->SetSubTotals( nFuncCount, nFuncArray );
2618 :
2619 : // ShowEmpty was implicit in old tables,
2620 : // must be set for data layout dimension (not accessible in dialog)
2621 0 : if ( nCol == PIVOT_DATA_FIELD )
2622 0 : pDim->SetShowEmpty( true );
2623 : }
2624 :
2625 0 : size_t nDimIndex = rField.nCol;
2626 0 : pDim->RemoveLayoutName();
2627 0 : pDim->RemoveSubtotalName();
2628 0 : if (nDimIndex < rLabels.size())
2629 : {
2630 0 : const ScDPLabelData& rLabel = rLabels[nDimIndex];
2631 0 : if (!rLabel.maLayoutName.isEmpty())
2632 0 : pDim->SetLayoutName(rLabel.maLayoutName);
2633 0 : if (!rLabel.maSubtotalName.isEmpty())
2634 0 : pDim->SetSubtotalName(rLabel.maSubtotalName);
2635 : }
2636 : }
2637 0 : }
2638 :
2639 0 : bool ScDPObject::IsOrientationAllowed( sal_uInt16 nOrient, sal_Int32 nDimFlags )
2640 : {
2641 0 : bool bAllowed = true;
2642 0 : switch (nOrient)
2643 : {
2644 : case sheet::DataPilotFieldOrientation_PAGE:
2645 0 : bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_PAGE_ORIENTATION ) == 0;
2646 0 : break;
2647 : case sheet::DataPilotFieldOrientation_COLUMN:
2648 0 : bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_COLUMN_ORIENTATION ) == 0;
2649 0 : break;
2650 : case sheet::DataPilotFieldOrientation_ROW:
2651 0 : bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_ROW_ORIENTATION ) == 0;
2652 0 : break;
2653 : case sheet::DataPilotFieldOrientation_DATA:
2654 0 : bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_DATA_ORIENTATION ) == 0;
2655 0 : break;
2656 : default:
2657 : {
2658 : // allowed to remove from previous orientation
2659 : }
2660 : }
2661 0 : return bAllowed;
2662 : }
2663 :
2664 0 : bool ScDPObject::HasRegisteredSources()
2665 : {
2666 0 : bool bFound = false;
2667 :
2668 0 : uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
2669 0 : uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
2670 0 : if ( xEnAc.is() )
2671 : {
2672 0 : uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
2673 0 : OUString( SCDPSOURCE_SERVICE ) );
2674 0 : if ( xEnum.is() && xEnum->hasMoreElements() )
2675 0 : bFound = true;
2676 : }
2677 :
2678 0 : return bFound;
2679 : }
2680 :
2681 0 : uno::Sequence<OUString> ScDPObject::GetRegisteredSources()
2682 : {
2683 0 : uno::Sequence<OUString> aSeq(0);
2684 :
2685 : // use implementation names...
2686 :
2687 0 : uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
2688 0 : uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
2689 0 : if ( xEnAc.is() )
2690 : {
2691 0 : uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
2692 0 : OUString( SCDPSOURCE_SERVICE ) );
2693 0 : if ( xEnum.is() )
2694 : {
2695 0 : long nCount = 0;
2696 0 : while ( xEnum->hasMoreElements() )
2697 : {
2698 0 : uno::Any aAddInAny = xEnum->nextElement();
2699 : // if ( aAddInAny.getReflection()->getTypeClass() == TypeClass_INTERFACE )
2700 : {
2701 0 : uno::Reference<uno::XInterface> xIntFac;
2702 0 : aAddInAny >>= xIntFac;
2703 0 : if ( xIntFac.is() )
2704 : {
2705 0 : uno::Reference<lang::XServiceInfo> xInfo( xIntFac, uno::UNO_QUERY );
2706 0 : if ( xInfo.is() )
2707 : {
2708 0 : OUString sName = xInfo->getImplementationName();
2709 :
2710 0 : aSeq.realloc( nCount+1 );
2711 0 : aSeq.getArray()[nCount] = sName;
2712 0 : ++nCount;
2713 0 : }
2714 0 : }
2715 : }
2716 0 : }
2717 0 : }
2718 : }
2719 :
2720 0 : return aSeq;
2721 : }
2722 :
2723 0 : uno::Reference<sheet::XDimensionsSupplier> ScDPObject::CreateSource( const ScDPServiceDesc& rDesc )
2724 : {
2725 0 : OUString aImplName = rDesc.aServiceName;
2726 0 : uno::Reference<sheet::XDimensionsSupplier> xRet = NULL;
2727 :
2728 0 : uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
2729 0 : uno::Reference<container::XContentEnumerationAccess> xEnAc(xManager, uno::UNO_QUERY);
2730 0 : if (!xEnAc.is())
2731 0 : return xRet;
2732 :
2733 : uno::Reference<container::XEnumeration> xEnum =
2734 0 : xEnAc->createContentEnumeration(OUString(SCDPSOURCE_SERVICE));
2735 0 : if (!xEnum.is())
2736 0 : return xRet;
2737 :
2738 0 : while (xEnum->hasMoreElements() && !xRet.is())
2739 : {
2740 0 : uno::Any aAddInAny = xEnum->nextElement();
2741 0 : uno::Reference<uno::XInterface> xIntFac;
2742 0 : aAddInAny >>= xIntFac;
2743 0 : if (!xIntFac.is())
2744 0 : continue;
2745 :
2746 0 : uno::Reference<lang::XServiceInfo> xInfo(xIntFac, uno::UNO_QUERY);
2747 0 : if (!xInfo.is() || xInfo->getImplementationName() != aImplName)
2748 0 : continue;
2749 :
2750 : try
2751 : {
2752 : // #i113160# try XSingleComponentFactory in addition to (old) XSingleServiceFactory,
2753 : // passing the context to the component (see ScUnoAddInCollection::Initialize)
2754 :
2755 0 : uno::Reference<uno::XInterface> xInterface;
2756 : uno::Reference<uno::XComponentContext> xCtx(
2757 0 : comphelper::getComponentContext(xManager));
2758 0 : uno::Reference<lang::XSingleComponentFactory> xCFac( xIntFac, uno::UNO_QUERY );
2759 0 : if (xCFac.is())
2760 0 : xInterface = xCFac->createInstanceWithContext(xCtx);
2761 :
2762 0 : if (!xInterface.is())
2763 : {
2764 0 : uno::Reference<lang::XSingleServiceFactory> xFac( xIntFac, uno::UNO_QUERY );
2765 0 : if ( xFac.is() )
2766 0 : xInterface = xFac->createInstance();
2767 : }
2768 :
2769 0 : uno::Reference<lang::XInitialization> xInit( xInterface, uno::UNO_QUERY );
2770 0 : if (xInit.is())
2771 : {
2772 : // initialize
2773 0 : uno::Sequence<uno::Any> aSeq(4);
2774 0 : uno::Any* pArray = aSeq.getArray();
2775 0 : pArray[0] <<= OUString( rDesc.aParSource );
2776 0 : pArray[1] <<= OUString( rDesc.aParName );
2777 0 : pArray[2] <<= OUString( rDesc.aParUser );
2778 0 : pArray[3] <<= OUString( rDesc.aParPass );
2779 0 : xInit->initialize( aSeq );
2780 : }
2781 0 : xRet = uno::Reference<sheet::XDimensionsSupplier>( xInterface, uno::UNO_QUERY );
2782 : }
2783 0 : catch(uno::Exception&)
2784 : {
2785 : }
2786 0 : }
2787 :
2788 0 : return xRet;
2789 : }
2790 :
2791 : #if DEBUG_PIVOT_TABLE
2792 : void ScDPObject::DumpCache() const
2793 : {
2794 : if (!mpTableData)
2795 : return;
2796 :
2797 : const ScDPCache* pCache = mpTableData->GetCacheTable().getCache();
2798 : if (!pCache)
2799 : return;
2800 :
2801 : pCache->Dump();
2802 : }
2803 : #endif
2804 :
2805 588 : ScDPCollection::SheetCaches::SheetCaches(ScDocument* pDoc) : mpDoc(pDoc) {}
2806 :
2807 : namespace {
2808 :
2809 : struct FindInvalidRange : public std::unary_function<ScRange, bool>
2810 : {
2811 56 : bool operator() (const ScRange& r) const
2812 : {
2813 56 : return !r.IsValid();
2814 : }
2815 : };
2816 :
2817 6 : void setGroupItemsToCache( ScDPCache& rCache, const std::set<ScDPObject*>& rRefs )
2818 : {
2819 : // Go through all referencing pivot tables, and re-fill the group dimension info.
2820 6 : std::set<ScDPObject*>::const_iterator itRef = rRefs.begin(), itRefEnd = rRefs.end();
2821 14 : for (; itRef != itRefEnd; ++itRef)
2822 : {
2823 8 : const ScDPObject* pObj = *itRef;
2824 8 : const ScDPSaveData* pSave = pObj->GetSaveData();
2825 8 : if (!pSave)
2826 0 : continue;
2827 :
2828 8 : const ScDPDimensionSaveData* pGroupDims = pSave->GetExistingDimensionData();
2829 8 : if (!pGroupDims)
2830 8 : continue;
2831 :
2832 0 : pGroupDims->WriteToCache(rCache);
2833 : }
2834 6 : }
2835 :
2836 : }
2837 :
2838 32 : bool ScDPCollection::SheetCaches::hasCache(const ScRange& rRange) const
2839 : {
2840 32 : RangeIndexType::const_iterator it = std::find(maRanges.begin(), maRanges.end(), rRange);
2841 32 : if (it == maRanges.end())
2842 10 : return false;
2843 :
2844 : // Already cached.
2845 22 : size_t nIndex = std::distance(maRanges.begin(), it);
2846 22 : CachesType::const_iterator itCache = maCaches.find(nIndex);
2847 22 : return itCache != maCaches.end();
2848 : }
2849 :
2850 186 : const ScDPCache* ScDPCollection::SheetCaches::getCache(const ScRange& rRange, const ScDPDimensionSaveData* pDimData)
2851 : {
2852 186 : RangeIndexType::iterator it = std::find(maRanges.begin(), maRanges.end(), rRange);
2853 186 : if (it != maRanges.end())
2854 : {
2855 : // Already cached.
2856 52 : size_t nIndex = std::distance(maRanges.begin(), it);
2857 52 : CachesType::iterator itCache = maCaches.find(nIndex);
2858 52 : if (itCache == maCaches.end())
2859 : {
2860 : OSL_FAIL("Cache pool and index pool out-of-sync !!!");
2861 0 : return NULL;
2862 : }
2863 :
2864 52 : if (pDimData)
2865 6 : pDimData->WriteToCache(*itCache->second);
2866 :
2867 52 : return itCache->second;
2868 : }
2869 :
2870 : // Not cached. Create a new cache.
2871 134 : ::std::unique_ptr<ScDPCache> pCache(new ScDPCache(mpDoc));
2872 134 : pCache->InitFromDoc(mpDoc, rRange);
2873 134 : if (pDimData)
2874 2 : pDimData->WriteToCache(*pCache);
2875 :
2876 : // Get the smallest available range index.
2877 134 : it = std::find_if(maRanges.begin(), maRanges.end(), FindInvalidRange());
2878 :
2879 134 : size_t nIndex = maRanges.size();
2880 134 : if (it == maRanges.end())
2881 : {
2882 : // All range indices are valid. Append a new index.
2883 86 : maRanges.push_back(rRange);
2884 : }
2885 : else
2886 : {
2887 : // Slot with invalid range. Re-use this slot.
2888 48 : *it = rRange;
2889 48 : nIndex = std::distance(maRanges.begin(), it);
2890 : }
2891 :
2892 134 : const ScDPCache* p = pCache.get();
2893 134 : o3tl::ptr_container::insert(maCaches, nIndex, std::move(pCache));
2894 134 : return p;
2895 : }
2896 :
2897 14 : ScDPCache* ScDPCollection::SheetCaches::getExistingCache(const ScRange& rRange)
2898 : {
2899 14 : RangeIndexType::iterator it = std::find(maRanges.begin(), maRanges.end(), rRange);
2900 14 : if (it == maRanges.end())
2901 : // Not cached.
2902 0 : return NULL;
2903 :
2904 : // Already cached.
2905 14 : size_t nIndex = std::distance(maRanges.begin(), it);
2906 14 : CachesType::iterator itCache = maCaches.find(nIndex);
2907 14 : if (itCache == maCaches.end())
2908 : {
2909 : OSL_FAIL("Cache pool and index pool out-of-sync !!!");
2910 0 : return NULL;
2911 : }
2912 :
2913 14 : return itCache->second;
2914 : }
2915 :
2916 12 : const ScDPCache* ScDPCollection::SheetCaches::getExistingCache(const ScRange& rRange) const
2917 : {
2918 12 : RangeIndexType::const_iterator it = std::find(maRanges.begin(), maRanges.end(), rRange);
2919 12 : if (it == maRanges.end())
2920 : // Not cached.
2921 0 : return NULL;
2922 :
2923 : // Already cached.
2924 12 : size_t nIndex = std::distance(maRanges.begin(), it);
2925 12 : CachesType::const_iterator itCache = maCaches.find(nIndex);
2926 12 : if (itCache == maCaches.end())
2927 : {
2928 : OSL_FAIL("Cache pool and index pool out-of-sync !!!");
2929 0 : return NULL;
2930 : }
2931 :
2932 12 : return itCache->second;
2933 : }
2934 :
2935 44 : size_t ScDPCollection::SheetCaches::size() const
2936 : {
2937 44 : return maCaches.size();
2938 : }
2939 :
2940 262 : void ScDPCollection::SheetCaches::updateReference(
2941 : UpdateRefMode eMode, const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz)
2942 : {
2943 262 : if (maRanges.empty())
2944 : // No caches.
2945 426 : return;
2946 :
2947 98 : RangeIndexType::iterator it = maRanges.begin(), itEnd = maRanges.end();
2948 260 : for (; it != itEnd; ++it)
2949 : {
2950 162 : const ScRange& rKeyRange = *it;
2951 162 : SCCOL nCol1 = rKeyRange.aStart.Col();
2952 162 : SCROW nRow1 = rKeyRange.aStart.Row();
2953 162 : SCTAB nTab1 = rKeyRange.aStart.Tab();
2954 162 : SCCOL nCol2 = rKeyRange.aEnd.Col();
2955 162 : SCROW nRow2 = rKeyRange.aEnd.Row();
2956 162 : SCTAB nTab2 = rKeyRange.aEnd.Tab();
2957 :
2958 : ScRefUpdateRes eRes = ScRefUpdate::Update(
2959 : mpDoc, eMode,
2960 324 : r.aStart.Col(), r.aStart.Row(), r.aStart.Tab(),
2961 324 : r.aEnd.Col(), r.aEnd.Row(), r.aEnd.Tab(), nDx, nDy, nDz,
2962 810 : nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
2963 :
2964 162 : if (eRes != UR_NOTHING)
2965 : {
2966 : // range updated.
2967 66 : ScRange aNew(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
2968 66 : *it = aNew;
2969 : }
2970 : }
2971 : }
2972 :
2973 6 : void ScDPCollection::SheetCaches::updateCache(const ScRange& rRange, std::set<ScDPObject*>& rRefs)
2974 : {
2975 6 : RangeIndexType::iterator it = std::find(maRanges.begin(), maRanges.end(), rRange);
2976 6 : if (it == maRanges.end())
2977 : {
2978 : // Not cached. Nothing to do.
2979 0 : rRefs.clear();
2980 0 : return;
2981 : }
2982 :
2983 6 : size_t nIndex = std::distance(maRanges.begin(), it);
2984 6 : CachesType::iterator itCache = maCaches.find(nIndex);
2985 6 : if (itCache == maCaches.end())
2986 : {
2987 : OSL_FAIL("Cache pool and index pool out-of-sync !!!");
2988 0 : rRefs.clear();
2989 0 : return;
2990 : }
2991 :
2992 6 : ScDPCache& rCache = *itCache->second;
2993 :
2994 : // Update the cache with new cell values. This will clear all group dimension info.
2995 6 : rCache.InitFromDoc(mpDoc, rRange);
2996 :
2997 6 : std::set<ScDPObject*> aRefs(rCache.GetAllReferences());
2998 6 : rRefs.swap(aRefs);
2999 :
3000 : // Make sure to re-populate the group dimension info.
3001 6 : setGroupItemsToCache(rCache, rRefs);
3002 : }
3003 :
3004 110 : bool ScDPCollection::SheetCaches::remove(const ScDPCache* p)
3005 : {
3006 110 : CachesType::iterator it = maCaches.begin(), itEnd = maCaches.end();
3007 116 : for (; it != itEnd; ++it)
3008 : {
3009 112 : if (it->second == p)
3010 : {
3011 106 : size_t idx = it->first;
3012 106 : maCaches.erase(it);
3013 106 : maRanges[idx].SetInvalid();
3014 106 : return true;
3015 : }
3016 : }
3017 4 : return false;
3018 : }
3019 :
3020 4 : const std::vector<ScRange>& ScDPCollection::SheetCaches::getAllRanges() const
3021 : {
3022 4 : return maRanges;
3023 : }
3024 :
3025 588 : ScDPCollection::NameCaches::NameCaches(ScDocument* pDoc) : mpDoc(pDoc) {}
3026 :
3027 2 : bool ScDPCollection::NameCaches::hasCache(const OUString& rName) const
3028 : {
3029 2 : return maCaches.count(rName) != 0;
3030 : }
3031 :
3032 4 : const ScDPCache* ScDPCollection::NameCaches::getCache(
3033 : const OUString& rName, const ScRange& rRange, const ScDPDimensionSaveData* pDimData)
3034 : {
3035 4 : CachesType::const_iterator itr = maCaches.find(rName);
3036 4 : if (itr != maCaches.end())
3037 : // already cached.
3038 0 : return itr->second;
3039 :
3040 4 : ::std::unique_ptr<ScDPCache> pCache(new ScDPCache(mpDoc));
3041 4 : pCache->InitFromDoc(mpDoc, rRange);
3042 4 : if (pDimData)
3043 0 : pDimData->WriteToCache(*pCache);
3044 :
3045 4 : const ScDPCache* p = pCache.get();
3046 4 : o3tl::ptr_container::insert(maCaches, rName, std::move(pCache));
3047 4 : return p;
3048 : }
3049 :
3050 0 : ScDPCache* ScDPCollection::NameCaches::getExistingCache(const OUString& rName)
3051 : {
3052 0 : CachesType::iterator itr = maCaches.find(rName);
3053 0 : return itr != maCaches.end() ? itr->second : NULL;
3054 : }
3055 :
3056 6 : size_t ScDPCollection::NameCaches::size() const
3057 : {
3058 6 : return maCaches.size();
3059 : }
3060 :
3061 0 : void ScDPCollection::NameCaches::updateCache(
3062 : const OUString& rName, const ScRange& rRange, std::set<ScDPObject*>& rRefs)
3063 : {
3064 0 : CachesType::iterator itr = maCaches.find(rName);
3065 0 : if (itr == maCaches.end())
3066 : {
3067 0 : rRefs.clear();
3068 0 : return;
3069 : }
3070 :
3071 0 : ScDPCache& rCache = *itr->second;
3072 : // Update the cache with new cell values. This will clear all group dimension info.
3073 0 : rCache.InitFromDoc(mpDoc, rRange);
3074 :
3075 0 : std::set<ScDPObject*> aRefs(rCache.GetAllReferences());
3076 0 : rRefs.swap(aRefs);
3077 :
3078 : // Make sure to re-populate the group dimension info.
3079 0 : setGroupItemsToCache(rCache, rRefs);
3080 : }
3081 :
3082 4 : bool ScDPCollection::NameCaches::remove(const ScDPCache* p)
3083 : {
3084 4 : CachesType::iterator it = maCaches.begin(), itEnd = maCaches.end();
3085 4 : for (; it != itEnd; ++it)
3086 : {
3087 4 : if (it->second == p)
3088 : {
3089 4 : maCaches.erase(it);
3090 4 : return true;
3091 : }
3092 : }
3093 0 : return false;
3094 : }
3095 :
3096 0 : ScDPCollection::DBType::DBType(sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand) :
3097 0 : mnSdbType(nSdbType), maDBName(rDBName), maCommand(rCommand) {}
3098 :
3099 0 : bool ScDPCollection::DBType::less::operator() (const DBType& left, const DBType& right) const
3100 : {
3101 0 : return left < right;
3102 : }
3103 :
3104 588 : ScDPCollection::DBCaches::DBCaches(ScDocument* pDoc) : mpDoc(pDoc) {}
3105 :
3106 0 : bool ScDPCollection::DBCaches::hasCache(sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand) const
3107 : {
3108 0 : DBType aType(nSdbType, rDBName, rCommand);
3109 0 : CachesType::const_iterator itr = maCaches.find(aType);
3110 0 : return itr != maCaches.end();
3111 : }
3112 :
3113 0 : const ScDPCache* ScDPCollection::DBCaches::getCache(
3114 : sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand,
3115 : const ScDPDimensionSaveData* pDimData)
3116 : {
3117 0 : DBType aType(nSdbType, rDBName, rCommand);
3118 0 : CachesType::const_iterator itr = maCaches.find(aType);
3119 0 : if (itr != maCaches.end())
3120 : // already cached.
3121 0 : return itr->second;
3122 :
3123 0 : uno::Reference<sdbc::XRowSet> xRowSet = createRowSet(nSdbType, rDBName, rCommand);
3124 0 : if (!xRowSet.is())
3125 0 : return NULL;
3126 :
3127 0 : ::std::unique_ptr<ScDPCache> pCache(new ScDPCache(mpDoc));
3128 0 : SvNumberFormatter aFormat( comphelper::getProcessComponentContext(), ScGlobal::eLnge);
3129 0 : DBConnector aDB(*pCache, xRowSet, *aFormat.GetNullDate());
3130 0 : if (!aDB.isValid())
3131 0 : return NULL;
3132 :
3133 0 : if (!pCache->InitFromDataBase(aDB))
3134 : {
3135 : // initialization failed.
3136 0 : comphelper::disposeComponent(xRowSet);
3137 0 : return NULL;
3138 : }
3139 :
3140 0 : if (pDimData)
3141 0 : pDimData->WriteToCache(*pCache);
3142 :
3143 0 : ::comphelper::disposeComponent(xRowSet);
3144 0 : const ScDPCache* p = pCache.get();
3145 0 : o3tl::ptr_container::insert(maCaches, aType, std::move(pCache));
3146 0 : return p;
3147 : }
3148 :
3149 0 : ScDPCache* ScDPCollection::DBCaches::getExistingCache(
3150 : sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand)
3151 : {
3152 0 : DBType aType(nSdbType, rDBName, rCommand);
3153 0 : CachesType::iterator itr = maCaches.find(aType);
3154 0 : return itr != maCaches.end() ? itr->second : NULL;
3155 : }
3156 :
3157 0 : uno::Reference<sdbc::XRowSet> ScDPCollection::DBCaches::createRowSet(
3158 : sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand)
3159 : {
3160 0 : uno::Reference<sdbc::XRowSet> xRowSet;
3161 : try
3162 : {
3163 0 : xRowSet = uno::Reference<sdbc::XRowSet>(
3164 0 : comphelper::getProcessServiceFactory()->createInstance(
3165 0 : OUString(SC_SERVICE_ROWSET)),
3166 0 : UNO_QUERY);
3167 :
3168 0 : uno::Reference<beans::XPropertySet> xRowProp(xRowSet, UNO_QUERY);
3169 : OSL_ENSURE( xRowProp.is(), "can't get RowSet" );
3170 0 : if (!xRowProp.is())
3171 : {
3172 0 : xRowSet.set(NULL);
3173 0 : return xRowSet;
3174 : }
3175 :
3176 : // set source parameters
3177 :
3178 0 : uno::Any aAny;
3179 0 : aAny <<= rDBName;
3180 0 : xRowProp->setPropertyValue(
3181 0 : OUString(SC_DBPROP_DATASOURCENAME), aAny );
3182 :
3183 0 : aAny <<= rCommand;
3184 0 : xRowProp->setPropertyValue(
3185 0 : OUString(SC_DBPROP_COMMAND), aAny );
3186 :
3187 0 : aAny <<= nSdbType;
3188 0 : xRowProp->setPropertyValue(
3189 0 : OUString(SC_DBPROP_COMMANDTYPE), aAny );
3190 :
3191 0 : uno::Reference<sdb::XCompletedExecution> xExecute( xRowSet, uno::UNO_QUERY );
3192 0 : if ( xExecute.is() )
3193 : {
3194 : uno::Reference<task::XInteractionHandler> xHandler(
3195 : task::InteractionHandler::createWithParent(comphelper::getProcessComponentContext(), 0),
3196 0 : uno::UNO_QUERY_THROW);
3197 0 : xExecute->executeWithCompletion( xHandler );
3198 : }
3199 : else
3200 0 : xRowSet->execute();
3201 :
3202 0 : return xRowSet;
3203 : }
3204 0 : catch ( const sdbc::SQLException& rError )
3205 : {
3206 : //! store error message
3207 0 : InfoBox aInfoBox( 0, OUString(rError.Message) );
3208 0 : aInfoBox.Execute();
3209 : }
3210 0 : catch ( uno::Exception& )
3211 : {
3212 : OSL_FAIL("Unexpected exception in database");
3213 : }
3214 :
3215 0 : xRowSet.set(NULL);
3216 0 : return xRowSet;
3217 : }
3218 :
3219 0 : void ScDPCollection::DBCaches::updateCache(
3220 : sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand,
3221 : std::set<ScDPObject*>& rRefs)
3222 : {
3223 0 : DBType aType(nSdbType, rDBName, rCommand);
3224 0 : CachesType::iterator it = maCaches.find(aType);
3225 0 : if (it == maCaches.end())
3226 : {
3227 : // not cached.
3228 0 : rRefs.clear();
3229 0 : return;
3230 : }
3231 :
3232 0 : ScDPCache& rCache = *it->second;
3233 :
3234 0 : uno::Reference<sdbc::XRowSet> xRowSet = createRowSet(nSdbType, rDBName, rCommand);
3235 0 : if (!xRowSet.is())
3236 : {
3237 0 : rRefs.clear();
3238 0 : return;
3239 : }
3240 :
3241 0 : SvNumberFormatter aFormat( comphelper::getProcessComponentContext(), ScGlobal::eLnge);
3242 0 : DBConnector aDB(rCache, xRowSet, *aFormat.GetNullDate());
3243 0 : if (!aDB.isValid())
3244 0 : return;
3245 :
3246 0 : if (!rCache.InitFromDataBase(aDB))
3247 : {
3248 : // initialization failed.
3249 0 : rRefs.clear();
3250 0 : comphelper::disposeComponent(xRowSet);
3251 0 : return;
3252 : }
3253 :
3254 0 : comphelper::disposeComponent(xRowSet);
3255 0 : std::set<ScDPObject*> aRefs(rCache.GetAllReferences());
3256 0 : aRefs.swap(rRefs);
3257 :
3258 : // Make sure to re-populate the group dimension info.
3259 0 : setGroupItemsToCache(rCache, rRefs);
3260 : }
3261 :
3262 0 : bool ScDPCollection::DBCaches::remove(const ScDPCache* p)
3263 : {
3264 0 : CachesType::iterator it = maCaches.begin(), itEnd = maCaches.end();
3265 0 : for (; it != itEnd; ++it)
3266 : {
3267 0 : if (it->second == p)
3268 : {
3269 0 : maCaches.erase(it);
3270 0 : return true;
3271 : }
3272 : }
3273 0 : return false;
3274 : }
3275 :
3276 466 : ScDPCollection::ScDPCollection(ScDocument* pDocument) :
3277 : mpDoc( pDocument ),
3278 : maSheetCaches(pDocument),
3279 : maNameCaches(pDocument),
3280 466 : maDBCaches(pDocument)
3281 : {
3282 466 : }
3283 :
3284 122 : ScDPCollection::ScDPCollection(const ScDPCollection& r) :
3285 : mpDoc(r.mpDoc),
3286 : maSheetCaches(r.mpDoc),
3287 : maNameCaches(r.mpDoc),
3288 122 : maDBCaches(r.mpDoc)
3289 : {
3290 122 : }
3291 :
3292 1176 : ScDPCollection::~ScDPCollection()
3293 : {
3294 588 : maTables.clear();
3295 588 : }
3296 :
3297 : namespace {
3298 :
3299 : /**
3300 : * Unary predicate to match DP objects by the table ID.
3301 : */
3302 : class MatchByTable : public unary_function<ScDPObject, bool>
3303 : {
3304 : SCTAB mnTab;
3305 : public:
3306 82 : MatchByTable(SCTAB nTab) : mnTab(nTab) {}
3307 :
3308 64 : bool operator() (const ScDPObject& rObj) const
3309 : {
3310 64 : return rObj.GetOutRange().aStart.Tab() == mnTab;
3311 : }
3312 : };
3313 :
3314 : }
3315 :
3316 10 : sal_uLong ScDPCollection::ReloadCache(ScDPObject* pDPObj, std::set<ScDPObject*>& rRefs)
3317 : {
3318 10 : if (!pDPObj)
3319 0 : return STR_ERR_DATAPILOTSOURCE;
3320 :
3321 10 : if (pDPObj->IsSheetData())
3322 : {
3323 : // data source is internal sheet.
3324 10 : const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc();
3325 10 : if (!pDesc)
3326 0 : return STR_ERR_DATAPILOTSOURCE;
3327 :
3328 10 : sal_uLong nErrId = pDesc->CheckSourceRange();
3329 10 : if (nErrId)
3330 0 : return nErrId;
3331 :
3332 10 : if (pDesc->HasRangeName())
3333 : {
3334 : // cache by named range
3335 0 : ScDPCollection::NameCaches& rCaches = GetNameCaches();
3336 0 : if (rCaches.hasCache(pDesc->GetRangeName()))
3337 0 : rCaches.updateCache(pDesc->GetRangeName(), pDesc->GetSourceRange(), rRefs);
3338 : else
3339 : {
3340 : // Not cached yet. Collect all tables that use this named
3341 : // range as data source.
3342 0 : GetAllTables(pDesc->GetRangeName(), rRefs);
3343 : }
3344 : }
3345 : else
3346 : {
3347 : // cache by cell range
3348 10 : ScDPCollection::SheetCaches& rCaches = GetSheetCaches();
3349 10 : if (rCaches.hasCache(pDesc->GetSourceRange()))
3350 6 : rCaches.updateCache(pDesc->GetSourceRange(), rRefs);
3351 : else
3352 : {
3353 : // Not cached yet. Collect all tables that use this range as
3354 : // data source.
3355 4 : GetAllTables(pDesc->GetSourceRange(), rRefs);
3356 : }
3357 : }
3358 : }
3359 0 : else if (pDPObj->IsImportData())
3360 : {
3361 : // data source is external database.
3362 0 : const ScImportSourceDesc* pDesc = pDPObj->GetImportSourceDesc();
3363 0 : if (!pDesc)
3364 0 : return STR_ERR_DATAPILOTSOURCE;
3365 :
3366 0 : ScDPCollection::DBCaches& rCaches = GetDBCaches();
3367 0 : if (rCaches.hasCache(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject))
3368 : rCaches.updateCache(
3369 0 : pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, rRefs);
3370 : else
3371 : {
3372 : // Not cached yet. Collect all tables that use this range as
3373 : // data source.
3374 0 : GetAllTables(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, rRefs);
3375 : }
3376 : }
3377 10 : return 0;
3378 : }
3379 :
3380 16 : bool ScDPCollection::ReloadGroupsInCache(ScDPObject* pDPObj, std::set<ScDPObject*>& rRefs)
3381 : {
3382 16 : if (!pDPObj)
3383 0 : return false;
3384 :
3385 16 : const ScDPSaveData* pSaveData = pDPObj->GetSaveData();
3386 16 : if (!pSaveData)
3387 0 : return false;
3388 :
3389 : // Note: Unlike reloading cache, when modifying the group dimensions the
3390 : // cache may not have all its references when this method is called.
3391 : // Therefore, we need to always call GetAllTables to get its correct
3392 : // references even when the cache exists. This may become a non-issue
3393 : // if/when we implement loading and saving of pivot caches.
3394 :
3395 16 : ScDPCache* pCache = NULL;
3396 :
3397 16 : if (pDPObj->IsSheetData())
3398 : {
3399 : // data source is internal sheet.
3400 16 : const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc();
3401 16 : if (!pDesc)
3402 0 : return false;
3403 :
3404 16 : if (pDesc->HasRangeName())
3405 : {
3406 : // cache by named range
3407 0 : ScDPCollection::NameCaches& rCaches = GetNameCaches();
3408 0 : if (rCaches.hasCache(pDesc->GetRangeName()))
3409 0 : pCache = rCaches.getExistingCache(pDesc->GetRangeName());
3410 : else
3411 : {
3412 : // Not cached yet. Cache the source dimensions. Groups will
3413 : // be added below.
3414 : pCache = const_cast<ScDPCache*>(
3415 0 : rCaches.getCache(pDesc->GetRangeName(), pDesc->GetSourceRange(), NULL));
3416 : }
3417 0 : GetAllTables(pDesc->GetRangeName(), rRefs);
3418 : }
3419 : else
3420 : {
3421 : // cache by cell range
3422 16 : ScDPCollection::SheetCaches& rCaches = GetSheetCaches();
3423 16 : if (rCaches.hasCache(pDesc->GetSourceRange()))
3424 12 : pCache = rCaches.getExistingCache(pDesc->GetSourceRange());
3425 : else
3426 : {
3427 : // Not cached yet. Cache the source dimensions. Groups will
3428 : // be added below.
3429 : pCache = const_cast<ScDPCache*>(
3430 4 : rCaches.getCache(pDesc->GetSourceRange(), NULL));
3431 : }
3432 16 : GetAllTables(pDesc->GetSourceRange(), rRefs);
3433 : }
3434 : }
3435 0 : else if (pDPObj->IsImportData())
3436 : {
3437 : // data source is external database.
3438 0 : const ScImportSourceDesc* pDesc = pDPObj->GetImportSourceDesc();
3439 0 : if (!pDesc)
3440 0 : return false;
3441 :
3442 0 : ScDPCollection::DBCaches& rCaches = GetDBCaches();
3443 0 : if (rCaches.hasCache(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject))
3444 : pCache = rCaches.getExistingCache(
3445 0 : pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject);
3446 : else
3447 : {
3448 : // Not cached yet. Cache the source dimensions. Groups will
3449 : // be added below.
3450 : pCache = const_cast<ScDPCache*>(
3451 0 : rCaches.getCache(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, NULL));
3452 : }
3453 0 : GetAllTables(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, rRefs);
3454 : }
3455 :
3456 16 : if (!pCache)
3457 0 : return false;
3458 :
3459 : // Clear the existing group data from the cache, and rebuild it from the
3460 : // dimension data.
3461 16 : pCache->ClearGroupFields();
3462 16 : const ScDPDimensionSaveData* pDimData = pSaveData->GetExistingDimensionData();
3463 16 : if (pDimData)
3464 16 : pDimData->WriteToCache(*pCache);
3465 16 : return true;
3466 : }
3467 :
3468 82 : void ScDPCollection::DeleteOnTab( SCTAB nTab )
3469 : {
3470 82 : maTables.erase_if(MatchByTable(nTab));
3471 82 : }
3472 :
3473 262 : void ScDPCollection::UpdateReference( UpdateRefMode eUpdateRefMode,
3474 : const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
3475 : {
3476 262 : TablesType::iterator itr = maTables.begin(), itrEnd = maTables.end();
3477 394 : for (; itr != itrEnd; ++itr)
3478 132 : itr->UpdateReference(eUpdateRefMode, r, nDx, nDy, nDz);
3479 :
3480 : // Update the source ranges of the caches.
3481 262 : maSheetCaches.updateReference(eUpdateRefMode, r, nDx, nDy, nDz);
3482 262 : }
3483 :
3484 0 : void ScDPCollection::CopyToTab( SCTAB nOld, SCTAB nNew )
3485 : {
3486 0 : TablesType aAdded;
3487 0 : TablesType::const_iterator it = maTables.begin(), itEnd = maTables.end();
3488 0 : for (; it != itEnd; ++it)
3489 : {
3490 0 : const ScDPObject& rObj = *it;
3491 0 : ScRange aOutRange = rObj.GetOutRange();
3492 0 : if (aOutRange.aStart.Tab() != nOld)
3493 0 : continue;
3494 :
3495 0 : ScAddress& s = aOutRange.aStart;
3496 0 : ScAddress& e = aOutRange.aEnd;
3497 0 : s.SetTab(nNew);
3498 0 : e.SetTab(nNew);
3499 0 : std::unique_ptr<ScDPObject> pNew(new ScDPObject(rObj));
3500 0 : pNew->SetOutRange(aOutRange);
3501 0 : mpDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
3502 0 : o3tl::ptr_container::push_back(aAdded, std::move(pNew));
3503 0 : }
3504 :
3505 0 : maTables.transfer(maTables.end(), aAdded.begin(), aAdded.end(), aAdded);
3506 0 : }
3507 :
3508 122 : bool ScDPCollection::RefsEqual( const ScDPCollection& r ) const
3509 : {
3510 122 : if (maTables.size() != r.maTables.size())
3511 32 : return false;
3512 :
3513 90 : TablesType::const_iterator itr = maTables.begin(), itr2 = r.maTables.begin(), itrEnd = maTables.end();
3514 90 : for (; itr != itrEnd; ++itr, ++itr2)
3515 0 : if (!itr->RefsEqual(*itr2))
3516 0 : return false;
3517 :
3518 90 : return true;
3519 : }
3520 :
3521 0 : void ScDPCollection::WriteRefsTo( ScDPCollection& r ) const
3522 : {
3523 0 : if ( maTables.size() == r.maTables.size() )
3524 : {
3525 : //! assert equal names?
3526 0 : TablesType::const_iterator itr = maTables.begin(), itrEnd = maTables.end();
3527 0 : TablesType::iterator itr2 = r.maTables.begin();
3528 0 : for (; itr != itrEnd; ++itr, ++itr2)
3529 0 : itr->WriteRefsTo(*itr2);
3530 : }
3531 : else
3532 : {
3533 : // #i8180# If data pilot tables were deleted with their sheet,
3534 : // this collection contains extra entries that must be restored.
3535 : // Matching objects are found by their names.
3536 0 : size_t nSrcSize = maTables.size();
3537 0 : size_t nDestSize = r.maTables.size();
3538 : OSL_ENSURE( nSrcSize >= nDestSize, "WriteRefsTo: missing entries in document" );
3539 0 : for (size_t nSrcPos = 0; nSrcPos < nSrcSize; ++nSrcPos)
3540 : {
3541 0 : const ScDPObject& rSrcObj = maTables[nSrcPos];
3542 0 : const OUString& aName = rSrcObj.GetName();
3543 0 : bool bFound = false;
3544 0 : for (size_t nDestPos = 0; nDestPos < nDestSize && !bFound; ++nDestPos)
3545 : {
3546 0 : ScDPObject& rDestObj = r.maTables[nDestPos];
3547 0 : if (rDestObj.GetName() == aName)
3548 : {
3549 0 : rSrcObj.WriteRefsTo(rDestObj); // found object, copy refs
3550 0 : bFound = true;
3551 : }
3552 : }
3553 :
3554 0 : if (!bFound)
3555 : {
3556 : // none found, re-insert deleted object (see ScUndoDataPilot::Undo)
3557 :
3558 0 : ScDPObject* pDestObj = new ScDPObject(rSrcObj);
3559 0 : r.InsertNewTable(pDestObj);
3560 : }
3561 : }
3562 : OSL_ENSURE( maTables.size() == r.maTables.size(), "WriteRefsTo: couldn't restore all entries" );
3563 : }
3564 0 : }
3565 :
3566 2568 : size_t ScDPCollection::GetCount() const
3567 : {
3568 2568 : return maTables.size();
3569 : }
3570 :
3571 2684 : ScDPObject* ScDPCollection::operator [](size_t nIndex)
3572 : {
3573 2684 : return &maTables[nIndex];
3574 : }
3575 :
3576 4 : const ScDPObject* ScDPCollection::operator [](size_t nIndex) const
3577 : {
3578 4 : return &maTables[nIndex];
3579 : }
3580 :
3581 58 : const ScDPObject* ScDPCollection::GetByName(const OUString& rName) const
3582 : {
3583 58 : TablesType::const_iterator itr = maTables.begin(), itrEnd = maTables.end();
3584 66 : for (; itr != itrEnd; ++itr)
3585 8 : if (itr->GetName() == rName)
3586 0 : return &(*itr);
3587 :
3588 58 : return NULL;
3589 : }
3590 :
3591 36 : OUString ScDPCollection::CreateNewName( sal_uInt16 nMin ) const
3592 : {
3593 36 : OUString aBase("DataPilot");
3594 :
3595 36 : size_t n = maTables.size();
3596 36 : for (size_t nAdd = 0; nAdd <= n; ++nAdd) // nCount+1 tries
3597 : {
3598 36 : OUStringBuffer aBuf;
3599 36 : aBuf.append(aBase);
3600 36 : aBuf.append(static_cast<sal_Int32>(nMin + nAdd));
3601 36 : OUString aNewName = aBuf.makeStringAndClear();
3602 36 : bool bFound = false;
3603 36 : TablesType::const_iterator itr = maTables.begin(), itrEnd = maTables.end();
3604 72 : for (; itr != itrEnd; ++itr)
3605 : {
3606 36 : if (itr->GetName() == aNewName)
3607 : {
3608 0 : bFound = true;
3609 0 : break;
3610 : }
3611 : }
3612 36 : if (!bFound)
3613 36 : return aNewName; // found unused Name
3614 0 : }
3615 0 : return OUString(); // should not happen
3616 : }
3617 :
3618 42 : void ScDPCollection::FreeTable(ScDPObject* pDPObj)
3619 : {
3620 42 : const ScRange& rOutRange = pDPObj->GetOutRange();
3621 42 : const ScAddress& s = rOutRange.aStart;
3622 42 : const ScAddress& e = rOutRange.aEnd;
3623 42 : mpDoc->RemoveFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
3624 42 : TablesType::iterator itr = maTables.begin(), itrEnd = maTables.end();
3625 44 : for (; itr != itrEnd; ++itr)
3626 : {
3627 44 : ScDPObject* p = &(*itr);
3628 44 : if (p == pDPObj)
3629 : {
3630 42 : maTables.erase(itr);
3631 42 : break;
3632 : }
3633 : }
3634 42 : }
3635 :
3636 98 : bool ScDPCollection::InsertNewTable(ScDPObject* pDPObj)
3637 : {
3638 98 : const ScRange& rOutRange = pDPObj->GetOutRange();
3639 98 : const ScAddress& s = rOutRange.aStart;
3640 98 : const ScAddress& e = rOutRange.aEnd;
3641 98 : mpDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
3642 :
3643 98 : maTables.push_back(pDPObj);
3644 98 : return true;
3645 : }
3646 :
3647 258 : ScDPCollection::SheetCaches& ScDPCollection::GetSheetCaches()
3648 : {
3649 258 : return maSheetCaches;
3650 : }
3651 :
3652 12 : const ScDPCollection::SheetCaches& ScDPCollection::GetSheetCaches() const
3653 : {
3654 12 : return maSheetCaches;
3655 : }
3656 :
3657 12 : ScDPCollection::NameCaches& ScDPCollection::GetNameCaches()
3658 : {
3659 12 : return maNameCaches;
3660 : }
3661 :
3662 0 : const ScDPCollection::NameCaches& ScDPCollection::GetNameCaches() const
3663 : {
3664 0 : return maNameCaches;
3665 : }
3666 :
3667 0 : ScDPCollection::DBCaches& ScDPCollection::GetDBCaches()
3668 : {
3669 0 : return maDBCaches;
3670 : }
3671 :
3672 0 : const ScDPCollection::DBCaches& ScDPCollection::GetDBCaches() const
3673 : {
3674 0 : return maDBCaches;
3675 : }
3676 :
3677 143 : ScRangeList ScDPCollection::GetAllTableRanges( SCTAB nTab ) const
3678 : {
3679 143 : return std::for_each(maTables.begin(), maTables.end(), AccumulateOutputRanges(nTab)).getRanges();
3680 : }
3681 :
3682 0 : bool ScDPCollection::IntersectsTableByColumns( SCCOL nCol1, SCCOL nCol2, SCROW nRow, SCTAB nTab ) const
3683 : {
3684 : return std::find_if(
3685 0 : maTables.begin(), maTables.end(), FindIntersetingTableByColumns(nCol1, nCol2, nRow, nTab)) != maTables.end();
3686 : }
3687 :
3688 0 : bool ScDPCollection::IntersectsTableByRows( SCCOL nCol, SCROW nRow1, SCROW nRow2, SCTAB nTab ) const
3689 : {
3690 : return std::find_if(
3691 0 : maTables.begin(), maTables.end(), FindIntersectingTableByRows(nCol, nRow1, nRow2, nTab)) != maTables.end();
3692 : }
3693 :
3694 0 : bool ScDPCollection::HasTable( const ScRange& rRange ) const
3695 : {
3696 : return std::find_if(
3697 0 : maTables.begin(), maTables.end(), FindIntersectingTable(rRange)) != maTables.end();
3698 : }
3699 :
3700 : #if DEBUG_PIVOT_TABLE
3701 :
3702 : namespace {
3703 :
3704 : struct DumpTable : std::unary_function<ScDPObject, void>
3705 : {
3706 : void operator() (const ScDPObject& rObj) const
3707 : {
3708 : cout << "-- '" << rObj.GetName() << "'" << endl;
3709 : ScDPSaveData* pSaveData = rObj.GetSaveData();
3710 : if (!pSaveData)
3711 : return;
3712 :
3713 : pSaveData->Dump();
3714 :
3715 : cout << endl; // blank line
3716 : }
3717 : };
3718 :
3719 : }
3720 :
3721 : void ScDPCollection::DumpTables() const
3722 : {
3723 : std::for_each(maTables.begin(), maTables.end(), DumpTable());
3724 : }
3725 :
3726 : #endif
3727 :
3728 110 : void ScDPCollection::RemoveCache(const ScDPCache* pCache)
3729 : {
3730 110 : if (maSheetCaches.remove(pCache))
3731 : // sheet cache removed.
3732 106 : return;
3733 :
3734 4 : if (maNameCaches.remove(pCache))
3735 : // named range cache removed.
3736 4 : return;
3737 :
3738 0 : if (maDBCaches.remove(pCache))
3739 : // database cache removed.
3740 0 : return;
3741 : }
3742 :
3743 20 : void ScDPCollection::GetAllTables(const ScRange& rSrcRange, std::set<ScDPObject*>& rRefs) const
3744 : {
3745 20 : std::set<ScDPObject*> aRefs;
3746 20 : TablesType::const_iterator it = maTables.begin(), itEnd = maTables.end();
3747 42 : for (; it != itEnd; ++it)
3748 : {
3749 22 : const ScDPObject& rObj = *it;
3750 22 : if (!rObj.IsSheetData())
3751 : // Source is not a sheet range.
3752 0 : continue;
3753 :
3754 22 : const ScSheetSourceDesc* pDesc = rObj.GetSheetDesc();
3755 22 : if (!pDesc)
3756 0 : continue;
3757 :
3758 22 : if (pDesc->HasRangeName())
3759 : // This table has a range name as its source.
3760 0 : continue;
3761 :
3762 22 : if (pDesc->GetSourceRange() != rSrcRange)
3763 : // Different source range.
3764 0 : continue;
3765 :
3766 22 : aRefs.insert(const_cast<ScDPObject*>(&rObj));
3767 : }
3768 :
3769 20 : rRefs.swap(aRefs);
3770 20 : }
3771 :
3772 0 : void ScDPCollection::GetAllTables(const OUString& rSrcName, std::set<ScDPObject*>& rRefs) const
3773 : {
3774 0 : std::set<ScDPObject*> aRefs;
3775 0 : TablesType::const_iterator it = maTables.begin(), itEnd = maTables.end();
3776 0 : for (; it != itEnd; ++it)
3777 : {
3778 0 : const ScDPObject& rObj = *it;
3779 0 : if (!rObj.IsSheetData())
3780 : // Source is not a sheet range.
3781 0 : continue;
3782 :
3783 0 : const ScSheetSourceDesc* pDesc = rObj.GetSheetDesc();
3784 0 : if (!pDesc)
3785 0 : continue;
3786 :
3787 0 : if (!pDesc->HasRangeName())
3788 : // This table probably has a sheet range as its source.
3789 0 : continue;
3790 :
3791 0 : if (pDesc->GetRangeName() != rSrcName)
3792 : // Different source name.
3793 0 : continue;
3794 :
3795 0 : aRefs.insert(const_cast<ScDPObject*>(&rObj));
3796 : }
3797 :
3798 0 : rRefs.swap(aRefs);
3799 0 : }
3800 :
3801 0 : void ScDPCollection::GetAllTables(
3802 : sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand,
3803 : std::set<ScDPObject*>& rRefs) const
3804 : {
3805 0 : std::set<ScDPObject*> aRefs;
3806 0 : TablesType::const_iterator it = maTables.begin(), itEnd = maTables.end();
3807 0 : for (; it != itEnd; ++it)
3808 : {
3809 0 : const ScDPObject& rObj = *it;
3810 0 : if (!rObj.IsImportData())
3811 : // Source data is not a database.
3812 0 : continue;
3813 :
3814 0 : const ScImportSourceDesc* pDesc = rObj.GetImportSourceDesc();
3815 0 : if (!pDesc)
3816 0 : continue;
3817 :
3818 0 : if (!pDesc->aDBName.equals(rDBName) || !pDesc->aObject.equals(rCommand) || pDesc->GetCommandType() != nSdbType)
3819 : // Different database source.
3820 0 : continue;
3821 :
3822 0 : aRefs.insert(const_cast<ScDPObject*>(&rObj));
3823 : }
3824 :
3825 0 : rRefs.swap(aRefs);
3826 0 : }
3827 :
3828 0 : bool operator<(const ScDPCollection::DBType& left, const ScDPCollection::DBType& right)
3829 : {
3830 0 : if (left.mnSdbType != right.mnSdbType)
3831 0 : return left.mnSdbType < right.mnSdbType;
3832 :
3833 0 : if (!left.maDBName.equals(right.maDBName))
3834 0 : return left.maDBName < right.maDBName;
3835 :
3836 0 : return left.maCommand < right.maCommand;
3837 228 : }
3838 :
3839 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|