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_forms.hxx"
26 
27 #include "propertysetbase.hxx"
28 
29 #include <cppuhelper/typeprovider.hxx>  // for getImplementationId()
30 
31 #include <com/sun/star/beans/XPropertySet.hpp>
32 #include <com/sun/star/beans/XMultiPropertySet.hpp>
33 #include <com/sun/star/beans/XPropertyState.hpp>
34 #include <com/sun/star/uno/Reference.hxx>
35 #include <tools/debug.hxx>
36 
37 #include <vector>
38 
39 using com::sun::star::uno::Any;
40 using com::sun::star::uno::Type;
41 using com::sun::star::uno::Sequence;
42 using com::sun::star::uno::Reference;
43 using com::sun::star::uno::Exception;
44 using com::sun::star::uno::RuntimeException;
45 using com::sun::star::lang::IllegalArgumentException;
46 using com::sun::star::beans::Property;
47 using com::sun::star::beans::XPropertySetInfo;
48 
acquire()49 oslInterlockedCount SAL_CALL PropertyAccessorBase::acquire()
50 {
51     return ++m_refCount;
52 }
53 
release()54 oslInterlockedCount SAL_CALL PropertyAccessorBase::release()
55 {
56     if ( --m_refCount == 0 )
57     {
58         delete this;
59         return 0;
60     }
61     return m_refCount;
62 }
63 
PropertySetBase()64 PropertySetBase::PropertySetBase( )
65     :m_pProperties( NULL )
66 {
67 }
68 
~PropertySetBase()69 PropertySetBase::~PropertySetBase( )
70 {
71     DELETEZ( m_pProperties );
72 }
73 
getInfoHelper()74 cppu::IPropertyArrayHelper& SAL_CALL PropertySetBase::getInfoHelper()
75 {
76     if ( !m_pProperties )
77     {
78         DBG_ASSERT( !m_aProperties.empty(), "PropertySetBase::getInfoHelper: no registered properties!" );
79         m_pProperties = new cppu::OPropertyArrayHelper( &m_aProperties[0], m_aProperties.size(), sal_False );
80     }
81     return *m_pProperties;
82 }
83 
getPropertySetInfo()84 Reference< XPropertySetInfo > SAL_CALL PropertySetBase::getPropertySetInfo(  ) throw(RuntimeException)
85 {
86 	return cppu::OPropertySetHelper::createPropertySetInfo( getInfoHelper() );
87 }
88 
registerProperty(const Property & rProperty,const::rtl::Reference<PropertyAccessorBase> & rAccessor)89 void PropertySetBase::registerProperty( const Property& rProperty,
90     const ::rtl::Reference< PropertyAccessorBase >& rAccessor )
91 {
92     DBG_ASSERT( rAccessor.get(), "PropertySetBase::registerProperty: invalid property accessor, this will crash!" );
93     m_aAccessors.insert( PropertyAccessors::value_type( rProperty.Handle, rAccessor ) );
94 
95     DBG_ASSERT( ( rAccessor->isWriteable() == true )
96                 == ( ( rProperty.Attributes & com::sun::star::beans::PropertyAttribute::READONLY ) == 0 ),
97         "PropertySetBase::registerProperty: inconsistence!" );
98 
99     m_aProperties.push_back( rProperty );
100 }
101 
notifyAndCachePropertyValue(sal_Int32 nHandle)102 void PropertySetBase::notifyAndCachePropertyValue( sal_Int32 nHandle )
103 {
104     ::osl::ClearableMutexGuard aGuard( GetMutex() );
105 
106     PropertyValueCache::iterator aPos = m_aCache.find( nHandle );
107     if ( aPos == m_aCache.end() )
108     {   // method has never before been invoked for this property
109         try
110         {
111             // determine the type of this property
112             ::cppu::IPropertyArrayHelper& rPropertyMetaData = getInfoHelper();
113             ::rtl::OUString sPropName;
114             OSL_VERIFY( rPropertyMetaData.fillPropertyMembersByHandle( &sPropName, NULL, nHandle ) );
115             Property aProperty = rPropertyMetaData.getPropertyByName( sPropName );
116             // default construct a value of this type
117             Any aEmptyValue( NULL, aProperty.Type );
118             // insert into the cache
119             aPos = m_aCache.insert( PropertyValueCache::value_type( nHandle, aEmptyValue ) ).first;
120         }
121         catch( Exception& )
122         {
123             DBG_ERROR( "PropertySetBase::notifyAndCachePropertyValue: this is not expected to fail!" );
124         }
125     }
126     Any aOldValue = aPos->second;
127     // determine the current value
128     Any aNewValue;
129     getFastPropertyValue( aNewValue, nHandle );
130     // remember the old value
131     aPos->second = aNewValue;
132 
133     aGuard.clear();
134     if ( aNewValue != aOldValue )
135         firePropertyChange( nHandle, aNewValue, aOldValue );
136 }
137 
initializePropertyValueCache(sal_Int32 nHandle)138 void PropertySetBase::initializePropertyValueCache( sal_Int32 nHandle )
139 {
140     Any aCurrentValue;
141     getFastPropertyValue( aCurrentValue, nHandle );
142 
143 #if OSL_DEBUG_LEVEL > 0
144     ::std::pair< PropertyValueCache::iterator, bool > aInsertResult =
145 #endif
146     m_aCache.insert( PropertyValueCache::value_type( nHandle, aCurrentValue ) );
147     DBG_ASSERT( aInsertResult.second, "PropertySetBase::initializePropertyValueCache: already cached a value for this property!" );
148 }
149 
locatePropertyHandler(sal_Int32 nHandle) const150 PropertyAccessorBase& PropertySetBase::locatePropertyHandler( sal_Int32 nHandle ) const
151 {
152     PropertyAccessors::const_iterator aPropertyPos = m_aAccessors.find( nHandle );
153     DBG_ASSERT( aPropertyPos != m_aAccessors.end() && aPropertyPos->second.get(),
154         "PropertySetBase::locatePropertyHandler: accessor map is corrupted!" );
155         // neither should this be called for handles where there is no accessor, nor should a
156         // NULL accssor be in the map
157     return *aPropertyPos->second;
158 }
159 
convertFastPropertyValue(Any & rConvertedValue,Any & rOldValue,sal_Int32 nHandle,const Any & rValue)160 sal_Bool SAL_CALL PropertySetBase::convertFastPropertyValue( Any& rConvertedValue, Any& rOldValue, sal_Int32 nHandle,
161 	const Any& rValue )
162     throw (IllegalArgumentException)
163 {
164     PropertyAccessorBase& rAccessor = locatePropertyHandler( nHandle );
165     if ( !rAccessor.approveValue( rValue ) )
166         throw IllegalArgumentException( ::rtl::OUString(), *this, 0 );
167 
168     rAccessor.getValue( rOldValue );
169     if ( rOldValue != rValue )
170     {
171         rConvertedValue = rValue;   // no conversion at all
172         return sal_True;
173     }
174     return sal_False;
175 }
176 
setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any & rValue)177 void SAL_CALL PropertySetBase::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
178     throw (Exception)
179 {
180     PropertyAccessorBase& rAccessor = locatePropertyHandler( nHandle );
181     rAccessor.setValue( rValue );
182 }
183 
getFastPropertyValue(Any & rValue,sal_Int32 nHandle) const184 void SAL_CALL PropertySetBase::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
185 {
186     PropertyAccessorBase& rAccessor = locatePropertyHandler( nHandle );
187     rAccessor.getValue( rValue );
188 }
189