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/propertystatecontainer.hxx"
31 #include <rtl/ustrbuf.hxx>
32 
33 //.........................................................................
34 namespace comphelper
35 {
36 //.........................................................................
37 
38 	using namespace ::com::sun::star::uno;
39 	using namespace ::com::sun::star::beans;
40 	using namespace ::com::sun::star::lang;
41 
42 	namespace
43 	{
44 		static ::rtl::OUString lcl_getUnknownPropertyErrorMessage( const ::rtl::OUString& _rPropertyName )
45 		{
46 			// TODO: perhaps it's time to think about resources in the comphelper module?
47 			// Would be nice to have localized exception strings (a simply resource file containing
48 			// strings only would suffice, and could be realized with an UNO service, so we do not
49 			// need the dependency to the Tools project)
50 			::rtl::OUStringBuffer sMessage;
51 			sMessage.appendAscii( "The property \"" );
52 			sMessage.append( _rPropertyName );
53 			sMessage.appendAscii( "\" is unknown." );
54 			return sMessage.makeStringAndClear();
55 		}
56 	}
57 
58 	//=====================================================================
59 	//= OPropertyStateContainer
60 	//=====================================================================
61 	//---------------------------------------------------------------------
62 	OPropertyStateContainer::OPropertyStateContainer( ::cppu::OBroadcastHelper&	_rBHelper )
63 		:OPropertyContainer( _rBHelper )
64 	{
65 	}
66 
67 	//--------------------------------------------------------------------
68 	Any SAL_CALL OPropertyStateContainer::queryInterface( const Type& _rType ) throw (RuntimeException)
69 	{
70 		Any aReturn = OPropertyContainer::queryInterface( _rType );
71 		if ( !aReturn.hasValue() )
72 			aReturn = OPropertyStateContainer_TBase::queryInterface( _rType );
73 		return aReturn;
74 	}
75 
76 	//--------------------------------------------------------------------
77 	IMPLEMENT_FORWARD_XTYPEPROVIDER2( OPropertyStateContainer, OPropertyContainer, OPropertyStateContainer_TBase )
78 
79 	//--------------------------------------------------------------------
80 	sal_Int32 OPropertyStateContainer::getHandleForName( const ::rtl::OUString& _rPropertyName ) SAL_THROW( ( UnknownPropertyException ) )
81 	{
82 		// look up the handle for the name
83 		::cppu::IPropertyArrayHelper& rPH = getInfoHelper();
84 		sal_Int32 nHandle = rPH.getHandleByName( _rPropertyName );
85 
86 		if ( -1 == nHandle )
87 			throw  UnknownPropertyException( lcl_getUnknownPropertyErrorMessage( _rPropertyName ), static_cast< XPropertyState* >( this ) );
88 
89 		return nHandle;
90 	}
91 
92 	//--------------------------------------------------------------------
93 	PropertyState SAL_CALL OPropertyStateContainer::getPropertyState( const ::rtl::OUString& _rPropertyName ) throw (UnknownPropertyException, RuntimeException)
94 	{
95 		return getPropertyStateByHandle( getHandleForName( _rPropertyName ) );
96 	}
97 
98 	//--------------------------------------------------------------------
99 	Sequence< PropertyState > SAL_CALL OPropertyStateContainer::getPropertyStates( const Sequence< ::rtl::OUString >& _rPropertyNames ) throw (UnknownPropertyException, RuntimeException)
100 	{
101 		sal_Int32 nProperties = _rPropertyNames.getLength();
102 		Sequence< PropertyState> aStates( nProperties );
103 		if ( !nProperties )
104 			return aStates;
105 
106 #ifdef _DEBUG
107 		// precondition: property sequence is sorted (the algorythm below relies on this)
108 		{
109 			const ::rtl::OUString* pNames = _rPropertyNames.getConstArray();
110 			const ::rtl::OUString* pNamesCompare = pNames + 1;
111 			const ::rtl::OUString* pNamesEnd = _rPropertyNames.getConstArray() + _rPropertyNames.getLength();
112 			for ( ; pNamesCompare != pNamesEnd; ++pNames, ++pNamesCompare )
113 				OSL_PRECOND( pNames->compareTo( *pNamesCompare ) < 0,
114 					"OPropertyStateContainer::getPropertyStates: property sequence not sorted!" );
115 		}
116 #endif
117 
118 		const ::rtl::OUString* pLookup = _rPropertyNames.getConstArray();
119 		const ::rtl::OUString* pLookupEnd = pLookup + nProperties;
120 		PropertyState* pStates = aStates.getArray();
121 
122 		cppu::IPropertyArrayHelper& rHelper = getInfoHelper();
123 		Sequence< Property> aAllProperties	= rHelper.getProperties();
124 		sal_Int32 nAllProperties			= aAllProperties.getLength();
125 		const  Property* pAllProperties		= aAllProperties.getConstArray();
126 		const  Property* pAllPropertiesEnd	= pAllProperties + nAllProperties;
127 
128 		osl::MutexGuard aGuard( rBHelper.rMutex );
129 		for ( ; ( pAllProperties != pAllPropertiesEnd ) && ( pLookup != pLookupEnd ); ++pAllProperties )
130 		{
131 #ifdef _DEBUG
132 			if ( pAllProperties < pAllPropertiesEnd - 1 )
133 				OSL_ENSURE( pAllProperties->Name.compareTo( (pAllProperties + 1)->Name ) < 0,
134 					"OPropertyStateContainer::getPropertyStates: all-properties not sorted!" );
135 #endif
136 			if ( pAllProperties->Name.equals( *pLookup ) )
137 			{
138 				*pStates++ = getPropertyState( *pLookup );
139 				++pLookup;
140 			}
141 		}
142 
143 		if ( pLookup != pLookupEnd )
144 			// we run out of properties from the IPropertyArrayHelper, but still have properties to lookup
145 			// -> we were asked for a nonexistent property
146 			throw UnknownPropertyException( lcl_getUnknownPropertyErrorMessage( *pLookup ), static_cast< XPropertyState* >( this ) );
147 
148 		return aStates;
149 	}
150 
151 	//--------------------------------------------------------------------
152 	void SAL_CALL OPropertyStateContainer::setPropertyToDefault( const ::rtl::OUString& _rPropertyName ) throw (UnknownPropertyException, RuntimeException)
153 	{
154 		setPropertyToDefaultByHandle( getHandleForName( _rPropertyName ) );
155 	}
156 
157 	//--------------------------------------------------------------------
158 	Any SAL_CALL OPropertyStateContainer::getPropertyDefault( const ::rtl::OUString& _rPropertyName ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
159 	{
160         Any aDefault;
161 		getPropertyDefaultByHandle( getHandleForName( _rPropertyName ), aDefault );
162         return aDefault;
163 	}
164 
165 	//--------------------------------------------------------------------
166 	PropertyState OPropertyStateContainer::getPropertyStateByHandle( sal_Int32 _nHandle )
167 	{
168 		// simply compare the current and the default value
169 		Any aCurrentValue; getFastPropertyValue( aCurrentValue, _nHandle );
170 		Any aDefaultValue; getPropertyDefaultByHandle( _nHandle, aDefaultValue );
171 
172 		sal_Bool bEqual = uno_type_equalData(
173 				const_cast< void* >( aCurrentValue.getValue() ), aCurrentValue.getValueType().getTypeLibType(),
174 				const_cast< void* >( aDefaultValue.getValue() ), aDefaultValue.getValueType().getTypeLibType(),
175 				reinterpret_cast< uno_QueryInterfaceFunc >(cpp_queryInterface),
176                 reinterpret_cast< uno_ReleaseFunc >(cpp_release)
177 			);
178 		if ( bEqual )
179 			return PropertyState_DEFAULT_VALUE;
180 		else
181 			return PropertyState_DIRECT_VALUE;
182 	}
183 
184 	//--------------------------------------------------------------------
185 	void OPropertyStateContainer::setPropertyToDefaultByHandle( sal_Int32 _nHandle )
186 	{
187         Any aDefault;
188         getPropertyDefaultByHandle( _nHandle, aDefault );
189 		setFastPropertyValue( _nHandle, aDefault );
190 	}
191 
192 //.........................................................................
193 }	// namespace comphelper
194 //.........................................................................
195 
196 #ifdef FS_PRIV_DEBUG
197 #define STATECONTAINER_TEST
198 #endif
199 
200 #ifdef STATECONTAINER_TEST
201 #include <com/sun/star/beans/PropertyAttribute.hpp>
202 #include <comphelper/proparrhlp.hxx>
203 #include <comphelper/broadcasthelper.hxx>
204 
205 //.........................................................................
206 namespace comphelper
207 {
208 //.........................................................................
209 
210 	using namespace ::com::sun::star::uno;
211 	using namespace ::com::sun::star::beans;
212 
213 	//=====================================================================
214 	//= Test - compiler test
215 	//=====================================================================
216 	typedef ::cppu::OWeakAggObject	Test_RefCountBase;
217 	class Test	:public OMutexAndBroadcastHelper
218 				,public OPropertyStateContainer
219 				,public OPropertyArrayUsageHelper< Test >
220 				,public Test_RefCountBase
221 	{
222 	private:
223 		::rtl::OUString			m_sStringProperty;
224 		Reference< XInterface >	m_xInterfaceProperty;
225 		Any						m_aMayBeVoidProperty;
226 
227 	protected:
228 		Test( );
229 
230 		DECLARE_XINTERFACE( )
231 
232 	public:
233 		static Test* Create( );
234 
235 	protected:
236 		virtual Reference< XPropertySetInfo > SAL_CALL getPropertySetInfo(  ) throw(RuntimeException);
237 		virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper();
238 		virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const;
239 
240 	protected:
241 		// OPropertyStateContainer overridables
242 		virtual void getPropertyDefaultByHandle( sal_Int32 _nHandle, Any& _rDefault ) const;
243 	};
244 
245 	//---------------------------------------------------------------------
246 	Test::Test( )
247 		:OPropertyStateContainer( GetBroadcastHelper() )
248 	{
249 		registerProperty(
250 			::rtl::OUString::createFromAscii( "StringProperty" ),
251 			1,
252 			PropertyAttribute::BOUND,
253 			&m_sStringProperty,
254 			::getCppuType( &m_sStringProperty )
255 		);
256 
257 		registerProperty(
258 			::rtl::OUString::createFromAscii( "InterfaceProperty" ),
259 			2,
260 			PropertyAttribute::BOUND,
261 			&m_xInterfaceProperty,
262 			::getCppuType( &m_xInterfaceProperty )
263 		);
264 
265 		registerMayBeVoidProperty(
266 			::rtl::OUString::createFromAscii( "IntProperty" ),
267 			3,
268 			PropertyAttribute::BOUND,
269 			&m_aMayBeVoidProperty,
270 			::getCppuType( static_cast< sal_Int32* >( NULL ) )
271 		);
272 
273 		registerPropertyNoMember(
274 			::rtl::OUString::createFromAscii( "OtherInterfaceProperty" ),
275 			4,
276 			PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID,
277 			::getCppuType( static_cast< Reference< XInterface >* >( NULL ) ),
278 			NULL
279 		);
280 	}
281 
282 	//---------------------------------------------------------------------
283 	IMPLEMENT_FORWARD_XINTERFACE2( Test, Test_RefCountBase, OPropertyStateContainer )
284 
285 	//---------------------------------------------------------------------
286 	void Test::getPropertyDefaultByHandle( sal_Int32 _nHandle, Any& _rDefault ) const
287 	{
288 		switch ( _nHandle )
289 		{
290 			case 1:
291 				_rDefault = makeAny( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StringPropertyDefault" ) ) );
292 				break;
293 			case 2:
294 				_rDefault = makeAny( Reference< XInterface >( ) );
295 				break;
296 			case 3:
297 				// void
298 				break;
299 			case 4:
300 				_rDefault = makeAny( Reference< XInterface >( ) );
301 				break;
302 			default:
303 				OSL_ENSURE( sal_False, "Test::getPropertyDefaultByHandle: invalid handle!" );
304 		}
305 	}
306 
307 	//---------------------------------------------------------------------
308 	Reference< XPropertySetInfo > SAL_CALL Test::getPropertySetInfo(  ) throw(RuntimeException)
309 	{
310 		return createPropertySetInfo( getInfoHelper() );
311 	}
312 
313 	//---------------------------------------------------------------------
314 	::cppu::IPropertyArrayHelper& SAL_CALL Test::getInfoHelper()
315 	{
316 		return *getArrayHelper();
317 	}
318 
319 	//---------------------------------------------------------------------
320 	::cppu::IPropertyArrayHelper* Test::createArrayHelper( ) const
321 	{
322 		Sequence< Property > aProps;
323 		describeProperties( aProps );
324 		return new ::cppu::OPropertyArrayHelper( aProps );
325 	}
326 
327 	//---------------------------------------------------------------------
328 	Test* Test::Create( )
329 	{
330 		Test* pInstance = new Test;
331 		return pInstance;
332 	}
333 
334 //.........................................................................
335 }	// namespace comphelper
336 //.........................................................................
337 
338 #endif
339 
340