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