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