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_comphelper.hxx"
30 #include <comphelper/namedvaluecollection.hxx>
31 
32 /** === begin UNO includes === **/
33 #include <com/sun/star/beans/NamedValue.hpp>
34 #include <com/sun/star/lang/IllegalArgumentException.hpp>
35 #include <com/sun/star/beans/PropertyState.hpp>
36 /** === end UNO includes === **/
37 
38 #include <rtl/ustrbuf.hxx>
39 #include <rtl/strbuf.hxx>
40 #include <osl/diagnose.h>
41 
42 #include <hash_map>
43 #include <functional>
44 #include <algorithm>
45 
46 //........................................................................
47 namespace comphelper
48 {
49 //........................................................................
50 
51     /** === begin UNO using === **/
52     using ::com::sun::star::uno::Any;
53     using ::com::sun::star::uno::Sequence;
54     using ::com::sun::star::beans::PropertyValue;
55     using ::com::sun::star::beans::NamedValue;
56     using ::com::sun::star::uno::Type;
57     using ::com::sun::star::uno::cpp_acquire;
58     using ::com::sun::star::uno::cpp_release;
59     using ::com::sun::star::uno::cpp_queryInterface;
60     using ::com::sun::star::lang::IllegalArgumentException;
61     using ::com::sun::star::beans::NamedValue;
62     using ::com::sun::star::beans::PropertyState_DIRECT_VALUE;
63     /** === end UNO using === **/
64 
65     //====================================================================
66 	//= NamedValueCollection_Impl
67 	//====================================================================
68     typedef ::std::hash_map< ::rtl::OUString, Any, ::rtl::OUStringHash >    NamedValueRepository;
69 
70     struct NamedValueCollection_Impl
71     {
72         NamedValueRepository    aValues;
73     };
74 
75     //====================================================================
76 	//= NamedValueCollection
77 	//====================================================================
78 	//--------------------------------------------------------------------
79     NamedValueCollection::NamedValueCollection()
80         :m_pImpl( new NamedValueCollection_Impl )
81     {
82     }
83 
84 	//--------------------------------------------------------------------
85     NamedValueCollection::NamedValueCollection( const NamedValueCollection& _rCopySource )
86         :m_pImpl( new NamedValueCollection_Impl )
87     {
88         *this = _rCopySource;
89     }
90 
91 	//--------------------------------------------------------------------
92     NamedValueCollection& NamedValueCollection::operator=( const NamedValueCollection& i_rCopySource )
93     {
94         m_pImpl->aValues = i_rCopySource.m_pImpl->aValues;
95         return *this;
96     }
97 
98 	//--------------------------------------------------------------------
99     NamedValueCollection::NamedValueCollection( const Any& _rElements )
100         :m_pImpl( new NamedValueCollection_Impl )
101     {
102         impl_assign( _rElements );
103     }
104 
105 	//--------------------------------------------------------------------
106     NamedValueCollection::NamedValueCollection( const Sequence< Any >& _rArguments )
107         :m_pImpl( new NamedValueCollection_Impl )
108     {
109         impl_assign( _rArguments );
110     }
111 
112 	//--------------------------------------------------------------------
113     NamedValueCollection::NamedValueCollection( const Sequence< PropertyValue >& _rArguments )
114         :m_pImpl( new NamedValueCollection_Impl )
115     {
116         impl_assign( _rArguments );
117     }
118 
119 	//--------------------------------------------------------------------
120     NamedValueCollection::NamedValueCollection( const Sequence< NamedValue >& _rArguments )
121         :m_pImpl( new NamedValueCollection_Impl )
122     {
123         impl_assign( _rArguments );
124     }
125 
126 	//--------------------------------------------------------------------
127     NamedValueCollection::~NamedValueCollection()
128     {
129     }
130 
131 	//--------------------------------------------------------------------
132     NamedValueCollection& NamedValueCollection::merge( const NamedValueCollection& _rAdditionalValues, bool _bOverwriteExisting )
133     {
134         for (   NamedValueRepository::const_iterator namedValue = _rAdditionalValues.m_pImpl->aValues.begin();
135                 namedValue != _rAdditionalValues.m_pImpl->aValues.end();
136                 ++namedValue
137             )
138         {
139             if ( _bOverwriteExisting || !impl_has( namedValue->first ) )
140                 impl_put( namedValue->first, namedValue->second );
141         }
142 
143         return *this;
144     }
145 
146 	//--------------------------------------------------------------------
147     size_t NamedValueCollection::size() const
148     {
149         return m_pImpl->aValues.size();
150     }
151 
152 	//--------------------------------------------------------------------
153     bool NamedValueCollection::empty() const
154     {
155         return m_pImpl->aValues.empty();
156     }
157 
158 	//--------------------------------------------------------------------
159     ::std::vector< ::rtl::OUString > NamedValueCollection::getNames() const
160     {
161         ::std::vector< ::rtl::OUString > aNames( m_pImpl->aValues.size() );
162         ::std::transform(
163             m_pImpl->aValues.begin(),
164             m_pImpl->aValues.end(),
165             aNames.begin(),
166             ::std::select1st< NamedValueRepository::value_type >()
167         );
168         return aNames;
169     }
170 
171 	//--------------------------------------------------------------------
172     void NamedValueCollection::impl_assign( const Any& i_rWrappedElements )
173     {
174         Sequence< NamedValue > aNamedValues;
175         Sequence< PropertyValue > aPropertyValues;
176         NamedValue aNamedValue;
177         PropertyValue aPropertyValue;
178 
179         if ( i_rWrappedElements >>= aNamedValues )
180             impl_assign( aNamedValues );
181         else if ( i_rWrappedElements >>= aPropertyValues )
182             impl_assign( aPropertyValues );
183         else if ( i_rWrappedElements >>= aNamedValue )
184             impl_assign( Sequence< NamedValue >( &aNamedValue, 1 ) );
185         else if ( i_rWrappedElements >>= aPropertyValue )
186             impl_assign( Sequence< PropertyValue >( &aPropertyValue, 1 ) );
187         else
188             OSL_ENSURE( !i_rWrappedElements.hasValue(), "NamedValueCollection::impl_assign(Any): unsupported type!" );
189     }
190 
191 	//--------------------------------------------------------------------
192     void NamedValueCollection::impl_assign( const Sequence< Any >& _rArguments )
193     {
194         {
195             NamedValueRepository aEmpty;
196             m_pImpl->aValues.swap( aEmpty );
197         }
198 
199         PropertyValue aPropertyValue;
200         NamedValue aNamedValue;
201 
202         const Any* pArgument = _rArguments.getConstArray();
203         const Any* pArgumentEnd = _rArguments.getConstArray() + _rArguments.getLength();
204         for ( ; pArgument != pArgumentEnd; ++pArgument )
205         {
206             if ( *pArgument >>= aPropertyValue )
207                 m_pImpl->aValues[ aPropertyValue.Name ] = aPropertyValue.Value;
208             else if ( *pArgument >>= aNamedValue )
209                 m_pImpl->aValues[ aNamedValue.Name ] = aNamedValue.Value;
210 #if OSL_DEBUG_LEVEL > 0
211             else if ( pArgument->hasValue() )
212             {
213                 ::rtl::OStringBuffer message;
214                 message.append( "NamedValueCollection::impl_assign: encountered a value type which I cannot handle:\n" );
215                 message.append( ::rtl::OUStringToOString( pArgument->getValueTypeName(), RTL_TEXTENCODING_ASCII_US ) );
216                 OSL_ENSURE( false, message.makeStringAndClear() );
217             }
218 #endif
219         }
220     }
221 
222 	//--------------------------------------------------------------------
223     void NamedValueCollection::impl_assign( const Sequence< PropertyValue >& _rArguments )
224     {
225         {
226             NamedValueRepository aEmpty;
227             m_pImpl->aValues.swap( aEmpty );
228         }
229 
230         const PropertyValue* pArgument = _rArguments.getConstArray();
231         const PropertyValue* pArgumentEnd = _rArguments.getConstArray() + _rArguments.getLength();
232         for ( ; pArgument != pArgumentEnd; ++pArgument )
233             m_pImpl->aValues[ pArgument->Name ] = pArgument->Value;
234     }
235 
236 	//--------------------------------------------------------------------
237     void NamedValueCollection::impl_assign( const Sequence< NamedValue >& _rArguments )
238     {
239         {
240             NamedValueRepository aEmpty;
241             m_pImpl->aValues.swap( aEmpty );
242         }
243 
244         const NamedValue* pArgument = _rArguments.getConstArray();
245         const NamedValue* pArgumentEnd = _rArguments.getConstArray() + _rArguments.getLength();
246         for ( ; pArgument != pArgumentEnd; ++pArgument )
247             m_pImpl->aValues[ pArgument->Name ] = pArgument->Value;
248     }
249 
250 	//--------------------------------------------------------------------
251     bool NamedValueCollection::get_ensureType( const ::rtl::OUString& _rValueName, void* _pValueLocation, const Type& _rExpectedValueType ) const
252     {
253         NamedValueRepository::const_iterator pos = m_pImpl->aValues.find( _rValueName );
254         if ( pos != m_pImpl->aValues.end() )
255         {
256 		    if ( uno_type_assignData(
257 			        _pValueLocation, _rExpectedValueType.getTypeLibType(),
258 				    const_cast< void* >( pos->second.getValue() ), pos->second.getValueType().getTypeLibType(),
259 			    	reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ),
260                     reinterpret_cast< uno_AcquireFunc >( cpp_acquire ),
261                     reinterpret_cast< uno_ReleaseFunc >( cpp_release )
262                 ) )
263                 // argument exists, and could be extracted
264                 return true;
265 
266             // argument exists, but is of wrong type
267             ::rtl::OUStringBuffer aBuffer;
268             aBuffer.appendAscii( "Invalid value type for '" );
269             aBuffer.append     ( _rValueName );
270             aBuffer.appendAscii( "'.\nExpected: " );
271             aBuffer.append     ( _rExpectedValueType.getTypeName() );
272             aBuffer.appendAscii( "\nFound: " );
273             aBuffer.append     ( pos->second.getValueType().getTypeName() );
274             throw IllegalArgumentException( aBuffer.makeStringAndClear(), NULL, 0 );
275         }
276 
277         // argument does not exist
278         return false;
279     }
280 
281     //--------------------------------------------------------------------
282     const Any& NamedValueCollection::impl_get( const ::rtl::OUString& _rValueName ) const
283     {
284         NamedValueRepository::const_iterator pos = m_pImpl->aValues.find( _rValueName );
285         if ( pos != m_pImpl->aValues.end() )
286             return pos->second;
287 
288         static Any aEmptyDefault;
289         return aEmptyDefault;
290     }
291 
292     //--------------------------------------------------------------------
293     bool NamedValueCollection::impl_has( const ::rtl::OUString& _rValueName ) const
294     {
295         NamedValueRepository::const_iterator pos = m_pImpl->aValues.find( _rValueName );
296         return ( pos != m_pImpl->aValues.end() );
297     }
298 
299     //--------------------------------------------------------------------
300     bool NamedValueCollection::impl_put( const ::rtl::OUString& _rValueName, const Any& _rValue )
301     {
302         bool bHas = impl_has( _rValueName );
303         m_pImpl->aValues[ _rValueName ] = _rValue;
304         return bHas;
305     }
306 
307     //--------------------------------------------------------------------
308     bool NamedValueCollection::impl_remove( const ::rtl::OUString& _rValueName )
309     {
310         NamedValueRepository::iterator pos = m_pImpl->aValues.find( _rValueName );
311         if ( pos == m_pImpl->aValues.end() )
312             return false;
313         m_pImpl->aValues.erase( pos );
314         return true;
315     }
316 
317     //--------------------------------------------------------------------
318     namespace
319     {
320         struct Value2PropertyValue : public ::std::unary_function< NamedValueRepository::value_type, PropertyValue >
321         {
322             PropertyValue operator()( const NamedValueRepository::value_type& _rValue )
323             {
324                 return PropertyValue(
325                     _rValue.first, 0, _rValue.second, PropertyState_DIRECT_VALUE );
326             }
327         };
328 
329         struct Value2NamedValue : public ::std::unary_function< NamedValueRepository::value_type, NamedValue >
330         {
331             NamedValue operator()( const NamedValueRepository::value_type& _rValue )
332             {
333                 return NamedValue( _rValue.first, _rValue.second );
334             }
335         };
336     }
337 
338     //--------------------------------------------------------------------
339     sal_Int32 NamedValueCollection::operator >>= ( Sequence< PropertyValue >& _out_rValues ) const
340     {
341         _out_rValues.realloc( m_pImpl->aValues.size() );
342         ::std::transform( m_pImpl->aValues.begin(), m_pImpl->aValues.end(), _out_rValues.getArray(), Value2PropertyValue() );
343         return _out_rValues.getLength();
344     }
345 
346     //--------------------------------------------------------------------
347     sal_Int32 NamedValueCollection::operator >>= ( Sequence< NamedValue >& _out_rValues ) const
348     {
349         _out_rValues.realloc( m_pImpl->aValues.size() );
350         ::std::transform( m_pImpl->aValues.begin(), m_pImpl->aValues.end(), _out_rValues.getArray(), Value2NamedValue() );
351         return _out_rValues.getLength();
352     }
353 
354 //........................................................................
355 } // namespace comphelper
356 //........................................................................
357 
358