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