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