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 34 // INCLUDE --------------------------------------------------------------- 35 36 #include <algorithm> 37 #include <vector> 38 #include <set> 39 #include <hash_map> 40 #include <hash_set> 41 42 #include <tools/debug.hxx> 43 #include <rtl/math.hxx> 44 #include <svl/itemprop.hxx> 45 #include <svl/intitem.hxx> 46 47 #include "scitems.hxx" 48 #include "document.hxx" 49 #include "docpool.hxx" 50 #include "patattr.hxx" 51 #include "cell.hxx" 52 53 #include "dptabsrc.hxx" 54 #include "dptabres.hxx" 55 #include "dptabdat.hxx" 56 #include "global.hxx" 57 #include "collect.hxx" 58 #include "datauno.hxx" // ScDataUnoConversion 59 #include "unoguard.hxx" 60 #include "miscuno.hxx" 61 #include "unonames.hxx" 62 63 #include <com/sun/star/beans/PropertyAttribute.hpp> 64 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp> 65 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp> 66 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp> 67 #include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp> 68 #include <com/sun/star/sheet/DataPilotFieldSortMode.hpp> 69 #include <com/sun/star/sheet/DataPilotFieldAutoShowInfo.hpp> 70 #include <com/sun/star/table/CellAddress.hpp> 71 72 #include <unotools/collatorwrapper.hxx> 73 #include <unotools/calendarwrapper.hxx> 74 #include <com/sun/star/i18n/CalendarDisplayIndex.hpp> 75 76 using namespace com::sun::star; 77 using ::std::vector; 78 using ::std::set; 79 using ::std::hash_map; 80 using ::std::hash_set; 81 using ::com::sun::star::uno::Reference; 82 using ::com::sun::star::uno::Sequence; 83 using ::com::sun::star::uno::Any; 84 using ::com::sun::star::sheet::DataPilotFieldAutoShowInfo; 85 using ::rtl::OUString; 86 87 // ----------------------------------------------------------------------- 88 89 #define SC_MINCOUNT_LIMIT 1000000 90 91 // ----------------------------------------------------------------------- 92 93 SC_SIMPLE_SERVICE_INFO( ScDPSource, "ScDPSource", "com.sun.star.sheet.DataPilotSource" ) 94 SC_SIMPLE_SERVICE_INFO( ScDPDimensions, "ScDPDimensions", "com.sun.star.sheet.DataPilotSourceDimensions" ) 95 SC_SIMPLE_SERVICE_INFO( ScDPDimension, "ScDPDimension", "com.sun.star.sheet.DataPilotSourceDimension" ) 96 SC_SIMPLE_SERVICE_INFO( ScDPHierarchies, "ScDPHierarchies", "com.sun.star.sheet.DataPilotSourceHierarcies" ) 97 SC_SIMPLE_SERVICE_INFO( ScDPHierarchy, "ScDPHierarchy", "com.sun.star.sheet.DataPilotSourceHierarcy" ) 98 SC_SIMPLE_SERVICE_INFO( ScDPLevels, "ScDPLevels", "com.sun.star.sheet.DataPilotSourceLevels" ) 99 SC_SIMPLE_SERVICE_INFO( ScDPLevel, "ScDPLevel", "com.sun.star.sheet.DataPilotSourceLevel" ) 100 SC_SIMPLE_SERVICE_INFO( ScDPMembers, "ScDPMembers", "com.sun.star.sheet.DataPilotSourceMembers" ) 101 SC_SIMPLE_SERVICE_INFO( ScDPMember, "ScDPMember", "com.sun.star.sheet.DataPilotSourceMember" ) 102 103 // ----------------------------------------------------------------------- 104 105 // property maps for PropertySetInfo 106 // DataDescription / NumberFormat are internal 107 108 // ----------------------------------------------------------------------- 109 110 //! move to a header? 111 sal_Bool lcl_GetBoolFromAny( const uno::Any& aAny ) 112 { 113 if ( aAny.getValueTypeClass() == uno::TypeClass_BOOLEAN ) 114 return *(sal_Bool*)aAny.getValue(); 115 return sal_False; 116 } 117 118 void lcl_SetBoolInAny( uno::Any& rAny, sal_Bool bValue ) 119 { 120 rAny.setValue( &bValue, getBooleanCppuType() ); 121 } 122 123 // ----------------------------------------------------------------------- 124 125 ScDPSource::ScDPSource( ScDPTableData* pD ) : 126 pData( pD ), 127 pDimensions( NULL ), 128 nColDimCount( 0 ), 129 nRowDimCount( 0 ), 130 nDataDimCount( 0 ), 131 nPageDimCount( 0 ), 132 bColumnGrand( sal_True ), // default is true 133 bRowGrand( sal_True ), 134 bIgnoreEmptyRows( sal_False ), 135 bRepeatIfEmpty( sal_False ), 136 nDupCount( 0 ), 137 pResData( NULL ), 138 pColResRoot( NULL ), 139 pRowResRoot( NULL ), 140 pColResults( NULL ), 141 pRowResults( NULL ), 142 bResultOverflow( sal_False ), 143 bPageFiltered( false ), 144 mpGrandTotalName(NULL) 145 { 146 pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty ); 147 } 148 149 ScDPSource::~ScDPSource() 150 { 151 if (pDimensions) 152 pDimensions->release(); // ref-counted 153 154 //! free lists 155 156 delete[] pColResults; 157 delete[] pRowResults; 158 159 delete pColResRoot; 160 delete pRowResRoot; 161 delete pResData; 162 } 163 164 void ScDPSource::SetGrandTotalName(const ::rtl::OUString& rName) 165 { 166 mpGrandTotalName.reset(new ::rtl::OUString(rName)); 167 } 168 169 const ::rtl::OUString* ScDPSource::GetGrandTotalName() const 170 { 171 return mpGrandTotalName.get(); 172 } 173 174 sal_uInt16 ScDPSource::GetOrientation(long nColumn) 175 { 176 long i; 177 for (i=0; i<nColDimCount; i++) 178 if (nColDims[i] == nColumn) 179 return sheet::DataPilotFieldOrientation_COLUMN; 180 for (i=0; i<nRowDimCount; i++) 181 if (nRowDims[i] == nColumn) 182 return sheet::DataPilotFieldOrientation_ROW; 183 for (i=0; i<nDataDimCount; i++) 184 if (nDataDims[i] == nColumn) 185 return sheet::DataPilotFieldOrientation_DATA; 186 for (i=0; i<nPageDimCount; i++) 187 if (nPageDims[i] == nColumn) 188 return sheet::DataPilotFieldOrientation_PAGE; 189 return sheet::DataPilotFieldOrientation_HIDDEN; 190 } 191 192 long ScDPSource::GetDataDimensionCount() 193 { 194 return nDataDimCount; 195 } 196 197 ScDPDimension* ScDPSource::GetDataDimension(long nIndex) 198 { 199 if (nIndex < 0 || nIndex >= nDataDimCount) 200 return NULL; 201 202 long nDimIndex = nDataDims[nIndex]; 203 return GetDimensionsObject()->getByIndex(nDimIndex); 204 } 205 206 String ScDPSource::GetDataDimName( long nIndex ) 207 { 208 String aRet; 209 ScDPDimension* pDim = GetDataDimension(nIndex); 210 if (pDim) 211 aRet = String(pDim->getName()); 212 return aRet; 213 } 214 215 long ScDPSource::GetPosition(long nColumn) 216 { 217 long i; 218 for (i=0; i<nColDimCount; i++) 219 if (nColDims[i] == nColumn) 220 return i; 221 for (i=0; i<nRowDimCount; i++) 222 if (nRowDims[i] == nColumn) 223 return i; 224 for (i=0; i<nDataDimCount; i++) 225 if (nDataDims[i] == nColumn) 226 return i; 227 for (i=0; i<nPageDimCount; i++) 228 if (nPageDims[i] == nColumn) 229 return i; 230 return 0; 231 } 232 233 sal_Bool lcl_TestSubTotal( sal_Bool& rAllowed, long nColumn, long* pArray, long nCount, ScDPSource* pSource ) 234 { 235 for (long i=0; i<nCount; i++) 236 if (pArray[i] == nColumn) 237 { 238 // no subtotals for data layout dim, no matter where 239 if ( pSource->IsDataLayoutDimension(nColumn) ) 240 rAllowed = sal_False; 241 else 242 { 243 // no subtotals if no other dim but data layout follows 244 long nNextIndex = i+1; 245 if ( nNextIndex < nCount && pSource->IsDataLayoutDimension(pArray[nNextIndex]) ) 246 ++nNextIndex; 247 if ( nNextIndex >= nCount ) 248 rAllowed = sal_False; 249 } 250 251 return sal_True; // found 252 } 253 return sal_False; 254 } 255 256 sal_Bool ScDPSource::SubTotalAllowed(long nColumn) 257 { 258 //! cache this at ScDPResultData 259 sal_Bool bAllowed = sal_True; 260 if ( lcl_TestSubTotal( bAllowed, nColumn, nColDims, nColDimCount, this ) ) 261 return bAllowed; 262 if ( lcl_TestSubTotal( bAllowed, nColumn, nRowDims, nRowDimCount, this ) ) 263 return bAllowed; 264 return bAllowed; 265 } 266 267 void lcl_RemoveDim( long nRemove, long* pDims, long& rCount ) 268 { 269 for (long i=0; i<rCount; i++) 270 if ( pDims[i] == nRemove ) 271 { 272 for (long j=i; j+1<rCount; j++) 273 pDims[j] = pDims[j+1]; 274 --rCount; 275 return; 276 } 277 } 278 279 void ScDPSource::SetOrientation(long nColumn, sal_uInt16 nNew) 280 { 281 //! change to no-op if new orientation is equal to old? 282 283 // remove from old list 284 lcl_RemoveDim( nColumn, nColDims, nColDimCount ); 285 lcl_RemoveDim( nColumn, nRowDims, nRowDimCount ); 286 lcl_RemoveDim( nColumn, nDataDims, nDataDimCount ); 287 lcl_RemoveDim( nColumn, nPageDims, nPageDimCount ); 288 289 // add to new list 290 switch (nNew) 291 { 292 case sheet::DataPilotFieldOrientation_COLUMN: 293 nColDims[nColDimCount++] = nColumn; 294 break; 295 case sheet::DataPilotFieldOrientation_ROW: 296 nRowDims[nRowDimCount++] = nColumn; 297 break; 298 case sheet::DataPilotFieldOrientation_DATA: 299 nDataDims[nDataDimCount++] = nColumn; 300 break; 301 case sheet::DataPilotFieldOrientation_PAGE: 302 nPageDims[nPageDimCount++] = nColumn; 303 break; 304 // Wang Xu Ming -- 2009-9-1 305 // DataPilot Migration - Cache&&Performance 306 case sheet::DataPilotFieldOrientation_HIDDEN: 307 break; 308 // End Comments 309 default: 310 DBG_ERROR( "ScDPSource::SetOrientation: unexpected orientation" ); 311 break; 312 } 313 } 314 315 sal_Bool ScDPSource::IsDataLayoutDimension(long nDim) 316 { 317 return nDim == pData->GetColumnCount(); 318 } 319 320 sal_uInt16 ScDPSource::GetDataLayoutOrientation() 321 { 322 return GetOrientation(pData->GetColumnCount()); 323 } 324 325 sal_Bool ScDPSource::IsDateDimension(long nDim) 326 { 327 return pData->IsDateDimension(nDim); 328 } 329 330 sal_uInt32 ScDPSource::GetNumberFormat(long nDim) 331 { 332 return pData->GetNumberFormat( nDim ); 333 } 334 335 ScDPDimensions* ScDPSource::GetDimensionsObject() 336 { 337 if (!pDimensions) 338 { 339 pDimensions = new ScDPDimensions(this); 340 pDimensions->acquire(); // ref-counted 341 } 342 return pDimensions; 343 } 344 345 uno::Reference<container::XNameAccess> SAL_CALL ScDPSource::getDimensions() throw(uno::RuntimeException) 346 { 347 return GetDimensionsObject(); 348 } 349 350 void ScDPSource::SetDupCount( long nNew ) 351 { 352 nDupCount = nNew; 353 } 354 355 ScDPDimension* ScDPSource::AddDuplicated(long /* nSource */, const String& rNewName) 356 { 357 DBG_ASSERT( pDimensions, "AddDuplicated without dimensions?" ); 358 359 // re-use 360 361 long nOldDimCount = pDimensions->getCount(); 362 for (long i=0; i<nOldDimCount; i++) 363 { 364 ScDPDimension* pDim = pDimensions->getByIndex(i); 365 if (pDim && String(pDim->getName()) == rNewName) 366 { 367 //! test if pDim is a duplicate of source 368 return pDim; 369 } 370 } 371 372 SetDupCount( nDupCount + 1 ); 373 pDimensions->CountChanged(); // uses nDupCount 374 375 return pDimensions->getByIndex( pDimensions->getCount() - 1 ); 376 } 377 378 long ScDPSource::GetSourceDim(long nDim) 379 { 380 // original source dimension or data layout dimension? 381 if ( nDim <= pData->GetColumnCount() ) 382 return nDim; 383 384 if ( nDim < pDimensions->getCount() ) 385 { 386 ScDPDimension* pDimObj = pDimensions->getByIndex( nDim ); 387 if ( pDimObj ) 388 { 389 long nSource = pDimObj->GetSourceDim(); 390 if ( nSource >= 0 ) 391 return nSource; 392 } 393 } 394 395 DBG_ERROR("GetSourceDim: wrong dim"); 396 return nDim; 397 } 398 399 uno::Sequence< uno::Sequence<sheet::DataResult> > SAL_CALL ScDPSource::getResults() 400 throw(uno::RuntimeException) 401 { 402 CreateRes_Impl(); // create pColResRoot and pRowResRoot 403 404 if ( bResultOverflow ) // set in CreateRes_Impl 405 { 406 // no results available 407 throw uno::RuntimeException(); 408 } 409 410 long nColCount = pColResRoot->GetSize(pResData->GetColStartMeasure()); 411 long nRowCount = pRowResRoot->GetSize(pResData->GetRowStartMeasure()); 412 413 // allocate full sequence 414 //! leave out empty rows??? 415 416 uno::Sequence< uno::Sequence<sheet::DataResult> > aSeq( nRowCount ); 417 uno::Sequence<sheet::DataResult>* pRowAry = aSeq.getArray(); 418 for (long nRow = 0; nRow < nRowCount; nRow++) 419 { 420 uno::Sequence<sheet::DataResult> aColSeq( nColCount ); 421 // use default values of DataResult 422 pRowAry[nRow] = aColSeq; 423 } 424 425 long nSeqRow = 0; 426 pRowResRoot->FillDataResults( pColResRoot, aSeq, nSeqRow, pResData->GetRowStartMeasure() ); 427 428 return aSeq; 429 } 430 431 void SAL_CALL ScDPSource::refresh() throw(uno::RuntimeException) 432 { 433 disposeData(); 434 } 435 436 void SAL_CALL ScDPSource::addRefreshListener( const uno::Reference<util::XRefreshListener >& ) 437 throw(uno::RuntimeException) 438 { 439 DBG_ERROR("not implemented"); //! exception? 440 } 441 442 void SAL_CALL ScDPSource::removeRefreshListener( const uno::Reference<util::XRefreshListener >& ) 443 throw(uno::RuntimeException) 444 { 445 DBG_ERROR("not implemented"); //! exception? 446 } 447 448 Sequence< Sequence<Any> > SAL_CALL ScDPSource::getDrillDownData(const Sequence<sheet::DataPilotFieldFilter>& aFilters) 449 throw (uno::RuntimeException) 450 { 451 long nColumnCount = GetData()->GetColumnCount(); 452 453 typedef hash_map<String, long, ScStringHashCode> FieldNameMapType; 454 FieldNameMapType aFieldNames; 455 for (long i = 0; i < nColumnCount; ++i) 456 { 457 aFieldNames.insert( 458 FieldNameMapType::value_type(GetData()->getDimensionName(i), i)); 459 } 460 461 // collect ScDPItemData for each filtered column 462 vector<ScDPCacheTable::Criterion> aFilterCriteria; 463 sal_Int32 nFilterCount = aFilters.getLength(); 464 for (sal_Int32 i = 0; i < nFilterCount; ++i) 465 { 466 const sheet::DataPilotFieldFilter& rFilter = aFilters[i]; 467 String aFieldName( rFilter.FieldName ); 468 for (long nCol = 0; nCol < nColumnCount; ++nCol) 469 { 470 if ( aFieldName == pData->getDimensionName(nCol) ) 471 { 472 ScDPDimension* pDim = GetDimensionsObject()->getByIndex( nCol ); 473 ScDPMembers* pMembers = pDim->GetHierarchiesObject()->getByIndex(0)-> 474 GetLevelsObject()->getByIndex(0)->GetMembersObject(); 475 sal_Int32 nIndex = pMembers->GetIndexFromName( rFilter.MatchValue ); 476 if ( nIndex >= 0 ) 477 { 478 ScDPItemData aItem; 479 pMembers->getByIndex(nIndex)->FillItemData( aItem ); 480 aFilterCriteria.push_back( ScDPCacheTable::Criterion() ); 481 aFilterCriteria.back().mnFieldIndex = nCol; 482 aFilterCriteria.back().mpFilter.reset( 483 new ScDPCacheTable::SingleFilter(aItem.GetString()/*rSharedString, nMatchStrId*/, aItem.GetValue(), aItem.IsValue()) ); 484 } 485 } 486 } 487 } 488 489 // Take into account the visibilities of field members. 490 ScDPResultVisibilityData aResVisData(/*rSharedString, */this); 491 pRowResRoot->FillVisibilityData(aResVisData); 492 pColResRoot->FillVisibilityData(aResVisData); 493 aResVisData.fillFieldFilters(aFilterCriteria); 494 495 Sequence< Sequence<Any> > aTabData; 496 hash_set<sal_Int32> aCatDims; 497 GetCategoryDimensionIndices(aCatDims); 498 pData->GetDrillDownData(aFilterCriteria, aCatDims, aTabData); 499 return aTabData; 500 } 501 502 String ScDPSource::getDataDescription() 503 { 504 CreateRes_Impl(); // create pResData 505 506 String aRet; 507 if ( pResData->GetMeasureCount() == 1 ) 508 { 509 bool bTotalResult = false; 510 aRet = pResData->GetMeasureString( 0, sal_True, SUBTOTAL_FUNC_NONE, bTotalResult ); 511 } 512 513 // empty for more than one measure 514 515 return aRet; 516 } 517 518 sal_Bool ScDPSource::getColumnGrand() const 519 { 520 return bColumnGrand; 521 } 522 523 void ScDPSource::setColumnGrand(sal_Bool bSet) 524 { 525 bColumnGrand = bSet; 526 } 527 528 sal_Bool ScDPSource::getRowGrand() const 529 { 530 return bRowGrand; 531 } 532 533 void ScDPSource::setRowGrand(sal_Bool bSet) 534 { 535 bRowGrand = bSet; 536 } 537 538 sal_Bool ScDPSource::getIgnoreEmptyRows() const 539 { 540 return bIgnoreEmptyRows; 541 } 542 543 void ScDPSource::setIgnoreEmptyRows(sal_Bool bSet) 544 { 545 bIgnoreEmptyRows = bSet; 546 pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty ); 547 } 548 549 sal_Bool ScDPSource::getRepeatIfEmpty() const 550 { 551 return bRepeatIfEmpty; 552 } 553 554 void ScDPSource::setRepeatIfEmpty(sal_Bool bSet) 555 { 556 bRepeatIfEmpty = bSet; 557 pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty ); 558 } 559 560 void ScDPSource::validate() //! ??? 561 { 562 CreateRes_Impl(); 563 } 564 565 void ScDPSource::disposeData() 566 { 567 if ( pResData ) 568 { 569 // reset all data... 570 571 DELETEZ(pColResRoot); 572 DELETEZ(pRowResRoot); 573 DELETEZ(pResData); 574 delete[] pColResults; 575 delete[] pRowResults; 576 pColResults = NULL; 577 pRowResults = NULL; 578 aColLevelList.Clear(); 579 aRowLevelList.Clear(); 580 } 581 582 if ( pDimensions ) 583 { 584 pDimensions->release(); // ref-counted 585 pDimensions = NULL; // settings have to be applied (from SaveData) again! 586 } 587 SetDupCount( 0 ); 588 589 //! Test ???? 590 nColDimCount = nRowDimCount = nDataDimCount = nPageDimCount = 0; 591 592 pData->DisposeData(); // cached entries etc. 593 bPageFiltered = false; 594 bResultOverflow = sal_False; 595 } 596 597 long lcl_CountMinMembers(const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLevel, long nLevels ) 598 { 599 // Calculate the product of the member count for those consecutive levels that 600 // have the "show all" flag, one following level, and the data layout dimension. 601 602 long nTotal = 1; 603 long nDataCount = 1; 604 sal_Bool bWasShowAll = sal_True; 605 long nPos = nLevels; 606 while ( nPos > 0 ) 607 { 608 --nPos; 609 610 if ( nPos+1 < nLevels && ppDim[nPos] == ppDim[nPos+1] ) 611 { 612 DBG_ERROR("lcl_CountMinMembers: multiple levels from one dimension not implemented"); 613 return 0; 614 } 615 616 sal_Bool bDo = sal_False; 617 if ( ppDim[nPos]->getIsDataLayoutDimension() ) 618 { 619 // data layout dim doesn't interfere with "show all" flags 620 nDataCount = ppLevel[nPos]->GetMembersObject()->getCount(); 621 if ( nDataCount == 0 ) 622 nDataCount = 1; 623 } 624 else if ( bWasShowAll ) // "show all" set for all following levels? 625 { 626 bDo = sal_True; 627 if ( !ppLevel[nPos]->getShowEmpty() ) 628 { 629 // this level is counted, following ones are not 630 bWasShowAll = sal_False; 631 } 632 } 633 if ( bDo ) 634 { 635 long nThisCount = ppLevel[nPos]->GetMembersObject()->getMinMembers(); 636 if ( nThisCount == 0 ) 637 { 638 nTotal = 1; // empty level -> start counting from here 639 //! start with visible elements in this level? 640 } 641 else 642 { 643 if ( nTotal >= LONG_MAX / nThisCount ) 644 return LONG_MAX; // overflow 645 nTotal *= nThisCount; 646 } 647 } 648 } 649 650 // always include data layout dim, even after restarting 651 if ( nTotal >= LONG_MAX / nDataCount ) 652 return LONG_MAX; // overflow 653 nTotal *= nDataCount; 654 655 return nTotal; 656 } 657 658 long lcl_GetIndexFromName( const rtl::OUString rName, const uno::Sequence<rtl::OUString>& rElements ) 659 { 660 long nCount = rElements.getLength(); 661 const rtl::OUString* pArray = rElements.getConstArray(); 662 for (long nPos=0; nPos<nCount; nPos++) 663 if (pArray[nPos] == rName) 664 return nPos; 665 666 return -1; // not found 667 } 668 669 void ScDPSource::FillCalcInfo(bool bIsRow, ScDPTableData::CalcInfo& rInfo, bool &rHasAutoShow) 670 { 671 long* nDims = bIsRow ? nRowDims : nColDims; 672 long nDimCount = bIsRow ? nRowDimCount : nColDimCount; 673 674 for (long i = 0; i < nDimCount; ++i) 675 { 676 ScDPDimension* pDim = GetDimensionsObject()->getByIndex( nDims[i] ); 677 long nHierarchy = pDim->getUsedHierarchy(); 678 if ( nHierarchy >= pDim->GetHierarchiesObject()->getCount() ) 679 nHierarchy = 0; 680 ScDPLevels* pLevels = pDim->GetHierarchiesObject()->getByIndex(nHierarchy)->GetLevelsObject(); 681 long nCount = pLevels->getCount(); 682 683 //! Test 684 if ( pDim->getIsDataLayoutDimension() && nDataDimCount < 2 ) 685 nCount = 0; 686 //! Test 687 688 for (long j = 0; j < nCount; ++j) 689 { 690 ScDPLevel* pLevel = pLevels->getByIndex(j); 691 pLevel->EvaluateSortOrder(); 692 693 // no layout flags for column fields, only for row fields 694 pLevel->SetEnableLayout( bIsRow ); 695 696 if ( pLevel->GetAutoShow().IsEnabled ) 697 rHasAutoShow = sal_True; 698 699 if (bIsRow) 700 { 701 rInfo.aRowLevelDims.push_back(nDims[i]); 702 rInfo.aRowDims.push_back(pDim); 703 rInfo.aRowLevels.push_back(pLevel); 704 } 705 else 706 { 707 rInfo.aColLevelDims.push_back(nDims[i]); 708 rInfo.aColDims.push_back(pDim); 709 rInfo.aColLevels.push_back(pLevel); 710 } 711 712 pLevel->GetMembersObject(); // initialize for groups 713 } 714 } 715 } 716 717 void ScDPSource::GetCategoryDimensionIndices(hash_set<sal_Int32>& rCatDims) 718 { 719 hash_set<sal_Int32> aCatDims; 720 for (long i = 0; i < nColDimCount; ++i) 721 { 722 sal_Int32 nDim = static_cast<sal_Int32>(nColDims[i]); 723 if (!IsDataLayoutDimension(nDim)) 724 aCatDims.insert(nDim); 725 } 726 727 for (long i = 0; i < nRowDimCount; ++i) 728 { 729 sal_Int32 nDim = static_cast<sal_Int32>(nRowDims[i]); 730 if (!IsDataLayoutDimension(nDim)) 731 aCatDims.insert(nDim); 732 } 733 734 for (long i = 0; i < nPageDimCount; ++i) 735 { 736 sal_Int32 nDim = static_cast<sal_Int32>(nPageDims[i]); 737 if (!IsDataLayoutDimension(nDim)) 738 aCatDims.insert(nDim); 739 } 740 741 rCatDims.swap(aCatDims); 742 } 743 744 void ScDPSource::FilterCacheTableByPageDimensions() 745 { 746 // #i117661# Repeated calls to ScDPCacheTable::filterByPageDimension are invalid because 747 // rows are only hidden, never shown again. If FilterCacheTableByPageDimensions is called 748 // again, the cache table must be re-initialized. Currently, CreateRes_Impl always uses 749 // a fresh cache because ScDBDocFunc::DataPilotUpdate calls InvalidateData. 750 751 if (bPageFiltered) 752 { 753 DBG_ERRORFILE("tried to apply page field filters several times"); 754 755 pData->DisposeData(); 756 pData->CreateCacheTable(); // re-initialize the cache table 757 bPageFiltered = false; 758 } 759 760 // filter table by page dimensions. 761 vector<ScDPCacheTable::Criterion> aCriteria; 762 for (long i = 0; i < nPageDimCount; ++i) 763 { 764 ScDPDimension* pDim = GetDimensionsObject()->getByIndex(nPageDims[i]); 765 long nField = pDim->GetDimension(); 766 767 ScDPMembers* pMems = pDim->GetHierarchiesObject()->getByIndex(0)-> 768 GetLevelsObject()->getByIndex(0)->GetMembersObject(); 769 770 long nMemCount = pMems->getCount(); 771 ScDPCacheTable::Criterion aFilter; 772 aFilter.mnFieldIndex = static_cast<sal_Int32>(nField); 773 aFilter.mpFilter.reset(new ScDPCacheTable::GroupFilter(/*rSharedString*/)); 774 ScDPCacheTable::GroupFilter* pGrpFilter = 775 static_cast<ScDPCacheTable::GroupFilter*>(aFilter.mpFilter.get()); 776 for (long j = 0; j < nMemCount; ++j) 777 { 778 ScDPMember* pMem = pMems->getByIndex(j); 779 if (pMem->getIsVisible()) 780 { 781 ScDPItemData aData; 782 pMem->FillItemData(aData); 783 pGrpFilter->addMatchItem(aData.GetString(), aData.GetValue(), aData.IsValue()); 784 } 785 } 786 if (pGrpFilter->getMatchItemCount() < static_cast<size_t>(nMemCount)) 787 // there is at least one invisible item. Add this filter criterion to the mix. 788 aCriteria.push_back(aFilter); 789 790 if (!pDim || !pDim->HasSelectedPage()) 791 continue; 792 793 const ScDPItemData& rData = pDim->GetSelectedData(); 794 aCriteria.push_back(ScDPCacheTable::Criterion()); 795 ScDPCacheTable::Criterion& r = aCriteria.back(); 796 r.mnFieldIndex = static_cast<sal_Int32>(nField); 797 r.mpFilter.reset( 798 new ScDPCacheTable::SingleFilter(rData.GetString()/*rSharedString, nStrId*/, rData.GetValue(), rData.IsValue())); 799 } 800 if (!aCriteria.empty()) 801 { 802 hash_set<sal_Int32> aCatDims; 803 GetCategoryDimensionIndices(aCatDims); 804 pData->FilterCacheTable(aCriteria, aCatDims); 805 bPageFiltered = true; 806 } 807 } 808 809 void ScDPSource::CreateRes_Impl() 810 { 811 if ( !pResData ) 812 { 813 sal_uInt16 nDataOrient = GetDataLayoutOrientation(); 814 if ( nDataDimCount > 1 && ( nDataOrient != sheet::DataPilotFieldOrientation_COLUMN && 815 nDataOrient != sheet::DataPilotFieldOrientation_ROW ) ) 816 { 817 // if more than one data dimension, data layout orientation must be set 818 SetOrientation( pData->GetColumnCount(), sheet::DataPilotFieldOrientation_ROW ); 819 nDataOrient = sheet::DataPilotFieldOrientation_ROW; 820 } 821 822 // TODO: Aggreate pDataNames, pDataRefValues, nDataRefOrient, and 823 // eDataFunctions into a structure and use vector instead of static 824 // or pointer arrays. 825 String* pDataNames = NULL; 826 sheet::DataPilotFieldReference* pDataRefValues = NULL; 827 ScSubTotalFunc eDataFunctions[SC_DAPI_MAXFIELDS]; 828 sal_uInt16 nDataRefOrient[SC_DAPI_MAXFIELDS]; 829 if (nDataDimCount) 830 { 831 pDataNames = new String[nDataDimCount]; 832 pDataRefValues = new sheet::DataPilotFieldReference[nDataDimCount]; 833 } 834 835 ScDPTableData::CalcInfo aInfo; 836 837 838 // LateInit (initialize only those rows/children that are used) can be used unless 839 // any data dimension needs reference values from column/row dimensions 840 sal_Bool bLateInit = sal_True; 841 842 // Go through all data dimensions (i.e. fields) and build their meta data 843 // so that they can be passed on to ScDPResultData instance later. 844 // TODO: aggregate all of data dimension info into a structure. 845 long i; 846 for (i=0; i<nDataDimCount; i++) 847 { 848 // Get function for each data field. 849 long nDimIndex = nDataDims[i]; 850 ScDPDimension* pDim = GetDimensionsObject()->getByIndex(nDimIndex); 851 sheet::GeneralFunction eUser = (sheet::GeneralFunction)pDim->getFunction(); 852 if (eUser == sheet::GeneralFunction_AUTO) 853 { 854 //! test for numeric data 855 eUser = sheet::GeneralFunction_SUM; 856 } 857 858 // Map UNO's enum to internal enum ScSubTotalFunc. 859 eDataFunctions[i] = ScDataUnoConversion::GeneralToSubTotal( eUser ); 860 861 // Get reference field/item information. 862 pDataRefValues[i] = pDim->GetReferenceValue(); 863 nDataRefOrient[i] = sheet::DataPilotFieldOrientation_HIDDEN; // default if not used 864 sal_Int32 eRefType = pDataRefValues[i].ReferenceType; 865 if ( eRefType == sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE || 866 eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE || 867 eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE || 868 eRefType == sheet::DataPilotFieldReferenceType::RUNNING_TOTAL ) 869 { 870 long nColumn = lcl_GetIndexFromName( pDataRefValues[i].ReferenceField, 871 GetDimensionsObject()->getElementNames() ); 872 if ( nColumn >= 0 ) 873 { 874 nDataRefOrient[i] = GetOrientation( nColumn ); 875 // need fully initialized results to find reference values 876 // (both in column or row dimensions), so updated values or 877 // differences to 0 can be displayed even for empty results. 878 bLateInit = sal_False; 879 } 880 } 881 882 pDataNames[i] = String( pDim->getName() ); //! label? 883 884 // asterisk is added to duplicated dimension names by ScDPSaveData::WriteToSource 885 //! modify user visible strings as in ScDPResultData::GetMeasureString instead! 886 887 pDataNames[i].EraseTrailingChars('*'); 888 889 //! if the name is overridden by user, a flag must be set 890 //! so the user defined name replaces the function string and field name. 891 892 //! the complete name (function and field) must be stored at the dimension 893 894 long nSource = ((ScDPDimension*)pDim)->GetSourceDim(); 895 if (nSource >= 0) 896 aInfo.aDataSrcCols.push_back(nSource); 897 else 898 aInfo.aDataSrcCols.push_back(nDimIndex); 899 } 900 901 pResData = new ScDPResultData( this ); 902 pResData->SetMeasureData( nDataDimCount, eDataFunctions, pDataRefValues, nDataRefOrient, pDataNames ); 903 pResData->SetDataLayoutOrientation(nDataOrient); 904 pResData->SetLateInit( bLateInit ); 905 906 delete[] pDataNames; 907 delete[] pDataRefValues; 908 909 bool bHasAutoShow = false; 910 911 ScDPInitState aInitState; 912 913 // Page field selections restrict the members shown in related fields 914 // (both in column and row fields). aInitState is filled with the page 915 // field selections, they are kept across the data iterator loop. 916 917 for (i=0; i<nPageDimCount; i++) 918 { 919 ScDPDimension* pDim = GetDimensionsObject()->getByIndex( nPageDims[i] ); 920 if ( pDim->HasSelectedPage() ) 921 aInitState.AddMember( nPageDims[i], GetMemberId( nPageDims[i], pDim->GetSelectedData() ) ); 922 } 923 924 pColResRoot = new ScDPResultMember( pResData, /*NULL, NULL, NULL, */bColumnGrand ); 925 pRowResRoot = new ScDPResultMember( pResData, /*NULL, NULL, NULL, */bRowGrand ); 926 927 FillCalcInfo(false, aInfo, bHasAutoShow); 928 long nColLevelCount = aInfo.aColLevels.size(); 929 930 pColResRoot->InitFrom( aInfo.aColDims, aInfo.aColLevels, 0, aInitState ); 931 pColResRoot->SetHasElements(); 932 933 FillCalcInfo(true, aInfo, bHasAutoShow); 934 long nRowLevelCount = aInfo.aRowLevels.size(); 935 936 if ( nRowLevelCount > 0 ) 937 { 938 // disable layout flags for the innermost row field (level) 939 aInfo.aRowLevels[nRowLevelCount-1]->SetEnableLayout( sal_False ); 940 } 941 942 pRowResRoot->InitFrom( aInfo.aRowDims, aInfo.aRowLevels, 0, aInitState ); 943 pRowResRoot->SetHasElements(); 944 945 // initialize members object also for all page dimensions (needed for numeric groups) 946 for (i=0; i<nPageDimCount; i++) 947 { 948 ScDPDimension* pDim = GetDimensionsObject()->getByIndex( nPageDims[i] ); 949 long nHierarchy = pDim->getUsedHierarchy(); 950 if ( nHierarchy >= pDim->GetHierarchiesObject()->getCount() ) 951 nHierarchy = 0; 952 953 ScDPLevels* pLevels = pDim->GetHierarchiesObject()->getByIndex(nHierarchy)->GetLevelsObject(); 954 long nCount = pLevels->getCount(); 955 for (long j=0; j<nCount; j++) 956 pLevels->getByIndex(j)->GetMembersObject(); // initialize for groups 957 } 958 959 // pre-check: calculate minimum number of result columns / rows from 960 // levels that have the "show all" flag set 961 962 long nMinColMembers = lcl_CountMinMembers( aInfo.aColDims, aInfo.aColLevels, nColLevelCount ); 963 long nMinRowMembers = lcl_CountMinMembers( aInfo.aRowDims, aInfo.aRowLevels, nRowLevelCount ); 964 965 if ( nMinColMembers > MAXCOLCOUNT/*SC_MINCOUNT_LIMIT*/ || nMinRowMembers > SC_MINCOUNT_LIMIT ) 966 { 967 // resulting table is too big -> abort before calculating 968 // (this relies on late init, so no members are allocated in InitFrom above) 969 970 bResultOverflow = sal_True; 971 } 972 else 973 { 974 FilterCacheTableByPageDimensions(); 975 976 aInfo.aPageDims.reserve(nPageDimCount); 977 for (i = 0; i < nPageDimCount; ++i) 978 aInfo.aPageDims.push_back(nPageDims[i]); 979 980 aInfo.pInitState = &aInitState; 981 aInfo.pColRoot = pColResRoot; 982 aInfo.pRowRoot = pRowResRoot; 983 pData->CalcResults(aInfo, false); 984 985 pColResRoot->CheckShowEmpty(); 986 pRowResRoot->CheckShowEmpty(); 987 // ---------------------------------------------------------------- 988 // With all data processed, calculate the final results: 989 990 // UpdateDataResults calculates all original results from the collected values, 991 // and stores them as reference values if needed. 992 pRowResRoot->UpdateDataResults( pColResRoot, pResData->GetRowStartMeasure() ); 993 994 if ( bHasAutoShow ) // do the double calculation only if AutoShow is used 995 { 996 // Find the desired members and set bAutoHidden flag for the others 997 pRowResRoot->DoAutoShow( pColResRoot ); 998 999 // Reset all results to empty, so they can be built again with data for the 1000 // desired members only. 1001 pColResRoot->ResetResults( sal_True ); 1002 pRowResRoot->ResetResults( sal_True ); 1003 pData->CalcResults(aInfo, true); 1004 1005 // Call UpdateDataResults again, with the new (limited) values. 1006 pRowResRoot->UpdateDataResults( pColResRoot, pResData->GetRowStartMeasure() ); 1007 } 1008 1009 // SortMembers does the sorting by a result dimension, using the orginal results, 1010 // but not running totals etc. 1011 pRowResRoot->SortMembers( pColResRoot ); 1012 1013 // UpdateRunningTotals calculates running totals along column/row dimensions, 1014 // differences from other members (named or relative), and column/row percentages 1015 // or index values. 1016 // Running totals and relative differences need to be done using the sorted values. 1017 // Column/row percentages and index values must be done after sorting, because the 1018 // results may no longer be in the right order (row total for percentage of row is 1019 // always 1). 1020 ScDPRunningTotalState aRunning( pColResRoot, pRowResRoot ); 1021 ScDPRowTotals aTotals; 1022 pRowResRoot->UpdateRunningTotals( pColResRoot, pResData->GetRowStartMeasure(), aRunning, aTotals ); 1023 1024 // ---------------------------------------------------------------- 1025 } 1026 } 1027 } 1028 1029 //UNUSED2009-05 void ScDPSource::DumpState( ScDocument* pDoc, const ScAddress& rPos ) 1030 //UNUSED2009-05 { 1031 //UNUSED2009-05 CreateRes_Impl(); 1032 //UNUSED2009-05 1033 //UNUSED2009-05 ScAddress aDocPos( rPos ); 1034 //UNUSED2009-05 1035 //UNUSED2009-05 if (pColResRoot->GetChildDimension()) 1036 //UNUSED2009-05 pColResRoot->GetChildDimension()->DumpState( NULL, pDoc, aDocPos ); 1037 //UNUSED2009-05 pRowResRoot->DumpState( pColResRoot, pDoc, aDocPos ); 1038 //UNUSED2009-05 } 1039 1040 void ScDPSource::FillLevelList( sal_uInt16 nOrientation, List& rList ) 1041 { 1042 rList.Clear(); 1043 1044 long nDimCount = 0; 1045 long* pDimIndex = NULL; 1046 switch (nOrientation) 1047 { 1048 case sheet::DataPilotFieldOrientation_COLUMN: 1049 pDimIndex = nColDims; 1050 nDimCount = nColDimCount; 1051 break; 1052 case sheet::DataPilotFieldOrientation_ROW: 1053 pDimIndex = nRowDims; 1054 nDimCount = nRowDimCount; 1055 break; 1056 case sheet::DataPilotFieldOrientation_DATA: 1057 pDimIndex = nDataDims; 1058 nDimCount = nDataDimCount; 1059 break; 1060 case sheet::DataPilotFieldOrientation_PAGE: 1061 pDimIndex = nPageDims; 1062 nDimCount = nPageDimCount; 1063 break; 1064 default: 1065 DBG_ERROR( "ScDPSource::FillLevelList: unexpected orientation" ); 1066 break; 1067 } 1068 if (!pDimIndex) 1069 { 1070 DBG_ERROR("invalid orientation"); 1071 return; 1072 } 1073 1074 ScDPDimensions* pDims = GetDimensionsObject(); 1075 for (long nDim=0; nDim<nDimCount; nDim++) 1076 { 1077 ScDPDimension* pDim = pDims->getByIndex(pDimIndex[nDim]); 1078 DBG_ASSERT( pDim->getOrientation() == nOrientation, "orientations are wrong" ); 1079 1080 ScDPHierarchies* pHiers = pDim->GetHierarchiesObject(); 1081 long nHierarchy = pDim->getUsedHierarchy(); 1082 if ( nHierarchy >= pHiers->getCount() ) 1083 nHierarchy = 0; 1084 ScDPHierarchy* pHier = pHiers->getByIndex(nHierarchy); 1085 ScDPLevels* pLevels = pHier->GetLevelsObject(); 1086 long nLevCount = pLevels->getCount(); 1087 for (long nLev=0; nLev<nLevCount; nLev++) 1088 { 1089 ScDPLevel* pLevel = pLevels->getByIndex(nLev); 1090 rList.Insert( pLevel, LIST_APPEND ); 1091 } 1092 } 1093 } 1094 1095 void ScDPSource::FillMemberResults() 1096 { 1097 if ( !pColResults && !pRowResults ) 1098 { 1099 CreateRes_Impl(); 1100 1101 if ( bResultOverflow ) // set in CreateRes_Impl 1102 { 1103 // no results available -> abort (leave empty) 1104 // exception is thrown in ScDPSource::getResults 1105 return; 1106 } 1107 1108 FillLevelList( sheet::DataPilotFieldOrientation_COLUMN, aColLevelList ); 1109 long nColLevelCount = aColLevelList.Count(); 1110 if (nColLevelCount) 1111 { 1112 long nColDimSize = pColResRoot->GetSize(pResData->GetColStartMeasure()); 1113 pColResults = new uno::Sequence<sheet::MemberResult>[nColLevelCount]; 1114 for (long i=0; i<nColLevelCount; i++) 1115 pColResults[i].realloc(nColDimSize); 1116 1117 // ScDPResultDimension* pColResDim = pColResRoot->GetChildDimension(); 1118 // pColResDim->FillMemberResults( pColResults, 0, pResData->GetColStartMeasure() ); 1119 long nPos = 0; 1120 pColResRoot->FillMemberResults( pColResults, nPos, pResData->GetColStartMeasure(), 1121 sal_True, NULL, NULL ); 1122 } 1123 1124 FillLevelList( sheet::DataPilotFieldOrientation_ROW, aRowLevelList ); 1125 long nRowLevelCount = aRowLevelList.Count(); 1126 if (nRowLevelCount) 1127 { 1128 long nRowDimSize = pRowResRoot->GetSize(pResData->GetRowStartMeasure()); 1129 pRowResults = new uno::Sequence<sheet::MemberResult>[nRowLevelCount]; 1130 for (long i=0; i<nRowLevelCount; i++) 1131 pRowResults[i].realloc(nRowDimSize); 1132 1133 // ScDPResultDimension* pRowResDim = pRowResRoot->GetChildDimension(); 1134 // pRowResDim->FillMemberResults( pRowResults, 0, pResData->GetRowStartMeasure() ); 1135 long nPos = 0; 1136 pRowResRoot->FillMemberResults( pRowResults, nPos, pResData->GetRowStartMeasure(), 1137 sal_True, NULL, NULL ); 1138 } 1139 } 1140 } 1141 1142 const uno::Sequence<sheet::MemberResult>* ScDPSource::GetMemberResults( ScDPLevel* pLevel ) 1143 { 1144 FillMemberResults(); 1145 1146 long i; 1147 long nColCount = aColLevelList.Count(); 1148 for (i=0; i<nColCount; i++) 1149 { 1150 ScDPLevel* pColLevel = (ScDPLevel*)aColLevelList.GetObject(i); 1151 if ( pColLevel == pLevel ) 1152 return pColResults+i; 1153 } 1154 long nRowCount = aRowLevelList.Count(); 1155 for (i=0; i<nRowCount; i++) 1156 { 1157 ScDPLevel* pRowLevel = (ScDPLevel*)aRowLevelList.GetObject(i); 1158 if ( pRowLevel == pLevel ) 1159 return pRowResults+i; 1160 } 1161 return NULL; 1162 } 1163 1164 // XPropertySet 1165 1166 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPSource::getPropertySetInfo() 1167 throw(uno::RuntimeException) 1168 { 1169 ScUnoGuard aGuard; 1170 using beans::PropertyAttribute::READONLY; 1171 1172 static SfxItemPropertyMapEntry aDPSourceMap_Impl[] = 1173 { 1174 {MAP_CHAR_LEN(SC_UNO_COLGRAND), 0, &getBooleanCppuType(), 0, 0 }, 1175 {MAP_CHAR_LEN(SC_UNO_DATADESC), 0, &getCppuType((rtl::OUString*)0), beans::PropertyAttribute::READONLY, 0 }, 1176 {MAP_CHAR_LEN(SC_UNO_IGNOREEM), 0, &getBooleanCppuType(), 0, 0 }, // for sheet data only 1177 {MAP_CHAR_LEN(SC_UNO_REPEATIF), 0, &getBooleanCppuType(), 0, 0 }, // for sheet data only 1178 {MAP_CHAR_LEN(SC_UNO_ROWGRAND), 0, &getBooleanCppuType(), 0, 0 }, 1179 {MAP_CHAR_LEN(SC_UNO_ROWFIELDCOUNT), 0, &getCppuType(static_cast<sal_Int32*>(0)), READONLY, 0 }, 1180 {MAP_CHAR_LEN(SC_UNO_COLUMNFIELDCOUNT), 0, &getCppuType(static_cast<sal_Int32*>(0)), READONLY, 0 }, 1181 {MAP_CHAR_LEN(SC_UNO_DATAFIELDCOUNT), 0, &getCppuType(static_cast<sal_Int32*>(0)), READONLY, 0 }, 1182 {MAP_CHAR_LEN(SC_UNO_GRANDTOTAL_NAME), 0, &getCppuType(static_cast<OUString*>(0)), 0, 0 }, 1183 {0,0,0,0,0,0} 1184 }; 1185 static uno::Reference<beans::XPropertySetInfo> aRef = 1186 new SfxItemPropertySetInfo( aDPSourceMap_Impl ); 1187 return aRef; 1188 } 1189 1190 void SAL_CALL ScDPSource::setPropertyValue( const rtl::OUString& aPropertyName, const uno::Any& aValue ) 1191 throw(beans::UnknownPropertyException, beans::PropertyVetoException, 1192 lang::IllegalArgumentException, lang::WrappedTargetException, 1193 uno::RuntimeException) 1194 { 1195 String aNameStr = aPropertyName; 1196 if ( aNameStr.EqualsAscii( SC_UNO_COLGRAND ) ) 1197 setColumnGrand( lcl_GetBoolFromAny( aValue ) ); 1198 else if ( aNameStr.EqualsAscii( SC_UNO_ROWGRAND ) ) 1199 setRowGrand( lcl_GetBoolFromAny( aValue ) ); 1200 else if ( aNameStr.EqualsAscii( SC_UNO_IGNOREEM ) ) 1201 setIgnoreEmptyRows( lcl_GetBoolFromAny( aValue ) ); 1202 else if ( aNameStr.EqualsAscii( SC_UNO_REPEATIF ) ) 1203 setRepeatIfEmpty( lcl_GetBoolFromAny( aValue ) ); 1204 else if (aNameStr.EqualsAscii(SC_UNO_GRANDTOTAL_NAME)) 1205 { 1206 OUString aName; 1207 if (aValue >>= aName) 1208 mpGrandTotalName.reset(new OUString(aName)); 1209 } 1210 else 1211 { 1212 DBG_ERROR("unknown property"); 1213 //! THROW( UnknownPropertyException() ); 1214 } 1215 } 1216 1217 uno::Any SAL_CALL ScDPSource::getPropertyValue( const rtl::OUString& aPropertyName ) 1218 throw(beans::UnknownPropertyException, lang::WrappedTargetException, 1219 uno::RuntimeException) 1220 { 1221 uno::Any aRet; 1222 String aNameStr = aPropertyName; 1223 if ( aNameStr.EqualsAscii( SC_UNO_COLGRAND ) ) 1224 lcl_SetBoolInAny( aRet, getColumnGrand() ); 1225 else if ( aNameStr.EqualsAscii( SC_UNO_ROWGRAND ) ) 1226 lcl_SetBoolInAny( aRet, getRowGrand() ); 1227 else if ( aNameStr.EqualsAscii( SC_UNO_IGNOREEM ) ) 1228 lcl_SetBoolInAny( aRet, getIgnoreEmptyRows() ); 1229 else if ( aNameStr.EqualsAscii( SC_UNO_REPEATIF ) ) 1230 lcl_SetBoolInAny( aRet, getRepeatIfEmpty() ); 1231 else if ( aNameStr.EqualsAscii( SC_UNO_DATADESC ) ) // read-only 1232 aRet <<= rtl::OUString( getDataDescription() ); 1233 else if ( aNameStr.EqualsAscii( SC_UNO_ROWFIELDCOUNT ) ) // read-only 1234 aRet <<= static_cast<sal_Int32>(nRowDimCount); 1235 else if ( aNameStr.EqualsAscii( SC_UNO_COLUMNFIELDCOUNT ) ) // read-only 1236 aRet <<= static_cast<sal_Int32>(nColDimCount); 1237 else if ( aNameStr.EqualsAscii( SC_UNO_DATAFIELDCOUNT ) ) // read-only 1238 aRet <<= static_cast<sal_Int32>(nDataDimCount); 1239 else if (aNameStr.EqualsAscii(SC_UNO_GRANDTOTAL_NAME)) 1240 { 1241 if (mpGrandTotalName.get()) 1242 aRet <<= *mpGrandTotalName; 1243 } 1244 else 1245 { 1246 DBG_ERROR("unknown property"); 1247 //! THROW( UnknownPropertyException() ); 1248 } 1249 return aRet; 1250 } 1251 1252 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPSource ) 1253 1254 // ----------------------------------------------------------------------- 1255 1256 ScDPDimensions::ScDPDimensions( ScDPSource* pSrc ) : 1257 pSource( pSrc ), 1258 ppDims( NULL ) 1259 { 1260 //! hold pSource 1261 1262 // include data layout dimension and duplicated dimensions 1263 nDimCount = pSource->GetData()->GetColumnCount() + 1 + pSource->GetDupCount(); 1264 } 1265 1266 ScDPDimensions::~ScDPDimensions() 1267 { 1268 //! release pSource 1269 1270 if (ppDims) 1271 { 1272 for (long i=0; i<nDimCount; i++) 1273 if ( ppDims[i] ) 1274 ppDims[i]->release(); // ref-counted 1275 delete[] ppDims; 1276 } 1277 } 1278 1279 void ScDPDimensions::CountChanged() 1280 { 1281 // include data layout dimension and duplicated dimensions 1282 long nNewCount = pSource->GetData()->GetColumnCount() + 1 + pSource->GetDupCount(); 1283 if ( ppDims ) 1284 { 1285 long i; 1286 long nCopy = Min( nNewCount, nDimCount ); 1287 ScDPDimension** ppNew = new ScDPDimension*[nNewCount]; 1288 1289 for (i=0; i<nCopy; i++) // copy existing dims 1290 ppNew[i] = ppDims[i]; 1291 for (i=nCopy; i<nNewCount; i++) // clear additional pointers 1292 ppNew[i] = NULL; 1293 for (i=nCopy; i<nDimCount; i++) // delete old dims if count is decreased 1294 if ( ppDims[i] ) 1295 ppDims[i]->release(); // ref-counted 1296 1297 delete[] ppDims; 1298 ppDims = ppNew; 1299 } 1300 nDimCount = nNewCount; 1301 } 1302 1303 // very simple XNameAccess implementation using getCount/getByIndex 1304 1305 uno::Any SAL_CALL ScDPDimensions::getByName( const rtl::OUString& aName ) 1306 throw(container::NoSuchElementException, 1307 lang::WrappedTargetException, uno::RuntimeException) 1308 { 1309 long nCount = getCount(); 1310 for (long i=0; i<nCount; i++) 1311 if ( getByIndex(i)->getName() == aName ) 1312 { 1313 uno::Reference<container::XNamed> xNamed = getByIndex(i); 1314 uno::Any aRet; 1315 aRet <<= xNamed; 1316 return aRet; 1317 } 1318 1319 throw container::NoSuchElementException(); 1320 // return uno::Any(); 1321 } 1322 1323 uno::Sequence<rtl::OUString> SAL_CALL ScDPDimensions::getElementNames() throw(uno::RuntimeException) 1324 { 1325 long nCount = getCount(); 1326 uno::Sequence<rtl::OUString> aSeq(nCount); 1327 rtl::OUString* pArr = aSeq.getArray(); 1328 for (long i=0; i<nCount; i++) 1329 pArr[i] = getByIndex(i)->getName(); 1330 return aSeq; 1331 } 1332 1333 sal_Bool SAL_CALL ScDPDimensions::hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException) 1334 { 1335 long nCount = getCount(); 1336 for (long i=0; i<nCount; i++) 1337 if ( getByIndex(i)->getName() == aName ) 1338 return sal_True; 1339 return sal_False; 1340 } 1341 1342 uno::Type SAL_CALL ScDPDimensions::getElementType() throw(uno::RuntimeException) 1343 { 1344 return getCppuType((uno::Reference<container::XNamed>*)0); 1345 } 1346 1347 sal_Bool SAL_CALL ScDPDimensions::hasElements() throw(uno::RuntimeException) 1348 { 1349 return ( getCount() > 0 ); 1350 } 1351 1352 // end of XNameAccess implementation 1353 1354 long ScDPDimensions::getCount() const 1355 { 1356 // in tabular data, every column of source data is a dimension 1357 1358 return nDimCount; 1359 } 1360 1361 ScDPDimension* ScDPDimensions::getByIndex(long nIndex) const 1362 { 1363 if ( nIndex >= 0 && nIndex < nDimCount ) 1364 { 1365 if ( !ppDims ) 1366 { 1367 ((ScDPDimensions*)this)->ppDims = new ScDPDimension*[nDimCount]; 1368 for (long i=0; i<nDimCount; i++) 1369 ppDims[i] = NULL; 1370 } 1371 if ( !ppDims[nIndex] ) 1372 { 1373 ppDims[nIndex] = new ScDPDimension( pSource, nIndex ); 1374 ppDims[nIndex]->acquire(); // ref-counted 1375 } 1376 1377 return ppDims[nIndex]; 1378 } 1379 1380 return NULL; //! exception? 1381 } 1382 1383 // ----------------------------------------------------------------------- 1384 1385 ScDPDimension::ScDPDimension( ScDPSource* pSrc, long nD ) : 1386 pSource( pSrc ), 1387 nDim( nD ), 1388 pHierarchies( NULL ), 1389 nUsedHier( 0 ), 1390 nFunction( SUBTOTAL_FUNC_SUM ), // sum is default 1391 mpLayoutName(NULL), 1392 mpSubtotalName(NULL), 1393 nSourceDim( -1 ), 1394 bHasSelectedPage( sal_False ), 1395 pSelectedData( NULL ), 1396 mbHasHiddenMember(false) 1397 { 1398 //! hold pSource 1399 } 1400 1401 ScDPDimension::~ScDPDimension() 1402 { 1403 //! release pSource 1404 1405 if ( pHierarchies ) 1406 pHierarchies->release(); // ref-counted 1407 1408 delete pSelectedData; 1409 } 1410 1411 ScDPHierarchies* ScDPDimension::GetHierarchiesObject() 1412 { 1413 if (!pHierarchies) 1414 { 1415 pHierarchies = new ScDPHierarchies( pSource, nDim ); 1416 pHierarchies->acquire(); // ref-counted 1417 } 1418 return pHierarchies; 1419 } 1420 1421 const rtl::OUString* ScDPDimension::GetLayoutName() const 1422 { 1423 return mpLayoutName.get(); 1424 } 1425 1426 const rtl::OUString* ScDPDimension::GetSubtotalName() const 1427 { 1428 return mpSubtotalName.get(); 1429 } 1430 1431 uno::Reference<container::XNameAccess> SAL_CALL ScDPDimension::getHierarchies() 1432 throw(uno::RuntimeException) 1433 { 1434 return GetHierarchiesObject(); 1435 } 1436 1437 ::rtl::OUString SAL_CALL ScDPDimension::getName() throw(uno::RuntimeException) 1438 { 1439 if (aName.Len()) 1440 return aName; 1441 else 1442 return pSource->GetData()->getDimensionName( nDim ); 1443 } 1444 1445 void SAL_CALL ScDPDimension::setName( const ::rtl::OUString& rNewName ) throw(uno::RuntimeException) 1446 { 1447 // used after cloning 1448 aName = String( rNewName ); 1449 } 1450 1451 sal_uInt16 ScDPDimension::getOrientation() const 1452 { 1453 return pSource->GetOrientation( nDim ); 1454 } 1455 1456 void ScDPDimension::setOrientation(sal_uInt16 nNew) 1457 { 1458 pSource->SetOrientation( nDim, nNew ); 1459 } 1460 1461 long ScDPDimension::getPosition() const 1462 { 1463 return pSource->GetPosition( nDim ); 1464 } 1465 1466 void ScDPDimension::setPosition(long /* nNew */) 1467 { 1468 //! ... 1469 } 1470 1471 sal_Bool ScDPDimension::getIsDataLayoutDimension() const 1472 { 1473 return pSource->GetData()->getIsDataLayoutDimension( nDim ); 1474 } 1475 1476 sal_uInt16 ScDPDimension::getFunction() const 1477 { 1478 return nFunction; 1479 } 1480 1481 void ScDPDimension::setFunction(sal_uInt16 nNew) 1482 { 1483 nFunction = nNew; 1484 } 1485 1486 long ScDPDimension::getUsedHierarchy() const 1487 { 1488 return nUsedHier; 1489 } 1490 1491 void ScDPDimension::setUsedHierarchy(long /* nNew */) 1492 { 1493 // #i52547# don't use the incomplete date hierarchy implementation - ignore the call 1494 // nUsedHier = nNew; 1495 } 1496 1497 ScDPDimension* ScDPDimension::CreateCloneObject() 1498 { 1499 DBG_ASSERT( nSourceDim < 0, "recursive duplicate - not implemented" ); 1500 1501 //! set new name here, or temporary name ??? 1502 String aNewName = aName; 1503 1504 ScDPDimension* pNew = pSource->AddDuplicated( nDim, aNewName ); 1505 1506 pNew->aName = aNewName; //! here or in source? 1507 pNew->nSourceDim = nDim; //! recursive? 1508 1509 return pNew; 1510 } 1511 1512 uno::Reference<util::XCloneable> SAL_CALL ScDPDimension::createClone() throw(uno::RuntimeException) 1513 { 1514 return CreateCloneObject(); 1515 } 1516 1517 sal_Bool ScDPDimension::isDuplicated() const 1518 { 1519 return (nSourceDim >= 0); 1520 } 1521 1522 const sheet::DataPilotFieldReference& ScDPDimension::GetReferenceValue() const 1523 { 1524 return aReferenceValue; 1525 } 1526 1527 const ScDPItemData& ScDPDimension::GetSelectedData() 1528 { 1529 if ( !pSelectedData ) 1530 { 1531 // find the named member to initialize pSelectedData from it, with name and value 1532 1533 long nLevel = 0; // same as in ScDPObject::FillPageList 1534 1535 long nHierarchy = getUsedHierarchy(); 1536 if ( nHierarchy >= GetHierarchiesObject()->getCount() ) 1537 nHierarchy = 0; 1538 ScDPLevels* pLevels = GetHierarchiesObject()->getByIndex(nHierarchy)->GetLevelsObject(); 1539 long nLevCount = pLevels->getCount(); 1540 if ( nLevel < nLevCount ) 1541 { 1542 ScDPMembers* pMembers = pLevels->getByIndex(nLevel)->GetMembersObject(); 1543 1544 //! merge with ScDPMembers::getByName 1545 long nCount = pMembers->getCount(); 1546 for (long i=0; i<nCount && !pSelectedData; i++) 1547 { 1548 ScDPMember* pMember = pMembers->getByIndex(i); 1549 if ( pMember->GetNameStr() == aSelectedPage ) 1550 { 1551 pSelectedData = new ScDPItemData(); 1552 pMember->FillItemData( *pSelectedData ); 1553 } 1554 } 1555 } 1556 1557 if ( !pSelectedData ) 1558 pSelectedData = new ScDPItemData( aSelectedPage, 0.0, sal_False ); // default - name only 1559 } 1560 1561 return *pSelectedData; 1562 } 1563 1564 //UNUSED2009-05 sal_Bool ScDPDimension::IsValidPage( const ScDPItemData& rData ) 1565 //UNUSED2009-05 { 1566 //UNUSED2009-05 if ( bHasSelectedPage ) 1567 //UNUSED2009-05 return rData.IsCaseInsEqual( GetSelectedData() ); 1568 //UNUSED2009-05 1569 //UNUSED2009-05 return sal_True; // no selection -> all data 1570 //UNUSED2009-05 } 1571 1572 sal_Bool ScDPDimension::IsVisible( const ScDPItemData& rData ) 1573 { 1574 if( ScDPMembers* pMembers = this->GetHierarchiesObject()->getByIndex(0)-> 1575 GetLevelsObject()->getByIndex(0)->GetMembersObject() ) 1576 { 1577 for( long i = pMembers->getCount()-1; i>=0; i-- ) 1578 if( ScDPMember *pDPMbr = pMembers->getByIndex( i ) ) 1579 if( rData.IsCaseInsEqual( pDPMbr->GetItemData() ) && !pDPMbr->getIsVisible() ) 1580 return sal_False; 1581 } 1582 1583 return sal_True; 1584 } 1585 // XPropertySet 1586 1587 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPDimension::getPropertySetInfo() 1588 throw(uno::RuntimeException) 1589 { 1590 ScUnoGuard aGuard; 1591 1592 static SfxItemPropertyMapEntry aDPDimensionMap_Impl[] = 1593 { 1594 {MAP_CHAR_LEN(SC_UNO_FILTER), 0, &getCppuType((uno::Sequence<sheet::TableFilterField>*)0), 0, 0 }, 1595 {MAP_CHAR_LEN(SC_UNO_FLAGS), 0, &getCppuType((sal_Int32*)0), beans::PropertyAttribute::READONLY, 0 }, 1596 {MAP_CHAR_LEN(SC_UNO_FUNCTION), 0, &getCppuType((sheet::GeneralFunction*)0), 0, 0 }, 1597 {MAP_CHAR_LEN(SC_UNO_ISDATALA), 0, &getBooleanCppuType(), beans::PropertyAttribute::READONLY, 0 }, 1598 {MAP_CHAR_LEN(SC_UNO_NUMBERFO), 0, &getCppuType((sal_Int32*)0), beans::PropertyAttribute::READONLY, 0 }, 1599 {MAP_CHAR_LEN(SC_UNO_ORIENTAT), 0, &getCppuType((sheet::DataPilotFieldOrientation*)0), 0, 0 }, 1600 {MAP_CHAR_LEN(SC_UNO_ORIGINAL), 0, &getCppuType((uno::Reference<container::XNamed>*)0), beans::PropertyAttribute::READONLY, 0 }, 1601 {MAP_CHAR_LEN(SC_UNO_POSITION), 0, &getCppuType((sal_Int32*)0), 0, 0 }, 1602 {MAP_CHAR_LEN(SC_UNO_REFVALUE), 0, &getCppuType((sheet::DataPilotFieldReference*)0), 0, 0 }, 1603 {MAP_CHAR_LEN(SC_UNO_USEDHIER), 0, &getCppuType((sal_Int32*)0), 0, 0 }, 1604 {MAP_CHAR_LEN(SC_UNO_LAYOUTNAME), 0, &getCppuType(static_cast<rtl::OUString*>(0)), 0, 0 }, 1605 {MAP_CHAR_LEN(SC_UNO_FIELD_SUBTOTALNAME), 0, &getCppuType(static_cast<rtl::OUString*>(0)), 0, 0 }, 1606 {MAP_CHAR_LEN(SC_UNO_HAS_HIDDEN_MEMBER), 0, &getBooleanCppuType(), 0, 0 }, 1607 {0,0,0,0,0,0} 1608 }; 1609 static uno::Reference<beans::XPropertySetInfo> aRef = 1610 new SfxItemPropertySetInfo( aDPDimensionMap_Impl ); 1611 return aRef; 1612 } 1613 1614 void SAL_CALL ScDPDimension::setPropertyValue( const rtl::OUString& aPropertyName, const uno::Any& aValue ) 1615 throw(beans::UnknownPropertyException, beans::PropertyVetoException, 1616 lang::IllegalArgumentException, lang::WrappedTargetException, 1617 uno::RuntimeException) 1618 { 1619 String aNameStr = aPropertyName; 1620 if ( aNameStr.EqualsAscii( SC_UNO_POSITION ) ) 1621 { 1622 sal_Int32 nInt = 0; 1623 if (aValue >>= nInt) 1624 setPosition( nInt ); 1625 } 1626 else if ( aNameStr.EqualsAscii( SC_UNO_USEDHIER ) ) 1627 { 1628 sal_Int32 nInt = 0; 1629 if (aValue >>= nInt) 1630 setUsedHierarchy( nInt ); 1631 } 1632 else if ( aNameStr.EqualsAscii( SC_UNO_ORIENTAT ) ) 1633 { 1634 sheet::DataPilotFieldOrientation eEnum; 1635 if (aValue >>= eEnum) 1636 setOrientation( sal::static_int_cast<sal_uInt16>(eEnum) ); 1637 } 1638 else if ( aNameStr.EqualsAscii( SC_UNO_FUNCTION ) ) 1639 { 1640 sheet::GeneralFunction eEnum; 1641 if (aValue >>= eEnum) 1642 setFunction( sal::static_int_cast<sal_uInt16>(eEnum) ); 1643 } 1644 else if ( aNameStr.EqualsAscii( SC_UNO_REFVALUE ) ) 1645 aValue >>= aReferenceValue; 1646 else if ( aNameStr.EqualsAscii( SC_UNO_FILTER ) ) 1647 { 1648 sal_Bool bDone = sal_False; 1649 uno::Sequence<sheet::TableFilterField> aSeq; 1650 if (aValue >>= aSeq) 1651 { 1652 sal_Int32 nLength = aSeq.getLength(); 1653 if ( nLength == 0 ) 1654 { 1655 aSelectedPage.Erase(); 1656 bHasSelectedPage = sal_False; 1657 bDone = sal_True; 1658 } 1659 else if ( nLength == 1 ) 1660 { 1661 const sheet::TableFilterField& rField = aSeq[0]; 1662 if ( rField.Field == 0 && rField.Operator == sheet::FilterOperator_EQUAL && !rField.IsNumeric ) 1663 { 1664 aSelectedPage = rField.StringValue; 1665 bHasSelectedPage = sal_True; 1666 bDone = sal_True; 1667 } 1668 } 1669 } 1670 if ( !bDone ) 1671 { 1672 DBG_ERROR("Filter property is not a single string"); 1673 throw lang::IllegalArgumentException(); 1674 } 1675 DELETEZ( pSelectedData ); // invalid after changing aSelectedPage 1676 } 1677 else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME)) 1678 { 1679 OUString aTmpName; 1680 if (aValue >>= aTmpName) 1681 mpLayoutName.reset(new OUString(aTmpName)); 1682 } 1683 else if (aNameStr.EqualsAscii(SC_UNO_FIELD_SUBTOTALNAME)) 1684 { 1685 OUString aTmpName; 1686 if (aValue >>= aTmpName) 1687 mpSubtotalName.reset(new OUString(aTmpName)); 1688 } 1689 else if (aNameStr.EqualsAscii(SC_UNO_HAS_HIDDEN_MEMBER)) 1690 aValue >>= mbHasHiddenMember; 1691 else 1692 { 1693 DBG_ERROR("unknown property"); 1694 //! THROW( UnknownPropertyException() ); 1695 } 1696 } 1697 1698 uno::Any SAL_CALL ScDPDimension::getPropertyValue( const rtl::OUString& aPropertyName ) 1699 throw(beans::UnknownPropertyException, lang::WrappedTargetException, 1700 uno::RuntimeException) 1701 { 1702 uno::Any aRet; 1703 String aNameStr = aPropertyName; 1704 if ( aNameStr.EqualsAscii( SC_UNO_POSITION ) ) 1705 aRet <<= (sal_Int32) getPosition(); 1706 else if ( aNameStr.EqualsAscii( SC_UNO_USEDHIER ) ) 1707 aRet <<= (sal_Int32) getUsedHierarchy(); 1708 else if ( aNameStr.EqualsAscii( SC_UNO_ORIENTAT ) ) 1709 { 1710 sheet::DataPilotFieldOrientation eVal = (sheet::DataPilotFieldOrientation)getOrientation(); 1711 aRet <<= eVal; 1712 } 1713 else if ( aNameStr.EqualsAscii( SC_UNO_FUNCTION ) ) 1714 { 1715 sheet::GeneralFunction eVal = (sheet::GeneralFunction)getFunction(); 1716 aRet <<= eVal; 1717 } 1718 else if ( aNameStr.EqualsAscii( SC_UNO_REFVALUE ) ) 1719 aRet <<= aReferenceValue; 1720 else if ( aNameStr.EqualsAscii( SC_UNO_ISDATALA ) ) // read-only properties 1721 lcl_SetBoolInAny( aRet, getIsDataLayoutDimension() ); 1722 else if ( aNameStr.EqualsAscii( SC_UNO_NUMBERFO ) ) 1723 { 1724 sal_Int32 nFormat = 0; 1725 sheet::GeneralFunction eFunc = (sheet::GeneralFunction)getFunction(); 1726 // #i63745# don't use source format for "count" 1727 if ( eFunc != sheet::GeneralFunction_COUNT && eFunc != sheet::GeneralFunction_COUNTNUMS ) 1728 nFormat = pSource->GetData()->GetNumberFormat( ( nSourceDim >= 0 ) ? nSourceDim : nDim ); 1729 1730 switch ( aReferenceValue.ReferenceType ) 1731 { 1732 case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE: 1733 case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE: 1734 case sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE: 1735 case sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE: 1736 case sheet::DataPilotFieldReferenceType::TOTAL_PERCENTAGE: 1737 nFormat = pSource->GetData()->GetNumberFormatByIdx( (NfIndexTableOffset)NF_PERCENT_DEC2 ); 1738 break; 1739 case sheet::DataPilotFieldReferenceType::INDEX: 1740 nFormat = pSource->GetData()->GetNumberFormatByIdx( (NfIndexTableOffset)NF_NUMBER_SYSTEM ); 1741 break; 1742 default: 1743 break; 1744 } 1745 1746 aRet <<= nFormat; 1747 } 1748 else if ( aNameStr.EqualsAscii( SC_UNO_ORIGINAL ) ) 1749 { 1750 uno::Reference<container::XNamed> xOriginal; 1751 if (nSourceDim >= 0) 1752 xOriginal = pSource->GetDimensionsObject()->getByIndex(nSourceDim); 1753 aRet <<= xOriginal; 1754 } 1755 else if ( aNameStr.EqualsAscii( SC_UNO_FILTER ) ) 1756 { 1757 if ( bHasSelectedPage ) 1758 { 1759 // single filter field: first field equal to selected string 1760 sheet::TableFilterField aField( sheet::FilterConnection_AND, 0, 1761 sheet::FilterOperator_EQUAL, sal_False, 0.0, aSelectedPage ); 1762 aRet <<= uno::Sequence<sheet::TableFilterField>( &aField, 1 ); 1763 } 1764 else 1765 aRet <<= uno::Sequence<sheet::TableFilterField>(0); 1766 } 1767 else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME)) 1768 aRet <<= mpLayoutName.get() ? *mpLayoutName : OUString::createFromAscii(""); 1769 else if (aNameStr.EqualsAscii(SC_UNO_FIELD_SUBTOTALNAME)) 1770 aRet <<= mpSubtotalName.get() ? *mpSubtotalName : OUString::createFromAscii(""); 1771 else if (aNameStr.EqualsAscii(SC_UNO_HAS_HIDDEN_MEMBER)) 1772 aRet <<= mbHasHiddenMember; 1773 else if (aNameStr.EqualsAscii(SC_UNO_FLAGS)) 1774 { 1775 sal_Int32 nFlags = 0; // tabular data: all orientations are possible 1776 aRet <<= nFlags; 1777 } 1778 else 1779 { 1780 DBG_ERROR("unknown property"); 1781 //! THROW( UnknownPropertyException() ); 1782 } 1783 return aRet; 1784 } 1785 1786 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPDimension ) 1787 1788 // ----------------------------------------------------------------------- 1789 1790 ScDPHierarchies::ScDPHierarchies( ScDPSource* pSrc, long nD ) : 1791 pSource( pSrc ), 1792 nDim( nD ), 1793 ppHiers( NULL ) 1794 { 1795 //! hold pSource 1796 1797 #if 0 1798 // date columns have 3 hierarchies (flat/quarter/week), other columns only one 1799 long nSrcDim = pSource->GetSourceDim( nDim ); 1800 if ( pSource->IsDateDimension( nSrcDim ) ) 1801 nHierCount = SC_DAPI_DATE_HIERARCHIES; 1802 else 1803 nHierCount = 1; 1804 #endif 1805 1806 // #i52547# don't offer the incomplete date hierarchy implementation 1807 nHierCount = 1; 1808 } 1809 1810 ScDPHierarchies::~ScDPHierarchies() 1811 { 1812 //! release pSource 1813 1814 if (ppHiers) 1815 { 1816 for (long i=0; i<nHierCount; i++) 1817 if ( ppHiers[i] ) 1818 ppHiers[i]->release(); // ref-counted 1819 delete[] ppHiers; 1820 } 1821 } 1822 1823 // very simple XNameAccess implementation using getCount/getByIndex 1824 1825 uno::Any SAL_CALL ScDPHierarchies::getByName( const rtl::OUString& aName ) 1826 throw(container::NoSuchElementException, 1827 lang::WrappedTargetException, uno::RuntimeException) 1828 { 1829 long nCount = getCount(); 1830 for (long i=0; i<nCount; i++) 1831 if ( getByIndex(i)->getName() == aName ) 1832 { 1833 uno::Reference<container::XNamed> xNamed = getByIndex(i); 1834 uno::Any aRet; 1835 aRet <<= xNamed; 1836 return aRet; 1837 } 1838 1839 throw container::NoSuchElementException(); 1840 // return uno::Any(); 1841 } 1842 1843 uno::Sequence<rtl::OUString> SAL_CALL ScDPHierarchies::getElementNames() throw(uno::RuntimeException) 1844 { 1845 long nCount = getCount(); 1846 uno::Sequence<rtl::OUString> aSeq(nCount); 1847 rtl::OUString* pArr = aSeq.getArray(); 1848 for (long i=0; i<nCount; i++) 1849 pArr[i] = getByIndex(i)->getName(); 1850 return aSeq; 1851 } 1852 1853 sal_Bool SAL_CALL ScDPHierarchies::hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException) 1854 { 1855 long nCount = getCount(); 1856 for (long i=0; i<nCount; i++) 1857 if ( getByIndex(i)->getName() == aName ) 1858 return sal_True; 1859 return sal_False; 1860 } 1861 1862 uno::Type SAL_CALL ScDPHierarchies::getElementType() throw(uno::RuntimeException) 1863 { 1864 return getCppuType((uno::Reference<container::XNamed>*)0); 1865 } 1866 1867 sal_Bool SAL_CALL ScDPHierarchies::hasElements() throw(uno::RuntimeException) 1868 { 1869 return ( getCount() > 0 ); 1870 } 1871 1872 // end of XNameAccess implementation 1873 1874 long ScDPHierarchies::getCount() const 1875 { 1876 return nHierCount; 1877 } 1878 1879 ScDPHierarchy* ScDPHierarchies::getByIndex(long nIndex) const 1880 { 1881 // pass hierarchy index to new object in case the implementation 1882 // will be extended to more than one hierarchy 1883 1884 if ( nIndex >= 0 && nIndex < nHierCount ) 1885 { 1886 if ( !ppHiers ) 1887 { 1888 ((ScDPHierarchies*)this)->ppHiers = new ScDPHierarchy*[nHierCount]; 1889 for (long i=0; i<nHierCount; i++) 1890 ppHiers[i] = NULL; 1891 } 1892 if ( !ppHiers[nIndex] ) 1893 { 1894 ppHiers[nIndex] = new ScDPHierarchy( pSource, nDim, nIndex ); 1895 ppHiers[nIndex]->acquire(); // ref-counted 1896 } 1897 1898 return ppHiers[nIndex]; 1899 } 1900 1901 return NULL; //! exception? 1902 } 1903 1904 // ----------------------------------------------------------------------- 1905 1906 ScDPHierarchy::ScDPHierarchy( ScDPSource* pSrc, long nD, long nH ) : 1907 pSource( pSrc ), 1908 nDim( nD ), 1909 nHier( nH ), 1910 pLevels( NULL ) 1911 { 1912 //! hold pSource 1913 } 1914 1915 ScDPHierarchy::~ScDPHierarchy() 1916 { 1917 //! release pSource 1918 1919 if (pLevels) 1920 pLevels->release(); // ref-counted 1921 } 1922 1923 ScDPLevels* ScDPHierarchy::GetLevelsObject() 1924 { 1925 if (!pLevels) 1926 { 1927 pLevels = new ScDPLevels( pSource, nDim, nHier ); 1928 pLevels->acquire(); // ref-counted 1929 } 1930 return pLevels; 1931 } 1932 1933 uno::Reference<container::XNameAccess> SAL_CALL ScDPHierarchy::getLevels() 1934 throw(uno::RuntimeException) 1935 { 1936 return GetLevelsObject(); 1937 } 1938 1939 ::rtl::OUString SAL_CALL ScDPHierarchy::getName() throw(uno::RuntimeException) 1940 { 1941 String aRet; //! globstr-ID !!!! 1942 switch (nHier) 1943 { 1944 case SC_DAPI_HIERARCHY_FLAT: 1945 aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("flat")); 1946 break; //! name ??????? 1947 case SC_DAPI_HIERARCHY_QUARTER: 1948 aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Quarter")); 1949 break; //! name ??????? 1950 case SC_DAPI_HIERARCHY_WEEK: 1951 aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Week")); 1952 break; //! name ??????? 1953 default: 1954 DBG_ERROR( "ScDPHierarchy::getName: unexpected hierarchy" ); 1955 break; 1956 } 1957 return aRet; 1958 } 1959 1960 void SAL_CALL ScDPHierarchy::setName( const ::rtl::OUString& /* rNewName */ ) throw(uno::RuntimeException) 1961 { 1962 DBG_ERROR("not implemented"); //! exception? 1963 } 1964 1965 // ----------------------------------------------------------------------- 1966 1967 ScDPLevels::ScDPLevels( ScDPSource* pSrc, long nD, long nH ) : 1968 pSource( pSrc ), 1969 nDim( nD ), 1970 nHier( nH ), 1971 ppLevs( NULL ) 1972 { 1973 //! hold pSource 1974 1975 // text columns have only one level 1976 1977 long nSrcDim = pSource->GetSourceDim( nDim ); 1978 if ( pSource->IsDateDimension( nSrcDim ) ) 1979 { 1980 switch ( nHier ) 1981 { 1982 case SC_DAPI_HIERARCHY_FLAT: nLevCount = SC_DAPI_FLAT_LEVELS; break; 1983 case SC_DAPI_HIERARCHY_QUARTER: nLevCount = SC_DAPI_QUARTER_LEVELS; break; 1984 case SC_DAPI_HIERARCHY_WEEK: nLevCount = SC_DAPI_WEEK_LEVELS; break; 1985 default: 1986 DBG_ERROR("wrong hierarchy"); 1987 nLevCount = 0; 1988 } 1989 } 1990 else 1991 nLevCount = 1; 1992 } 1993 1994 ScDPLevels::~ScDPLevels() 1995 { 1996 //! release pSource 1997 1998 if (ppLevs) 1999 { 2000 for (long i=0; i<nLevCount; i++) 2001 if ( ppLevs[i] ) 2002 ppLevs[i]->release(); // ref-counted 2003 delete[] ppLevs; 2004 } 2005 } 2006 2007 // very simple XNameAccess implementation using getCount/getByIndex 2008 2009 uno::Any SAL_CALL ScDPLevels::getByName( const rtl::OUString& aName ) 2010 throw(container::NoSuchElementException, 2011 lang::WrappedTargetException, uno::RuntimeException) 2012 { 2013 long nCount = getCount(); 2014 for (long i=0; i<nCount; i++) 2015 if ( getByIndex(i)->getName() == aName ) 2016 { 2017 uno::Reference<container::XNamed> xNamed = getByIndex(i); 2018 uno::Any aRet; 2019 aRet <<= xNamed; 2020 return aRet; 2021 } 2022 2023 throw container::NoSuchElementException(); 2024 // return uno::Any(); 2025 } 2026 2027 uno::Sequence<rtl::OUString> SAL_CALL ScDPLevels::getElementNames() throw(uno::RuntimeException) 2028 { 2029 long nCount = getCount(); 2030 uno::Sequence<rtl::OUString> aSeq(nCount); 2031 rtl::OUString* pArr = aSeq.getArray(); 2032 for (long i=0; i<nCount; i++) 2033 pArr[i] = getByIndex(i)->getName(); 2034 return aSeq; 2035 } 2036 2037 sal_Bool SAL_CALL ScDPLevels::hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException) 2038 { 2039 long nCount = getCount(); 2040 for (long i=0; i<nCount; i++) 2041 if ( getByIndex(i)->getName() == aName ) 2042 return sal_True; 2043 return sal_False; 2044 } 2045 2046 uno::Type SAL_CALL ScDPLevels::getElementType() throw(uno::RuntimeException) 2047 { 2048 return getCppuType((uno::Reference<container::XNamed>*)0); 2049 } 2050 2051 sal_Bool SAL_CALL ScDPLevels::hasElements() throw(uno::RuntimeException) 2052 { 2053 return ( getCount() > 0 ); 2054 } 2055 2056 // end of XNameAccess implementation 2057 2058 long ScDPLevels::getCount() const 2059 { 2060 return nLevCount; 2061 } 2062 2063 ScDPLevel* ScDPLevels::getByIndex(long nIndex) const 2064 { 2065 if ( nIndex >= 0 && nIndex < nLevCount ) 2066 { 2067 if ( !ppLevs ) 2068 { 2069 ((ScDPLevels*)this)->ppLevs = new ScDPLevel*[nLevCount]; 2070 for (long i=0; i<nLevCount; i++) 2071 ppLevs[i] = NULL; 2072 } 2073 if ( !ppLevs[nIndex] ) 2074 { 2075 ppLevs[nIndex] = new ScDPLevel( pSource, nDim, nHier, nIndex ); 2076 ppLevs[nIndex]->acquire(); // ref-counted 2077 } 2078 2079 return ppLevs[nIndex]; 2080 } 2081 2082 return NULL; //! exception? 2083 } 2084 2085 // ----------------------------------------------------------------------- 2086 2087 class ScDPGlobalMembersOrder 2088 { 2089 ScDPLevel& rLevel; 2090 sal_Bool bAscending; 2091 2092 public: 2093 ScDPGlobalMembersOrder( ScDPLevel& rLev, sal_Bool bAsc ) : 2094 rLevel(rLev), 2095 bAscending(bAsc) 2096 {} 2097 ~ScDPGlobalMembersOrder() {} 2098 2099 sal_Bool operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const; 2100 }; 2101 2102 sal_Bool ScDPGlobalMembersOrder::operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const 2103 { 2104 sal_Int32 nCompare = 0; 2105 // seems that some ::std::sort() implementations pass the same index twice 2106 if( nIndex1 != nIndex2 ) 2107 { 2108 ScDPMembers* pMembers = rLevel.GetMembersObject(); 2109 ScDPMember* pMember1 = pMembers->getByIndex(nIndex1); 2110 ScDPMember* pMember2 = pMembers->getByIndex(nIndex2); 2111 nCompare = pMember1->Compare( *pMember2 ); 2112 } 2113 return bAscending ? (nCompare < 0) : (nCompare > 0); 2114 } 2115 2116 // ----------------------------------------------------------------------- 2117 2118 ScDPLevel::ScDPLevel( ScDPSource* pSrc, long nD, long nH, long nL ) : 2119 pSource( pSrc ), 2120 nDim( nD ), 2121 nHier( nH ), 2122 nLev( nL ), 2123 pMembers( NULL ), 2124 bShowEmpty( sal_False ), 2125 aSortInfo( EMPTY_STRING, sal_True, sheet::DataPilotFieldSortMode::NAME ), // default: sort by name 2126 nSortMeasure( 0 ), 2127 nAutoMeasure( 0 ), 2128 bEnableLayout( sal_False ) 2129 { 2130 //! hold pSource 2131 // aSubTotals is empty 2132 } 2133 2134 ScDPLevel::~ScDPLevel() 2135 { 2136 //! release pSource 2137 2138 if ( pMembers ) 2139 pMembers->release(); // ref-counted 2140 } 2141 2142 void ScDPLevel::EvaluateSortOrder() 2143 { 2144 switch (aSortInfo.Mode) 2145 { 2146 case sheet::DataPilotFieldSortMode::DATA: 2147 { 2148 // find index of measure (index among data dimensions) 2149 2150 String aDataFieldName = aSortInfo.Field; 2151 long nMeasureCount = pSource->GetDataDimensionCount(); 2152 for (long nMeasure=0; nMeasure<nMeasureCount; nMeasure++) 2153 { 2154 if ( pSource->GetDataDimName(nMeasure) == aDataFieldName ) 2155 { 2156 nSortMeasure = nMeasure; 2157 break; 2158 } 2159 } 2160 2161 //! error if not found? 2162 } 2163 break; 2164 case sheet::DataPilotFieldSortMode::MANUAL: 2165 case sheet::DataPilotFieldSortMode::NAME: 2166 { 2167 ScDPMembers* pLocalMembers = GetMembersObject(); 2168 long nCount = pLocalMembers->getCount(); 2169 2170 // DBG_ASSERT( aGlobalOrder.empty(), "sort twice?" ); 2171 aGlobalOrder.resize( nCount ); 2172 for (long nPos=0; nPos<nCount; nPos++) 2173 aGlobalOrder[nPos] = nPos; 2174 2175 // allow manual or name (manual is always ascending) 2176 sal_Bool bAscending = ( aSortInfo.Mode == sheet::DataPilotFieldSortMode::MANUAL || aSortInfo.IsAscending ); 2177 ScDPGlobalMembersOrder aComp( *this, bAscending ); 2178 ::std::sort( aGlobalOrder.begin(), aGlobalOrder.end(), aComp ); 2179 } 2180 break; 2181 } 2182 2183 if ( aAutoShowInfo.IsEnabled ) 2184 { 2185 // find index of measure (index among data dimensions) 2186 2187 String aDataFieldName = aAutoShowInfo.DataField; 2188 long nMeasureCount = pSource->GetDataDimensionCount(); 2189 for (long nMeasure=0; nMeasure<nMeasureCount; nMeasure++) 2190 { 2191 if ( pSource->GetDataDimName(nMeasure) == aDataFieldName ) 2192 { 2193 nAutoMeasure = nMeasure; 2194 break; 2195 } 2196 } 2197 2198 //! error if not found? 2199 } 2200 } 2201 2202 void ScDPLevel::SetEnableLayout( sal_Bool bSet ) 2203 { 2204 bEnableLayout = bSet; 2205 } 2206 2207 ScDPMembers* ScDPLevel::GetMembersObject() 2208 { 2209 if (!pMembers) 2210 { 2211 pMembers = new ScDPMembers( pSource, nDim, nHier, nLev ); 2212 pMembers->acquire(); // ref-counted 2213 } 2214 return pMembers; 2215 } 2216 2217 uno::Reference<container::XNameAccess> SAL_CALL ScDPLevel::getMembers() throw(uno::RuntimeException) 2218 { 2219 return GetMembersObject(); 2220 } 2221 2222 uno::Sequence<sheet::MemberResult> SAL_CALL ScDPLevel::getResults() throw(uno::RuntimeException) 2223 { 2224 const uno::Sequence<sheet::MemberResult>* pRes = pSource->GetMemberResults( this ); 2225 if (pRes) 2226 return *pRes; 2227 2228 return uno::Sequence<sheet::MemberResult>(0); //! Error? 2229 } 2230 2231 ::rtl::OUString SAL_CALL ScDPLevel::getName() throw(uno::RuntimeException) 2232 { 2233 long nSrcDim = pSource->GetSourceDim( nDim ); 2234 if ( pSource->IsDateDimension( nSrcDim ) ) 2235 { 2236 String aRet; //! globstr-ID !!!! 2237 2238 if ( nHier == SC_DAPI_HIERARCHY_QUARTER ) 2239 { 2240 switch ( nLev ) 2241 { 2242 case SC_DAPI_LEVEL_YEAR: 2243 aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Year")); 2244 break; 2245 case SC_DAPI_LEVEL_QUARTER: 2246 aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Quarter")); 2247 break; 2248 case SC_DAPI_LEVEL_MONTH: 2249 aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Month")); 2250 break; 2251 case SC_DAPI_LEVEL_DAY: 2252 aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Day")); 2253 break; 2254 default: 2255 DBG_ERROR( "ScDPLevel::getName: unexpected level" ); 2256 break; 2257 } 2258 } 2259 else if ( nHier == SC_DAPI_HIERARCHY_WEEK ) 2260 { 2261 switch ( nLev ) 2262 { 2263 case SC_DAPI_LEVEL_YEAR: 2264 aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Year")); 2265 break; 2266 case SC_DAPI_LEVEL_WEEK: 2267 aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Week")); 2268 break; 2269 case SC_DAPI_LEVEL_WEEKDAY: 2270 aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Weekday")); 2271 break; 2272 default: 2273 DBG_ERROR( "ScDPLevel::getName: unexpected level" ); 2274 break; 2275 } 2276 } 2277 if (aRet.Len()) 2278 return aRet; 2279 } 2280 2281 ScDPDimension* pDim = pSource->GetDimensionsObject()->getByIndex(nSrcDim); 2282 if (!pDim) 2283 return rtl::OUString(); 2284 2285 return pDim->getName(); 2286 } 2287 2288 void SAL_CALL ScDPLevel::setName( const ::rtl::OUString& /* rNewName */ ) throw(uno::RuntimeException) 2289 { 2290 DBG_ERROR("not implemented"); //! exception? 2291 } 2292 2293 uno::Sequence<sheet::GeneralFunction> ScDPLevel::getSubTotals() const 2294 { 2295 //! separate functions for settings and evaluation? 2296 2297 long nSrcDim = pSource->GetSourceDim( nDim ); 2298 if ( !pSource->SubTotalAllowed( nSrcDim ) ) 2299 return uno::Sequence<sheet::GeneralFunction>(0); 2300 2301 return aSubTotals; 2302 } 2303 2304 void ScDPLevel::setSubTotals(const uno::Sequence<sheet::GeneralFunction>& rNew) 2305 { 2306 aSubTotals = rNew; 2307 //! set "manual change" flag? 2308 } 2309 2310 sal_Bool ScDPLevel::getShowEmpty() const 2311 { 2312 return bShowEmpty; 2313 } 2314 2315 void ScDPLevel::setShowEmpty(sal_Bool bSet) 2316 { 2317 bShowEmpty = bSet; 2318 } 2319 2320 // XPropertySet 2321 2322 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPLevel::getPropertySetInfo() 2323 throw(uno::RuntimeException) 2324 { 2325 ScUnoGuard aGuard; 2326 2327 static SfxItemPropertyMapEntry aDPLevelMap_Impl[] = 2328 { 2329 //! change type of AutoShow/Layout/Sorting to API struct when available 2330 {MAP_CHAR_LEN(SC_UNO_AUTOSHOW), 0, &getCppuType((sheet::DataPilotFieldAutoShowInfo*)0), 0, 0 }, 2331 {MAP_CHAR_LEN(SC_UNO_LAYOUT), 0, &getCppuType((sheet::DataPilotFieldLayoutInfo*)0), 0, 0 }, 2332 {MAP_CHAR_LEN(SC_UNO_SHOWEMPT), 0, &getBooleanCppuType(), 0, 0 }, 2333 {MAP_CHAR_LEN(SC_UNO_SORTING), 0, &getCppuType((sheet::DataPilotFieldSortInfo*)0), 0, 0 }, 2334 {MAP_CHAR_LEN(SC_UNO_SUBTOTAL), 0, &getCppuType((uno::Sequence<sheet::GeneralFunction>*)0), 0, 0 }, 2335 {0,0,0,0,0,0} 2336 }; 2337 static uno::Reference<beans::XPropertySetInfo> aRef = 2338 new SfxItemPropertySetInfo( aDPLevelMap_Impl ); 2339 return aRef; 2340 } 2341 2342 void SAL_CALL ScDPLevel::setPropertyValue( const rtl::OUString& aPropertyName, const uno::Any& aValue ) 2343 throw(beans::UnknownPropertyException, beans::PropertyVetoException, 2344 lang::IllegalArgumentException, lang::WrappedTargetException, 2345 uno::RuntimeException) 2346 { 2347 String aNameStr = aPropertyName; 2348 if ( aNameStr.EqualsAscii( SC_UNO_SHOWEMPT ) ) 2349 setShowEmpty( lcl_GetBoolFromAny( aValue ) ); 2350 else if ( aNameStr.EqualsAscii( SC_UNO_SUBTOTAL ) ) 2351 { 2352 uno::Sequence<sheet::GeneralFunction> aSeq; 2353 if ( aValue >>= aSeq ) 2354 setSubTotals( aSeq ); 2355 } 2356 else if ( aNameStr.EqualsAscii( SC_UNO_SORTING ) ) 2357 aValue >>= aSortInfo; 2358 else if ( aNameStr.EqualsAscii( SC_UNO_AUTOSHOW ) ) 2359 aValue >>= aAutoShowInfo; 2360 else if ( aNameStr.EqualsAscii( SC_UNO_LAYOUT ) ) 2361 aValue >>= aLayoutInfo; 2362 else 2363 { 2364 DBG_ERROR("unknown property"); 2365 //! THROW( UnknownPropertyException() ); 2366 } 2367 } 2368 2369 uno::Any SAL_CALL ScDPLevel::getPropertyValue( const rtl::OUString& aPropertyName ) 2370 throw(beans::UnknownPropertyException, lang::WrappedTargetException, 2371 uno::RuntimeException) 2372 { 2373 uno::Any aRet; 2374 String aNameStr = aPropertyName; 2375 if ( aNameStr.EqualsAscii( SC_UNO_SHOWEMPT ) ) 2376 lcl_SetBoolInAny( aRet, getShowEmpty() ); 2377 else if ( aNameStr.EqualsAscii( SC_UNO_SUBTOTAL ) ) 2378 { 2379 uno::Sequence<sheet::GeneralFunction> aSeq = getSubTotals(); //! avoid extra copy? 2380 aRet <<= aSeq; 2381 } 2382 else if ( aNameStr.EqualsAscii( SC_UNO_SORTING ) ) 2383 aRet <<= aSortInfo; 2384 else if ( aNameStr.EqualsAscii( SC_UNO_AUTOSHOW ) ) 2385 aRet <<= aAutoShowInfo; 2386 else if ( aNameStr.EqualsAscii( SC_UNO_LAYOUT ) ) 2387 aRet <<= aLayoutInfo; 2388 else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME)) 2389 { 2390 // read only property 2391 long nSrcDim = pSource->GetSourceDim(nDim); 2392 ScDPDimension* pDim = pSource->GetDimensionsObject()->getByIndex(nSrcDim); 2393 if (!pDim) 2394 return aRet; 2395 2396 const OUString* pLayoutName = pDim->GetLayoutName(); 2397 if (!pLayoutName) 2398 return aRet; 2399 2400 aRet <<= *pLayoutName; 2401 } 2402 else 2403 { 2404 DBG_ERROR("unknown property"); 2405 //! THROW( UnknownPropertyException() ); 2406 } 2407 return aRet; 2408 } 2409 2410 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPLevel ) 2411 2412 // ----------------------------------------------------------------------- 2413 2414 ScDPMembers::ScDPMembers( ScDPSource* pSrc, long nD, long nH, long nL ) : 2415 pSource( pSrc ), 2416 nDim( nD ), 2417 nHier( nH ), 2418 nLev( nL ), 2419 ppMbrs( NULL ) 2420 { 2421 //! hold pSource 2422 2423 long nSrcDim = pSource->GetSourceDim( nDim ); 2424 if ( pSource->IsDataLayoutDimension(nSrcDim) ) 2425 nMbrCount = pSource->GetDataDimensionCount(); 2426 else if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) ) 2427 { 2428 nMbrCount = 0; 2429 if ( nHier == SC_DAPI_HIERARCHY_QUARTER ) 2430 { 2431 switch (nLev) 2432 { 2433 case SC_DAPI_LEVEL_YEAR: 2434 { 2435 // Wang Xu Ming - DataPilot migration 2436 const ScDPItemData* pLastNumData = NULL; 2437 for ( SCROW n = 0 ;n <GetSrcItemsCount() ; n-- ) 2438 { 2439 const ScDPItemData* pData = GetSrcItemDataByIndex( n ); 2440 if ( pData && pData->HasStringData() ) 2441 break; 2442 else 2443 pLastNumData = pData; 2444 } 2445 // End Comments 2446 2447 if ( pLastNumData ) 2448 { 2449 const ScDPItemData* pFirstData = GetSrcItemDataByIndex( 0 ); 2450 double fFirstVal = pFirstData->GetValue(); 2451 double fLastVal = pLastNumData->GetValue(); 2452 2453 long nFirstYear = pSource->GetData()->GetDatePart( 2454 (long)::rtl::math::approxFloor( fFirstVal ), 2455 nHier, nLev ); 2456 long nLastYear = pSource->GetData()->GetDatePart( 2457 (long)::rtl::math::approxFloor( fLastVal ), 2458 nHier, nLev ); 2459 2460 nMbrCount = nLastYear + 1 - nFirstYear; 2461 } 2462 else 2463 nMbrCount = 0; // no values 2464 } 2465 break; 2466 case SC_DAPI_LEVEL_QUARTER: nMbrCount = 4; break; 2467 case SC_DAPI_LEVEL_MONTH: nMbrCount = 12; break; 2468 case SC_DAPI_LEVEL_DAY: nMbrCount = 31; break; 2469 default: 2470 DBG_ERROR( "ScDPMembers::ScDPMembers: unexpected level" ); 2471 break; 2472 } 2473 } 2474 else if ( nHier == SC_DAPI_HIERARCHY_WEEK ) 2475 { 2476 switch (nLev) 2477 { 2478 case SC_DAPI_LEVEL_YEAR: nMbrCount = 1; break; //! get years from source 2479 case SC_DAPI_LEVEL_WEEK: nMbrCount = 53; break; 2480 case SC_DAPI_LEVEL_WEEKDAY: nMbrCount = 7; break; 2481 default: 2482 DBG_ERROR( "ScDPMembers::ScDPMembers: unexpected level" ); 2483 break; 2484 } 2485 } 2486 } 2487 else 2488 nMbrCount = pSource->GetData()->GetMembersCount( nSrcDim ); 2489 } 2490 2491 ScDPMembers::~ScDPMembers() 2492 { 2493 //! release pSource 2494 2495 if (ppMbrs) 2496 { 2497 for (long i=0; i<nMbrCount; i++) 2498 if ( ppMbrs[i] ) 2499 ppMbrs[i]->release(); // ref-counted 2500 delete[] ppMbrs; 2501 } 2502 } 2503 2504 // XNameAccess implementation using getCount/getByIndex 2505 2506 sal_Int32 ScDPMembers::GetIndexFromName( const ::rtl::OUString& rName ) const 2507 { 2508 if ( aHashMap.empty() ) 2509 { 2510 // store the index for each name 2511 2512 sal_Int32 nCount = getCount(); 2513 for (sal_Int32 i=0; i<nCount; i++) 2514 aHashMap[ getByIndex(i)->getName() ] = i; 2515 } 2516 2517 ScDPMembersHashMap::const_iterator aIter = aHashMap.find( rName ); 2518 if ( aIter != aHashMap.end() ) 2519 return aIter->second; // found index 2520 else 2521 return -1; // not found 2522 } 2523 2524 uno::Any SAL_CALL ScDPMembers::getByName( const rtl::OUString& aName ) 2525 throw(container::NoSuchElementException, 2526 lang::WrappedTargetException, uno::RuntimeException) 2527 { 2528 sal_Int32 nIndex = GetIndexFromName( aName ); 2529 if ( nIndex >= 0 ) 2530 { 2531 uno::Reference<container::XNamed> xNamed = getByIndex(nIndex); 2532 uno::Any aRet; 2533 aRet <<= xNamed; 2534 return aRet; 2535 } 2536 2537 throw container::NoSuchElementException(); 2538 // return uno::Any(); 2539 } 2540 2541 uno::Sequence<rtl::OUString> SAL_CALL ScDPMembers::getElementNames() throw(uno::RuntimeException) 2542 { 2543 // Return list of names in sorted order, 2544 // so it's displayed in that order in the field options dialog. 2545 // Sorting is done at the level object (parent of this). 2546 2547 ScDPLevel* pLevel = pSource->GetDimensionsObject()->getByIndex(nDim)-> 2548 GetHierarchiesObject()->getByIndex(nHier)->GetLevelsObject()->getByIndex(nLev); 2549 pLevel->EvaluateSortOrder(); 2550 const std::vector<sal_Int32>& rGlobalOrder = pLevel->GetGlobalOrder(); 2551 bool bSort = !rGlobalOrder.empty(); 2552 2553 long nCount = getCount(); 2554 uno::Sequence<rtl::OUString> aSeq(nCount); 2555 rtl::OUString* pArr = aSeq.getArray(); 2556 for (long i=0; i<nCount; i++) 2557 pArr[i] = getByIndex(bSort ? rGlobalOrder[i] : i)->getName(); 2558 return aSeq; 2559 } 2560 2561 sal_Bool SAL_CALL ScDPMembers::hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException) 2562 { 2563 return ( GetIndexFromName( aName ) >= 0 ); 2564 } 2565 2566 uno::Type SAL_CALL ScDPMembers::getElementType() throw(uno::RuntimeException) 2567 { 2568 return getCppuType((uno::Reference<container::XNamed>*)0); 2569 } 2570 2571 sal_Bool SAL_CALL ScDPMembers::hasElements() throw(uno::RuntimeException) 2572 { 2573 return ( getCount() > 0 ); 2574 } 2575 2576 // end of XNameAccess implementation 2577 2578 long ScDPMembers::getCount() const 2579 { 2580 return nMbrCount; 2581 } 2582 2583 long ScDPMembers::getMinMembers() const 2584 { 2585 // used in lcl_CountMinMembers 2586 2587 long nVisCount = 0; 2588 if ( ppMbrs ) 2589 { 2590 for (long i=0; i<nMbrCount; i++) 2591 { 2592 // count only visible with details (default is true for both) 2593 const ScDPMember* pMbr = ppMbrs[i]; 2594 if ( !pMbr || ( pMbr->getIsVisible() && pMbr->getShowDetails() ) ) 2595 ++nVisCount; 2596 } 2597 } 2598 else 2599 nVisCount = nMbrCount; // default for all 2600 2601 return nVisCount; 2602 } 2603 2604 ScDPMember* ScDPMembers::getByIndex(long nIndex) const 2605 { 2606 // result of GetColumnEntries must not change between ScDPMembers ctor 2607 // and all calls to getByIndex 2608 2609 if ( nIndex >= 0 && nIndex < nMbrCount ) 2610 { 2611 if ( !ppMbrs ) 2612 { 2613 ((ScDPMembers*)this)->ppMbrs = new ScDPMember*[nMbrCount]; 2614 for (long i=0; i<nMbrCount; i++) 2615 ppMbrs[i] = NULL; 2616 } 2617 if ( !ppMbrs[nIndex] ) 2618 { 2619 ScDPMember* pNew; 2620 long nSrcDim = pSource->GetSourceDim( nDim ); 2621 if ( pSource->IsDataLayoutDimension(nSrcDim) ) 2622 { 2623 // empty name (never shown, not used for lookup) 2624 pNew = new ScDPMember( pSource, nDim, nHier, nLev, 0 ); 2625 } 2626 else if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) ) 2627 { 2628 long nVal = 0; 2629 String aName; 2630 2631 if ( nLev == SC_DAPI_LEVEL_YEAR ) // YEAR is in both hierarchies 2632 { 2633 //! cache year range here! 2634 2635 // Wang Xu Ming - DataPilot migration 2636 double fFirstVal = pSource->GetData()->GetMemberByIndex( nSrcDim, 0 )->GetValue(); 2637 long nFirstYear = pSource->GetData()->GetDatePart( 2638 (long)::rtl::math::approxFloor( fFirstVal ), 2639 nHier, nLev ); 2640 2641 // End Comments 2642 nVal = nFirstYear + nIndex; 2643 } 2644 else if ( nHier == SC_DAPI_HIERARCHY_WEEK && nLev == SC_DAPI_LEVEL_WEEKDAY ) 2645 { 2646 nVal = nIndex; // DayOfWeek is 0-based 2647 aName = ScGlobal::GetCalendar()->getDisplayName( 2648 ::com::sun::star::i18n::CalendarDisplayIndex::DAY, 2649 sal::static_int_cast<sal_Int16>(nVal), 0 ); 2650 } 2651 else if ( nHier == SC_DAPI_HIERARCHY_QUARTER && nLev == SC_DAPI_LEVEL_MONTH ) 2652 { 2653 nVal = nIndex; // Month is 0-based 2654 aName = ScGlobal::GetCalendar()->getDisplayName( 2655 ::com::sun::star::i18n::CalendarDisplayIndex::MONTH, 2656 sal::static_int_cast<sal_Int16>(nVal), 0 ); 2657 } 2658 else 2659 nVal = nIndex + 1; // Quarter, Day, Week are 1-based 2660 2661 if ( !aName.Len() ) 2662 aName = String::CreateFromInt32(nVal); 2663 2664 ScDPItemData rData( aName, nVal, sal_True, 0 ) ; 2665 pNew = new ScDPMember( pSource, nDim, nHier, nLev, pSource->GetCache()->GetAdditionalItemID(rData)); 2666 } 2667 else 2668 { 2669 const std::vector< SCROW >& memberIndexs = pSource->GetData()->GetColumnEntries( nSrcDim ); 2670 pNew = new ScDPMember( pSource, nDim, nHier, nLev, memberIndexs[nIndex] ); 2671 } 2672 pNew->acquire(); // ref-counted 2673 ppMbrs[nIndex] = pNew; 2674 } 2675 2676 DBG_ASSERT( ppMbrs[nIndex] ," member is not initialized " ); 2677 2678 return ppMbrs[nIndex]; 2679 } 2680 2681 return NULL; //! exception? 2682 } 2683 2684 // ----------------------------------------------------------------------- 2685 2686 ScDPMember::ScDPMember( ScDPSource* pSrc, long nD, long nH, long nL, 2687 SCROW nIndex /*const String& rN, double fV, sal_Bool bHV*/ ) : 2688 pSource( pSrc ), 2689 nDim( nD ), 2690 nHier( nH ), 2691 nLev( nL ), 2692 mnDataId( nIndex ), 2693 mpLayoutName(NULL), 2694 nPosition( -1 ), 2695 bVisible( sal_True ), 2696 bShowDet( sal_True ) 2697 { 2698 //! hold pSource 2699 } 2700 2701 ScDPMember::~ScDPMember() 2702 { 2703 //! release pSource 2704 } 2705 2706 sal_Bool ScDPMember::IsNamedItem( const ScDPItemData& r ) const 2707 { 2708 long nSrcDim = pSource->GetSourceDim( nDim ); 2709 if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) && r.IsValue() ) 2710 { 2711 long nComp = pSource->GetData()->GetDatePart( 2712 (long)::rtl::math::approxFloor( r.GetValue() ), 2713 nHier, nLev ); 2714 2715 // fValue is converted from integer, so simple comparison works 2716 return nComp == GetItemData().GetValue(); 2717 } 2718 2719 return r.IsCaseInsEqual( GetItemData() ); 2720 } 2721 2722 sal_Bool ScDPMember::IsNamedItem( SCROW nIndex ) const 2723 { 2724 long nSrcDim = pSource->GetSourceDim( nDim ); 2725 if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) ) 2726 { 2727 const ScDPItemData* pData = pSource->GetCache()->GetItemDataById( (SCCOL) nSrcDim, nIndex ); 2728 if ( pData->IsValue() ) 2729 { 2730 long nComp = pSource->GetData()->GetDatePart( 2731 (long)::rtl::math::approxFloor( pData->GetValue() ), 2732 nHier, nLev ); 2733 // fValue is converted from integer, so simple comparison works 2734 return nComp == GetItemData().GetValue(); 2735 } 2736 } 2737 2738 return nIndex == mnDataId; 2739 } 2740 2741 sal_Int32 ScDPMember::Compare( const ScDPMember& rOther ) const 2742 { 2743 if ( nPosition >= 0 ) 2744 { 2745 if ( rOther.nPosition >= 0 ) 2746 { 2747 DBG_ASSERT( nPosition != rOther.nPosition, "same position for two members" ); 2748 return ( nPosition < rOther.nPosition ) ? -1 : 1; 2749 } 2750 else 2751 { 2752 // only this has a position - members with specified positions come before those without 2753 return -1; 2754 } 2755 } 2756 else if ( rOther.nPosition >= 0 ) 2757 { 2758 // only rOther has a position 2759 return 1; 2760 } 2761 2762 // no positions set - compare names 2763 return pSource->GetData()->Compare( pSource->GetSourceDim(nDim),mnDataId,rOther.GetItemDataId()); 2764 } 2765 2766 void ScDPMember::FillItemData( ScDPItemData& rData ) const 2767 { 2768 //! handle date hierarchy... 2769 2770 rData = GetItemData() ; 2771 } 2772 2773 const OUString* ScDPMember::GetLayoutName() const 2774 { 2775 return mpLayoutName.get(); 2776 } 2777 2778 String ScDPMember::GetNameStr() const 2779 { 2780 return GetItemData().GetString(); 2781 } 2782 2783 ::rtl::OUString SAL_CALL ScDPMember::getName() throw(uno::RuntimeException) 2784 { 2785 return GetItemData().GetString(); 2786 } 2787 2788 void SAL_CALL ScDPMember::setName( const ::rtl::OUString& /* rNewName */ ) throw(uno::RuntimeException) 2789 { 2790 DBG_ERROR("not implemented"); //! exception? 2791 } 2792 2793 sal_Bool ScDPMember::getIsVisible() const 2794 { 2795 return bVisible; 2796 } 2797 2798 void ScDPMember::setIsVisible(sal_Bool bSet) 2799 { 2800 bVisible = bSet; 2801 //! set "manual change" flag 2802 } 2803 2804 sal_Bool ScDPMember::getShowDetails() const 2805 { 2806 return bShowDet; 2807 } 2808 2809 void ScDPMember::setShowDetails(sal_Bool bSet) 2810 { 2811 bShowDet = bSet; 2812 //! set "manual change" flag 2813 } 2814 2815 sal_Int32 ScDPMember::getPosition() const 2816 { 2817 return nPosition; 2818 } 2819 2820 void ScDPMember::setPosition(sal_Int32 nNew) 2821 { 2822 nPosition = nNew; 2823 } 2824 2825 // XPropertySet 2826 2827 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPMember::getPropertySetInfo() 2828 throw(uno::RuntimeException) 2829 { 2830 ScUnoGuard aGuard; 2831 2832 static SfxItemPropertyMapEntry aDPMemberMap_Impl[] = 2833 { 2834 {MAP_CHAR_LEN(SC_UNO_ISVISIBL), 0, &getBooleanCppuType(), 0, 0 }, 2835 {MAP_CHAR_LEN(SC_UNO_POSITION), 0, &getCppuType((sal_Int32*)0), 0, 0 }, 2836 {MAP_CHAR_LEN(SC_UNO_SHOWDETA), 0, &getBooleanCppuType(), 0, 0 }, 2837 {MAP_CHAR_LEN(SC_UNO_LAYOUTNAME), 0, &getCppuType(static_cast<rtl::OUString*>(0)), 0, 0 }, 2838 {0,0,0,0,0,0} 2839 }; 2840 static uno::Reference<beans::XPropertySetInfo> aRef = 2841 new SfxItemPropertySetInfo( aDPMemberMap_Impl ); 2842 return aRef; 2843 } 2844 2845 void SAL_CALL ScDPMember::setPropertyValue( const rtl::OUString& aPropertyName, const uno::Any& aValue ) 2846 throw(beans::UnknownPropertyException, beans::PropertyVetoException, 2847 lang::IllegalArgumentException, lang::WrappedTargetException, 2848 uno::RuntimeException) 2849 { 2850 String aNameStr = aPropertyName; 2851 if ( aNameStr.EqualsAscii( SC_UNO_ISVISIBL ) ) 2852 setIsVisible( lcl_GetBoolFromAny( aValue ) ); 2853 else if ( aNameStr.EqualsAscii( SC_UNO_SHOWDETA ) ) 2854 setShowDetails( lcl_GetBoolFromAny( aValue ) ); 2855 else if ( aNameStr.EqualsAscii( SC_UNO_POSITION ) ) 2856 { 2857 sal_Int32 nInt = 0; 2858 if (aValue >>= nInt) 2859 setPosition( nInt ); 2860 } 2861 else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME)) 2862 { 2863 rtl::OUString aName; 2864 if (aValue >>= aName) 2865 mpLayoutName.reset(new rtl::OUString(aName)); 2866 } 2867 else 2868 { 2869 DBG_ERROR("unknown property"); 2870 //! THROW( UnknownPropertyException() ); 2871 } 2872 } 2873 2874 uno::Any SAL_CALL ScDPMember::getPropertyValue( const rtl::OUString& aPropertyName ) 2875 throw(beans::UnknownPropertyException, lang::WrappedTargetException, 2876 uno::RuntimeException) 2877 { 2878 uno::Any aRet; 2879 String aNameStr = aPropertyName; 2880 if ( aNameStr.EqualsAscii( SC_UNO_ISVISIBL ) ) 2881 lcl_SetBoolInAny( aRet, getIsVisible() ); 2882 else if ( aNameStr.EqualsAscii( SC_UNO_SHOWDETA ) ) 2883 lcl_SetBoolInAny( aRet, getShowDetails() ); 2884 else if ( aNameStr.EqualsAscii( SC_UNO_POSITION ) ) 2885 aRet <<= (sal_Int32) getPosition(); 2886 else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME)) 2887 aRet <<= mpLayoutName.get() ? *mpLayoutName : rtl::OUString(); 2888 else 2889 { 2890 DBG_ERROR("unknown property"); 2891 //! THROW( UnknownPropertyException() ); 2892 } 2893 return aRet; 2894 } 2895 2896 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPMember ) 2897 2898 2899 ScDPTableDataCache* ScDPSource::GetCache() 2900 { 2901 DBG_ASSERT( GetData() , "empty ScDPTableData pointer"); 2902 return ( GetData()!=NULL) ? GetData()->GetCacheTable().GetCache() : NULL ; 2903 } 2904 2905 const ScDPItemData& ScDPMember::GetItemData() const 2906 { 2907 return *pSource->GetItemDataById( (SCCOL)nDim, mnDataId );//ms-cache-core 2908 } 2909 2910 const ScDPItemData* ScDPSource::GetItemDataById(long nDim, long nId) 2911 { 2912 long nSrcDim = GetSourceDim( nDim ); 2913 const ScDPItemData* pItemData = GetData()->GetMemberById( nSrcDim, nId ); 2914 if ( !pItemData ) 2915 { //todo: 2916 ScDPItemData item; 2917 nId = GetCache()->GetAdditionalItemID( item ); 2918 pItemData = GetData()->GetMemberById( nSrcDim, nId ); 2919 } 2920 return pItemData; 2921 } 2922 2923 SCROW ScDPSource::GetMemberId( long nDim, const ScDPItemData& rData ) 2924 { 2925 long nSrcDim = GetSourceDim( nDim ); 2926 return GetCache()->GetIdByItemData( nSrcDim, rData ); 2927 } 2928 2929 const ScDPItemData* ScDPMembers::GetSrcItemDataByIndex( SCROW nIndex) 2930 { 2931 const std::vector< SCROW >& memberIds = pSource->GetData()->GetColumnEntries( nDim ); 2932 if ( nIndex >= (long )(memberIds.size()) || nIndex < 0 ) 2933 return NULL; 2934 SCROW nId = memberIds[ nIndex ]; 2935 return pSource->GetItemDataById( nDim, nId ); 2936 } 2937 2938 SCROW ScDPMembers::GetSrcItemsCount() 2939 { 2940 return pSource->GetData()->GetColumnEntries( nDim ).size(); 2941 } 2942 // End Comments 2943 2944