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