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 #include "propertybaghelper.hxx" 27 28 #include "property.hxx" 29 30 /** === begin UNO includes === **/ 31 #include <com/sun/star/lang/DisposedException.hpp> 32 #include <com/sun/star/beans/PropertyExistException.hpp> 33 #include <com/sun/star/beans/XMultiPropertySet.hpp> 34 #include <com/sun/star/beans/NotRemoveableException.hpp> 35 #include <com/sun/star/beans/UnknownPropertyException.hpp> 36 /** === end UNO includes === **/ 37 38 #include <tools/diagnose_ex.h> 39 40 #include <comphelper/sequence.hxx> 41 #include <rtl/logfile.hxx> 42 #include "rtl/instance.hxx" 43 44 45 #define NEW_HANDLE_BASE 10000 46 47 //........................................................................ 48 namespace frm 49 { 50 //........................................................................ 51 52 /** === begin UNO using === **/ 53 using ::com::sun::star::lang::DisposedException; 54 using ::com::sun::star::uno::Sequence; 55 using ::com::sun::star::beans::Property; 56 using ::com::sun::star::uno::Any; 57 using ::com::sun::star::beans::PropertyExistException; 58 using ::com::sun::star::beans::PropertyValue; 59 using ::com::sun::star::uno::Reference; 60 using ::com::sun::star::uno::UNO_QUERY_THROW; 61 using ::com::sun::star::beans::XMultiPropertySet; 62 using ::com::sun::star::beans::XPropertySetInfo; 63 using ::com::sun::star::uno::RuntimeException; 64 using ::com::sun::star::uno::Exception; 65 using ::com::sun::star::beans::NotRemoveableException; 66 using ::com::sun::star::beans::UnknownPropertyException; 67 /** === end UNO using === **/ 68 namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute; 69 70 //==================================================================== 71 //= helper 72 //==================================================================== 73 namespace 74 { 75 //---------------------------------------------------------------- lcl_getPropertyInfos()76 static ::comphelper::IPropertyInfoService& lcl_getPropertyInfos() 77 { 78 static ConcreteInfoService s_aPropInfos; 79 return s_aPropInfos; 80 } 81 } 82 83 //==================================================================== 84 //= PropertyBagHelper 85 //==================================================================== 86 //-------------------------------------------------------------------- PropertyBagHelper(IPropertyBagHelperContext & _rContext)87 PropertyBagHelper::PropertyBagHelper( IPropertyBagHelperContext& _rContext ) 88 :m_rContext( _rContext ) 89 ,m_pPropertyArrayHelper( NULL ) 90 ,m_bDisposed( false ) 91 { 92 // RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "forms", "dev@dba.openoffice.org", "PropertyBagHelper::PropertyBagHelper" ); 93 } 94 95 //-------------------------------------------------------------------- ~PropertyBagHelper()96 PropertyBagHelper::~PropertyBagHelper() 97 { 98 delete m_pPropertyArrayHelper, m_pPropertyArrayHelper = NULL; 99 } 100 101 //-------------------------------------------------------------------- dispose()102 void PropertyBagHelper::dispose() 103 { 104 // RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "forms", "dev@dba.openoffice.org", "PropertyBagHelper::dispose" ); 105 m_bDisposed = true; 106 } 107 108 //-------------------------------------------------------------------- impl_nts_checkDisposed_throw() const109 void PropertyBagHelper::impl_nts_checkDisposed_throw() const 110 { 111 // RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "forms", "dev@dba.openoffice.org", "PropertyBagHelper::impl_nts_checkDisposed_throw" ); 112 if ( m_bDisposed ) 113 throw DisposedException(); 114 } 115 116 //-------------------------------------------------------------------- impl_nts_invalidatePropertySetInfo()117 void PropertyBagHelper::impl_nts_invalidatePropertySetInfo() 118 { 119 // RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "forms", "dev@dba.openoffice.org", "PropertyBagHelper::impl_nts_invalidatePropertySetInfo" ); 120 delete m_pPropertyArrayHelper, m_pPropertyArrayHelper = NULL; 121 } 122 123 //-------------------------------------------------------------------- impl_findFreeHandle(const::rtl::OUString & _rPropertyName)124 sal_Int32 PropertyBagHelper::impl_findFreeHandle( const ::rtl::OUString& _rPropertyName ) 125 { 126 // RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "forms", "dev@dba.openoffice.org", "PropertyBagHelper::impl_findFreeHandle" ); 127 ::comphelper::OPropertyArrayAggregationHelper& rPropInfo( impl_ts_getArrayHelper() ); 128 129 // check the preferred handle 130 sal_Int32 nHandle = lcl_getPropertyInfos().getPreferedPropertyId( _rPropertyName ); 131 if ( ( nHandle != -1 ) && rPropInfo.fillPropertyMembersByHandle( NULL, NULL, nHandle ) ) 132 nHandle = -1; 133 134 // search a free handle in <math>F_1009</math> 135 if ( nHandle == -1 ) 136 { 137 sal_Int32 nPrime = 1009; 138 sal_Int32 nFactor = 11; 139 sal_Int32 nNum = nFactor; 140 while ( nNum != 1 ) 141 { 142 if ( !rPropInfo.fillPropertyMembersByHandle( NULL, NULL, nNum + NEW_HANDLE_BASE ) ) 143 { 144 // handle not used, yet 145 nHandle = nNum + NEW_HANDLE_BASE; 146 break; 147 } 148 nNum = ( nNum * nFactor ) % nPrime; 149 } 150 } 151 152 // search a free handle greater NEW_HANDLE_BASE 153 if ( nHandle == -1 ) 154 { 155 nHandle = NEW_HANDLE_BASE + 1009; 156 while ( rPropInfo.fillPropertyMembersByHandle( NULL, NULL, nHandle ) ) 157 ++nHandle; 158 } 159 160 return nHandle; 161 } 162 163 //-------------------------------------------------------------------- impl_ts_getArrayHelper() const164 ::comphelper::OPropertyArrayAggregationHelper& PropertyBagHelper::impl_ts_getArrayHelper() const 165 { 166 // RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "forms", "dev@dba.openoffice.org", "PropertyBagHelper::impl_ts_getArrayHelper" ); 167 //::osl::MutexGuard aGuard( m_rContext.getMutex() ); 168 OPropertyArrayAggregationHelper* p = m_pPropertyArrayHelper; 169 if ( !p ) 170 { 171 ::osl::MutexGuard aGuard( m_rContext.getMutex() ); 172 p = m_pPropertyArrayHelper; 173 if ( !p ) 174 { 175 // our own fixed and our aggregate's properties 176 Sequence< Property > aFixedProps; 177 Sequence< Property > aAggregateProps; 178 m_rContext.describeFixedAndAggregateProperties( aFixedProps, aAggregateProps ); 179 180 // our dynamic properties 181 Sequence< Property > aDynamicProps; 182 m_aDynamicProperties.describeProperties( aDynamicProps ); 183 184 Sequence< Property > aOwnProps( 185 ::comphelper::concatSequences( aFixedProps, aDynamicProps ) ); 186 187 p = new OPropertyArrayAggregationHelper( aOwnProps, aAggregateProps, &lcl_getPropertyInfos(), NEW_HANDLE_BASE ); 188 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); 189 const_cast< PropertyBagHelper* >( this )->m_pPropertyArrayHelper = p; 190 } 191 } // if ( !p ) 192 else 193 { 194 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); 195 } 196 return *p; 197 } 198 199 //-------------------------------------------------------------------- addProperty(const::rtl::OUString & _rName,::sal_Int16 _nAttributes,const Any & _rInitialValue)200 void PropertyBagHelper::addProperty( const ::rtl::OUString& _rName, ::sal_Int16 _nAttributes, const Any& _rInitialValue ) 201 { 202 // RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "forms", "dev@dba.openoffice.org", "PropertyBagHelper::addProperty" ); 203 ::osl::MutexGuard aGuard( m_rContext.getMutex() ); 204 impl_nts_checkDisposed_throw(); 205 206 //---------------------------------------------- 207 // check name sanity 208 ::comphelper::OPropertyArrayAggregationHelper& aPropInfo( impl_ts_getArrayHelper() ); 209 if ( aPropInfo.hasPropertyByName( _rName ) ) 210 throw PropertyExistException( _rName, m_rContext.getPropertiesInterface() ); 211 212 //---------------------------------------------- 213 // normalize the REMOVEABLE attribute - the FormComponent service 214 // requires that all dynamic properties are REMOVEABLE 215 _nAttributes |= PropertyAttribute::REMOVEABLE; 216 217 //---------------------------------------------- 218 // find a free handle 219 sal_Int32 nHandle = impl_findFreeHandle( _rName ); 220 221 //---------------------------------------------- 222 // register the property, and invalidate our property meta data 223 m_aDynamicProperties.addProperty( _rName, nHandle, _nAttributes, _rInitialValue ); 224 impl_nts_invalidatePropertySetInfo(); 225 } 226 227 //-------------------------------------------------------------------- removeProperty(const::rtl::OUString & _rName)228 void PropertyBagHelper::removeProperty( const ::rtl::OUString& _rName ) 229 { 230 // RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "forms", "dev@dba.openoffice.org", "PropertyBagHelper::removeProperty" ); 231 ::osl::MutexGuard aGuard( m_rContext.getMutex() ); 232 impl_nts_checkDisposed_throw(); 233 234 // check whether it's removeable at all 235 Reference< XMultiPropertySet > xMe( m_rContext.getPropertiesInterface(), UNO_QUERY_THROW ); 236 Reference< XPropertySetInfo > xPSI( xMe->getPropertySetInfo(), UNO_QUERY_THROW ); 237 Property aProperty( xPSI->getPropertyByName( _rName ) ); 238 if ( ( aProperty.Attributes & PropertyAttribute::REMOVEABLE ) == 0 ) 239 throw NotRemoveableException( _rName, xMe ); 240 241 m_aDynamicProperties.removeProperty( _rName ); 242 impl_nts_invalidatePropertySetInfo(); 243 } 244 245 //-------------------------------------------------------------------- 246 namespace 247 { 248 //---------------------------------------------------------------- 249 struct SelectNameOfProperty : public ::std::unary_function< Property, ::rtl::OUString > 250 { operator ()frm::__anon194e87560211::SelectNameOfProperty251 const ::rtl::OUString& operator()( const Property& _rProp ) const { return _rProp.Name; } 252 }; 253 254 //---------------------------------------------------------------- 255 struct SelectNameOfPropertyValue : public ::std::unary_function< PropertyValue, ::rtl::OUString > 256 { operator ()frm::__anon194e87560211::SelectNameOfPropertyValue257 const ::rtl::OUString& operator()( const PropertyValue& _rProp ) const { return _rProp.Name; } 258 }; 259 260 //---------------------------------------------------------------- 261 struct SelectValueOfPropertyValue : public ::std::unary_function< PropertyValue, Any > 262 { operator ()frm::__anon194e87560211::SelectValueOfPropertyValue263 const Any& operator()( const PropertyValue& _rProp ) const { return _rProp.Value; } 264 }; 265 266 //---------------------------------------------------------------- 267 struct PropertyValueLessByName : public ::std::binary_function< PropertyValue, PropertyValue, bool > 268 { operator ()frm::__anon194e87560211::PropertyValueLessByName269 bool operator()( const PropertyValue& _lhs, const PropertyValue _rhs ) const 270 { 271 return _lhs.Name < _rhs.Name; 272 } 273 }; 274 } 275 276 //-------------------------------------------------------------------- getPropertyValues()277 Sequence< PropertyValue > PropertyBagHelper::getPropertyValues() 278 { 279 // RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "forms", "dev@dba.openoffice.org", "PropertyBagHelper::getPropertyValues" ); 280 ::osl::MutexGuard aGuard( m_rContext.getMutex() ); 281 impl_nts_checkDisposed_throw(); 282 283 Reference< XMultiPropertySet > xMe( m_rContext.getPropertiesInterface(), UNO_QUERY_THROW ); 284 Reference< XPropertySetInfo > xPSI( xMe->getPropertySetInfo(), UNO_QUERY_THROW ); 285 286 Sequence< Property > aProperties( xPSI->getProperties() ); 287 Sequence< ::rtl::OUString > aPropertyNames( aProperties.getLength() ); 288 ::std::transform( aProperties.getConstArray(), aProperties.getConstArray() + aProperties.getLength(), 289 aPropertyNames.getArray(), SelectNameOfProperty() ); 290 291 Sequence< Any > aValues; 292 try 293 { 294 aValues = xMe->getPropertyValues( aPropertyNames ); 295 296 if ( aValues.getLength() != aPropertyNames.getLength() ) 297 throw RuntimeException(); 298 } 299 catch( const RuntimeException& ) { throw; } 300 catch( const Exception& ) 301 { 302 DBG_UNHANDLED_EXCEPTION(); 303 } 304 Sequence< PropertyValue > aPropertyValues( aValues.getLength() ); 305 PropertyValue* pPropertyValue = aPropertyValues.getArray(); 306 307 const ::rtl::OUString* pName = aPropertyNames.getConstArray(); 308 const ::rtl::OUString* pNameEnd = aPropertyNames.getConstArray() + aPropertyNames.getLength(); 309 const Any* pValue = aValues.getConstArray(); 310 for ( ; pName != pNameEnd; ++pName, ++pValue, ++pPropertyValue ) 311 { 312 pPropertyValue->Name = *pName; 313 pPropertyValue->Value = *pValue; 314 } 315 316 return aPropertyValues; 317 } 318 319 //-------------------------------------------------------------------- setPropertyValues(const Sequence<PropertyValue> & _rProps)320 void PropertyBagHelper::setPropertyValues( const Sequence< PropertyValue >& _rProps ) 321 { 322 // RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "forms", "dev@dba.openoffice.org", "PropertyBagHelper::setPropertyValues" ); 323 ::osl::ClearableMutexGuard aGuard( m_rContext.getMutex() ); 324 impl_nts_checkDisposed_throw(); 325 326 sal_Int32 nPropertyValues = _rProps.getLength(); 327 328 // XMultiPropertySet::setPropertyValues expects its arguments to be sorted by name 329 // while XPropertyAccess::setPropertyValues doesn't. So first of all, sort. 330 Sequence< PropertyValue > aSortedProps( _rProps ); 331 ::std::sort( aSortedProps.getArray(), aSortedProps.getArray() + nPropertyValues, PropertyValueLessByName() ); 332 333 // also, XPropertyAccess::setPropertyValues is expected to throw an UnknownPropertyException 334 // for unsupported properties, while XMultiPropertySet::setPropertyValues is expected to ignore 335 // those. So, check for unsupported properties first. 336 ::comphelper::OPropertyArrayAggregationHelper& rArrayHelper( impl_ts_getArrayHelper() ); 337 for ( const PropertyValue* pProperties = aSortedProps.getConstArray(); 338 pProperties != aSortedProps.getConstArray() + nPropertyValues; 339 ++pProperties 340 ) 341 { 342 if ( !rArrayHelper.hasPropertyByName( pProperties->Name ) ) 343 throw UnknownPropertyException( pProperties->Name, m_rContext.getPropertiesInterface() ); 344 } 345 346 // Now finally split into a Name and a Value sequence, and forward to 347 // XMultiPropertySet::setPropertyValues 348 Sequence< ::rtl::OUString > aNames( nPropertyValues ); 349 ::std::transform( aSortedProps.getConstArray(), aSortedProps.getConstArray() + nPropertyValues, 350 aNames.getArray(), SelectNameOfPropertyValue() ); 351 352 Sequence< Any > aValues( nPropertyValues ); 353 ::std::transform( aSortedProps.getConstArray(), aSortedProps.getConstArray() + nPropertyValues, 354 aValues.getArray(), SelectValueOfPropertyValue() ); 355 356 Reference< XMultiPropertySet > xMe( m_rContext.getPropertiesInterface(), UNO_QUERY_THROW ); 357 358 aGuard.clear(); 359 xMe->setPropertyValues( aNames, aValues ); 360 } 361 362 //........................................................................ 363 } // namespace frm 364 //........................................................................ 365 366