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