1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sc.hxx" 30 31 32 33 // INCLUDE --------------------------------------------------------------- 34 35 #include "dpobject.hxx" 36 #include "dptabsrc.hxx" 37 #include "dpsave.hxx" 38 #include "dpdimsave.hxx" 39 #include "dpoutput.hxx" 40 #include "dpshttab.hxx" 41 #include "dpsdbtab.hxx" 42 #include "dpgroup.hxx" 43 #include "document.hxx" 44 #include "rechead.hxx" 45 #include "pivot.hxx" // PIVOT_DATA_FIELD 46 #include "dapiuno.hxx" // ScDataPilotConversion 47 #include "miscuno.hxx" 48 #include "scerrors.hxx" 49 #include "refupdat.hxx" 50 #include "scresid.hxx" 51 #include "sc.hrc" 52 #include "attrib.hxx" 53 #include "scitems.hxx" 54 #include "unonames.hxx" 55 // Wang Xu Ming -- 2009-8-17 56 // DataPilot Migration - Cache&&Performance 57 #include "dpglobal.hxx" 58 #include "globstr.hrc" 59 // End Comments 60 #include <com/sun/star/beans/XPropertySet.hpp> 61 #include <com/sun/star/sheet/GeneralFunction.hpp> 62 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp> 63 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp> 64 #include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp> 65 #include <com/sun/star/sheet/DataPilotTableHeaderData.hpp> 66 #include <com/sun/star/sheet/DataPilotTablePositionData.hpp> 67 #include <com/sun/star/sheet/DataPilotTablePositionType.hpp> 68 #include <com/sun/star/sheet/DimensionFlags.hpp> 69 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 70 #include <com/sun/star/lang/XSingleServiceFactory.hpp> 71 #include <com/sun/star/lang/XSingleComponentFactory.hpp> 72 #include <com/sun/star/lang/XInitialization.hpp> 73 #include <com/sun/star/container/XContentEnumerationAccess.hpp> 74 #include <com/sun/star/sheet/XDrillDownDataSupplier.hpp> 75 76 #include <comphelper/processfactory.hxx> 77 #include <tools/debug.hxx> 78 #include <tools/diagnose_ex.h> 79 #include <svl/zforlist.hxx> // IsNumberFormat 80 81 #include <vector> 82 #include <stdio.h> 83 84 using namespace com::sun::star; 85 using ::std::vector; 86 using ::boost::shared_ptr; 87 using ::com::sun::star::uno::Sequence; 88 using ::com::sun::star::uno::Reference; 89 using ::com::sun::star::uno::UNO_QUERY; 90 using ::com::sun::star::uno::Any; 91 using ::com::sun::star::uno::Exception; 92 using ::com::sun::star::lang::XComponent; 93 using ::com::sun::star::sheet::DataPilotTableHeaderData; 94 using ::com::sun::star::sheet::DataPilotTablePositionData; 95 using ::com::sun::star::beans::XPropertySet; 96 using ::rtl::OUString; 97 98 99 // ----------------------------------------------------------------------- 100 101 #define SCDPSOURCE_SERVICE "com.sun.star.sheet.DataPilotSource" 102 103 // ----------------------------------------------------------------------- 104 105 // incompatible versions of data pilot files 106 #define SC_DP_VERSION_CURRENT 6 107 108 // type of source data 109 #define SC_DP_SOURCE_SHEET 0 110 #define SC_DP_SOURCE_DATABASE 1 111 #define SC_DP_SOURCE_SERVICE 2 112 113 // ----------------------------------------------------------------------- 114 115 //! move to a header file 116 #define DP_PROP_COLUMNGRAND "ColumnGrand" 117 #define DP_PROP_FUNCTION "Function" 118 #define DP_PROP_IGNOREEMPTY "IgnoreEmptyRows" 119 #define DP_PROP_ISDATALAYOUT "IsDataLayoutDimension" 120 //#define DP_PROP_ISVISIBLE "IsVisible" 121 #define DP_PROP_ORIENTATION "Orientation" 122 #define DP_PROP_ORIGINAL "Original" 123 #define DP_PROP_POSITION "Position" 124 #define DP_PROP_REPEATIFEMPTY "RepeatIfEmpty" 125 #define DP_PROP_ROWGRAND "RowGrand" 126 #define DP_PROP_SHOWDETAILS "ShowDetails" 127 #define DP_PROP_SHOWEMPTY "ShowEmpty" 128 #define DP_PROP_SUBTOTALS "SubTotals" 129 #define DP_PROP_USEDHIERARCHY "UsedHierarchy" 130 131 // ----------------------------------------------------------------------- 132 133 sal_uInt16 lcl_GetDataGetOrientation( const uno::Reference<sheet::XDimensionsSupplier>& xSource ) 134 { 135 long nRet = sheet::DataPilotFieldOrientation_HIDDEN; 136 if ( xSource.is() ) 137 { 138 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions(); 139 uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName ); 140 long nIntCount = xIntDims->getCount(); 141 sal_Bool bFound = sal_False; 142 for (long nIntDim=0; nIntDim<nIntCount && !bFound; nIntDim++) 143 { 144 uno::Reference<uno::XInterface> xIntDim = 145 ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nIntDim) ); 146 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY ); 147 if ( xDimProp.is() ) 148 { 149 bFound = ScUnoHelpFunctions::GetBoolProperty( xDimProp, 150 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) ); 151 //! error checking -- is "IsDataLayoutDimension" property required?? 152 if (bFound) 153 nRet = ScUnoHelpFunctions::GetEnumProperty( 154 xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION), 155 sheet::DataPilotFieldOrientation_HIDDEN ); 156 } 157 } 158 } 159 return static_cast< sal_uInt16 >( nRet ); 160 } 161 162 // ----------------------------------------------------------------------- 163 164 ScDPObject::ScDPObject( ScDocument* pD ) : 165 pDoc( pD ), 166 pSaveData( NULL ), 167 pSheetDesc( NULL ), 168 pImpDesc( NULL ), 169 pServDesc( NULL ), 170 mpTableData(static_cast<ScDPTableData*>(NULL)), 171 pOutput( NULL ), 172 bSettingsChanged( sal_False ), 173 bAlive( sal_False ), 174 bAllowMove( sal_False ), 175 nHeaderRows( 0 ), 176 mbHeaderLayout(false), 177 bRefresh( sal_False ), // Wang Xu Ming - DataPilot migration 178 mnCacheId( -1 ), // Wang Xu Ming - DataPilot migration 179 mbCreatingTableData( false ) 180 { 181 } 182 183 ScDPObject::ScDPObject(const ScDPObject& r) : 184 ScDataObject(), 185 pDoc( r.pDoc ), 186 pSaveData( NULL ), 187 aTableName( r.aTableName ), 188 aTableTag( r.aTableTag ), 189 aOutRange( r.aOutRange ), 190 pSheetDesc( NULL ), 191 pImpDesc( NULL ), 192 pServDesc( NULL ), 193 mpTableData(static_cast<ScDPTableData*>(NULL)), 194 pOutput( NULL ), 195 bSettingsChanged( sal_False ), 196 bAlive( sal_False ), 197 bAllowMove( sal_False ), 198 nHeaderRows( r.nHeaderRows ), 199 mbHeaderLayout( r.mbHeaderLayout ), 200 bRefresh( r.bRefresh ), // Wang Xu Ming - DataPilot migration 201 mnCacheId ( r.mnCacheId ), // Wang Xu Ming - DataPilot migration 202 mbCreatingTableData( false ) 203 { 204 if (r.pSaveData) 205 pSaveData = new ScDPSaveData(*r.pSaveData); 206 if (r.pSheetDesc) 207 pSheetDesc = new ScSheetSourceDesc(*r.pSheetDesc); 208 if (r.pImpDesc) 209 pImpDesc = new ScImportSourceDesc(*r.pImpDesc); 210 if (r.pServDesc) 211 pServDesc = new ScDPServiceDesc(*r.pServDesc); 212 // xSource (and pOutput) is not copied 213 } 214 215 ScDPObject::~ScDPObject() 216 { 217 delete pOutput; 218 delete pSaveData; 219 delete pSheetDesc; 220 delete pImpDesc; 221 delete pServDesc; 222 mnCacheId = -1; // Wang Xu Ming - DataPilot migration 223 InvalidateSource(); 224 } 225 226 ScDataObject* ScDPObject::Clone() const 227 { 228 return new ScDPObject(*this); 229 } 230 231 void ScDPObject::SetAlive(sal_Bool bSet) 232 { 233 bAlive = bSet; 234 } 235 236 void ScDPObject::SetAllowMove(sal_Bool bSet) 237 { 238 bAllowMove = bSet; 239 } 240 241 void ScDPObject::SetSaveData(const ScDPSaveData& rData) 242 { 243 if ( pSaveData != &rData ) // API implementation modifies the original SaveData object 244 { 245 delete pSaveData; 246 pSaveData = new ScDPSaveData( rData ); 247 // Wang Xu Ming -- 2009-8-17 248 // DataPilot Migration - Cache&&Performance 249 if ( rData.GetCacheId() >= 0 ) 250 mnCacheId = rData.GetCacheId(); 251 else if ( mnCacheId >= 0 ) 252 pSaveData->SetCacheId( mnCacheId ); 253 // End Comments 254 } 255 256 InvalidateData(); // re-init source from SaveData 257 } 258 259 void ScDPObject::SetHeaderLayout (bool bUseGrid) 260 { 261 mbHeaderLayout = bUseGrid; 262 } 263 264 bool ScDPObject::GetHeaderLayout() const 265 { 266 return mbHeaderLayout; 267 } 268 269 void ScDPObject::SetOutRange(const ScRange& rRange) 270 { 271 aOutRange = rRange; 272 273 if ( pOutput ) 274 pOutput->SetPosition( rRange.aStart ); 275 } 276 277 void ScDPObject::SetSheetDesc(const ScSheetSourceDesc& rDesc, bool bFromRefUpdate) 278 { 279 if ( pSheetDesc && rDesc == *pSheetDesc ) 280 return; // nothing to do 281 282 DELETEZ( pImpDesc ); 283 DELETEZ( pServDesc ); 284 285 delete pSheetDesc; 286 pSheetDesc = new ScSheetSourceDesc(rDesc); 287 288 // make valid QueryParam 289 290 pSheetDesc->aQueryParam.nCol1 = pSheetDesc->aSourceRange.aStart.Col(); 291 pSheetDesc->aQueryParam.nRow1 = pSheetDesc->aSourceRange.aStart.Row(); 292 pSheetDesc->aQueryParam.nCol2 = pSheetDesc->aSourceRange.aEnd.Col(); 293 pSheetDesc->aQueryParam.nRow2 = pSheetDesc->aSourceRange.aEnd.Row();; 294 pSheetDesc->aQueryParam.bHasHeader = sal_True; 295 296 InvalidateSource(); // new source must be created 297 if (!bFromRefUpdate) 298 SetCacheId( -1 ); // #i116504# don't use the same cache ID for a different range (except reference update) 299 } 300 301 void ScDPObject::SetImportDesc(const ScImportSourceDesc& rDesc) 302 { 303 if ( pImpDesc && rDesc == *pImpDesc ) 304 return; // nothing to do 305 306 DELETEZ( pSheetDesc ); 307 DELETEZ( pServDesc ); 308 309 delete pImpDesc; 310 pImpDesc = new ScImportSourceDesc(rDesc); 311 312 InvalidateSource(); // new source must be created 313 SetCacheId( -1 ); 314 } 315 316 void ScDPObject::SetServiceData(const ScDPServiceDesc& rDesc) 317 { 318 if ( pServDesc && rDesc == *pServDesc ) 319 return; // nothing to do 320 321 DELETEZ( pSheetDesc ); 322 DELETEZ( pImpDesc ); 323 324 delete pServDesc; 325 pServDesc = new ScDPServiceDesc(rDesc); 326 327 InvalidateSource(); // new source must be created 328 } 329 330 void ScDPObject::WriteSourceDataTo( ScDPObject& rDest ) const 331 { 332 if ( pSheetDesc ) 333 rDest.SetSheetDesc( *pSheetDesc ); 334 else if ( pImpDesc ) 335 rDest.SetImportDesc( *pImpDesc ); 336 else if ( pServDesc ) 337 rDest.SetServiceData( *pServDesc ); 338 339 // name/tag are not source data, but needed along with source data 340 341 rDest.aTableName = aTableName; 342 rDest.aTableTag = aTableTag; 343 } 344 345 void ScDPObject::WriteTempDataTo( ScDPObject& rDest ) const 346 { 347 rDest.nHeaderRows = nHeaderRows; 348 } 349 350 sal_Bool ScDPObject::IsSheetData() const 351 { 352 return ( pSheetDesc != NULL ); 353 } 354 355 void ScDPObject::SetName(const String& rNew) 356 { 357 aTableName = rNew; 358 } 359 360 void ScDPObject::SetTag(const String& rNew) 361 { 362 aTableTag = rNew; 363 } 364 365 bool ScDPObject::IsDataDescriptionCell(const ScAddress& rPos) 366 { 367 if (!pSaveData) 368 return false; 369 370 long nDataDimCount = pSaveData->GetDataDimensionCount(); 371 if (nDataDimCount != 1) 372 // There has to be exactly one data dimension for the description to 373 // appear at top-left corner. 374 return false; 375 376 CreateOutput(); 377 ScRange aTabRange = pOutput->GetOutputRange(sheet::DataPilotOutputRangeType::TABLE); 378 return (rPos == aTabRange.aStart); 379 } 380 381 uno::Reference<sheet::XDimensionsSupplier> ScDPObject::GetSource() 382 { 383 CreateObjects(); 384 return xSource; 385 } 386 387 void ScDPObject::CreateOutput() 388 { 389 CreateObjects(); 390 if (!pOutput) 391 { 392 sal_Bool bFilterButton = IsSheetData() && pSaveData && pSaveData->GetFilterButton(); 393 pOutput = new ScDPOutput( pDoc, xSource, aOutRange.aStart, bFilterButton ); 394 pOutput->SetHeaderLayout ( mbHeaderLayout ); 395 396 long nOldRows = nHeaderRows; 397 nHeaderRows = pOutput->GetHeaderRows(); 398 399 if ( bAllowMove && nHeaderRows != nOldRows ) 400 { 401 long nDiff = nOldRows - nHeaderRows; 402 if ( nOldRows == 0 ) 403 --nDiff; 404 if ( nHeaderRows == 0 ) 405 ++nDiff; 406 407 long nNewRow = aOutRange.aStart.Row() + nDiff; 408 if ( nNewRow < 0 ) 409 nNewRow = 0; 410 411 ScAddress aStart( aOutRange.aStart ); 412 aStart.SetRow(nNewRow); 413 pOutput->SetPosition( aStart ); 414 415 //! modify aOutRange? 416 417 bAllowMove = sal_False; // use only once 418 } 419 } 420 } 421 422 ScDPTableData* ScDPObject::GetTableData() 423 { 424 if (!mpTableData && !mbCreatingTableData) 425 { 426 // #i117239# While filling the cache, mpTableData is still null. 427 // Prevent nested calls from GetPivotData and similar functions. 428 mbCreatingTableData = true; 429 430 shared_ptr<ScDPTableData> pData; 431 if ( pImpDesc ) 432 { 433 // database data 434 pData.reset(new ScDatabaseDPData(pDoc, *pImpDesc, GetCacheId())); 435 } 436 else 437 { 438 // cell data 439 if (!pSheetDesc) 440 { 441 DBG_ERROR("no source descriptor"); 442 pSheetDesc = new ScSheetSourceDesc; // dummy defaults 443 } 444 // Wang Xu Ming -- 2009-8-17 445 // DataPilot Migration - Cache&&Performance 446 pData.reset(new ScSheetDPData(pDoc, *pSheetDesc, GetCacheId())); 447 // End Comments 448 } 449 450 // grouping (for cell or database data) 451 if ( pSaveData && pSaveData->GetExistingDimensionData() ) 452 { 453 shared_ptr<ScDPGroupTableData> pGroupData(new ScDPGroupTableData(pData, pDoc)); 454 pSaveData->GetExistingDimensionData()->WriteToData(*pGroupData); 455 pData = pGroupData; 456 } 457 458 // Wang Xu Ming -- 2009-8-17 459 // DataPilot Migration - Cache&&Performance 460 if ( pData ) 461 SetCacheId( pData->GetCacheId()); // resets mpTableData 462 // End Comments 463 464 mpTableData = pData; // after SetCacheId 465 466 mbCreatingTableData = false; 467 } 468 469 return mpTableData.get(); 470 } 471 472 void ScDPObject::CreateObjects() 473 { 474 // if groups are involved, create a new source with the ScDPGroupTableData 475 if ( bSettingsChanged && pSaveData && pSaveData->GetExistingDimensionData() ) 476 InvalidateSource(); 477 478 if (!xSource.is()) 479 { 480 //! cache DPSource and/or Output? 481 482 DBG_ASSERT( bAlive, "CreateObjects on non-inserted DPObject" ); 483 484 DELETEZ( pOutput ); // not valid when xSource is changed 485 486 if ( pServDesc ) 487 { 488 xSource = CreateSource( *pServDesc ); 489 } 490 491 if ( !xSource.is() ) // database or sheet data, or error in CreateSource 492 { 493 DBG_ASSERT( !pServDesc, "DPSource could not be created" ); 494 ScDPTableData* pData = GetTableData(); 495 496 if ( pData ) // nested GetTableData calls may return NULL 497 { 498 ScDPSource* pSource = new ScDPSource( pData ); 499 xSource = pSource; 500 501 if ( pSaveData && bRefresh ) 502 { 503 pSaveData->Refresh( xSource ); 504 bRefresh = sal_False; 505 } 506 } 507 } 508 if ( xSource.is() && pSaveData ) 509 pSaveData->WriteToSource( xSource ); 510 } 511 else if (bSettingsChanged) 512 { 513 DELETEZ( pOutput ); // not valid when xSource is changed 514 515 uno::Reference<util::XRefreshable> xRef( xSource, uno::UNO_QUERY ); 516 if (xRef.is()) 517 { 518 try 519 { 520 xRef->refresh(); 521 } 522 catch(uno::Exception&) 523 { 524 DBG_ERROR("exception in refresh"); 525 } 526 } 527 528 if (pSaveData) 529 pSaveData->WriteToSource( xSource ); 530 } 531 bSettingsChanged = sal_False; 532 } 533 534 void ScDPObject::InvalidateData() 535 { 536 bSettingsChanged = sal_True; 537 } 538 539 void ScDPObject::InvalidateSource() 540 { 541 Reference< XComponent > xObjectComp( xSource, UNO_QUERY ); 542 if ( xObjectComp.is() ) 543 { 544 try 545 { 546 xObjectComp->dispose(); 547 } 548 catch( const Exception& ) 549 { 550 DBG_UNHANDLED_EXCEPTION(); 551 } 552 } 553 xSource = NULL; 554 mpTableData.reset(); 555 } 556 557 ScRange ScDPObject::GetNewOutputRange( sal_Bool& rOverflow ) 558 { 559 CreateOutput(); // create xSource and pOutput if not already done 560 561 rOverflow = pOutput->HasError(); // range overflow or exception from source 562 if ( rOverflow ) 563 return ScRange( aOutRange.aStart ); 564 else 565 { 566 // don't store the result in aOutRange, because nothing has been output yet 567 return pOutput->GetOutputRange(); 568 } 569 } 570 571 void ScDPObject::Output( const ScAddress& rPos ) 572 { 573 // clear old output area 574 pDoc->DeleteAreaTab( aOutRange.aStart.Col(), aOutRange.aStart.Row(), 575 aOutRange.aEnd.Col(), aOutRange.aEnd.Row(), 576 aOutRange.aStart.Tab(), IDF_ALL ); 577 pDoc->RemoveFlagsTab( aOutRange.aStart.Col(), aOutRange.aStart.Row(), 578 aOutRange.aEnd.Col(), aOutRange.aEnd.Row(), 579 aOutRange.aStart.Tab(), SC_MF_AUTO ); 580 581 CreateOutput(); // create xSource and pOutput if not already done 582 583 pOutput->SetPosition( rPos ); 584 585 pOutput->Output(); 586 587 // aOutRange is always the range that was last output to the document 588 aOutRange = pOutput->GetOutputRange(); 589 const ScAddress& s = aOutRange.aStart; 590 const ScAddress& e = aOutRange.aEnd; 591 pDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE); 592 } 593 594 const ScRange ScDPObject::GetOutputRangeByType( sal_Int32 nType ) 595 { 596 CreateOutput(); 597 598 if (pOutput->HasError()) 599 return ScRange(aOutRange.aStart); 600 601 return pOutput->GetOutputRange(nType); 602 } 603 604 sal_Bool lcl_HasButton( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab ) 605 { 606 return ((const ScMergeFlagAttr*)pDoc->GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG ))->HasButton(); 607 } 608 609 void ScDPObject::RefreshAfterLoad() 610 { 611 // apply drop-down attribute, initialize nHeaderRows, without accessing the source 612 // (button attribute must be present) 613 614 // simple test: block of button cells at the top, followed by an empty cell 615 616 SCCOL nFirstCol = aOutRange.aStart.Col(); 617 SCROW nFirstRow = aOutRange.aStart.Row(); 618 SCTAB nTab = aOutRange.aStart.Tab(); 619 620 SCROW nInitial = 0; 621 SCROW nOutRows = aOutRange.aEnd.Row() + 1 - aOutRange.aStart.Row(); 622 while ( nInitial + 1 < nOutRows && lcl_HasButton( pDoc, nFirstCol, nFirstRow + nInitial, nTab ) ) 623 ++nInitial; 624 625 if ( nInitial + 1 < nOutRows && 626 pDoc->IsBlockEmpty( nTab, nFirstCol, nFirstRow + nInitial, nFirstCol, nFirstRow + nInitial ) && 627 aOutRange.aEnd.Col() > nFirstCol ) 628 { 629 sal_Bool bFilterButton = IsSheetData(); // when available, filter button setting must be checked here 630 631 SCROW nSkip = bFilterButton ? 1 : 0; 632 for (SCROW nPos=nSkip; nPos<nInitial; nPos++) 633 pDoc->ApplyAttr( nFirstCol + 1, nFirstRow + nPos, nTab, ScMergeFlagAttr(SC_MF_AUTO) ); 634 635 nHeaderRows = nInitial; 636 } 637 else 638 nHeaderRows = 0; // nothing found, no drop-down lists 639 } 640 641 void ScDPObject::BuildAllDimensionMembers() 642 { 643 if (!pSaveData) 644 return; 645 646 // #i111857# don't always create empty mpTableData for external service. 647 // #163781# Initialize all members from xSource instead. 648 if (pServDesc) 649 { 650 pSaveData->BuildAllDimensionMembersFromSource( this ); 651 return; 652 } 653 654 pSaveData->BuildAllDimensionMembers(GetTableData()); 655 } 656 657 bool ScDPObject::GetMemberNames( sal_Int32 nDim, Sequence<OUString>& rNames ) 658 { 659 vector<ScDPLabelData::Member> aMembers; 660 if (!GetMembers(nDim, GetUsedHierarchy(nDim), aMembers)) 661 return false; 662 663 size_t n = aMembers.size(); 664 rNames.realloc(n); 665 for (size_t i = 0; i < n; ++i) 666 rNames[i] = aMembers[i].maName; 667 668 return true; 669 } 670 671 bool ScDPObject::GetMembers( sal_Int32 nDim, sal_Int32 nHier, vector<ScDPLabelData::Member>& rMembers ) 672 { 673 Reference< container::XNameAccess > xMembersNA; 674 if (!GetMembersNA( nDim, nHier, xMembersNA )) 675 return false; 676 677 Reference<container::XIndexAccess> xMembersIA( new ScNameToIndexAccess(xMembersNA) ); 678 sal_Int32 nCount = xMembersIA->getCount(); 679 vector<ScDPLabelData::Member> aMembers; 680 aMembers.reserve(nCount); 681 682 for (sal_Int32 i = 0; i < nCount; ++i) 683 { 684 Reference<container::XNamed> xMember(xMembersIA->getByIndex(i), UNO_QUERY); 685 ScDPLabelData::Member aMem; 686 687 if (xMember.is()) 688 aMem.maName = xMember->getName(); 689 690 Reference<beans::XPropertySet> xMemProp(xMember, UNO_QUERY); 691 if (xMemProp.is()) 692 { 693 aMem.mbVisible = ScUnoHelpFunctions::GetBoolProperty(xMemProp, OUString::createFromAscii(SC_UNO_ISVISIBL)); 694 aMem.mbShowDetails = ScUnoHelpFunctions::GetBoolProperty(xMemProp, OUString::createFromAscii(SC_UNO_SHOWDETA)); 695 696 aMem.maLayoutName = ScUnoHelpFunctions::GetStringProperty( 697 xMemProp, OUString::createFromAscii(SC_UNO_LAYOUTNAME), OUString()); 698 } 699 700 aMembers.push_back(aMem); 701 } 702 rMembers.swap(aMembers); 703 return true; 704 } 705 706 void ScDPObject::UpdateReference( UpdateRefMode eUpdateRefMode, 707 const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz ) 708 { 709 // Output area 710 711 SCCOL nCol1 = aOutRange.aStart.Col(); 712 SCROW nRow1 = aOutRange.aStart.Row(); 713 SCTAB nTab1 = aOutRange.aStart.Tab(); 714 SCCOL nCol2 = aOutRange.aEnd.Col(); 715 SCROW nRow2 = aOutRange.aEnd.Row(); 716 SCTAB nTab2 = aOutRange.aEnd.Tab(); 717 718 ScRefUpdateRes eRes = 719 ScRefUpdate::Update( pDoc, eUpdateRefMode, 720 rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(), 721 rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz, 722 nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); 723 if ( eRes != UR_NOTHING ) 724 SetOutRange( ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ) ); 725 726 // sheet source data 727 728 if ( pSheetDesc ) 729 { 730 nCol1 = pSheetDesc->aSourceRange.aStart.Col(); 731 nRow1 = pSheetDesc->aSourceRange.aStart.Row(); 732 nTab1 = pSheetDesc->aSourceRange.aStart.Tab(); 733 nCol2 = pSheetDesc->aSourceRange.aEnd.Col(); 734 nRow2 = pSheetDesc->aSourceRange.aEnd.Row(); 735 nTab2 = pSheetDesc->aSourceRange.aEnd.Tab(); 736 737 eRes = ScRefUpdate::Update( pDoc, eUpdateRefMode, 738 rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(), 739 rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz, 740 nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); 741 if ( eRes != UR_NOTHING ) 742 { 743 ScSheetSourceDesc aNewDesc; 744 aNewDesc.aSourceRange = ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); 745 746 SCsCOL nDiffX = nCol1 - (SCsCOL) pSheetDesc->aSourceRange.aStart.Col(); 747 SCsROW nDiffY = nRow1 - (SCsROW) pSheetDesc->aSourceRange.aStart.Row(); 748 749 aNewDesc.aQueryParam = pSheetDesc->aQueryParam; 750 aNewDesc.aQueryParam.nCol1 = sal::static_int_cast<SCCOL>( aNewDesc.aQueryParam.nCol1 + nDiffX ); 751 aNewDesc.aQueryParam.nCol2 = sal::static_int_cast<SCCOL>( aNewDesc.aQueryParam.nCol2 + nDiffX ); 752 aNewDesc.aQueryParam.nRow1 += nDiffY; //! used? 753 aNewDesc.aQueryParam.nRow2 += nDiffY; //! used? 754 SCSIZE nEC = aNewDesc.aQueryParam.GetEntryCount(); 755 for (SCSIZE i=0; i<nEC; i++) 756 if (aNewDesc.aQueryParam.GetEntry(i).bDoQuery) 757 aNewDesc.aQueryParam.GetEntry(i).nField += nDiffX; 758 759 SetSheetDesc( aNewDesc, true ); // allocates new pSheetDesc 760 } 761 } 762 } 763 764 sal_Bool ScDPObject::RefsEqual( const ScDPObject& r ) const 765 { 766 if ( aOutRange != r.aOutRange ) 767 return sal_False; 768 769 if ( pSheetDesc && r.pSheetDesc ) 770 { 771 if ( pSheetDesc->aSourceRange != r.pSheetDesc->aSourceRange ) 772 return sal_False; 773 } 774 else if ( pSheetDesc || r.pSheetDesc ) 775 { 776 DBG_ERROR("RefsEqual: SheetDesc set at only one object"); 777 return sal_False; 778 } 779 780 return sal_True; 781 } 782 783 void ScDPObject::WriteRefsTo( ScDPObject& r ) const 784 { 785 r.SetOutRange( aOutRange ); 786 if ( pSheetDesc ) 787 r.SetSheetDesc( *pSheetDesc, true ); 788 } 789 790 void ScDPObject::GetPositionData(const ScAddress& rPos, DataPilotTablePositionData& rPosData) 791 { 792 CreateOutput(); 793 pOutput->GetPositionData(rPos, rPosData); 794 } 795 796 bool ScDPObject::GetDataFieldPositionData( 797 const ScAddress& rPos, Sequence<sheet::DataPilotFieldFilter>& rFilters) 798 { 799 CreateOutput(); 800 801 vector<sheet::DataPilotFieldFilter> aFilters; 802 if (!pOutput->GetDataResultPositionData(aFilters, rPos)) 803 return false; 804 805 sal_Int32 n = static_cast<sal_Int32>(aFilters.size()); 806 rFilters.realloc(n); 807 for (sal_Int32 i = 0; i < n; ++i) 808 rFilters[i] = aFilters[i]; 809 810 return true; 811 } 812 813 void ScDPObject::GetDrillDownData(const ScAddress& rPos, Sequence< Sequence<Any> >& rTableData) 814 { 815 CreateOutput(); 816 817 Reference<sheet::XDrillDownDataSupplier> xDrillDownData(xSource, UNO_QUERY); 818 if (!xDrillDownData.is()) 819 return; 820 821 Sequence<sheet::DataPilotFieldFilter> filters; 822 if (!GetDataFieldPositionData(rPos, filters)) 823 return; 824 825 rTableData = xDrillDownData->getDrillDownData(filters); 826 } 827 828 bool ScDPObject::IsDimNameInUse(const OUString& rName) const 829 { 830 if (!xSource.is()) 831 return false; 832 833 Reference<container::XNameAccess> xDims = xSource->getDimensions(); 834 Sequence<OUString> aDimNames = xDims->getElementNames(); 835 sal_Int32 n = aDimNames.getLength(); 836 for (sal_Int32 i = 0; i < n; ++i) 837 { 838 const OUString& rDimName = aDimNames[i]; 839 if (rDimName.equalsIgnoreAsciiCase(rName)) 840 return true; 841 842 Reference<beans::XPropertySet> xPropSet(xDims->getByName(rDimName), UNO_QUERY); 843 if (!xPropSet.is()) 844 continue; 845 846 OUString aLayoutName = ScUnoHelpFunctions::GetStringProperty( 847 xPropSet, OUString::createFromAscii(SC_UNO_LAYOUTNAME), OUString()); 848 if (aLayoutName.equalsIgnoreAsciiCase(rName)) 849 return true; 850 } 851 return false; 852 } 853 854 String ScDPObject::GetDimName( long nDim, sal_Bool& rIsDataLayout, sal_Int32* pFlags ) 855 { 856 rIsDataLayout = sal_False; 857 String aRet; 858 859 if ( xSource.is() ) 860 { 861 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions(); 862 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName ); 863 long nDimCount = xDims->getCount(); 864 if ( nDim < nDimCount ) 865 { 866 uno::Reference<uno::XInterface> xIntDim = 867 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) ); 868 uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY ); 869 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY ); 870 if ( xDimName.is() && xDimProp.is() ) 871 { 872 sal_Bool bData = ScUnoHelpFunctions::GetBoolProperty( xDimProp, 873 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) ); 874 //! error checking -- is "IsDataLayoutDimension" property required?? 875 876 rtl::OUString aName; 877 try 878 { 879 aName = xDimName->getName(); 880 } 881 catch(uno::Exception&) 882 { 883 } 884 if ( bData ) 885 rIsDataLayout = sal_True; 886 else 887 aRet = String( aName ); 888 889 if (pFlags) 890 *pFlags = ScUnoHelpFunctions::GetLongProperty( xDimProp, 891 rtl::OUString::createFromAscii(SC_UNO_FLAGS), 0 ); 892 } 893 } 894 } 895 896 return aRet; 897 } 898 899 sal_Bool ScDPObject::IsDuplicated( long nDim ) 900 { 901 sal_Bool bDuplicated = sal_False; 902 if ( xSource.is() ) 903 { 904 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions(); 905 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName ); 906 long nDimCount = xDims->getCount(); 907 if ( nDim < nDimCount ) 908 { 909 uno::Reference<uno::XInterface> xIntDim = 910 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) ); 911 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY ); 912 if ( xDimProp.is() ) 913 { 914 try 915 { 916 uno::Any aOrigAny = xDimProp->getPropertyValue( 917 rtl::OUString::createFromAscii(DP_PROP_ORIGINAL) ); 918 uno::Reference<uno::XInterface> xIntOrig; 919 if ( (aOrigAny >>= xIntOrig) && xIntOrig.is() ) 920 bDuplicated = sal_True; 921 } 922 catch(uno::Exception&) 923 { 924 } 925 } 926 } 927 } 928 return bDuplicated; 929 } 930 931 long ScDPObject::GetDimCount() 932 { 933 long nRet = 0; 934 if ( xSource.is() ) 935 { 936 try 937 { 938 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions(); 939 if ( xDimsName.is() ) 940 nRet = xDimsName->getElementNames().getLength(); 941 } 942 catch(uno::Exception&) 943 { 944 } 945 } 946 return nRet; 947 } 948 949 void ScDPObject::FillPageList( TypedScStrCollection& rStrings, long nField ) 950 { 951 //! merge members access with ToggleDetails? 952 953 //! convert field index to dimension index? 954 955 DBG_ASSERT( xSource.is(), "no source" ); 956 if ( !xSource.is() ) return; 957 958 uno::Reference<container::XNamed> xDim; 959 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions(); 960 uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName ); 961 long nIntCount = xIntDims->getCount(); 962 if ( nField < nIntCount ) 963 { 964 uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface( 965 xIntDims->getByIndex(nField) ); 966 xDim = uno::Reference<container::XNamed>( xIntDim, uno::UNO_QUERY ); 967 } 968 DBG_ASSERT( xDim.is(), "dimension not found" ); 969 if ( !xDim.is() ) return; 970 971 uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY ); 972 long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp, 973 rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) ); 974 long nLevel = 0; 975 976 long nHierCount = 0; 977 uno::Reference<container::XIndexAccess> xHiers; 978 uno::Reference<sheet::XHierarchiesSupplier> xHierSupp( xDim, uno::UNO_QUERY ); 979 if ( xHierSupp.is() ) 980 { 981 uno::Reference<container::XNameAccess> xHiersName = xHierSupp->getHierarchies(); 982 xHiers = new ScNameToIndexAccess( xHiersName ); 983 nHierCount = xHiers->getCount(); 984 } 985 uno::Reference<uno::XInterface> xHier; 986 if ( nHierarchy < nHierCount ) 987 xHier = ScUnoHelpFunctions::AnyToInterface( xHiers->getByIndex(nHierarchy) ); 988 DBG_ASSERT( xHier.is(), "hierarchy not found" ); 989 if ( !xHier.is() ) return; 990 991 long nLevCount = 0; 992 uno::Reference<container::XIndexAccess> xLevels; 993 uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHier, uno::UNO_QUERY ); 994 if ( xLevSupp.is() ) 995 { 996 uno::Reference<container::XNameAccess> xLevsName = xLevSupp->getLevels(); 997 xLevels = new ScNameToIndexAccess( xLevsName ); 998 nLevCount = xLevels->getCount(); 999 } 1000 uno::Reference<uno::XInterface> xLevel; 1001 if ( nLevel < nLevCount ) 1002 xLevel = ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex(nLevel) ); 1003 DBG_ASSERT( xLevel.is(), "level not found" ); 1004 if ( !xLevel.is() ) return; 1005 1006 uno::Reference<container::XNameAccess> xMembers; 1007 uno::Reference<sheet::XMembersSupplier> xMbrSupp( xLevel, uno::UNO_QUERY ); 1008 if ( xMbrSupp.is() ) 1009 xMembers = xMbrSupp->getMembers(); 1010 DBG_ASSERT( xMembers.is(), "members not found" ); 1011 if ( !xMembers.is() ) return; 1012 1013 uno::Sequence<rtl::OUString> aNames = xMembers->getElementNames(); 1014 long nNameCount = aNames.getLength(); 1015 const rtl::OUString* pNameArr = aNames.getConstArray(); 1016 for (long nPos = 0; nPos < nNameCount; ++nPos) 1017 { 1018 // Make sure to insert only visible members. 1019 Reference<XPropertySet> xPropSet(xMembers->getByName(pNameArr[nPos]), UNO_QUERY); 1020 sal_Bool bVisible = false; 1021 if (xPropSet.is()) 1022 { 1023 Any any = xPropSet->getPropertyValue(OUString::createFromAscii(SC_UNO_ISVISIBL)); 1024 any >>= bVisible; 1025 } 1026 1027 if (bVisible) 1028 { 1029 // use the order from getElementNames 1030 TypedStrData* pData = new TypedStrData( pNameArr[nPos] ); 1031 if ( !rStrings.AtInsert( rStrings.GetCount(), pData ) ) 1032 delete pData; 1033 } 1034 } 1035 1036 // add "-all-" entry to the top (unsorted) 1037 TypedStrData* pAllData = new TypedStrData( String( ScResId( SCSTR_ALL ) ) ); //! separate string? (also output) 1038 if ( !rStrings.AtInsert( 0, pAllData ) ) 1039 delete pAllData; 1040 } 1041 1042 void ScDPObject::GetHeaderPositionData(const ScAddress& rPos, DataPilotTableHeaderData& rData) 1043 { 1044 using namespace ::com::sun::star::sheet::DataPilotTablePositionType; 1045 1046 CreateOutput(); // create xSource and pOutput if not already done 1047 1048 // Reset member values to invalid state. 1049 rData.Dimension = rData.Hierarchy = rData.Level = -1; 1050 rData.Flags = 0; 1051 1052 DataPilotTablePositionData aPosData; 1053 pOutput->GetPositionData(rPos, aPosData); 1054 const sal_Int32 nPosType = aPosData.PositionType; 1055 if (nPosType == COLUMN_HEADER || nPosType == ROW_HEADER) 1056 aPosData.PositionData >>= rData; 1057 } 1058 1059 // Returns sal_True on success and stores the result in rTarget 1060 sal_Bool ScDPObject::GetPivotData( ScDPGetPivotDataField& rTarget, 1061 const std::vector< ScDPGetPivotDataField >& rFilters ) 1062 { 1063 // #i117239# Exit with an error if called from creating the cache for this object 1064 // (don't create an empty pOutput object) 1065 if (mbCreatingTableData) 1066 return sal_False; 1067 1068 CreateOutput(); // create xSource and pOutput if not already done 1069 1070 return pOutput->GetPivotData( rTarget, rFilters ); 1071 } 1072 1073 sal_Bool ScDPObject::IsFilterButton( const ScAddress& rPos ) 1074 { 1075 CreateOutput(); // create xSource and pOutput if not already done 1076 1077 return pOutput->IsFilterButton( rPos ); 1078 } 1079 1080 long ScDPObject::GetHeaderDim( const ScAddress& rPos, sal_uInt16& rOrient ) 1081 { 1082 CreateOutput(); // create xSource and pOutput if not already done 1083 1084 return pOutput->GetHeaderDim( rPos, rOrient ); 1085 } 1086 1087 sal_Bool ScDPObject::GetHeaderDrag( const ScAddress& rPos, sal_Bool bMouseLeft, sal_Bool bMouseTop, long nDragDim, 1088 Rectangle& rPosRect, sal_uInt16& rOrient, long& rDimPos ) 1089 { 1090 CreateOutput(); // create xSource and pOutput if not already done 1091 1092 return pOutput->GetHeaderDrag( rPos, bMouseLeft, bMouseTop, nDragDim, rPosRect, rOrient, rDimPos ); 1093 } 1094 1095 void ScDPObject::GetMemberResultNames( ScStrCollection& rNames, long nDimension ) 1096 { 1097 CreateOutput(); // create xSource and pOutput if not already done 1098 1099 pOutput->GetMemberResultNames( rNames, nDimension ); // used only with table data -> level not needed 1100 } 1101 1102 bool lcl_Dequote( const String& rSource, xub_StrLen nStartPos, xub_StrLen& rEndPos, String& rResult ) 1103 { 1104 // nStartPos has to point to opening quote 1105 1106 bool bRet = false; 1107 const sal_Unicode cQuote = '\''; 1108 1109 if ( rSource.GetChar(nStartPos) == cQuote ) 1110 { 1111 rtl::OUStringBuffer aBuffer; 1112 xub_StrLen nPos = nStartPos + 1; 1113 const xub_StrLen nLen = rSource.Len(); 1114 1115 while ( nPos < nLen ) 1116 { 1117 const sal_Unicode cNext = rSource.GetChar(nPos); 1118 if ( cNext == cQuote ) 1119 { 1120 if ( nPos+1 < nLen && rSource.GetChar(nPos+1) == cQuote ) 1121 { 1122 // double quote is used for an embedded quote 1123 aBuffer.append( cNext ); // append one quote 1124 ++nPos; // skip the next one 1125 } 1126 else 1127 { 1128 // end of quoted string 1129 rResult = aBuffer.makeStringAndClear(); 1130 rEndPos = nPos + 1; // behind closing quote 1131 return true; 1132 } 1133 } 1134 else 1135 aBuffer.append( cNext ); 1136 1137 ++nPos; 1138 } 1139 // no closing quote before the end of the string -> error (bRet still false) 1140 } 1141 1142 return bRet; 1143 } 1144 1145 struct ScGetPivotDataFunctionEntry 1146 { 1147 const sal_Char* pName; 1148 sheet::GeneralFunction eFunc; 1149 }; 1150 1151 bool lcl_ParseFunction( const String& rList, xub_StrLen nStartPos, xub_StrLen& rEndPos, sheet::GeneralFunction& rFunc ) 1152 { 1153 static const ScGetPivotDataFunctionEntry aFunctions[] = 1154 { 1155 // our names 1156 { "Sum", sheet::GeneralFunction_SUM }, 1157 { "Count", sheet::GeneralFunction_COUNT }, 1158 { "Average", sheet::GeneralFunction_AVERAGE }, 1159 { "Max", sheet::GeneralFunction_MAX }, 1160 { "Min", sheet::GeneralFunction_MIN }, 1161 { "Product", sheet::GeneralFunction_PRODUCT }, 1162 { "CountNums", sheet::GeneralFunction_COUNTNUMS }, 1163 { "StDev", sheet::GeneralFunction_STDEV }, 1164 { "StDevp", sheet::GeneralFunction_STDEVP }, 1165 { "Var", sheet::GeneralFunction_VAR }, 1166 { "VarP", sheet::GeneralFunction_VARP }, 1167 // compatibility names 1168 { "Count Nums", sheet::GeneralFunction_COUNTNUMS }, 1169 { "StdDev", sheet::GeneralFunction_STDEV }, 1170 { "StdDevp", sheet::GeneralFunction_STDEVP } 1171 }; 1172 1173 const xub_StrLen nListLen = rList.Len(); 1174 while ( nStartPos < nListLen && rList.GetChar(nStartPos) == ' ' ) 1175 ++nStartPos; 1176 1177 bool bParsed = false; 1178 bool bFound = false; 1179 String aFuncStr; 1180 xub_StrLen nFuncEnd = 0; 1181 if ( nStartPos < nListLen && rList.GetChar(nStartPos) == '\'' ) 1182 bParsed = lcl_Dequote( rList, nStartPos, nFuncEnd, aFuncStr ); 1183 else 1184 { 1185 nFuncEnd = rList.Search( static_cast<sal_Unicode>(']'), nStartPos ); 1186 if ( nFuncEnd != STRING_NOTFOUND ) 1187 { 1188 aFuncStr = rList.Copy( nStartPos, nFuncEnd - nStartPos ); 1189 bParsed = true; 1190 } 1191 } 1192 1193 if ( bParsed ) 1194 { 1195 aFuncStr.EraseLeadingAndTrailingChars( ' ' ); 1196 1197 const sal_Int32 nFuncCount = sizeof(aFunctions) / sizeof(aFunctions[0]); 1198 for ( sal_Int32 nFunc=0; nFunc<nFuncCount && !bFound; nFunc++ ) 1199 { 1200 if ( aFuncStr.EqualsIgnoreCaseAscii( aFunctions[nFunc].pName ) ) 1201 { 1202 rFunc = aFunctions[nFunc].eFunc; 1203 bFound = true; 1204 1205 while ( nFuncEnd < nListLen && rList.GetChar(nFuncEnd) == ' ' ) 1206 ++nFuncEnd; 1207 rEndPos = nFuncEnd; 1208 } 1209 } 1210 } 1211 1212 return bFound; 1213 } 1214 1215 bool lcl_IsAtStart( const String& rList, const String& rSearch, sal_Int32& rMatched, 1216 bool bAllowBracket, sheet::GeneralFunction* pFunc ) 1217 { 1218 sal_Int32 nMatchList = 0; 1219 sal_Int32 nMatchSearch = 0; 1220 sal_Unicode cFirst = rList.GetChar(0); 1221 if ( cFirst == '\'' || cFirst == '[' ) 1222 { 1223 // quoted string or string in brackets must match completely 1224 1225 String aDequoted; 1226 xub_StrLen nQuoteEnd = 0; 1227 bool bParsed = false; 1228 1229 if ( cFirst == '\'' ) 1230 bParsed = lcl_Dequote( rList, 0, nQuoteEnd, aDequoted ); 1231 else if ( cFirst == '[' ) 1232 { 1233 // skip spaces after the opening bracket 1234 1235 xub_StrLen nStartPos = 1; 1236 const xub_StrLen nListLen = rList.Len(); 1237 while ( nStartPos < nListLen && rList.GetChar(nStartPos) == ' ' ) 1238 ++nStartPos; 1239 1240 if ( rList.GetChar(nStartPos) == '\'' ) // quoted within the brackets? 1241 { 1242 if ( lcl_Dequote( rList, nStartPos, nQuoteEnd, aDequoted ) ) 1243 { 1244 // after the quoted string, there must be the closing bracket, optionally preceded by spaces, 1245 // and/or a function name 1246 while ( nQuoteEnd < nListLen && rList.GetChar(nQuoteEnd) == ' ' ) 1247 ++nQuoteEnd; 1248 1249 // semicolon separates function name 1250 if ( nQuoteEnd < nListLen && rList.GetChar(nQuoteEnd) == ';' && pFunc ) 1251 { 1252 xub_StrLen nFuncEnd = 0; 1253 if ( lcl_ParseFunction( rList, nQuoteEnd + 1, nFuncEnd, *pFunc ) ) 1254 nQuoteEnd = nFuncEnd; 1255 } 1256 if ( nQuoteEnd < nListLen && rList.GetChar(nQuoteEnd) == ']' ) 1257 { 1258 ++nQuoteEnd; // include the closing bracket for the matched length 1259 bParsed = true; 1260 } 1261 } 1262 } 1263 else 1264 { 1265 // implicit quoting to the closing bracket 1266 1267 xub_StrLen nClosePos = rList.Search( static_cast<sal_Unicode>(']'), nStartPos ); 1268 if ( nClosePos != STRING_NOTFOUND ) 1269 { 1270 xub_StrLen nNameEnd = nClosePos; 1271 xub_StrLen nSemiPos = rList.Search( static_cast<sal_Unicode>(';'), nStartPos ); 1272 if ( nSemiPos != STRING_NOTFOUND && nSemiPos < nClosePos && pFunc ) 1273 { 1274 xub_StrLen nFuncEnd = 0; 1275 if ( lcl_ParseFunction( rList, nSemiPos + 1, nFuncEnd, *pFunc ) ) 1276 nNameEnd = nSemiPos; 1277 } 1278 1279 aDequoted = rList.Copy( nStartPos, nNameEnd - nStartPos ); 1280 aDequoted.EraseTrailingChars( ' ' ); // spaces before the closing bracket or semicolon 1281 nQuoteEnd = nClosePos + 1; 1282 bParsed = true; 1283 } 1284 } 1285 } 1286 1287 if ( bParsed && ScGlobal::GetpTransliteration()->isEqual( aDequoted, rSearch ) ) 1288 { 1289 nMatchList = nQuoteEnd; // match count in the list string, including quotes 1290 nMatchSearch = rSearch.Len(); 1291 } 1292 } 1293 else 1294 { 1295 // otherwise look for search string at the start of rList 1296 ScGlobal::GetpTransliteration()->equals( rList, 0, rList.Len(), nMatchList, 1297 rSearch, 0, rSearch.Len(), nMatchSearch ); 1298 } 1299 1300 if ( nMatchSearch == rSearch.Len() ) 1301 { 1302 // search string is at start of rList - look for following space or end of string 1303 1304 bool bValid = false; 1305 if ( sal::static_int_cast<xub_StrLen>(nMatchList) >= rList.Len() ) 1306 bValid = true; 1307 else 1308 { 1309 sal_Unicode cNext = rList.GetChar(sal::static_int_cast<xub_StrLen>(nMatchList)); 1310 if ( cNext == ' ' || ( bAllowBracket && cNext == '[' ) ) 1311 bValid = true; 1312 } 1313 1314 if ( bValid ) 1315 { 1316 rMatched = nMatchList; 1317 return true; 1318 } 1319 } 1320 1321 return false; 1322 } 1323 1324 sal_Bool ScDPObject::ParseFilters( ScDPGetPivotDataField& rTarget, 1325 std::vector< ScDPGetPivotDataField >& rFilters, 1326 const String& rFilterList ) 1327 { 1328 // parse the string rFilterList into parameters for GetPivotData 1329 1330 CreateObjects(); // create xSource if not already done 1331 1332 std::vector<String> aDataNames; // data fields (source name) 1333 std::vector<String> aGivenNames; // data fields (compound name) 1334 std::vector<String> aFieldNames; // column/row/data fields 1335 std::vector< uno::Sequence<rtl::OUString> > aFieldValues; 1336 1337 // 1338 // get all the field and item names 1339 // 1340 1341 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions(); 1342 uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName ); 1343 sal_Int32 nDimCount = xIntDims->getCount(); 1344 for ( sal_Int32 nDim = 0; nDim<nDimCount; nDim++ ) 1345 { 1346 uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nDim) ); 1347 uno::Reference<container::XNamed> xDim( xIntDim, uno::UNO_QUERY ); 1348 uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY ); 1349 uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDim, uno::UNO_QUERY ); 1350 sal_Bool bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp, 1351 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) ); 1352 sal_Int32 nOrient = ScUnoHelpFunctions::GetEnumProperty( 1353 xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION), 1354 sheet::DataPilotFieldOrientation_HIDDEN ); 1355 if ( !bDataLayout ) 1356 { 1357 if ( nOrient == sheet::DataPilotFieldOrientation_DATA ) 1358 { 1359 String aSourceName; 1360 String aGivenName; 1361 ScDPOutput::GetDataDimensionNames( aSourceName, aGivenName, xIntDim ); 1362 aDataNames.push_back( aSourceName ); 1363 aGivenNames.push_back( aGivenName ); 1364 } 1365 else if ( nOrient != sheet::DataPilotFieldOrientation_HIDDEN ) 1366 { 1367 // get level names, as in ScDPOutput 1368 1369 uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() ); 1370 sal_Int32 nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp, 1371 rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) ); 1372 if ( nHierarchy >= xHiers->getCount() ) 1373 nHierarchy = 0; 1374 1375 uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface( 1376 xHiers->getByIndex(nHierarchy) ); 1377 uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY ); 1378 if ( xHierSupp.is() ) 1379 { 1380 uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() ); 1381 sal_Int32 nLevCount = xLevels->getCount(); 1382 for (sal_Int32 nLev=0; nLev<nLevCount; nLev++) 1383 { 1384 uno::Reference<uno::XInterface> xLevel = ScUnoHelpFunctions::AnyToInterface( 1385 xLevels->getByIndex(nLev) ); 1386 uno::Reference<container::XNamed> xLevNam( xLevel, uno::UNO_QUERY ); 1387 uno::Reference<sheet::XMembersSupplier> xLevSupp( xLevel, uno::UNO_QUERY ); 1388 if ( xLevNam.is() && xLevSupp.is() ) 1389 { 1390 uno::Reference<container::XNameAccess> xMembers = xLevSupp->getMembers(); 1391 1392 String aFieldName( xLevNam->getName() ); 1393 uno::Sequence<rtl::OUString> aMemberNames( xMembers->getElementNames() ); 1394 1395 aFieldNames.push_back( aFieldName ); 1396 aFieldValues.push_back( aMemberNames ); 1397 } 1398 } 1399 } 1400 } 1401 } 1402 } 1403 1404 // 1405 // compare and build filters 1406 // 1407 1408 SCSIZE nDataFields = aDataNames.size(); 1409 SCSIZE nFieldCount = aFieldNames.size(); 1410 DBG_ASSERT( aGivenNames.size() == nDataFields && aFieldValues.size() == nFieldCount, "wrong count" ); 1411 1412 bool bError = false; 1413 bool bHasData = false; 1414 String aRemaining( rFilterList ); 1415 aRemaining.EraseLeadingAndTrailingChars( ' ' ); 1416 while ( aRemaining.Len() && !bError ) 1417 { 1418 bool bUsed = false; 1419 1420 // look for data field name 1421 1422 for ( SCSIZE nDataPos=0; nDataPos<nDataFields && !bUsed; nDataPos++ ) 1423 { 1424 String aFound; 1425 sal_Int32 nMatched = 0; 1426 if ( lcl_IsAtStart( aRemaining, aDataNames[nDataPos], nMatched, false, NULL ) ) 1427 aFound = aDataNames[nDataPos]; 1428 else if ( lcl_IsAtStart( aRemaining, aGivenNames[nDataPos], nMatched, false, NULL ) ) 1429 aFound = aGivenNames[nDataPos]; 1430 1431 if ( aFound.Len() ) 1432 { 1433 rTarget.maFieldName = aFound; 1434 aRemaining.Erase( 0, sal::static_int_cast<xub_StrLen>(nMatched) ); 1435 bHasData = true; 1436 bUsed = true; 1437 } 1438 } 1439 1440 // look for field name 1441 1442 String aSpecField; 1443 bool bHasFieldName = false; 1444 if ( !bUsed ) 1445 { 1446 sal_Int32 nMatched = 0; 1447 for ( SCSIZE nField=0; nField<nFieldCount && !bHasFieldName; nField++ ) 1448 { 1449 if ( lcl_IsAtStart( aRemaining, aFieldNames[nField], nMatched, true, NULL ) ) 1450 { 1451 aSpecField = aFieldNames[nField]; 1452 aRemaining.Erase( 0, sal::static_int_cast<xub_StrLen>(nMatched) ); 1453 aRemaining.EraseLeadingChars( ' ' ); 1454 1455 // field name has to be followed by item name in brackets 1456 if ( aRemaining.GetChar(0) == '[' ) 1457 { 1458 bHasFieldName = true; 1459 // bUsed remains false - still need the item 1460 } 1461 else 1462 { 1463 bUsed = true; 1464 bError = true; 1465 } 1466 } 1467 } 1468 } 1469 1470 // look for field item 1471 1472 if ( !bUsed ) 1473 { 1474 bool bItemFound = false; 1475 sal_Int32 nMatched = 0; 1476 String aFoundName; 1477 String aFoundValue; 1478 sheet::GeneralFunction eFunc = sheet::GeneralFunction_NONE; 1479 sheet::GeneralFunction eFoundFunc = sheet::GeneralFunction_NONE; 1480 1481 for ( SCSIZE nField=0; nField<nFieldCount; nField++ ) 1482 { 1483 // If a field name is given, look in that field only, otherwise in all fields. 1484 // aSpecField is initialized from aFieldNames array, so exact comparison can be used. 1485 if ( !bHasFieldName || aFieldNames[nField] == aSpecField ) 1486 { 1487 const uno::Sequence<rtl::OUString>& rItems = aFieldValues[nField]; 1488 sal_Int32 nItemCount = rItems.getLength(); 1489 const rtl::OUString* pItemArr = rItems.getConstArray(); 1490 for ( sal_Int32 nItem=0; nItem<nItemCount; nItem++ ) 1491 { 1492 if ( lcl_IsAtStart( aRemaining, pItemArr[nItem], nMatched, false, &eFunc ) ) 1493 { 1494 if ( bItemFound ) 1495 bError = true; // duplicate (also across fields) 1496 else 1497 { 1498 aFoundName = aFieldNames[nField]; 1499 aFoundValue = pItemArr[nItem]; 1500 eFoundFunc = eFunc; 1501 bItemFound = true; 1502 bUsed = true; 1503 } 1504 } 1505 } 1506 } 1507 } 1508 1509 if ( bItemFound && !bError ) 1510 { 1511 ScDPGetPivotDataField aField; 1512 aField.maFieldName = aFoundName; 1513 aField.meFunction = eFoundFunc; 1514 aField.mbValIsStr = true; 1515 aField.maValStr = aFoundValue; 1516 aField.mnValNum = 0.0; 1517 rFilters.push_back( aField ); 1518 1519 aRemaining.Erase( 0, sal::static_int_cast<xub_StrLen>(nMatched) ); 1520 } 1521 } 1522 1523 if ( !bUsed ) 1524 bError = true; 1525 1526 aRemaining.EraseLeadingChars( ' ' ); // remove any number of spaces between entries 1527 } 1528 1529 if ( !bError && !bHasData && aDataNames.size() == 1 ) 1530 { 1531 // if there's only one data field, its name need not be specified 1532 rTarget.maFieldName = aDataNames[0]; 1533 bHasData = true; 1534 } 1535 1536 return bHasData && !bError; 1537 } 1538 1539 void ScDPObject::ToggleDetails(const DataPilotTableHeaderData& rElemDesc, ScDPObject* pDestObj) 1540 { 1541 CreateObjects(); // create xSource if not already done 1542 1543 // find dimension name 1544 1545 uno::Reference<container::XNamed> xDim; 1546 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions(); 1547 uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName ); 1548 long nIntCount = xIntDims->getCount(); 1549 if ( rElemDesc.Dimension < nIntCount ) 1550 { 1551 uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface( 1552 xIntDims->getByIndex(rElemDesc.Dimension) ); 1553 xDim = uno::Reference<container::XNamed>( xIntDim, uno::UNO_QUERY ); 1554 } 1555 DBG_ASSERT( xDim.is(), "dimension not found" ); 1556 if ( !xDim.is() ) return; 1557 String aDimName = xDim->getName(); 1558 1559 uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY ); 1560 sal_Bool bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp, 1561 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) ); 1562 if (bDataLayout) 1563 { 1564 // the elements of the data layout dimension can't be found by their names 1565 // -> don't change anything 1566 return; 1567 } 1568 1569 // query old state 1570 1571 long nHierCount = 0; 1572 uno::Reference<container::XIndexAccess> xHiers; 1573 uno::Reference<sheet::XHierarchiesSupplier> xHierSupp( xDim, uno::UNO_QUERY ); 1574 if ( xHierSupp.is() ) 1575 { 1576 uno::Reference<container::XNameAccess> xHiersName = xHierSupp->getHierarchies(); 1577 xHiers = new ScNameToIndexAccess( xHiersName ); 1578 nHierCount = xHiers->getCount(); 1579 } 1580 uno::Reference<uno::XInterface> xHier; 1581 if ( rElemDesc.Hierarchy < nHierCount ) 1582 xHier = ScUnoHelpFunctions::AnyToInterface( xHiers->getByIndex(rElemDesc.Hierarchy) ); 1583 DBG_ASSERT( xHier.is(), "hierarchy not found" ); 1584 if ( !xHier.is() ) return; 1585 1586 long nLevCount = 0; 1587 uno::Reference<container::XIndexAccess> xLevels; 1588 uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHier, uno::UNO_QUERY ); 1589 if ( xLevSupp.is() ) 1590 { 1591 uno::Reference<container::XNameAccess> xLevsName = xLevSupp->getLevels(); 1592 xLevels = new ScNameToIndexAccess( xLevsName ); 1593 nLevCount = xLevels->getCount(); 1594 } 1595 uno::Reference<uno::XInterface> xLevel; 1596 if ( rElemDesc.Level < nLevCount ) 1597 xLevel = ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex(rElemDesc.Level) ); 1598 DBG_ASSERT( xLevel.is(), "level not found" ); 1599 if ( !xLevel.is() ) return; 1600 1601 uno::Reference<container::XNameAccess> xMembers; 1602 uno::Reference<sheet::XMembersSupplier> xMbrSupp( xLevel, uno::UNO_QUERY ); 1603 if ( xMbrSupp.is() ) 1604 xMembers = xMbrSupp->getMembers(); 1605 1606 sal_Bool bFound = sal_False; 1607 sal_Bool bShowDetails = sal_True; 1608 1609 if ( xMembers.is() ) 1610 { 1611 if ( xMembers->hasByName(rElemDesc.MemberName) ) 1612 { 1613 uno::Reference<uno::XInterface> xMemberInt = ScUnoHelpFunctions::AnyToInterface( 1614 xMembers->getByName(rElemDesc.MemberName) ); 1615 uno::Reference<beans::XPropertySet> xMbrProp( xMemberInt, uno::UNO_QUERY ); 1616 if ( xMbrProp.is() ) 1617 { 1618 bShowDetails = ScUnoHelpFunctions::GetBoolProperty( xMbrProp, 1619 rtl::OUString::createFromAscii(DP_PROP_SHOWDETAILS) ); 1620 //! don't set bFound if property is unknown? 1621 bFound = sal_True; 1622 } 1623 } 1624 } 1625 1626 DBG_ASSERT( bFound, "member not found" ); 1627 1628 //! use Hierarchy and Level in SaveData !!!! 1629 1630 // modify pDestObj if set, this object otherwise 1631 ScDPSaveData* pModifyData = pDestObj ? ( pDestObj->pSaveData ) : pSaveData; 1632 DBG_ASSERT( pModifyData, "no data?" ); 1633 if ( pModifyData ) 1634 { 1635 const String aName = rElemDesc.MemberName; 1636 pModifyData->GetDimensionByName(aDimName)-> 1637 GetMemberByName(aName)->SetShowDetails( !bShowDetails ); // toggle 1638 1639 if ( pDestObj ) 1640 pDestObj->InvalidateData(); // re-init source from SaveData 1641 else 1642 InvalidateData(); // re-init source from SaveData 1643 } 1644 } 1645 1646 long lcl_FindName( const rtl::OUString& rString, const uno::Reference<container::XNameAccess>& xCollection ) 1647 { 1648 if ( xCollection.is() ) 1649 { 1650 uno::Sequence<rtl::OUString> aSeq = xCollection->getElementNames(); 1651 long nCount = aSeq.getLength(); 1652 const rtl::OUString* pArr = aSeq.getConstArray(); 1653 for (long nPos=0; nPos<nCount; nPos++) 1654 if ( pArr[nPos] == rString ) 1655 return nPos; 1656 } 1657 return -1; // not found 1658 } 1659 1660 sal_uInt16 lcl_FirstSubTotal( const uno::Reference<beans::XPropertySet>& xDimProp ) // PIVOT_FUNC mask 1661 { 1662 uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDimProp, uno::UNO_QUERY ); 1663 if ( xDimProp.is() && xDimSupp.is() ) 1664 { 1665 uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() ); 1666 long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp, 1667 rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) ); 1668 if ( nHierarchy >= xHiers->getCount() ) 1669 nHierarchy = 0; 1670 1671 uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface( 1672 xHiers->getByIndex(nHierarchy) ); 1673 uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY ); 1674 if ( xHierSupp.is() ) 1675 { 1676 uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() ); 1677 uno::Reference<uno::XInterface> xLevel = 1678 ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex( 0 ) ); 1679 uno::Reference<beans::XPropertySet> xLevProp( xLevel, uno::UNO_QUERY ); 1680 if ( xLevProp.is() ) 1681 { 1682 uno::Any aSubAny; 1683 try 1684 { 1685 aSubAny = xLevProp->getPropertyValue( 1686 rtl::OUString::createFromAscii(DP_PROP_SUBTOTALS) ); 1687 } 1688 catch(uno::Exception&) 1689 { 1690 } 1691 uno::Sequence<sheet::GeneralFunction> aSeq; 1692 if ( aSubAny >>= aSeq ) 1693 { 1694 sal_uInt16 nMask = 0; 1695 const sheet::GeneralFunction* pArray = aSeq.getConstArray(); 1696 long nCount = aSeq.getLength(); 1697 for (long i=0; i<nCount; i++) 1698 nMask |= ScDataPilotConversion::FunctionBit(pArray[i]); 1699 return nMask; 1700 } 1701 } 1702 } 1703 } 1704 1705 DBG_ERROR("FirstSubTotal: NULL"); 1706 return 0; 1707 } 1708 1709 sal_uInt16 lcl_CountBits( sal_uInt16 nBits ) 1710 { 1711 if (!nBits) return 0; 1712 1713 sal_uInt16 nCount = 0; 1714 sal_uInt16 nMask = 1; 1715 for (sal_uInt16 i=0; i<16; i++) 1716 { 1717 if ( nBits & nMask ) 1718 ++nCount; 1719 nMask <<= 1; 1720 } 1721 return nCount; 1722 } 1723 1724 void lcl_FillOldFields( ScPivotFieldVector& rFields, 1725 const uno::Reference<sheet::XDimensionsSupplier>& xSource, 1726 sal_uInt16 nOrient, SCCOL nColAdd, bool bAddData ) 1727 { 1728 bool bDataFound = false; 1729 rFields.clear(); 1730 1731 //! merge multiple occurences (data field with different functions) 1732 //! force data field in one dimension 1733 1734 std::vector< long > aPos; 1735 1736 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions(); 1737 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName ); 1738 long nDimCount = xDims->getCount(); 1739 for (long nDim=0; nDim < nDimCount; nDim++) 1740 { 1741 uno::Reference<uno::XInterface> xIntDim = 1742 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) ); 1743 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY ); 1744 long nDimOrient = ScUnoHelpFunctions::GetEnumProperty( 1745 xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION), 1746 sheet::DataPilotFieldOrientation_HIDDEN ); 1747 if ( xDimProp.is() && nDimOrient == nOrient ) 1748 { 1749 sal_uInt16 nMask = 0; 1750 if ( nOrient == sheet::DataPilotFieldOrientation_DATA ) 1751 { 1752 sheet::GeneralFunction eFunc = (sheet::GeneralFunction)ScUnoHelpFunctions::GetEnumProperty( 1753 xDimProp, rtl::OUString::createFromAscii(DP_PROP_FUNCTION), 1754 sheet::GeneralFunction_NONE ); 1755 if ( eFunc == sheet::GeneralFunction_AUTO ) 1756 { 1757 //! test for numeric data 1758 eFunc = sheet::GeneralFunction_SUM; 1759 } 1760 nMask = ScDataPilotConversion::FunctionBit(eFunc); 1761 } 1762 else 1763 nMask = lcl_FirstSubTotal( xDimProp ); // from first hierarchy 1764 1765 sal_Bool bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp, 1766 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) ); 1767 uno::Any aOrigAny; 1768 try 1769 { 1770 aOrigAny = xDimProp->getPropertyValue( 1771 rtl::OUString::createFromAscii(DP_PROP_ORIGINAL) ); 1772 } 1773 catch(uno::Exception&) 1774 { 1775 } 1776 1777 long nDupSource = -1; 1778 uno::Reference<uno::XInterface> xIntOrig = ScUnoHelpFunctions::AnyToInterface( aOrigAny ); 1779 if ( xIntOrig.is() ) 1780 { 1781 uno::Reference<container::XNamed> xNameOrig( xIntOrig, uno::UNO_QUERY ); 1782 if ( xNameOrig.is() ) 1783 nDupSource = lcl_FindName( xNameOrig->getName(), xDimsName ); 1784 } 1785 1786 bool bDupUsed = false; 1787 if ( nDupSource >= 0 ) 1788 { 1789 // add function bit to previous entry 1790 1791 SCsCOL nCompCol; 1792 if ( bDataLayout ) 1793 nCompCol = PIVOT_DATA_FIELD; 1794 else 1795 nCompCol = static_cast<SCsCOL>(nDupSource)+nColAdd; //! seek source column from name 1796 1797 for (ScPivotFieldVector::iterator aIt = rFields.begin(), aEnd = rFields.end(); (aIt != aEnd) && !bDupUsed; ++aIt) 1798 if ( aIt->nCol == nCompCol ) 1799 { 1800 // add to previous column only if new bits aren't already set there 1801 if ( ( aIt->nFuncMask & nMask ) == 0 ) 1802 { 1803 aIt->nFuncMask |= nMask; 1804 aIt->nFuncCount = lcl_CountBits( aIt->nFuncMask ); 1805 bDupUsed = true; 1806 } 1807 } 1808 } 1809 1810 if ( !bDupUsed ) // also for duplicated dim if original has different orientation 1811 { 1812 rFields.resize( rFields.size() + 1 ); 1813 ScPivotField& rField = rFields.back(); 1814 1815 if ( bDataLayout ) 1816 { 1817 rField.nCol = PIVOT_DATA_FIELD; 1818 bDataFound = true; 1819 } 1820 else if ( nDupSource >= 0 ) // if source was not found (different orientation) 1821 rField.nCol = static_cast<SCsCOL>(nDupSource)+nColAdd; //! seek from name 1822 else 1823 rField.nCol = static_cast<SCsCOL>(nDim)+nColAdd; //! seek source column from name 1824 1825 rField.nFuncMask = nMask; 1826 rField.nFuncCount = lcl_CountBits( nMask ); 1827 1828 aPos.push_back( ScUnoHelpFunctions::GetLongProperty( xDimProp, 1829 rtl::OUString::createFromAscii(DP_PROP_POSITION) ) ); 1830 1831 try 1832 { 1833 if( nOrient == sheet::DataPilotFieldOrientation_DATA ) 1834 xDimProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_REFVALUE ) ) ) 1835 >>= rFields.back().maFieldRef; 1836 } 1837 catch( uno::Exception& ) 1838 { 1839 } 1840 } 1841 } 1842 } 1843 1844 // sort by getPosition() value 1845 size_t nSize = aPos.size(); 1846 for (size_t i=0; i+1<nSize; i++) 1847 { 1848 for (size_t j=0; j+i+1<nSize; j++) 1849 if ( aPos[j+1] < aPos[j] ) 1850 { 1851 std::swap( aPos[j], aPos[j+1] ); 1852 std::swap( rFields[j], rFields[j+1] ); 1853 } 1854 } 1855 1856 if ( bAddData && !bDataFound ) 1857 { 1858 rFields.resize( rFields.size() + 1 ); 1859 ScPivotField& rField = rFields.back(); 1860 rField.nCol = PIVOT_DATA_FIELD; 1861 rField.nFuncMask = 0; 1862 rField.nFuncCount = 0; 1863 } 1864 } 1865 1866 sal_Bool ScDPObject::FillOldParam(ScPivotParam& rParam) const 1867 { 1868 ((ScDPObject*)this)->CreateObjects(); // xSource is needed for field numbers 1869 1870 rParam.nCol = aOutRange.aStart.Col(); 1871 rParam.nRow = aOutRange.aStart.Row(); 1872 rParam.nTab = aOutRange.aStart.Tab(); 1873 // ppLabelArr / nLabels is not changed 1874 1875 SCCOL nColAdd = 0; 1876 bool bAddData = ( lcl_GetDataGetOrientation( xSource ) == sheet::DataPilotFieldOrientation_HIDDEN ); 1877 lcl_FillOldFields( rParam.maPageArr, xSource, sheet::DataPilotFieldOrientation_PAGE, nColAdd, false ); 1878 lcl_FillOldFields( rParam.maColArr, xSource, sheet::DataPilotFieldOrientation_COLUMN, nColAdd, bAddData ); 1879 lcl_FillOldFields( rParam.maRowArr, xSource, sheet::DataPilotFieldOrientation_ROW, nColAdd, false ); 1880 lcl_FillOldFields( rParam.maDataArr, xSource, sheet::DataPilotFieldOrientation_DATA, nColAdd, false ); 1881 1882 uno::Reference<beans::XPropertySet> xProp( xSource, uno::UNO_QUERY ); 1883 if (xProp.is()) 1884 { 1885 try 1886 { 1887 rParam.bMakeTotalCol = ScUnoHelpFunctions::GetBoolProperty( xProp, 1888 rtl::OUString::createFromAscii(DP_PROP_COLUMNGRAND), sal_True ); 1889 rParam.bMakeTotalRow = ScUnoHelpFunctions::GetBoolProperty( xProp, 1890 rtl::OUString::createFromAscii(DP_PROP_ROWGRAND), sal_True ); 1891 1892 // following properties may be missing for external sources 1893 rParam.bIgnoreEmptyRows = ScUnoHelpFunctions::GetBoolProperty( xProp, 1894 rtl::OUString::createFromAscii(DP_PROP_IGNOREEMPTY) ); 1895 rParam.bDetectCategories = ScUnoHelpFunctions::GetBoolProperty( xProp, 1896 rtl::OUString::createFromAscii(DP_PROP_REPEATIFEMPTY) ); 1897 } 1898 catch(uno::Exception&) 1899 { 1900 // no error 1901 } 1902 } 1903 return sal_True; 1904 } 1905 1906 void lcl_FillLabelData( ScDPLabelData& rData, const uno::Reference< beans::XPropertySet >& xDimProp ) 1907 { 1908 uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDimProp, uno::UNO_QUERY ); 1909 if ( xDimProp.is() && xDimSupp.is() ) 1910 { 1911 uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() ); 1912 long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp, 1913 rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) ); 1914 if ( nHierarchy >= xHiers->getCount() ) 1915 nHierarchy = 0; 1916 rData.mnUsedHier = nHierarchy; 1917 1918 uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface( 1919 xHiers->getByIndex(nHierarchy) ); 1920 1921 uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY ); 1922 if ( xHierSupp.is() ) 1923 { 1924 uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() ); 1925 uno::Reference<uno::XInterface> xLevel = 1926 ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex( 0 ) ); 1927 uno::Reference<beans::XPropertySet> xLevProp( xLevel, uno::UNO_QUERY ); 1928 if ( xLevProp.is() ) 1929 { 1930 rData.mbShowAll = ScUnoHelpFunctions::GetBoolProperty( xLevProp, 1931 rtl::OUString::createFromAscii(DP_PROP_SHOWEMPTY) ); 1932 1933 try 1934 { 1935 xLevProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_SORTING ) ) ) 1936 >>= rData.maSortInfo; 1937 xLevProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_LAYOUT ) ) ) 1938 >>= rData.maLayoutInfo; 1939 xLevProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_AUTOSHOW ) ) ) 1940 >>= rData.maShowInfo; 1941 } 1942 catch(uno::Exception&) 1943 { 1944 } 1945 } 1946 } 1947 } 1948 } 1949 1950 sal_Bool ScDPObject::FillLabelData(ScPivotParam& rParam) 1951 { 1952 rParam.maLabelArray.clear(); 1953 1954 ((ScDPObject*)this)->CreateObjects(); 1955 1956 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions(); 1957 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName ); 1958 long nDimCount = xDims->getCount(); 1959 if ( nDimCount > MAX_LABELS ) 1960 nDimCount = MAX_LABELS; 1961 if (!nDimCount) 1962 return sal_False; 1963 1964 for (long nDim=0; nDim < nDimCount; nDim++) 1965 { 1966 String aFieldName; 1967 uno::Reference<uno::XInterface> xIntDim = 1968 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) ); 1969 uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY ); 1970 uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY ); 1971 1972 if ( xDimName.is() && xDimProp.is() ) 1973 { 1974 sal_Bool bDuplicated = sal_False; 1975 sal_Bool bData = ScUnoHelpFunctions::GetBoolProperty( xDimProp, 1976 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) ); 1977 //! error checking -- is "IsDataLayoutDimension" property required?? 1978 1979 try 1980 { 1981 aFieldName = String( xDimName->getName() ); 1982 1983 uno::Any aOrigAny = xDimProp->getPropertyValue( 1984 rtl::OUString::createFromAscii(DP_PROP_ORIGINAL) ); 1985 uno::Reference<uno::XInterface> xIntOrig; 1986 if ( (aOrigAny >>= xIntOrig) && xIntOrig.is() ) 1987 bDuplicated = sal_True; 1988 } 1989 catch(uno::Exception&) 1990 { 1991 } 1992 1993 OUString aLayoutName = ScUnoHelpFunctions::GetStringProperty( 1994 xDimProp, OUString::createFromAscii(SC_UNO_LAYOUTNAME), OUString()); 1995 1996 if ( aFieldName.Len() && !bData && !bDuplicated ) 1997 { 1998 SCsCOL nCol = static_cast< SCsCOL >( nDim ); //! ??? 1999 bool bIsValue = true; //! check 2000 2001 ScDPLabelData aNewLabel(aFieldName, nCol, bIsValue); 2002 aNewLabel.maLayoutName = aLayoutName; 2003 GetHierarchies(nDim, aNewLabel.maHiers); 2004 GetMembers(nDim, GetUsedHierarchy(nDim), aNewLabel.maMembers); 2005 lcl_FillLabelData(aNewLabel, xDimProp); 2006 aNewLabel.mnFlags = ScUnoHelpFunctions::GetLongProperty( xDimProp, 2007 rtl::OUString::createFromAscii(SC_UNO_FLAGS), 0 ); 2008 rParam.maLabelArray.push_back(aNewLabel); 2009 } 2010 } 2011 } 2012 2013 return sal_True; 2014 } 2015 2016 sal_Bool ScDPObject::GetHierarchiesNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xHiers ) 2017 { 2018 sal_Bool bRet = sal_False; 2019 uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() ); 2020 uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName )); 2021 if( xIntDims.is() ) 2022 { 2023 uno::Reference<sheet::XHierarchiesSupplier> xHierSup(xIntDims->getByIndex( nDim ), uno::UNO_QUERY); 2024 if (xHierSup.is()) 2025 { 2026 xHiers.set( xHierSup->getHierarchies() ); 2027 bRet = xHiers.is(); 2028 } 2029 } 2030 return bRet; 2031 } 2032 2033 sal_Bool ScDPObject::GetHierarchies( sal_Int32 nDim, uno::Sequence< rtl::OUString >& rHiers ) 2034 { 2035 sal_Bool bRet = sal_False; 2036 uno::Reference< container::XNameAccess > xHiersNA; 2037 if( GetHierarchiesNA( nDim, xHiersNA ) ) 2038 { 2039 rHiers = xHiersNA->getElementNames(); 2040 bRet = sal_True; 2041 } 2042 return bRet; 2043 } 2044 2045 sal_Int32 ScDPObject::GetUsedHierarchy( sal_Int32 nDim ) 2046 { 2047 sal_Int32 nHier = 0; 2048 uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() ); 2049 uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName )); 2050 uno::Reference<beans::XPropertySet> xDim(xIntDims->getByIndex( nDim ), uno::UNO_QUERY); 2051 if (xDim.is()) 2052 nHier = ScUnoHelpFunctions::GetLongProperty( xDim, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( SC_UNO_USEDHIER ) ) ); 2053 return nHier; 2054 } 2055 2056 sal_Bool ScDPObject::GetMembersNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xMembers ) 2057 { 2058 return GetMembersNA( nDim, GetUsedHierarchy( nDim ), xMembers ); 2059 } 2060 2061 sal_Bool ScDPObject::GetMembersNA( sal_Int32 nDim, sal_Int32 nHier, uno::Reference< container::XNameAccess >& xMembers ) 2062 { 2063 sal_Bool bRet = sal_False; 2064 uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() ); 2065 uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName )); 2066 uno::Reference<beans::XPropertySet> xDim(xIntDims->getByIndex( nDim ), uno::UNO_QUERY); 2067 if (xDim.is()) 2068 { 2069 uno::Reference<sheet::XHierarchiesSupplier> xHierSup(xDim, uno::UNO_QUERY); 2070 if (xHierSup.is()) 2071 { 2072 uno::Reference<container::XIndexAccess> xHiers(new ScNameToIndexAccess(xHierSup->getHierarchies())); 2073 uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHiers->getByIndex(nHier), uno::UNO_QUERY ); 2074 if ( xLevSupp.is() ) 2075 { 2076 uno::Reference<container::XIndexAccess> xLevels(new ScNameToIndexAccess( xLevSupp->getLevels())); 2077 if (xLevels.is()) 2078 { 2079 sal_Int32 nLevCount = xLevels->getCount(); 2080 if (nLevCount > 0) 2081 { 2082 uno::Reference<sheet::XMembersSupplier> xMembSupp( xLevels->getByIndex(0), uno::UNO_QUERY ); 2083 if ( xMembSupp.is() ) 2084 { 2085 xMembers.set(xMembSupp->getMembers()); 2086 bRet = sal_True; 2087 } 2088 } 2089 } 2090 } 2091 } 2092 } 2093 return bRet; 2094 } 2095 2096 //------------------------------------------------------------------------ 2097 // convert old pivot tables into new datapilot tables 2098 2099 String lcl_GetDimName( const uno::Reference<sheet::XDimensionsSupplier>& xSource, long nDim ) 2100 { 2101 rtl::OUString aName; 2102 if ( xSource.is() ) 2103 { 2104 uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions(); 2105 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName ); 2106 long nDimCount = xDims->getCount(); 2107 if ( nDim < nDimCount ) 2108 { 2109 uno::Reference<uno::XInterface> xIntDim = 2110 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) ); 2111 uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY ); 2112 if (xDimName.is()) 2113 { 2114 try 2115 { 2116 aName = xDimName->getName(); 2117 } 2118 catch(uno::Exception&) 2119 { 2120 } 2121 } 2122 } 2123 } 2124 return aName; 2125 } 2126 2127 // static 2128 void ScDPObject::ConvertOrientation( ScDPSaveData& rSaveData, 2129 const ScPivotFieldVector& rFields, sal_uInt16 nOrient, 2130 ScDocument* pDoc, SCROW nRow, SCTAB nTab, 2131 const uno::Reference<sheet::XDimensionsSupplier>& xSource, 2132 bool bOldDefaults, 2133 const ScPivotFieldVector* pRefColFields, 2134 const ScPivotFieldVector* pRefRowFields, 2135 const ScPivotFieldVector* pRefPageFields ) 2136 { 2137 // pDoc or xSource must be set 2138 DBG_ASSERT( pDoc || xSource.is(), "missing string source" ); 2139 2140 String aDocStr; 2141 ScDPSaveDimension* pDim; 2142 2143 for (ScPivotFieldVector::const_iterator aIt = rFields.begin(), aEnd = rFields.end(); aIt != aEnd; ++aIt) 2144 { 2145 SCCOL nCol = aIt->nCol; 2146 sal_uInt16 nFuncs = aIt->nFuncMask; 2147 const sheet::DataPilotFieldReference& rFieldRef = aIt->maFieldRef; 2148 2149 if ( nCol == PIVOT_DATA_FIELD ) 2150 pDim = rSaveData.GetDataLayoutDimension(); 2151 else 2152 { 2153 if ( pDoc ) 2154 pDoc->GetString( nCol, nRow, nTab, aDocStr ); 2155 else 2156 aDocStr = lcl_GetDimName( xSource, nCol ); // cols must start at 0 2157 2158 if ( aDocStr.Len() ) 2159 pDim = rSaveData.GetDimensionByName(aDocStr); 2160 else 2161 pDim = NULL; 2162 } 2163 2164 if ( pDim ) 2165 { 2166 if ( nOrient == sheet::DataPilotFieldOrientation_DATA ) // set summary function 2167 { 2168 // generate an individual entry for each function 2169 bool bFirst = true; 2170 2171 // if a dimension is used for column/row/page and data, 2172 // use duplicated dimensions for all data occurrences 2173 if (pRefColFields) 2174 for (ScPivotFieldVector::const_iterator aRefIt = pRefColFields->begin(), aRefEnd = pRefColFields->end(); bFirst && (aRefIt != aRefEnd); ++aRefIt) 2175 if (aRefIt->nCol == nCol) 2176 bFirst = false; 2177 if (pRefRowFields) 2178 for (ScPivotFieldVector::const_iterator aRefIt = pRefRowFields->begin(), aRefEnd = pRefRowFields->end(); bFirst && (aRefIt != aRefEnd); ++aRefIt) 2179 if (aRefIt->nCol == nCol) 2180 bFirst = false; 2181 if (pRefPageFields) 2182 for (ScPivotFieldVector::const_iterator aRefIt = pRefPageFields->begin(), aRefEnd = pRefPageFields->end(); bFirst && (aRefIt != aRefEnd); ++aRefIt) 2183 if (aRefIt->nCol == nCol) 2184 bFirst = false; 2185 2186 // if set via api, a data column may occur several times 2187 // (if the function hasn't been changed yet) -> also look for duplicate data column 2188 for (ScPivotFieldVector::const_iterator aRefIt = rFields.begin(); bFirst && (aRefIt != aIt); ++aRefIt) 2189 if (aRefIt->nCol == nCol) 2190 bFirst = false; 2191 2192 sal_uInt16 nMask = 1; 2193 for (sal_uInt16 nBit=0; nBit<16; nBit++) 2194 { 2195 if ( nFuncs & nMask ) 2196 { 2197 sheet::GeneralFunction eFunc = ScDataPilotConversion::FirstFunc( nMask ); 2198 ScDPSaveDimension* pCurrDim = bFirst ? pDim : rSaveData.DuplicateDimension(pDim->GetName()); 2199 pCurrDim->SetOrientation( nOrient ); 2200 pCurrDim->SetFunction( sal::static_int_cast<sal_uInt16>(eFunc) ); 2201 2202 if( rFieldRef.ReferenceType == sheet::DataPilotFieldReferenceType::NONE ) 2203 pCurrDim->SetReferenceValue( 0 ); 2204 else 2205 pCurrDim->SetReferenceValue( &rFieldRef ); 2206 2207 bFirst = false; 2208 } 2209 nMask *= 2; 2210 } 2211 } 2212 else // set SubTotals 2213 { 2214 pDim->SetOrientation( nOrient ); 2215 2216 sal_uInt16 nFuncArray[16]; 2217 sal_uInt16 nFuncCount = 0; 2218 sal_uInt16 nMask = 1; 2219 for (sal_uInt16 nBit=0; nBit<16; nBit++) 2220 { 2221 if ( nFuncs & nMask ) 2222 nFuncArray[nFuncCount++] = sal::static_int_cast<sal_uInt16>(ScDataPilotConversion::FirstFunc( nMask )); 2223 nMask *= 2; 2224 } 2225 pDim->SetSubTotals( nFuncCount, nFuncArray ); 2226 2227 // ShowEmpty was implicit in old tables, 2228 // must be set for data layout dimension (not accessible in dialog) 2229 if ( bOldDefaults || nCol == PIVOT_DATA_FIELD ) 2230 pDim->SetShowEmpty( sal_True ); 2231 } 2232 } 2233 } 2234 } 2235 2236 // static 2237 bool ScDPObject::IsOrientationAllowed( sal_uInt16 nOrient, sal_Int32 nDimFlags ) 2238 { 2239 bool bAllowed = true; 2240 switch (nOrient) 2241 { 2242 case sheet::DataPilotFieldOrientation_PAGE: 2243 bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_PAGE_ORIENTATION ) == 0; 2244 break; 2245 case sheet::DataPilotFieldOrientation_COLUMN: 2246 bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_COLUMN_ORIENTATION ) == 0; 2247 break; 2248 case sheet::DataPilotFieldOrientation_ROW: 2249 bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_ROW_ORIENTATION ) == 0; 2250 break; 2251 case sheet::DataPilotFieldOrientation_DATA: 2252 bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_DATA_ORIENTATION ) == 0; 2253 break; 2254 default: 2255 { 2256 // allowed to remove from previous orientation 2257 } 2258 } 2259 return bAllowed; 2260 } 2261 2262 // ----------------------------------------------------------------------- 2263 2264 // static 2265 sal_Bool ScDPObject::HasRegisteredSources() 2266 { 2267 sal_Bool bFound = sal_False; 2268 2269 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory(); 2270 uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY ); 2271 if ( xEnAc.is() ) 2272 { 2273 uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration( 2274 rtl::OUString::createFromAscii( SCDPSOURCE_SERVICE ) ); 2275 if ( xEnum.is() && xEnum->hasMoreElements() ) 2276 bFound = sal_True; 2277 } 2278 2279 return bFound; 2280 } 2281 2282 // static 2283 uno::Sequence<rtl::OUString> ScDPObject::GetRegisteredSources() 2284 { 2285 long nCount = 0; 2286 uno::Sequence<rtl::OUString> aSeq(0); 2287 2288 // use implementation names... 2289 2290 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory(); 2291 uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY ); 2292 if ( xEnAc.is() ) 2293 { 2294 uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration( 2295 rtl::OUString::createFromAscii( SCDPSOURCE_SERVICE ) ); 2296 if ( xEnum.is() ) 2297 { 2298 while ( xEnum->hasMoreElements() ) 2299 { 2300 uno::Any aAddInAny = xEnum->nextElement(); 2301 // if ( aAddInAny.getReflection()->getTypeClass() == TypeClass_INTERFACE ) 2302 { 2303 uno::Reference<uno::XInterface> xIntFac; 2304 aAddInAny >>= xIntFac; 2305 if ( xIntFac.is() ) 2306 { 2307 uno::Reference<lang::XServiceInfo> xInfo( xIntFac, uno::UNO_QUERY ); 2308 if ( xInfo.is() ) 2309 { 2310 rtl::OUString sName = xInfo->getImplementationName(); 2311 2312 aSeq.realloc( nCount+1 ); 2313 aSeq.getArray()[nCount] = sName; 2314 ++nCount; 2315 } 2316 } 2317 } 2318 } 2319 } 2320 } 2321 2322 return aSeq; 2323 } 2324 2325 // use getContext from addincol.cxx 2326 uno::Reference<uno::XComponentContext> getContext(uno::Reference<lang::XMultiServiceFactory> xMSF); 2327 2328 // static 2329 uno::Reference<sheet::XDimensionsSupplier> ScDPObject::CreateSource( const ScDPServiceDesc& rDesc ) 2330 { 2331 rtl::OUString aImplName = rDesc.aServiceName; 2332 uno::Reference<sheet::XDimensionsSupplier> xRet = NULL; 2333 2334 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory(); 2335 uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY ); 2336 if ( xEnAc.is() ) 2337 { 2338 uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration( 2339 rtl::OUString::createFromAscii( SCDPSOURCE_SERVICE ) ); 2340 if ( xEnum.is() ) 2341 { 2342 while ( xEnum->hasMoreElements() && !xRet.is() ) 2343 { 2344 uno::Any aAddInAny = xEnum->nextElement(); 2345 // if ( aAddInAny.getReflection()->getTypeClass() == TypeClass_INTERFACE ) 2346 { 2347 uno::Reference<uno::XInterface> xIntFac; 2348 aAddInAny >>= xIntFac; 2349 if ( xIntFac.is() ) 2350 { 2351 uno::Reference<lang::XServiceInfo> xInfo( xIntFac, uno::UNO_QUERY ); 2352 if ( xInfo.is() && xInfo->getImplementationName() == aImplName ) 2353 { 2354 try 2355 { 2356 // #i113160# try XSingleComponentFactory in addition to (old) XSingleServiceFactory, 2357 // passing the context to the component (see ScUnoAddInCollection::Initialize) 2358 2359 uno::Reference<uno::XInterface> xInterface; 2360 uno::Reference<uno::XComponentContext> xCtx = getContext(xManager); 2361 uno::Reference<lang::XSingleComponentFactory> xCFac( xIntFac, uno::UNO_QUERY ); 2362 if (xCtx.is() && xCFac.is()) 2363 xInterface = xCFac->createInstanceWithContext(xCtx); 2364 2365 if (!xInterface.is()) 2366 { 2367 uno::Reference<lang::XSingleServiceFactory> xFac( xIntFac, uno::UNO_QUERY ); 2368 if ( xFac.is() ) 2369 xInterface = xFac->createInstance(); 2370 } 2371 2372 uno::Reference<lang::XInitialization> xInit( xInterface, uno::UNO_QUERY ); 2373 if (xInit.is()) 2374 { 2375 // initialize 2376 uno::Sequence<uno::Any> aSeq(4); 2377 uno::Any* pArray = aSeq.getArray(); 2378 pArray[0] <<= rtl::OUString( rDesc.aParSource ); 2379 pArray[1] <<= rtl::OUString( rDesc.aParName ); 2380 pArray[2] <<= rtl::OUString( rDesc.aParUser ); 2381 pArray[3] <<= rtl::OUString( rDesc.aParPass ); 2382 xInit->initialize( aSeq ); 2383 } 2384 xRet = uno::Reference<sheet::XDimensionsSupplier>( xInterface, uno::UNO_QUERY ); 2385 } 2386 catch(uno::Exception&) 2387 { 2388 } 2389 } 2390 } 2391 } 2392 } 2393 } 2394 } 2395 2396 return xRet; 2397 } 2398 2399 // ---------------------------------------------------------------------------- 2400 2401 ScDPCollection::ScDPCollection(ScDocument* pDocument) : 2402 pDoc( pDocument ) 2403 { 2404 } 2405 2406 ScDPCollection::ScDPCollection(const ScDPCollection& r) : 2407 ScCollection(r), 2408 pDoc(r.pDoc) 2409 { 2410 } 2411 2412 ScDPCollection::~ScDPCollection() 2413 { 2414 } 2415 2416 ScDataObject* ScDPCollection::Clone() const 2417 { 2418 return new ScDPCollection(*this); 2419 } 2420 2421 void ScDPCollection::DeleteOnTab( SCTAB nTab ) 2422 { 2423 sal_uInt16 nPos = 0; 2424 while ( nPos < nCount ) 2425 { 2426 // look for output positions on the deleted sheet 2427 if ( static_cast<const ScDPObject*>(At(nPos))->GetOutRange().aStart.Tab() == nTab ) 2428 AtFree(nPos); 2429 else 2430 ++nPos; 2431 } 2432 } 2433 2434 void ScDPCollection::UpdateReference( UpdateRefMode eUpdateRefMode, 2435 const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz ) 2436 { 2437 for (sal_uInt16 i=0; i<nCount; i++) 2438 ((ScDPObject*)At(i))->UpdateReference( eUpdateRefMode, r, nDx, nDy, nDz ); 2439 } 2440 2441 sal_Bool ScDPCollection::RefsEqual( const ScDPCollection& r ) const 2442 { 2443 if ( nCount != r.nCount ) 2444 return sal_False; 2445 2446 for (sal_uInt16 i=0; i<nCount; i++) 2447 if ( ! ((const ScDPObject*)At(i))->RefsEqual( *((const ScDPObject*)r.At(i)) ) ) 2448 return sal_False; 2449 2450 return sal_True; // all equal 2451 } 2452 2453 void ScDPCollection::WriteRefsTo( ScDPCollection& r ) const 2454 { 2455 if ( nCount == r.nCount ) 2456 { 2457 //! assert equal names? 2458 for (sal_uInt16 i=0; i<nCount; i++) 2459 ((const ScDPObject*)At(i))->WriteRefsTo( *((ScDPObject*)r.At(i)) ); 2460 } 2461 else 2462 { 2463 // #i8180# If data pilot tables were deleted with their sheet, 2464 // this collection contains extra entries that must be restored. 2465 // Matching objects are found by their names. 2466 2467 DBG_ASSERT( nCount >= r.nCount, "WriteRefsTo: missing entries in document" ); 2468 for (sal_uInt16 nSourcePos=0; nSourcePos<nCount; nSourcePos++) 2469 { 2470 const ScDPObject* pSourceObj = static_cast<const ScDPObject*>(At(nSourcePos)); 2471 String aName = pSourceObj->GetName(); 2472 bool bFound = false; 2473 for (sal_uInt16 nDestPos=0; nDestPos<r.nCount && !bFound; nDestPos++) 2474 { 2475 ScDPObject* pDestObj = static_cast<ScDPObject*>(r.At(nDestPos)); 2476 if ( pDestObj->GetName() == aName ) 2477 { 2478 pSourceObj->WriteRefsTo( *pDestObj ); // found object, copy refs 2479 bFound = true; 2480 } 2481 } 2482 if ( !bFound ) 2483 { 2484 // none found, re-insert deleted object (see ScUndoDataPilot::Undo) 2485 2486 ScDPObject* pDestObj = new ScDPObject( *pSourceObj ); 2487 pDestObj->SetAlive(sal_True); 2488 if ( !r.InsertNewTable(pDestObj) ) 2489 { 2490 DBG_ERROR("cannot insert DPObject"); 2491 DELETEZ( pDestObj ); 2492 } 2493 } 2494 } 2495 DBG_ASSERT( nCount == r.nCount, "WriteRefsTo: couldn't restore all entries" ); 2496 } 2497 } 2498 2499 ScDPObject* ScDPCollection::GetByName(const String& rName) const 2500 { 2501 for (sal_uInt16 i=0; i<nCount; i++) 2502 if (static_cast<const ScDPObject*>(pItems[i])->GetName() == rName) 2503 return static_cast<ScDPObject*>(pItems[i]); 2504 return NULL; 2505 } 2506 2507 String ScDPCollection::CreateNewName( sal_uInt16 nMin ) const 2508 { 2509 String aBase( RTL_CONSTASCII_USTRINGPARAM( "Pivot" ) ); 2510 //! from Resource? 2511 2512 for (sal_uInt16 nAdd=0; nAdd<=nCount; nAdd++) // nCount+1 tries 2513 { 2514 String aNewName = aBase; 2515 aNewName += String::CreateFromInt32( nMin + nAdd ); 2516 sal_Bool bFound = sal_False; 2517 for (sal_uInt16 i=0; i<nCount && !bFound; i++) 2518 if (((const ScDPObject*)pItems[i])->GetName() == aNewName) 2519 bFound = sal_True; 2520 if (!bFound) 2521 return aNewName; // found unused Name 2522 } 2523 return String(); // should not happen 2524 } 2525 2526 2527 2528 // Wang Xu Ming -- 2009-8-17 2529 // DataPilot Migration - Cache&&Performance 2530 long ScDPObject::GetCacheId() const 2531 { 2532 if ( GetSaveData() ) 2533 return GetSaveData()->GetCacheId(); 2534 else 2535 return mnCacheId; 2536 } 2537 sal_uLong ScDPObject::RefreshCache() 2538 { 2539 if ( pServDesc ) 2540 { 2541 // cache table isn't used for external service - do nothing, no error 2542 return 0; 2543 } 2544 2545 CreateObjects(); 2546 sal_uLong nErrId = 0; 2547 if ( pSheetDesc) 2548 nErrId = pSheetDesc->CheckValidate( pDoc ); 2549 if ( nErrId == 0 ) 2550 { 2551 long nOldId = GetCacheId(); 2552 long nNewId = pDoc->GetNewDPObjectCacheId(); 2553 if ( nOldId >= 0 ) 2554 pDoc->RemoveDPObjectCache( nOldId ); 2555 2556 ScDPTableDataCache* pCache = NULL; 2557 if ( pSheetDesc ) 2558 pCache = pSheetDesc->CreateCache( pDoc, nNewId ); 2559 else if ( pImpDesc ) 2560 pCache = pImpDesc->CreateCache( pDoc, nNewId ); 2561 2562 if ( pCache == NULL ) 2563 { 2564 //cache failed 2565 DBG_ASSERT( pCache , " pCache == NULL" ); 2566 return STR_ERR_DATAPILOTSOURCE; 2567 } 2568 2569 nNewId = pCache->GetId(); 2570 2571 bRefresh = sal_True; 2572 ScDPCollection* pDPCollection = pDoc->GetDPCollection(); 2573 sal_uInt16 nCount = pDPCollection->GetCount(); 2574 for (sal_uInt16 i=0; i<nCount; i++) 2575 { //set new cache id 2576 if ( (*pDPCollection)[i]->GetCacheId() == nOldId ) 2577 { 2578 (*pDPCollection)[i]->SetCacheId( nNewId ); 2579 (*pDPCollection)[i]->SetRefresh(); 2580 2581 } 2582 } 2583 DBG_ASSERT( GetCacheId() >= 0, " GetCacheId() >= 0 " ); 2584 } 2585 return nErrId; 2586 } 2587 void ScDPObject::SetCacheId( long nCacheId ) 2588 { 2589 if ( GetCacheId() != nCacheId ) 2590 { 2591 InvalidateSource(); 2592 if ( GetSaveData() ) 2593 GetSaveData()->SetCacheId( nCacheId ); 2594 2595 mnCacheId = nCacheId; 2596 } 2597 } 2598 const ScDPTableDataCache* ScDPObject::GetCache() const 2599 { 2600 return pDoc->GetDPObjectCache( GetCacheId() ); 2601 } 2602 // End Comments 2603 2604 void ScDPCollection::FreeTable(ScDPObject* pDPObj) 2605 { 2606 const ScRange& rOutRange = pDPObj->GetOutRange(); 2607 const ScAddress& s = rOutRange.aStart; 2608 const ScAddress& e = rOutRange.aEnd; 2609 pDoc->RemoveFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE); 2610 Free(pDPObj); 2611 } 2612 2613 bool ScDPCollection::InsertNewTable(ScDPObject* pDPObj) 2614 { 2615 bool bSuccess = Insert(pDPObj); 2616 if (bSuccess) 2617 { 2618 const ScRange& rOutRange = pDPObj->GetOutRange(); 2619 const ScAddress& s = rOutRange.aStart; 2620 const ScAddress& e = rOutRange.aEnd; 2621 pDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE); 2622 } 2623 return bSuccess; 2624 } 2625 2626 bool ScDPCollection::HasDPTable(SCCOL nCol, SCROW nRow, SCTAB nTab) const 2627 { 2628 const ScMergeFlagAttr* pMergeAttr = static_cast<const ScMergeFlagAttr*>( 2629 pDoc->GetAttr(nCol, nRow, nTab, ATTR_MERGE_FLAG)); 2630 2631 if (!pMergeAttr) 2632 return false; 2633 2634 return pMergeAttr->HasDPTable(); 2635 } 2636 2637 2638