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     bool NamedValueCollection::canExtractFrom( ::com::sun::star::uno::Any const & i_value )
133     {
134         Type const & aValueType = i_value.getValueType();
135         if  (   aValueType.equals( ::cppu::UnoType< PropertyValue >::get() )
136             ||  aValueType.equals( ::cppu::UnoType< NamedValue >::get() )
137             ||  aValueType.equals( ::cppu::UnoType< Sequence< PropertyValue > >::get() )
138             ||  aValueType.equals( ::cppu::UnoType< Sequence< NamedValue > >::get() )
139             )
140             return true;
141         return false;
142     }
143 
144 	//--------------------------------------------------------------------
145     NamedValueCollection& NamedValueCollection::merge( const NamedValueCollection& _rAdditionalValues, bool _bOverwriteExisting )
146     {
147         for (   NamedValueRepository::const_iterator namedValue = _rAdditionalValues.m_pImpl->aValues.begin();
148                 namedValue != _rAdditionalValues.m_pImpl->aValues.end();
149                 ++namedValue
150             )
151         {
152             if ( _bOverwriteExisting || !impl_has( namedValue->first ) )
153                 impl_put( namedValue->first, namedValue->second );
154         }
155 
156         return *this;
157     }
158 
159 	//--------------------------------------------------------------------
160     size_t NamedValueCollection::size() const
161     {
162         return m_pImpl->aValues.size();
163     }
164 
165 	//--------------------------------------------------------------------
166     bool NamedValueCollection::empty() const
167     {
168         return m_pImpl->aValues.empty();
169     }
170 
171 	//--------------------------------------------------------------------
172     ::std::vector< ::rtl::OUString > NamedValueCollection::getNames() const
173     {
174         ::std::vector< ::rtl::OUString > aNames( m_pImpl->aValues.size() );
175         ::std::transform(
176             m_pImpl->aValues.begin(),
177             m_pImpl->aValues.end(),
178             aNames.begin(),
179             ::std::select1st< NamedValueRepository::value_type >()
180         );
181         return aNames;
182     }
183 
184 	//--------------------------------------------------------------------
185     void NamedValueCollection::impl_assign( const Any& i_rWrappedElements )
186     {
187         Sequence< NamedValue > aNamedValues;
188         Sequence< PropertyValue > aPropertyValues;
189         NamedValue aNamedValue;
190         PropertyValue aPropertyValue;
191 
192         if ( i_rWrappedElements >>= aNamedValues )
193             impl_assign( aNamedValues );
194         else if ( i_rWrappedElements >>= aPropertyValues )
195             impl_assign( aPropertyValues );
196         else if ( i_rWrappedElements >>= aNamedValue )
197             impl_assign( Sequence< NamedValue >( &aNamedValue, 1 ) );
198         else if ( i_rWrappedElements >>= aPropertyValue )
199             impl_assign( Sequence< PropertyValue >( &aPropertyValue, 1 ) );
200         else
201             OSL_ENSURE( !i_rWrappedElements.hasValue(), "NamedValueCollection::impl_assign(Any): unsupported type!" );
202     }
203 
204 	//--------------------------------------------------------------------
205     void NamedValueCollection::impl_assign( const Sequence< Any >& _rArguments )
206     {
207         {
208             NamedValueRepository aEmpty;
209             m_pImpl->aValues.swap( aEmpty );
210         }
211 
212         PropertyValue aPropertyValue;
213         NamedValue aNamedValue;
214 
215         const Any* pArgument = _rArguments.getConstArray();
216         const Any* pArgumentEnd = _rArguments.getConstArray() + _rArguments.getLength();
217         for ( ; pArgument != pArgumentEnd; ++pArgument )
218         {
219             if ( *pArgument >>= aPropertyValue )
220                 m_pImpl->aValues[ aPropertyValue.Name ] = aPropertyValue.Value;
221             else if ( *pArgument >>= aNamedValue )
222                 m_pImpl->aValues[ aNamedValue.Name ] = aNamedValue.Value;
223 #if OSL_DEBUG_LEVEL > 0
224             else if ( pArgument->hasValue() )
225             {
226                 ::rtl::OStringBuffer message;
227                 message.append( "NamedValueCollection::impl_assign: encountered a value type which I cannot handle:\n" );
228                 message.append( ::rtl::OUStringToOString( pArgument->getValueTypeName(), RTL_TEXTENCODING_ASCII_US ) );
229                 OSL_ENSURE( false, message.makeStringAndClear() );
230             }
231 #endif
232         }
233     }
234 
235 	//--------------------------------------------------------------------
236     void NamedValueCollection::impl_assign( const Sequence< PropertyValue >& _rArguments )
237     {
238         {
239             NamedValueRepository aEmpty;
240             m_pImpl->aValues.swap( aEmpty );
241         }
242 
243         const PropertyValue* pArgument = _rArguments.getConstArray();
244         const PropertyValue* pArgumentEnd = _rArguments.getConstArray() + _rArguments.getLength();
245         for ( ; pArgument != pArgumentEnd; ++pArgument )
246             m_pImpl->aValues[ pArgument->Name ] = pArgument->Value;
247     }
248 
249 	//--------------------------------------------------------------------
250     void NamedValueCollection::impl_assign( const Sequence< NamedValue >& _rArguments )
251     {
252         {
253             NamedValueRepository aEmpty;
254             m_pImpl->aValues.swap( aEmpty );
255         }
256 
257         const NamedValue* pArgument = _rArguments.getConstArray();
258         const NamedValue* pArgumentEnd = _rArguments.getConstArray() + _rArguments.getLength();
259         for ( ; pArgument != pArgumentEnd; ++pArgument )
260             m_pImpl->aValues[ pArgument->Name ] = pArgument->Value;
261     }
262 
263 	//--------------------------------------------------------------------
264     bool NamedValueCollection::get_ensureType( const ::rtl::OUString& _rValueName, void* _pValueLocation, const Type& _rExpectedValueType ) const
265     {
266         NamedValueRepository::const_iterator pos = m_pImpl->aValues.find( _rValueName );
267         if ( pos != m_pImpl->aValues.end() )
268         {
269 		    if ( uno_type_assignData(
270 			        _pValueLocation, _rExpectedValueType.getTypeLibType(),
271 				    const_cast< void* >( pos->second.getValue() ), pos->second.getValueType().getTypeLibType(),
272 			    	reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ),
273                     reinterpret_cast< uno_AcquireFunc >( cpp_acquire ),
274                     reinterpret_cast< uno_ReleaseFunc >( cpp_release )
275                 ) )
276                 // argument exists, and could be extracted
277                 return true;
278 
279             // argument exists, but is of wrong type
280             ::rtl::OUStringBuffer aBuffer;
281             aBuffer.appendAscii( "Invalid value type for '" );
282             aBuffer.append     ( _rValueName );
283             aBuffer.appendAscii( "'.\nExpected: " );
284             aBuffer.append     ( _rExpectedValueType.getTypeName() );
285             aBuffer.appendAscii( "\nFound: " );
286             aBuffer.append     ( pos->second.getValueType().getTypeName() );
287             throw IllegalArgumentException( aBuffer.makeStringAndClear(), NULL, 0 );
288         }
289 
290         // argument does not exist
291         return false;
292     }
293 
294     //--------------------------------------------------------------------
295     const Any& NamedValueCollection::impl_get( const ::rtl::OUString& _rValueName ) const
296     {
297         NamedValueRepository::const_iterator pos = m_pImpl->aValues.find( _rValueName );
298         if ( pos != m_pImpl->aValues.end() )
299             return pos->second;
300 
301         static Any aEmptyDefault;
302         return aEmptyDefault;
303     }
304 
305     //--------------------------------------------------------------------
306     bool NamedValueCollection::impl_has( const ::rtl::OUString& _rValueName ) const
307     {
308         NamedValueRepository::const_iterator pos = m_pImpl->aValues.find( _rValueName );
309         return ( pos != m_pImpl->aValues.end() );
310     }
311 
312     //--------------------------------------------------------------------
313     bool NamedValueCollection::impl_put( const ::rtl::OUString& _rValueName, const Any& _rValue )
314     {
315         bool bHas = impl_has( _rValueName );
316         m_pImpl->aValues[ _rValueName ] = _rValue;
317         return bHas;
318     }
319 
320     //--------------------------------------------------------------------
321     bool NamedValueCollection::impl_remove( const ::rtl::OUString& _rValueName )
322     {
323         NamedValueRepository::iterator pos = m_pImpl->aValues.find( _rValueName );
324         if ( pos == m_pImpl->aValues.end() )
325             return false;
326         m_pImpl->aValues.erase( pos );
327         return true;
328     }
329 
330     //--------------------------------------------------------------------
331     namespace
332     {
333         struct Value2PropertyValue : public ::std::unary_function< NamedValueRepository::value_type, PropertyValue >
334         {
335             PropertyValue operator()( const NamedValueRepository::value_type& _rValue )
336             {
337                 return PropertyValue(
338                     _rValue.first, 0, _rValue.second, PropertyState_DIRECT_VALUE );
339             }
340         };
341 
342         struct Value2NamedValue : public ::std::unary_function< NamedValueRepository::value_type, NamedValue >
343         {
344             NamedValue operator()( const NamedValueRepository::value_type& _rValue )
345             {
346                 return NamedValue( _rValue.first, _rValue.second );
347             }
348         };
349     }
350 
351     //--------------------------------------------------------------------
352     sal_Int32 NamedValueCollection::operator >>= ( Sequence< PropertyValue >& _out_rValues ) const
353     {
354         _out_rValues.realloc( m_pImpl->aValues.size() );
355         ::std::transform( m_pImpl->aValues.begin(), m_pImpl->aValues.end(), _out_rValues.getArray(), Value2PropertyValue() );
356         return _out_rValues.getLength();
357     }
358 
359     //--------------------------------------------------------------------
360     sal_Int32 NamedValueCollection::operator >>= ( Sequence< NamedValue >& _out_rValues ) const
361     {
362         _out_rValues.realloc( m_pImpl->aValues.size() );
363         ::std::transform( m_pImpl->aValues.begin(), m_pImpl->aValues.end(), _out_rValues.getArray(), Value2NamedValue() );
364         return _out_rValues.getLength();
365     }
366 
367 //........................................................................
368 } // namespace comphelper
369 //........................................................................
370 
371