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 $
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>
46 // ============================================================================
48 ScDPSaveGroupItem::ScDPSaveGroupItem( const String
& 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
);
117 for ( std::vector
<String
>::const_iterator
aIter(aElements
.begin()); aIter
!= aElements
.end(); aIter
++ )
119 sal_uInt32 nFormat
= 0; //! ...
121 if ( pFormatter
->IsNumberFormat( *aIter
, nFormat
, fValue
) )
122 aData
= ScDPItemData( *aIter
, fValue
, TRUE
);
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
),
142 ScDPSaveGroupDimension::ScDPSaveGroupDimension( const String
& rSource
, const String
& rName
, const ScDPNumGroupInfo
& rDateInfo
, sal_Int32 nPart
) :
143 aSourceDim( rSource
),
144 aGroupDimName( rName
),
145 aDateInfo( rDateInfo
),
150 ScDPSaveGroupDimension::~ScDPSaveGroupDimension()
154 void ScDPSaveGroupDimension::SetDateInfo( const ScDPNumGroupInfo
& rInfo
, sal_Int32 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
187 return aGroupName
; // found a new name
189 ++nAdd
; // continue with higher number
192 DBG_ERROR("CreateGroupName: no valid name found");
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
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() );
264 if ( rVisible
.Search( &aSearch
, nCollIndex
) )
265 bAllHidden
= false; // found one that is visible
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
);
285 aDim
.MakeDateHelper( aDateInfo
, nDatePart
);
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
),
310 ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const String
& rName
, const ScDPNumGroupInfo
& rDateInfo
, sal_Int32 nPart
) :
311 aDimensionName( rName
),
312 aDateInfo( rDateInfo
),
317 ScDPSaveNumGroupDimension::~ScDPSaveNumGroupDimension()
321 void ScDPSaveNumGroupDimension::AddToData( ScDPGroupTableData
& rData
) const
323 long nSource
= rData
.GetDimensionIndex( aDimensionName
);
326 ScDPNumGroupDimension
aDim( aGroupInfo
); // aGroupInfo: value grouping
328 aDim
.MakeDateHelper( aDateInfo
, nDatePart
); // date grouping
330 rData
.SetNumGroupDimension( nSource
, aDim
);
334 void ScDPSaveNumGroupDimension::SetGroupInfo( const ScDPNumGroupInfo
& rNew
)
339 void ScDPSaveNumGroupDimension::SetDateInfo( const ScDPNumGroupInfo
& rInfo
, sal_Int32 nPart
)
345 // ============================================================================
349 struct ScDPSaveGroupDimNameFunc
352 inline explicit ScDPSaveGroupDimNameFunc( const String
& rDimName
) : maDimName( rDimName
) {}
353 inline bool operator()( const ScDPSaveGroupDimension
& rGroupDim
) const { return rGroupDim
.GetGroupDimName() == maDimName
; }
356 struct ScDPSaveGroupSourceNameFunc
359 inline explicit ScDPSaveGroupSourceNameFunc( const String
& rSrcDimName
) : maSrcDimName( rSrcDimName
) {}
360 inline bool operator()( const ScDPSaveGroupDimension
& rGroupDim
) const { return rGroupDim
.GetSourceDimName() == maSrcDimName
; }
365 // ----------------------------------------------------------------------------
367 ScDPDimensionSaveData::ScDPDimensionSaveData()
371 ScDPDimensionSaveData::~ScDPDimensionSaveData()
375 bool ScDPDimensionSaveData::operator==( const ScDPDimensionSaveData
& ) const
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
);
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
) );
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();
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
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
);
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
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
556 return aDimName
; // found a new name
561 ++nAdd
; // continue with higher number
563 DBG_ERROR("CreateGroupDimName: no valid name found");
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
;
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 // ============================================================================