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 <com/sun/star/lang/XServiceInfo.hpp>
31 #include <com/sun/star/lang/XTypeProvider.hpp>
32 #include <cppuhelper/weakagg.hxx>
33 #include <cppuhelper/interfacecontainer.hxx>
34 #include <comphelper/propertysethelper.hxx>
35 #include <osl/mutex.hxx>
36 #include <comphelper/genericpropertyset.hxx>
37 #include <comphelper/propertysetinfo.hxx>
38 #include <comphelper/stl_types.hxx>
39 #include <vos/mutex.hxx>
40 #include <rtl/uuid.h>
41 #include <boost/mem_fn.hpp>
42 #include <boost/bind.hpp>
43 #include <boost/utility.hpp>
44 
45 ///////////////////////////////////////////////////////////////////////
46 
47 using namespace ::rtl;
48 using namespace ::osl;
49 using namespace ::cppu;
50 using namespace ::comphelper;
51 using namespace ::com::sun::star;
52 using namespace ::com::sun::star::uno;
53 using namespace ::com::sun::star::beans;
54 using namespace ::com::sun::star::lang;
55 
56 DECLARE_STL_USTRINGACCESS_MAP( Any, GenericAnyMapImpl );
57 
58 namespace comphelper
59 {
60 	struct IMPL_GenericPropertySet_MutexContainer
61 	{
62 		Mutex maMutex ;
63 	} ;
64 
65 	class GenericPropertySet :	public OWeakAggObject,
66 								public XServiceInfo,
67 								public XTypeProvider,
68 								public PropertySetHelper,
69 								private IMPL_GenericPropertySet_MutexContainer
70 	{
71 	private:
72 		GenericAnyMapImpl	maAnyMap;
73         ::cppu::OMultiTypeInterfaceContainerHelperVar< ::rtl::OUString,UStringHash,UStringEqual> m_aListener;
74 
75 	protected:
76 		virtual void _setPropertyValues( const PropertyMapEntry** ppEntries, const  Any* pValues ) throw( UnknownPropertyException,  PropertyVetoException,  IllegalArgumentException,  WrappedTargetException );
77 		virtual void _getPropertyValues( const PropertyMapEntry** ppEntries,  Any* pValue ) throw( UnknownPropertyException,  WrappedTargetException );
78 
79 	public:
80 		GenericPropertySet( PropertySetInfo* pInfo ) throw();
81 		virtual ~GenericPropertySet() throw();
82 
83 		// XInterface
84 		virtual  Any SAL_CALL queryAggregation( const  Type & rType ) throw( RuntimeException);
85 		virtual  Any SAL_CALL queryInterface( const  Type & rType ) throw( RuntimeException);
86 		virtual void SAL_CALL acquire() throw();
87 		virtual void SAL_CALL release() throw();
88 
89 		// XTypeProvider
90 		virtual  Sequence<  Type > SAL_CALL getTypes(  ) throw( RuntimeException);
91 		virtual  Sequence< sal_Int8 > SAL_CALL getImplementationId(  ) throw( RuntimeException);
92 
93 		// XServiceInfo
94 		virtual rtl::OUString SAL_CALL getImplementationName() throw(  RuntimeException );
95 		virtual sal_Bool SAL_CALL supportsService( const rtl::OUString& ServiceName ) throw(  RuntimeException );
96 		virtual  Sequence< rtl::OUString > SAL_CALL getSupportedServiceNames() throw(  RuntimeException );
97 
98         // XPropertySet
99         virtual void SAL_CALL addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& xListener ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
100         virtual void SAL_CALL removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& aListener ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
101 	};
102 
103 }
104 
105 ///////////////////////////////////////////////////////////////////////
106 
107 GenericPropertySet::GenericPropertySet( PropertySetInfo* pInfo ) throw()
108 : PropertySetHelper( pInfo )
109 ,m_aListener(maMutex)
110 {
111 }
112 
113 GenericPropertySet::~GenericPropertySet() throw()
114 {
115 }
116 void SAL_CALL GenericPropertySet::addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const Reference< XPropertyChangeListener >& xListener ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
117 {
118     Reference < XPropertySetInfo > xInfo = getPropertySetInfo(  );
119     if ( xInfo.is() )
120     {
121         if ( !aPropertyName.getLength() )
122         {
123             Sequence< Property> aSeq = xInfo->getProperties();
124             const Property* pIter = aSeq.getConstArray();
125             const Property* pEnd  = pIter + aSeq.getLength();
126             for( ; pIter != pEnd ; ++pIter)
127             {
128                 m_aListener.addInterface(pIter->Name,xListener);
129             }
130         }
131         else if ( xInfo->hasPropertyByName(aPropertyName) )
132 	        m_aListener.addInterface(aPropertyName,xListener);
133         else
134             throw UnknownPropertyException( aPropertyName, *this );
135     }
136 }
137 
138 void SAL_CALL GenericPropertySet::removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const Reference< XPropertyChangeListener >& xListener ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
139 {
140     ResettableMutexGuard aGuard( maMutex );
141     Reference < XPropertySetInfo > xInfo = getPropertySetInfo(  );
142     aGuard.clear();
143     if ( xInfo.is() )
144     {
145         if ( !aPropertyName.getLength() )
146         {
147             Sequence< Property> aSeq = xInfo->getProperties();
148             const Property* pIter = aSeq.getConstArray();
149             const Property* pEnd  = pIter + aSeq.getLength();
150             for( ; pIter != pEnd ; ++pIter)
151             {
152                 m_aListener.removeInterface(pIter->Name,xListener);
153             }
154         }
155         else if ( xInfo->hasPropertyByName(aPropertyName) )
156 	        m_aListener.removeInterface(aPropertyName,xListener);
157         else
158             throw UnknownPropertyException( aPropertyName, *this );
159     }
160 }
161 
162 void GenericPropertySet::_setPropertyValues( const PropertyMapEntry** ppEntries, const Any* pValues )
163 	throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException )
164 {
165 	ResettableMutexGuard aGuard( maMutex );
166 
167 	while( *ppEntries )
168 	{
169 		const OUString aPropertyName( (*ppEntries)->mpName, (*ppEntries)->mnNameLen, RTL_TEXTENCODING_ASCII_US );
170         OInterfaceContainerHelper * pHelper = m_aListener.getContainer(aPropertyName);
171 
172 		maAnyMap[ aPropertyName ] = *pValues;
173 
174         if ( pHelper )
175         {
176             PropertyChangeEvent aEvt;
177             aEvt.PropertyName = aPropertyName;
178             aEvt.NewValue = *pValues;
179             aGuard.clear();
180             pHelper->notifyEach( &XPropertyChangeListener::propertyChange, aEvt );
181             aGuard.reset();
182         }
183 
184 		ppEntries++;
185 		pValues++;
186 	}
187 }
188 
189 void GenericPropertySet::_getPropertyValues( const comphelper::PropertyMapEntry** ppEntries, Any* pValue )
190 	throw( UnknownPropertyException, WrappedTargetException )
191 {
192 	MutexGuard aGuard( maMutex );
193 
194 	while( *ppEntries )
195 	{
196 		const OUString aPropertyName( (*ppEntries)->mpName, (*ppEntries)->mnNameLen, RTL_TEXTENCODING_ASCII_US );
197 		*pValue = maAnyMap[ aPropertyName ];
198 
199 		ppEntries++;
200 		pValue++;
201 	}
202 }
203 
204 // XInterface
205 
206 Any SAL_CALL GenericPropertySet::queryInterface( const Type & rType )
207 	throw( RuntimeException )
208 {
209 	return OWeakAggObject::queryInterface( rType );
210 }
211 
212 Any SAL_CALL GenericPropertySet::queryAggregation( const Type & rType )
213 	throw(RuntimeException)
214 {
215 	Any aAny;
216 
217 	if( rType == ::getCppuType((const Reference< XServiceInfo >*)0) )
218 		aAny <<= Reference< XServiceInfo >(this);
219 	else if( rType == ::getCppuType((const Reference< XTypeProvider >*)0) )
220 		aAny <<= Reference< XTypeProvider >(this);
221 	else if( rType == ::getCppuType((const Reference< XPropertySet >*)0) )
222 		aAny <<= Reference< XPropertySet >(this);
223 	else if( rType == ::getCppuType((const Reference< XMultiPropertySet >*)0) )
224 		aAny <<= Reference< XMultiPropertySet >(this);
225 	else
226 		aAny <<= OWeakAggObject::queryAggregation( rType );
227 
228 	return aAny;
229 }
230 
231 void SAL_CALL GenericPropertySet::acquire() throw()
232 {
233 	OWeakAggObject::acquire();
234 }
235 
236 void SAL_CALL GenericPropertySet::release() throw()
237 {
238 	OWeakAggObject::release();
239 }
240 
241 uno::Sequence< uno::Type > SAL_CALL GenericPropertySet::getTypes()
242 	throw (uno::RuntimeException)
243 {
244 	uno::Sequence< uno::Type > aTypes( 5 );
245 	uno::Type* pTypes = aTypes.getArray();
246 
247 	*pTypes++ = ::getCppuType((const uno::Reference< XAggregation>*)0);
248 	*pTypes++ = ::getCppuType((const uno::Reference< XServiceInfo>*)0);
249 	*pTypes++ = ::getCppuType((const uno::Reference< XTypeProvider>*)0);
250 	*pTypes++ = ::getCppuType((const uno::Reference< XPropertySet>*)0);
251 	*pTypes++ = ::getCppuType((const uno::Reference< XMultiPropertySet>*)0);
252 
253 	return aTypes;
254 }
255 
256 uno::Sequence< sal_Int8 > SAL_CALL GenericPropertySet::getImplementationId()
257 	throw (uno::RuntimeException)
258 {
259 	MutexGuard aGuard( maMutex );
260 
261 	static uno::Sequence< sal_Int8 > aId;
262 	if( aId.getLength() == 0 )
263 	{
264 		aId.realloc( 16 );
265 		rtl_createUuid( (sal_uInt8 *)aId.getArray(), 0, sal_True );
266 	}
267 	return aId;
268 }
269 
270 // XServiceInfo
271 
272 sal_Bool SAL_CALL GenericPropertySet::supportsService( const  OUString& ServiceName ) throw(RuntimeException)
273 {
274     Sequence< OUString > aSNL( getSupportedServiceNames() );
275     const OUString * pArray = aSNL.getConstArray();
276 
277     for( sal_Int32 i = 0; i < aSNL.getLength(); ++i )
278         if( pArray[i] == ServiceName )
279             return sal_True;
280 
281     return sal_False;
282 }
283 
284 OUString SAL_CALL GenericPropertySet::getImplementationName() throw( RuntimeException )
285 {
286 	return OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.comphelper.GenericPropertySet") );
287 }
288 
289 Sequence< OUString > SAL_CALL GenericPropertySet::getSupportedServiceNames(  )
290 	throw( RuntimeException )
291 {
292     Sequence< OUString > aSNS( 1 );
293     aSNS.getArray()[0] = OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.beans.XPropertySet" ));
294     return aSNS;
295 }
296 
297 ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > comphelper::GenericPropertySet_CreateInstance( comphelper::PropertySetInfo* pInfo )
298 {
299 	return (XPropertySet*)new GenericPropertySet( pInfo );
300 }
301 
302