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