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