Update ooo320-m1
[ooovba.git] / sc / source / core / data / dpdimsave.cxx
blob7e1bc0389eaf62b5dd4d5465f8ddfd1f36f16fb4
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: dpdimsave.cxx,v $
10 * $Revision: 1.7 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 #include "dpdimsave.hxx"
35 #include "dpgroup.hxx"
36 #include "dpobject.hxx"
37 #include "document.hxx"
39 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
41 #include <svtools/zforlist.hxx>
42 #include <tools/debug.hxx>
43 #include <rtl/math.hxx>
44 #include <algorithm>
46 // ============================================================================
48 ScDPSaveGroupItem::ScDPSaveGroupItem( const String& rName ) :
49 aGroupName( rName )
53 ScDPSaveGroupItem::~ScDPSaveGroupItem()
57 void ScDPSaveGroupItem::AddElement( const String& rName )
59 aElements.push_back( rName );
62 void ScDPSaveGroupItem::AddElementsFromGroup( const ScDPSaveGroupItem& rGroup )
64 // add all elements of the other group (used for nested grouping)
66 for ( std::vector<String>::const_iterator aIter(rGroup.aElements.begin());
67 aIter != rGroup.aElements.end(); aIter++ )
68 aElements.push_back( *aIter );
71 bool ScDPSaveGroupItem::RemoveElement( const String& rName )
73 for ( std::vector<String>::iterator aIter(aElements.begin()); aIter != aElements.end(); aIter++ )
74 if ( *aIter == rName ) //! ignore case
76 aElements.erase( aIter ); // found -> remove
77 return true; // don't have to look further
80 return false; // not found
83 bool ScDPSaveGroupItem::IsEmpty() const
85 return aElements.empty();
88 size_t ScDPSaveGroupItem::GetElementCount() const
90 return aElements.size();
93 const String* ScDPSaveGroupItem::GetElementByIndex( size_t nIndex ) const
95 return (nIndex < aElements.size()) ? &aElements[ nIndex ] : 0;
98 void ScDPSaveGroupItem::Rename( const String& rNewName )
100 aGroupName = rNewName;
103 void ScDPSaveGroupItem::RemoveElementsFromGroups( ScDPSaveGroupDimension& rDimension ) const
105 // remove this group's elements from their groups in rDimension
106 // (rDimension must be a different dimension from the one which contains this)
108 for ( std::vector<String>::const_iterator aIter(aElements.begin()); aIter != aElements.end(); aIter++ )
109 rDimension.RemoveFromGroups( *aIter );
112 void ScDPSaveGroupItem::AddToData( ScDPGroupDimension& rDataDim, SvNumberFormatter* pFormatter ) const
114 ScDPGroupItem aGroup( aGroupName );
115 ScDPItemData aData;
117 for ( std::vector<String>::const_iterator aIter(aElements.begin()); aIter != aElements.end(); aIter++ )
119 sal_uInt32 nFormat = 0; //! ...
120 double fValue;
121 if ( pFormatter->IsNumberFormat( *aIter, nFormat, fValue ) )
122 aData = ScDPItemData( *aIter, fValue, TRUE );
123 else
124 aData.SetString( *aIter );
126 aGroup.AddElement( aData );
127 //! for numeric data, look at source members?
130 rDataDim.AddItem( aGroup );
133 // ============================================================================
135 ScDPSaveGroupDimension::ScDPSaveGroupDimension( const String& rSource, const String& rName ) :
136 aSourceDim( rSource ),
137 aGroupDimName( rName ),
138 nDatePart( 0 )
142 ScDPSaveGroupDimension::ScDPSaveGroupDimension( const String& rSource, const String& rName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) :
143 aSourceDim( rSource ),
144 aGroupDimName( rName ),
145 aDateInfo( rDateInfo ),
146 nDatePart( nPart )
150 ScDPSaveGroupDimension::~ScDPSaveGroupDimension()
154 void ScDPSaveGroupDimension::SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
156 aDateInfo = rInfo;
157 nDatePart = nPart;
160 void ScDPSaveGroupDimension::AddGroupItem( const ScDPSaveGroupItem& rItem )
162 aGroups.push_back( rItem );
165 String ScDPSaveGroupDimension::CreateGroupName( const String& rPrefix )
167 // create a name for a new group, using "Group1", "Group2" etc. (translated prefix in rPrefix)
169 //! look in all dimensions, to avoid clashes with automatic groups (=name of base element)?
170 //! (only dimensions for the same base)
172 sal_Int32 nAdd = 1; // first try is "Group1"
173 const sal_Int32 nMaxAdd = nAdd + aGroups.size(); // limit the loop
174 while ( nAdd <= nMaxAdd )
176 String aGroupName( rPrefix );
177 aGroupName.Append( String::CreateFromInt32( nAdd ) );
178 bool bExists = false;
180 // look for existing groups
181 for ( ScDPSaveGroupItemVec::const_iterator aIter(aGroups.begin());
182 aIter != aGroups.end() && !bExists; aIter++ )
183 if ( aIter->GetGroupName() == aGroupName ) //! ignore case
184 bExists = true;
186 if ( !bExists )
187 return aGroupName; // found a new name
189 ++nAdd; // continue with higher number
192 DBG_ERROR("CreateGroupName: no valid name found");
193 return EMPTY_STRING;
196 const ScDPSaveGroupItem* ScDPSaveGroupDimension::GetNamedGroup( const String& rGroupName ) const
198 return const_cast< ScDPSaveGroupDimension* >( this )->GetNamedGroupAcc( rGroupName );
201 ScDPSaveGroupItem* ScDPSaveGroupDimension::GetNamedGroupAcc( const String& rGroupName )
203 for ( ScDPSaveGroupItemVec::iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ )
204 if ( aIter->GetGroupName() == rGroupName ) //! ignore case
205 return &*aIter;
207 return NULL; // none found
210 long ScDPSaveGroupDimension::GetGroupCount() const
212 return aGroups.size();
215 const ScDPSaveGroupItem* ScDPSaveGroupDimension::GetGroupByIndex( long nIndex ) const
217 return const_cast< ScDPSaveGroupDimension* >( this )->GetGroupAccByIndex( nIndex );
220 ScDPSaveGroupItem* ScDPSaveGroupDimension::GetGroupAccByIndex( long nIndex )
222 return &aGroups[nIndex];
225 void ScDPSaveGroupDimension::RemoveFromGroups( const String& rItemName )
227 // if the item is in any group, remove it from the group,
228 // also remove the group if it is empty afterwards
230 for ( ScDPSaveGroupItemVec::iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ )
231 if ( aIter->RemoveElement( rItemName ) )
233 if ( aIter->IsEmpty() ) // removed last item from the group?
234 aGroups.erase( aIter ); // then remove the group
236 return; // don't have to look further
240 void ScDPSaveGroupDimension::RemoveGroup( const String& rGroupName )
242 for ( ScDPSaveGroupItemVec::iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ )
243 if ( aIter->GetGroupName() == rGroupName ) //! ignore case
245 aGroups.erase( aIter );
246 return; // don't have to look further
250 bool ScDPSaveGroupDimension::IsEmpty() const
252 return aGroups.empty();
255 bool ScDPSaveGroupDimension::HasOnlyHidden( const ScStrCollection& rVisible )
257 // check if there are only groups that don't appear in the list of visible names
259 bool bAllHidden = true;
260 for ( ScDPSaveGroupItemVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end() && bAllHidden; aIter++ )
262 StrData aSearch( aIter->GetGroupName() );
263 USHORT nCollIndex;
264 if ( rVisible.Search( &aSearch, nCollIndex ) )
265 bAllHidden = false; // found one that is visible
267 return bAllHidden;
270 void ScDPSaveGroupDimension::Rename( const String& rNewName )
272 aGroupDimName = rNewName;
275 void ScDPSaveGroupDimension::AddToData( ScDPGroupTableData& rData ) const
277 long nSourceIndex = rData.GetDimensionIndex( aSourceDim );
278 if ( nSourceIndex >= 0 )
280 ScDPGroupDimension aDim( nSourceIndex, aGroupDimName );
281 if ( nDatePart )
283 // date grouping
285 aDim.MakeDateHelper( aDateInfo, nDatePart );
287 else
289 // normal (manual) grouping
291 SvNumberFormatter* pFormatter = rData.GetDocument()->GetFormatTable();
293 for ( ScDPSaveGroupItemVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ )
294 aIter->AddToData( aDim, pFormatter );
297 rData.AddGroupDimension( aDim );
301 // ============================================================================
303 ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const String& rName, const ScDPNumGroupInfo& rInfo ) :
304 aDimensionName( rName ),
305 aGroupInfo( rInfo ),
306 nDatePart( 0 )
310 ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const String& rName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) :
311 aDimensionName( rName ),
312 aDateInfo( rDateInfo ),
313 nDatePart( nPart )
317 ScDPSaveNumGroupDimension::~ScDPSaveNumGroupDimension()
321 void ScDPSaveNumGroupDimension::AddToData( ScDPGroupTableData& rData ) const
323 long nSource = rData.GetDimensionIndex( aDimensionName );
324 if ( nSource >= 0 )
326 ScDPNumGroupDimension aDim( aGroupInfo ); // aGroupInfo: value grouping
327 if ( nDatePart )
328 aDim.MakeDateHelper( aDateInfo, nDatePart ); // date grouping
330 rData.SetNumGroupDimension( nSource, aDim );
334 void ScDPSaveNumGroupDimension::SetGroupInfo( const ScDPNumGroupInfo& rNew )
336 aGroupInfo = rNew;
339 void ScDPSaveNumGroupDimension::SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
341 aDateInfo = rInfo;
342 nDatePart = nPart;
345 // ============================================================================
347 namespace {
349 struct ScDPSaveGroupDimNameFunc
351 String maDimName;
352 inline explicit ScDPSaveGroupDimNameFunc( const String& rDimName ) : maDimName( rDimName ) {}
353 inline bool operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetGroupDimName() == maDimName; }
356 struct ScDPSaveGroupSourceNameFunc
358 String maSrcDimName;
359 inline explicit ScDPSaveGroupSourceNameFunc( const String& rSrcDimName ) : maSrcDimName( rSrcDimName ) {}
360 inline bool operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetSourceDimName() == maSrcDimName; }
363 } // namespace
365 // ----------------------------------------------------------------------------
367 ScDPDimensionSaveData::ScDPDimensionSaveData()
371 ScDPDimensionSaveData::~ScDPDimensionSaveData()
375 bool ScDPDimensionSaveData::operator==( const ScDPDimensionSaveData& ) const
377 return false;
380 void ScDPDimensionSaveData::AddGroupDimension( const ScDPSaveGroupDimension& rGroupDim )
382 DBG_ASSERT( ::std::find_if( maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDim.GetGroupDimName() ) ) == maGroupDims.end(),
383 "ScDPDimensionSaveData::AddGroupDimension - group dimension exists already" );
384 // ReplaceGroupDimension() adds new or replaces existing
385 ReplaceGroupDimension( rGroupDim );
388 void ScDPDimensionSaveData::ReplaceGroupDimension( const ScDPSaveGroupDimension& rGroupDim )
390 ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
391 maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDim.GetGroupDimName() ) );
392 if( aIt == maGroupDims.end() )
393 maGroupDims.push_back( rGroupDim );
394 else
395 *aIt = rGroupDim;
398 void ScDPDimensionSaveData::RemoveGroupDimension( const String& rGroupDimName )
400 ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
401 maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
402 if( aIt != maGroupDims.end() )
403 maGroupDims.erase( aIt );
406 void ScDPDimensionSaveData::AddNumGroupDimension( const ScDPSaveNumGroupDimension& rGroupDim )
408 DBG_ASSERT( maNumGroupDims.count( rGroupDim.GetDimensionName() ) == 0,
409 "ScDPDimensionSaveData::AddNumGroupDimension - numeric group dimension exists already" );
410 // ReplaceNumGroupDimension() adds new or replaces existing
411 ReplaceNumGroupDimension( rGroupDim );
414 void ScDPDimensionSaveData::ReplaceNumGroupDimension( const ScDPSaveNumGroupDimension& rGroupDim )
416 ScDPSaveNumGroupDimMap::iterator aIt = maNumGroupDims.find( rGroupDim.GetDimensionName() );
417 if( aIt == maNumGroupDims.end() )
418 maNumGroupDims.insert( ScDPSaveNumGroupDimMap::value_type( rGroupDim.GetDimensionName(), rGroupDim ) );
419 else
420 aIt->second = rGroupDim;
423 void ScDPDimensionSaveData::RemoveNumGroupDimension( const String& rGroupDimName )
425 maNumGroupDims.erase( rGroupDimName );
428 void ScDPDimensionSaveData::WriteToData( ScDPGroupTableData& rData ) const
430 // rData is assumed to be empty
431 // AddToData also handles date grouping
433 for( ScDPSaveGroupDimVec::const_iterator aIt = maGroupDims.begin(), aEnd = maGroupDims.end(); aIt != aEnd; ++aIt )
434 aIt->AddToData( rData );
436 for( ScDPSaveNumGroupDimMap::const_iterator aIt = maNumGroupDims.begin(), aEnd = maNumGroupDims.end(); aIt != aEnd; ++aIt )
437 aIt->second.AddToData( rData );
440 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetGroupDimForBase( const String& rBaseDimName ) const
442 return const_cast< ScDPDimensionSaveData* >( this )->GetGroupDimAccForBase( rBaseDimName );
445 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNamedGroupDim( const String& rGroupDimName ) const
447 return const_cast< ScDPDimensionSaveData* >( this )->GetNamedGroupDimAcc( rGroupDimName );
450 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetFirstNamedGroupDim( const String& rBaseDimName ) const
452 return const_cast< ScDPDimensionSaveData* >( this )->GetFirstNamedGroupDimAcc( rBaseDimName );
455 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNextNamedGroupDim( const String& rGroupDimName ) const
457 return const_cast< ScDPDimensionSaveData* >( this )->GetNextNamedGroupDimAcc( rGroupDimName );
460 const ScDPSaveNumGroupDimension* ScDPDimensionSaveData::GetNumGroupDim( const String& rGroupDimName ) const
462 return const_cast< ScDPDimensionSaveData* >( this )->GetNumGroupDimAcc( rGroupDimName );
465 ScDPSaveGroupDimension* ScDPDimensionSaveData::GetGroupDimAccForBase( const String& rBaseDimName )
467 ScDPSaveGroupDimension* pGroupDim = GetFirstNamedGroupDimAcc( rBaseDimName );
468 return pGroupDim ? pGroupDim : GetNextNamedGroupDimAcc( rBaseDimName );
471 ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNamedGroupDimAcc( const String& rGroupDimName )
473 ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
474 maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
475 return (aIt == maGroupDims.end()) ? 0 : &*aIt;
478 ScDPSaveGroupDimension* ScDPDimensionSaveData::GetFirstNamedGroupDimAcc( const String& rBaseDimName )
480 ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
481 maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupSourceNameFunc( rBaseDimName ) );
482 return (aIt == maGroupDims.end()) ? 0 : &*aIt;
485 ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNextNamedGroupDimAcc( const String& rGroupDimName )
487 // find the group dimension with the passed name
488 ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
489 maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
490 // find next group dimension based on the same source dimension name
491 if( aIt != maGroupDims.end() )
492 aIt = ::std::find_if( aIt + 1, maGroupDims.end(), ScDPSaveGroupSourceNameFunc( aIt->GetSourceDimName() ) );
493 return (aIt == maGroupDims.end()) ? 0 : &*aIt;
496 ScDPSaveNumGroupDimension* ScDPDimensionSaveData::GetNumGroupDimAcc( const String& rGroupDimName )
498 ScDPSaveNumGroupDimMap::iterator aIt = maNumGroupDims.find( rGroupDimName );
499 return (aIt == maNumGroupDims.end()) ? 0 : &aIt->second;
502 bool ScDPDimensionSaveData::HasGroupDimensions() const
504 return !maGroupDims.empty() || !maNumGroupDims.empty();
507 sal_Int32 ScDPDimensionSaveData::CollectDateParts( const String& rBaseDimName ) const
509 sal_Int32 nParts = 0;
510 // start with part of numeric group
511 if( const ScDPSaveNumGroupDimension* pNumDim = GetNumGroupDim( rBaseDimName ) )
512 nParts |= pNumDim->GetDatePart();
513 // collect parts from all matching group dimensions
514 for( const ScDPSaveGroupDimension* pGroupDim = GetFirstNamedGroupDim( rBaseDimName ); pGroupDim; pGroupDim = GetNextNamedGroupDim( pGroupDim->GetGroupDimName() ) )
515 nParts |= pGroupDim->GetDatePart();
517 return nParts;
520 String ScDPDimensionSaveData::CreateGroupDimName( const String& rSourceName,
521 const ScDPObject& rObject, bool bAllowSource,
522 const std::vector<String>* pDeletedNames )
524 // create a name for the new dimension by appending a number to the original
525 // dimension's name
527 bool bUseSource = bAllowSource; // if set, try the unchanged original name first
529 sal_Int32 nAdd = 2; // first try is "Name2"
530 const sal_Int32 nMaxAdd = 1000; // limit the loop
531 while ( nAdd <= nMaxAdd )
533 String aDimName( rSourceName );
534 if ( !bUseSource )
535 aDimName.Append( String::CreateFromInt32( nAdd ) );
536 bool bExists = false;
538 // look for existing group dimensions
539 for( ScDPSaveGroupDimVec::const_iterator aIt = maGroupDims.begin(), aEnd = maGroupDims.end(); (aIt != aEnd) && !bExists; ++aIt )
540 if( aIt->GetGroupDimName() == aDimName ) //! ignore case
541 bExists = true;
543 // look for base dimensions that happen to have that name
544 if ( !bExists && rObject.IsDimNameInUse( aDimName ) )
546 if ( pDeletedNames &&
547 std::find( pDeletedNames->begin(), pDeletedNames->end(), aDimName ) != pDeletedNames->end() )
549 // allow the name anyway if the name is in pDeletedNames
551 else
552 bExists = true;
555 if ( !bExists )
556 return aDimName; // found a new name
558 if ( bUseSource )
559 bUseSource = false;
560 else
561 ++nAdd; // continue with higher number
563 DBG_ERROR("CreateGroupDimName: no valid name found");
564 return EMPTY_STRING;
567 String ScDPDimensionSaveData::CreateDateGroupDimName( sal_Int32 nDatePart, const ScDPObject& rObject, bool bAllowSource, const ::std::vector< String >* pDeletedNames )
569 using namespace ::com::sun::star::sheet::DataPilotFieldGroupBy;
570 String aPartName;
571 switch( nDatePart )
573 //! use translated strings from globstr.src
574 case SECONDS: aPartName = String::CreateFromAscii( "Seconds" ); break;
575 case MINUTES: aPartName = String::CreateFromAscii( "Minutes" ); break;
576 case HOURS: aPartName = String::CreateFromAscii( "Hours" ); break;
577 case DAYS: aPartName = String::CreateFromAscii( "Days" ); break;
578 case MONTHS: aPartName = String::CreateFromAscii( "Months" ); break;
579 case QUARTERS: aPartName = String::CreateFromAscii( "Quarters" ); break;
580 case YEARS: aPartName = String::CreateFromAscii( "Years" ); break;
582 DBG_ASSERT( aPartName.Len() > 0, "ScDPDimensionSaveData::CreateDateGroupDimName - invalid date part" );
583 return CreateGroupDimName( aPartName, rObject, bAllowSource, pDeletedNames );
586 // ============================================================================