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