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