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