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 #include "dpdimsave.hxx" 28 #include "dpgroup.hxx" 29 #include "dpobject.hxx" 30 #include "document.hxx" 31 32 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp> 33 34 #include <svl/zforlist.hxx> 35 #include <tools/debug.hxx> 36 #include <rtl/math.hxx> 37 #include <algorithm> 38 39 // ============================================================================ 40 41 ScDPSaveGroupItem::ScDPSaveGroupItem( const String& rName ) : 42 aGroupName( rName ) 43 { 44 } 45 46 ScDPSaveGroupItem::~ScDPSaveGroupItem() 47 { 48 } 49 50 void ScDPSaveGroupItem::AddElement( const String& rName ) 51 { 52 aElements.push_back( rName ); 53 } 54 55 void ScDPSaveGroupItem::AddElementsFromGroup( const ScDPSaveGroupItem& rGroup ) 56 { 57 // add all elements of the other group (used for nested grouping) 58 59 for ( std::vector<String>::const_iterator aIter(rGroup.aElements.begin()); 60 aIter != rGroup.aElements.end(); aIter++ ) 61 aElements.push_back( *aIter ); 62 } 63 64 bool ScDPSaveGroupItem::RemoveElement( const String& rName ) 65 { 66 for ( std::vector<String>::iterator aIter(aElements.begin()); aIter != aElements.end(); aIter++ ) 67 if ( *aIter == rName ) //! ignore case 68 { 69 aElements.erase( aIter ); // found -> remove 70 return true; // don't have to look further 71 } 72 73 return false; // not found 74 } 75 76 bool ScDPSaveGroupItem::IsEmpty() const 77 { 78 return aElements.empty(); 79 } 80 81 size_t ScDPSaveGroupItem::GetElementCount() const 82 { 83 return aElements.size(); 84 } 85 86 const String* ScDPSaveGroupItem::GetElementByIndex( size_t nIndex ) const 87 { 88 return (nIndex < aElements.size()) ? &aElements[ nIndex ] : 0; 89 } 90 91 void ScDPSaveGroupItem::Rename( const String& rNewName ) 92 { 93 aGroupName = rNewName; 94 } 95 96 void ScDPSaveGroupItem::RemoveElementsFromGroups( ScDPSaveGroupDimension& rDimension ) const 97 { 98 // remove this group's elements from their groups in rDimension 99 // (rDimension must be a different dimension from the one which contains this) 100 101 for ( std::vector<String>::const_iterator aIter(aElements.begin()); aIter != aElements.end(); aIter++ ) 102 rDimension.RemoveFromGroups( *aIter ); 103 } 104 105 void ScDPSaveGroupItem::AddToData( ScDPGroupDimension& rDataDim, SvNumberFormatter* pFormatter ) const 106 { 107 ScDPGroupItem aGroup( aGroupName ); 108 ScDPItemData aData; 109 110 for ( std::vector<String>::const_iterator aIter(aElements.begin()); aIter != aElements.end(); aIter++ ) 111 { 112 sal_uInt32 nFormat = 0; //! ... 113 double fValue; 114 if ( pFormatter->IsNumberFormat( *aIter, nFormat, fValue ) ) 115 aData = ScDPItemData( *aIter, fValue, sal_True ); 116 else 117 aData.SetString( *aIter ); 118 119 aGroup.AddElement( aData ); 120 //! for numeric data, look at source members? 121 } 122 123 rDataDim.AddItem( aGroup ); 124 } 125 126 // ============================================================================ 127 128 ScDPSaveGroupDimension::ScDPSaveGroupDimension( const String& rSource, const String& rName ) : 129 aSourceDim( rSource ), 130 aGroupDimName( rName ), 131 nDatePart( 0 ) 132 { 133 } 134 135 ScDPSaveGroupDimension::ScDPSaveGroupDimension( const String& rSource, const String& rName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) : 136 aSourceDim( rSource ), 137 aGroupDimName( rName ), 138 aDateInfo( rDateInfo ), 139 nDatePart( nPart ) 140 { 141 } 142 143 ScDPSaveGroupDimension::~ScDPSaveGroupDimension() 144 { 145 } 146 147 void ScDPSaveGroupDimension::SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart ) 148 { 149 aDateInfo = rInfo; 150 nDatePart = nPart; 151 } 152 153 void ScDPSaveGroupDimension::AddGroupItem( const ScDPSaveGroupItem& rItem ) 154 { 155 aGroups.push_back( rItem ); 156 } 157 158 String ScDPSaveGroupDimension::CreateGroupName( const String& rPrefix ) 159 { 160 // create a name for a new group, using "Group1", "Group2" etc. (translated prefix in rPrefix) 161 162 //! look in all dimensions, to avoid clashes with automatic groups (=name of base element)? 163 //! (only dimensions for the same base) 164 165 sal_Int32 nAdd = 1; // first try is "Group1" 166 const sal_Int32 nMaxAdd = nAdd + aGroups.size(); // limit the loop 167 while ( nAdd <= nMaxAdd ) 168 { 169 String aGroupName( rPrefix ); 170 aGroupName.Append( String::CreateFromInt32( nAdd ) ); 171 bool bExists = false; 172 173 // look for existing groups 174 for ( ScDPSaveGroupItemVec::const_iterator aIter(aGroups.begin()); 175 aIter != aGroups.end() && !bExists; aIter++ ) 176 if ( aIter->GetGroupName() == aGroupName ) //! ignore case 177 bExists = true; 178 179 if ( !bExists ) 180 return aGroupName; // found a new name 181 182 ++nAdd; // continue with higher number 183 } 184 185 DBG_ERROR("CreateGroupName: no valid name found"); 186 return EMPTY_STRING; 187 } 188 189 const ScDPSaveGroupItem* ScDPSaveGroupDimension::GetNamedGroup( const String& rGroupName ) const 190 { 191 return const_cast< ScDPSaveGroupDimension* >( this )->GetNamedGroupAcc( rGroupName ); 192 } 193 194 ScDPSaveGroupItem* ScDPSaveGroupDimension::GetNamedGroupAcc( const String& rGroupName ) 195 { 196 for ( ScDPSaveGroupItemVec::iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ ) 197 if ( aIter->GetGroupName() == rGroupName ) //! ignore case 198 return &*aIter; 199 200 return NULL; // none found 201 } 202 203 long ScDPSaveGroupDimension::GetGroupCount() const 204 { 205 return aGroups.size(); 206 } 207 208 const ScDPSaveGroupItem* ScDPSaveGroupDimension::GetGroupByIndex( long nIndex ) const 209 { 210 return const_cast< ScDPSaveGroupDimension* >( this )->GetGroupAccByIndex( nIndex ); 211 } 212 213 ScDPSaveGroupItem* ScDPSaveGroupDimension::GetGroupAccByIndex( long nIndex ) 214 { 215 return &aGroups[nIndex]; 216 } 217 218 void ScDPSaveGroupDimension::RemoveFromGroups( const String& rItemName ) 219 { 220 // if the item is in any group, remove it from the group, 221 // also remove the group if it is empty afterwards 222 223 for ( ScDPSaveGroupItemVec::iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ ) 224 if ( aIter->RemoveElement( rItemName ) ) 225 { 226 if ( aIter->IsEmpty() ) // removed last item from the group? 227 aGroups.erase( aIter ); // then remove the group 228 229 return; // don't have to look further 230 } 231 } 232 233 void ScDPSaveGroupDimension::RemoveGroup( const String& rGroupName ) 234 { 235 for ( ScDPSaveGroupItemVec::iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ ) 236 if ( aIter->GetGroupName() == rGroupName ) //! ignore case 237 { 238 aGroups.erase( aIter ); 239 return; // don't have to look further 240 } 241 } 242 243 bool ScDPSaveGroupDimension::IsEmpty() const 244 { 245 return aGroups.empty(); 246 } 247 248 bool ScDPSaveGroupDimension::HasOnlyHidden( const ScStrCollection& rVisible ) 249 { 250 // check if there are only groups that don't appear in the list of visible names 251 252 bool bAllHidden = true; 253 for ( ScDPSaveGroupItemVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end() && bAllHidden; aIter++ ) 254 { 255 StrData aSearch( aIter->GetGroupName() ); 256 sal_uInt16 nCollIndex; 257 if ( rVisible.Search( &aSearch, nCollIndex ) ) 258 bAllHidden = false; // found one that is visible 259 } 260 return bAllHidden; 261 } 262 263 void ScDPSaveGroupDimension::Rename( const String& rNewName ) 264 { 265 aGroupDimName = rNewName; 266 } 267 268 void ScDPSaveGroupDimension::AddToData( ScDPGroupTableData& rData ) const 269 { 270 long nSourceIndex = rData.GetDimensionIndex( aSourceDim ); 271 if ( nSourceIndex >= 0 ) 272 { 273 ScDPGroupDimension aDim( nSourceIndex, aGroupDimName ); 274 if ( nDatePart ) 275 { 276 // date grouping 277 278 aDim.MakeDateHelper( aDateInfo, nDatePart ); 279 } 280 else 281 { 282 // normal (manual) grouping 283 284 SvNumberFormatter* pFormatter = rData.GetDocument()->GetFormatTable(); 285 286 for ( ScDPSaveGroupItemVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ ) 287 aIter->AddToData( aDim, pFormatter ); 288 } 289 290 rData.AddGroupDimension( aDim ); 291 } 292 } 293 294 // ============================================================================ 295 296 ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const String& rName, const ScDPNumGroupInfo& rInfo ) : 297 aDimensionName( rName ), 298 aGroupInfo( rInfo ), 299 nDatePart( 0 ) 300 { 301 } 302 303 ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const String& rName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) : 304 aDimensionName( rName ), 305 aDateInfo( rDateInfo ), 306 nDatePart( nPart ) 307 { 308 } 309 310 ScDPSaveNumGroupDimension::~ScDPSaveNumGroupDimension() 311 { 312 } 313 314 void ScDPSaveNumGroupDimension::AddToData( ScDPGroupTableData& rData ) const 315 { 316 long nSource = rData.GetDimensionIndex( aDimensionName ); 317 if ( nSource >= 0 ) 318 { 319 ScDPNumGroupDimension aDim( aGroupInfo ); // aGroupInfo: value grouping 320 if ( nDatePart ) 321 aDim.MakeDateHelper( aDateInfo, nDatePart ); // date grouping 322 323 rData.SetNumGroupDimension( nSource, aDim ); 324 } 325 } 326 327 void ScDPSaveNumGroupDimension::SetGroupInfo( const ScDPNumGroupInfo& rNew ) 328 { 329 aGroupInfo = rNew; 330 } 331 332 void ScDPSaveNumGroupDimension::SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart ) 333 { 334 aDateInfo = rInfo; 335 nDatePart = nPart; 336 } 337 338 // ============================================================================ 339 340 namespace { 341 342 struct ScDPSaveGroupDimNameFunc 343 { 344 String maDimName; 345 inline explicit ScDPSaveGroupDimNameFunc( const String& rDimName ) : maDimName( rDimName ) {} 346 inline bool operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetGroupDimName() == maDimName; } 347 }; 348 349 struct ScDPSaveGroupSourceNameFunc 350 { 351 String maSrcDimName; 352 inline explicit ScDPSaveGroupSourceNameFunc( const String& rSrcDimName ) : maSrcDimName( rSrcDimName ) {} 353 inline bool operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetSourceDimName() == maSrcDimName; } 354 }; 355 356 } // namespace 357 358 // ---------------------------------------------------------------------------- 359 360 ScDPDimensionSaveData::ScDPDimensionSaveData() 361 { 362 } 363 364 ScDPDimensionSaveData::~ScDPDimensionSaveData() 365 { 366 } 367 368 bool ScDPDimensionSaveData::operator==( const ScDPDimensionSaveData& ) const 369 { 370 return false; 371 } 372 373 void ScDPDimensionSaveData::AddGroupDimension( const ScDPSaveGroupDimension& rGroupDim ) 374 { 375 DBG_ASSERT( ::std::find_if( maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDim.GetGroupDimName() ) ) == maGroupDims.end(), 376 "ScDPDimensionSaveData::AddGroupDimension - group dimension exists already" ); 377 // ReplaceGroupDimension() adds new or replaces existing 378 ReplaceGroupDimension( rGroupDim ); 379 } 380 381 void ScDPDimensionSaveData::ReplaceGroupDimension( const ScDPSaveGroupDimension& rGroupDim ) 382 { 383 ScDPSaveGroupDimVec::iterator aIt = ::std::find_if( 384 maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDim.GetGroupDimName() ) ); 385 if( aIt == maGroupDims.end() ) 386 maGroupDims.push_back( rGroupDim ); 387 else 388 *aIt = rGroupDim; 389 } 390 391 void ScDPDimensionSaveData::RemoveGroupDimension( const String& rGroupDimName ) 392 { 393 ScDPSaveGroupDimVec::iterator aIt = ::std::find_if( 394 maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) ); 395 if( aIt != maGroupDims.end() ) 396 maGroupDims.erase( aIt ); 397 } 398 399 void ScDPDimensionSaveData::AddNumGroupDimension( const ScDPSaveNumGroupDimension& rGroupDim ) 400 { 401 DBG_ASSERT( maNumGroupDims.count( rGroupDim.GetDimensionName() ) == 0, 402 "ScDPDimensionSaveData::AddNumGroupDimension - numeric group dimension exists already" ); 403 // ReplaceNumGroupDimension() adds new or replaces existing 404 ReplaceNumGroupDimension( rGroupDim ); 405 } 406 407 void ScDPDimensionSaveData::ReplaceNumGroupDimension( const ScDPSaveNumGroupDimension& rGroupDim ) 408 { 409 ScDPSaveNumGroupDimMap::iterator aIt = maNumGroupDims.find( rGroupDim.GetDimensionName() ); 410 if( aIt == maNumGroupDims.end() ) 411 maNumGroupDims.insert( ScDPSaveNumGroupDimMap::value_type( rGroupDim.GetDimensionName(), rGroupDim ) ); 412 else 413 aIt->second = rGroupDim; 414 } 415 416 void ScDPDimensionSaveData::RemoveNumGroupDimension( const String& rGroupDimName ) 417 { 418 maNumGroupDims.erase( rGroupDimName ); 419 } 420 421 void ScDPDimensionSaveData::WriteToData( ScDPGroupTableData& rData ) const 422 { 423 // rData is assumed to be empty 424 // AddToData also handles date grouping 425 426 for( ScDPSaveGroupDimVec::const_iterator aIt = maGroupDims.begin(), aEnd = maGroupDims.end(); aIt != aEnd; ++aIt ) 427 aIt->AddToData( rData ); 428 429 for( ScDPSaveNumGroupDimMap::const_iterator aIt = maNumGroupDims.begin(), aEnd = maNumGroupDims.end(); aIt != aEnd; ++aIt ) 430 aIt->second.AddToData( rData ); 431 } 432 433 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetGroupDimForBase( const String& rBaseDimName ) const 434 { 435 return const_cast< ScDPDimensionSaveData* >( this )->GetGroupDimAccForBase( rBaseDimName ); 436 } 437 438 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNamedGroupDim( const String& rGroupDimName ) const 439 { 440 return const_cast< ScDPDimensionSaveData* >( this )->GetNamedGroupDimAcc( rGroupDimName ); 441 } 442 443 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetFirstNamedGroupDim( const String& rBaseDimName ) const 444 { 445 return const_cast< ScDPDimensionSaveData* >( this )->GetFirstNamedGroupDimAcc( rBaseDimName ); 446 } 447 448 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNextNamedGroupDim( const String& rGroupDimName ) const 449 { 450 return const_cast< ScDPDimensionSaveData* >( this )->GetNextNamedGroupDimAcc( rGroupDimName ); 451 } 452 453 const ScDPSaveNumGroupDimension* ScDPDimensionSaveData::GetNumGroupDim( const String& rGroupDimName ) const 454 { 455 return const_cast< ScDPDimensionSaveData* >( this )->GetNumGroupDimAcc( rGroupDimName ); 456 } 457 458 ScDPSaveGroupDimension* ScDPDimensionSaveData::GetGroupDimAccForBase( const String& rBaseDimName ) 459 { 460 ScDPSaveGroupDimension* pGroupDim = GetFirstNamedGroupDimAcc( rBaseDimName ); 461 return pGroupDim ? pGroupDim : GetNextNamedGroupDimAcc( rBaseDimName ); 462 } 463 464 ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNamedGroupDimAcc( const String& rGroupDimName ) 465 { 466 ScDPSaveGroupDimVec::iterator aIt = ::std::find_if( 467 maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) ); 468 return (aIt == maGroupDims.end()) ? 0 : &*aIt; 469 } 470 471 ScDPSaveGroupDimension* ScDPDimensionSaveData::GetFirstNamedGroupDimAcc( const String& rBaseDimName ) 472 { 473 ScDPSaveGroupDimVec::iterator aIt = ::std::find_if( 474 maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupSourceNameFunc( rBaseDimName ) ); 475 return (aIt == maGroupDims.end()) ? 0 : &*aIt; 476 } 477 478 ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNextNamedGroupDimAcc( const String& rGroupDimName ) 479 { 480 // find the group dimension with the passed name 481 ScDPSaveGroupDimVec::iterator aIt = ::std::find_if( 482 maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) ); 483 // find next group dimension based on the same source dimension name 484 if( aIt != maGroupDims.end() ) 485 aIt = ::std::find_if( aIt + 1, maGroupDims.end(), ScDPSaveGroupSourceNameFunc( aIt->GetSourceDimName() ) ); 486 return (aIt == maGroupDims.end()) ? 0 : &*aIt; 487 } 488 489 ScDPSaveNumGroupDimension* ScDPDimensionSaveData::GetNumGroupDimAcc( const String& rGroupDimName ) 490 { 491 ScDPSaveNumGroupDimMap::iterator aIt = maNumGroupDims.find( rGroupDimName ); 492 return (aIt == maNumGroupDims.end()) ? 0 : &aIt->second; 493 } 494 495 bool ScDPDimensionSaveData::HasGroupDimensions() const 496 { 497 return !maGroupDims.empty() || !maNumGroupDims.empty(); 498 } 499 500 sal_Int32 ScDPDimensionSaveData::CollectDateParts( const String& rBaseDimName ) const 501 { 502 sal_Int32 nParts = 0; 503 // start with part of numeric group 504 if( const ScDPSaveNumGroupDimension* pNumDim = GetNumGroupDim( rBaseDimName ) ) 505 nParts |= pNumDim->GetDatePart(); 506 // collect parts from all matching group dimensions 507 for( const ScDPSaveGroupDimension* pGroupDim = GetFirstNamedGroupDim( rBaseDimName ); pGroupDim; pGroupDim = GetNextNamedGroupDim( pGroupDim->GetGroupDimName() ) ) 508 nParts |= pGroupDim->GetDatePart(); 509 510 return nParts; 511 } 512 513 String ScDPDimensionSaveData::CreateGroupDimName( const String& rSourceName, 514 const ScDPObject& rObject, bool bAllowSource, 515 const std::vector<String>* pDeletedNames ) 516 { 517 // create a name for the new dimension by appending a number to the original 518 // dimension's name 519 520 bool bUseSource = bAllowSource; // if set, try the unchanged original name first 521 522 sal_Int32 nAdd = 2; // first try is "Name2" 523 const sal_Int32 nMaxAdd = 1000; // limit the loop 524 while ( nAdd <= nMaxAdd ) 525 { 526 String aDimName( rSourceName ); 527 if ( !bUseSource ) 528 aDimName.Append( String::CreateFromInt32( nAdd ) ); 529 bool bExists = false; 530 531 // look for existing group dimensions 532 for( ScDPSaveGroupDimVec::const_iterator aIt = maGroupDims.begin(), aEnd = maGroupDims.end(); (aIt != aEnd) && !bExists; ++aIt ) 533 if( aIt->GetGroupDimName() == aDimName ) //! ignore case 534 bExists = true; 535 536 // look for base dimensions that happen to have that name 537 if ( !bExists && rObject.IsDimNameInUse( aDimName ) ) 538 { 539 if ( pDeletedNames && 540 std::find( pDeletedNames->begin(), pDeletedNames->end(), aDimName ) != pDeletedNames->end() ) 541 { 542 // allow the name anyway if the name is in pDeletedNames 543 } 544 else 545 bExists = true; 546 } 547 548 if ( !bExists ) 549 return aDimName; // found a new name 550 551 if ( bUseSource ) 552 bUseSource = false; 553 else 554 ++nAdd; // continue with higher number 555 } 556 DBG_ERROR("CreateGroupDimName: no valid name found"); 557 return EMPTY_STRING; 558 } 559 560 String ScDPDimensionSaveData::CreateDateGroupDimName( sal_Int32 nDatePart, const ScDPObject& rObject, bool bAllowSource, const ::std::vector< String >* pDeletedNames ) 561 { 562 using namespace ::com::sun::star::sheet::DataPilotFieldGroupBy; 563 String aPartName; 564 switch( nDatePart ) 565 { 566 //! use translated strings from globstr.src 567 case SECONDS: aPartName = String::CreateFromAscii( "Seconds" ); break; 568 case MINUTES: aPartName = String::CreateFromAscii( "Minutes" ); break; 569 case HOURS: aPartName = String::CreateFromAscii( "Hours" ); break; 570 case DAYS: aPartName = String::CreateFromAscii( "Days" ); break; 571 case MONTHS: aPartName = String::CreateFromAscii( "Months" ); break; 572 case QUARTERS: aPartName = String::CreateFromAscii( "Quarters" ); break; 573 case YEARS: aPartName = String::CreateFromAscii( "Years" ); break; 574 } 575 DBG_ASSERT( aPartName.Len() > 0, "ScDPDimensionSaveData::CreateDateGroupDimName - invalid date part" ); 576 return CreateGroupDimName( aPartName, rObject, bAllowSource, pDeletedNames ); 577 } 578 579 // ============================================================================ 580 581