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 #include "precompiled_toolkit.hxx" 25 26 #include "toolkit/awt/animatedimagespeer.hxx" 27 #include "toolkit/helper/property.hxx" 28 29 /** === begin UNO includes === **/ 30 #include <com/sun/star/awt/XAnimatedImages.hpp> 31 #include <com/sun/star/awt/Size.hpp> 32 #include <com/sun/star/graphic/XGraphicProvider.hpp> 33 #include <com/sun/star/beans/XPropertySet.hpp> 34 #include <com/sun/star/graphic/XGraphic.hpp> 35 #include <com/sun/star/awt/ImageScaleMode.hpp> 36 /** === end UNO includes === **/ 37 38 #include <comphelper/componentcontext.hxx> 39 #include <comphelper/namedvaluecollection.hxx> 40 #include <comphelper/processfactory.hxx> 41 #include <rtl/ustrbuf.hxx> 42 #include <tools/diagnose_ex.h> 43 #include <tools/urlobj.hxx> 44 #include <vcl/throbber.hxx> 45 46 #include <limits> 47 48 //...................................................................................................................... 49 namespace toolkit 50 { 51 //...................................................................................................................... 52 53 /** === begin UNO using === **/ 54 using ::com::sun::star::uno::Reference; 55 using ::com::sun::star::uno::XInterface; 56 using ::com::sun::star::uno::UNO_QUERY; 57 using ::com::sun::star::uno::UNO_QUERY_THROW; 58 using ::com::sun::star::uno::UNO_SET_THROW; 59 using ::com::sun::star::uno::Exception; 60 using ::com::sun::star::uno::RuntimeException; 61 using ::com::sun::star::uno::Any; 62 using ::com::sun::star::uno::makeAny; 63 using ::com::sun::star::uno::Sequence; 64 using ::com::sun::star::uno::Type; 65 using ::com::sun::star::lang::EventObject; 66 using ::com::sun::star::container::ContainerEvent; 67 using ::com::sun::star::awt::XAnimatedImages; 68 using ::com::sun::star::awt::Size; 69 using ::com::sun::star::lang::XMultiServiceFactory; 70 using ::com::sun::star::graphic::XGraphicProvider; 71 using ::com::sun::star::beans::XPropertySet; 72 using ::com::sun::star::graphic::XGraphic; 73 /** === end UNO using === **/ 74 namespace ImageScaleMode = ::com::sun::star::awt::ImageScaleMode; 75 76 //================================================================================================================== 77 //= AnimatedImagesPeer_Data 78 //================================================================================================================== 79 struct CachedImage 80 { 81 ::rtl::OUString sImageURL; 82 mutable Reference< XGraphic > xGraphic; 83 84 CachedImage() 85 :sImageURL() 86 ,xGraphic() 87 { 88 } 89 90 CachedImage( ::rtl::OUString const& i_imageURL ) 91 :sImageURL( i_imageURL ) 92 ,xGraphic() 93 { 94 } 95 }; 96 97 struct AnimatedImagesPeer_Data 98 { 99 AnimatedImagesPeer& rAntiImpl; 100 ::std::vector< ::std::vector< CachedImage > > aCachedImageSets; 101 102 AnimatedImagesPeer_Data( AnimatedImagesPeer& i_antiImpl ) 103 :rAntiImpl( i_antiImpl ) 104 ,aCachedImageSets() 105 { 106 } 107 }; 108 109 //================================================================================================================== 110 //= helper 111 //================================================================================================================== 112 namespace 113 { 114 //-------------------------------------------------------------------------------------------------------------- 115 ::rtl::OUString lcl_getHighContrastURL( ::rtl::OUString const& i_imageURL ) 116 { 117 INetURLObject aURL( i_imageURL ); 118 if ( aURL.GetProtocol() != INET_PROT_PRIV_SOFFICE ) 119 { 120 OSL_VERIFY( aURL.insertName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "hicontrast" ) ), false, 0 ) ); 121 return aURL.GetMainURL( INetURLObject::NO_DECODE ); 122 } 123 // the private: scheme is not considered to be hierarchical by INetURLObject, so manually insert the 124 // segment 125 const sal_Int32 separatorPos = i_imageURL.indexOf( '/' ); 126 ENSURE_OR_RETURN( separatorPos != -1, "lcl_getHighContrastURL: unsipported URL scheme - cannot automatically determine HC version!", i_imageURL ); 127 128 ::rtl::OUStringBuffer composer; 129 composer.append( i_imageURL.copy( 0, separatorPos ) ); 130 composer.appendAscii( "/hicontrast" ); 131 composer.append( i_imageURL.copy( separatorPos ) ); 132 return composer.makeStringAndClear(); 133 } 134 135 //-------------------------------------------------------------------------------------------------------------- 136 bool lcl_ensureImage_throw( Reference< XGraphicProvider > const& i_graphicProvider, const bool i_isHighContrast, const CachedImage& i_cachedImage ) 137 { 138 if ( !i_cachedImage.xGraphic.is() ) 139 { 140 ::comphelper::NamedValueCollection aMediaProperties; 141 if ( i_isHighContrast ) 142 { 143 // try (to find) the high-contrast version of the graphic first 144 aMediaProperties.put( "URL", lcl_getHighContrastURL( i_cachedImage.sImageURL ) ); 145 i_cachedImage.xGraphic.set( i_graphicProvider->queryGraphic( aMediaProperties.getPropertyValues() ), UNO_QUERY ); 146 } 147 if ( !i_cachedImage.xGraphic.is() ) 148 { 149 aMediaProperties.put( "URL", i_cachedImage.sImageURL ); 150 i_cachedImage.xGraphic.set( i_graphicProvider->queryGraphic( aMediaProperties.getPropertyValues() ), UNO_QUERY ); 151 } 152 } 153 return i_cachedImage.xGraphic.is(); 154 } 155 156 //-------------------------------------------------------------------------------------------------------------- 157 Size lcl_getGraphicSizePixel( Reference< XGraphic > const& i_graphic ) 158 { 159 Size aSizePixel; 160 try 161 { 162 if ( i_graphic.is() ) 163 { 164 const Reference< XPropertySet > xGraphicProps( i_graphic, UNO_QUERY_THROW ); 165 OSL_VERIFY( xGraphicProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "SizePixel" ) ) ) >>= aSizePixel ); 166 } 167 } 168 catch( const Exception& ) 169 { 170 DBG_UNHANDLED_EXCEPTION(); 171 } 172 return aSizePixel; 173 } 174 175 //-------------------------------------------------------------------------------------------------------------- 176 void lcl_init( Sequence< ::rtl::OUString > const& i_imageURLs, ::std::vector< CachedImage >& o_images ) 177 { 178 o_images.resize(0); 179 size_t count = size_t( i_imageURLs.getLength() ); 180 o_images.reserve( count ); 181 for ( size_t i = 0; i < count; ++i ) 182 { 183 o_images.push_back( CachedImage( i_imageURLs[i] ) ); 184 } 185 } 186 187 //-------------------------------------------------------------------------------------------------------------- 188 void lcl_updateImageList_nothrow( AnimatedImagesPeer_Data& i_data ) 189 { 190 Throbber* pThrobber = dynamic_cast< Throbber* >( i_data.rAntiImpl.GetWindow() ); 191 if ( pThrobber == NULL ) 192 return; 193 194 try 195 { 196 // collect the image sizes of the different image sets 197 const ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() ); 198 const Reference< XGraphicProvider > xGraphicProvider( aContext.createComponent( "com.sun.star.graphic.GraphicProvider" ), UNO_QUERY_THROW ); 199 200 const bool isHighContrast = pThrobber->GetSettings().GetStyleSettings().GetHighContrastMode(); 201 202 sal_Int32 nPreferredSet = -1; 203 const size_t nImageSetCount = i_data.aCachedImageSets.size(); 204 if ( nImageSetCount < 2 ) 205 { 206 nPreferredSet = sal_Int32( nImageSetCount ) - 1; 207 } 208 else 209 { 210 ::std::vector< Size > aImageSizes( nImageSetCount ); 211 for ( sal_Int32 nImageSet = 0; size_t( nImageSet ) < nImageSetCount; ++nImageSet ) 212 { 213 ::std::vector< CachedImage > const& rImageSet( i_data.aCachedImageSets[ nImageSet ] ); 214 if ( ( rImageSet.empty() ) 215 || ( !lcl_ensureImage_throw( xGraphicProvider, isHighContrast, rImageSet[0] ) ) 216 ) 217 { 218 aImageSizes[ nImageSet ] = Size( ::std::numeric_limits< long >::max(), ::std::numeric_limits< long >::max() ); 219 } 220 else 221 { 222 aImageSizes[ nImageSet ] = lcl_getGraphicSizePixel( rImageSet[0].xGraphic ); 223 } 224 } 225 226 // find the set with the smallest difference between window size and image size 227 const ::Size aWindowSizePixel = pThrobber->GetSizePixel(); 228 long nMinimalDistance = ::std::numeric_limits< long >::max(); 229 for ( ::std::vector< Size >::const_iterator check = aImageSizes.begin(); 230 check != aImageSizes.end(); 231 ++check 232 ) 233 { 234 if ( ( check->Width > aWindowSizePixel.Width() ) 235 || ( check->Height > aWindowSizePixel.Height() ) 236 ) 237 // do not use an image set which doesn't fit into the window 238 continue; 239 240 const sal_Int64 distance = 241 ( aWindowSizePixel.Width() - check->Width ) * ( aWindowSizePixel.Width() - check->Width ) 242 + ( aWindowSizePixel.Height() - check->Height ) * ( aWindowSizePixel.Height() - check->Height ); 243 if ( distance < nMinimalDistance ) 244 { 245 nMinimalDistance = distance; 246 nPreferredSet = check - aImageSizes.begin(); 247 } 248 } 249 } 250 251 // found a set? 252 Sequence< Reference< XGraphic > > aImages; 253 if ( ( nPreferredSet >= 0 ) && ( size_t( nPreferredSet ) < nImageSetCount ) ) 254 { 255 // => set the images 256 ::std::vector< CachedImage > const& rImageSet( i_data.aCachedImageSets[ nPreferredSet ] ); 257 aImages.realloc( rImageSet.size() ); 258 sal_Int32 imageIndex = 0; 259 for ( ::std::vector< CachedImage >::const_iterator cachedImage = rImageSet.begin(); 260 cachedImage != rImageSet.end(); 261 ++cachedImage, ++imageIndex 262 ) 263 { 264 lcl_ensureImage_throw( xGraphicProvider, isHighContrast, *cachedImage ); 265 aImages[ imageIndex ] = cachedImage->xGraphic; 266 } 267 } 268 pThrobber->setImageList( aImages ); 269 } 270 catch( const Exception& ) 271 { 272 DBG_UNHANDLED_EXCEPTION(); 273 } 274 } 275 276 //-------------------------------------------------------------------------------------------------------------- 277 void lcl_updateImageList_nothrow( AnimatedImagesPeer_Data& i_data, const Reference< XAnimatedImages >& i_images ) 278 { 279 try 280 { 281 const sal_Int32 nImageSetCount = i_images->getImageSetCount(); 282 i_data.aCachedImageSets.resize(0); 283 for ( sal_Int32 set = 0; set < nImageSetCount; ++set ) 284 { 285 const Sequence< ::rtl::OUString > aImageURLs( i_images->getImageSet( set ) ); 286 ::std::vector< CachedImage > aImages; 287 lcl_init( aImageURLs, aImages ); 288 i_data.aCachedImageSets.push_back( aImages ); 289 } 290 291 lcl_updateImageList_nothrow( i_data ); 292 } 293 catch( const Exception& ) 294 { 295 DBG_UNHANDLED_EXCEPTION(); 296 } 297 } 298 } 299 300 //================================================================================================================== 301 //= AnimatedImagesPeer 302 //================================================================================================================== 303 //------------------------------------------------------------------------------------------------------------------ 304 AnimatedImagesPeer::AnimatedImagesPeer() 305 :AnimatedImagesPeer_Base() 306 ,m_pData( new AnimatedImagesPeer_Data( *this ) ) 307 { 308 } 309 310 //------------------------------------------------------------------------------------------------------------------ 311 AnimatedImagesPeer::~AnimatedImagesPeer() 312 { 313 } 314 315 //------------------------------------------------------------------------------------------------------------------ 316 void SAL_CALL AnimatedImagesPeer::startAnimation( ) throw (RuntimeException) 317 { 318 ::vos::OGuard aGuard( GetMutex() ); 319 Throbber* pThrobber( dynamic_cast< Throbber* >( GetWindow() ) ); 320 if ( pThrobber != NULL) 321 pThrobber->start(); 322 } 323 324 //------------------------------------------------------------------------------------------------------------------ 325 void SAL_CALL AnimatedImagesPeer::stopAnimation( ) throw (RuntimeException) 326 { 327 ::vos::OGuard aGuard( GetMutex() ); 328 Throbber* pThrobber( dynamic_cast< Throbber* >( GetWindow() ) ); 329 if ( pThrobber != NULL) 330 pThrobber->stop(); 331 } 332 333 //------------------------------------------------------------------------------------------------------------------ 334 ::sal_Bool SAL_CALL AnimatedImagesPeer::isAnimationRunning( ) throw (RuntimeException) 335 { 336 ::vos::OGuard aGuard( GetMutex() ); 337 Throbber* pThrobber( dynamic_cast< Throbber* >( GetWindow() ) ); 338 if ( pThrobber != NULL) 339 return pThrobber->isRunning(); 340 return sal_False; 341 } 342 343 //------------------------------------------------------------------------------------------------------------------ 344 void SAL_CALL AnimatedImagesPeer::setProperty( const ::rtl::OUString& i_propertyName, const Any& i_value ) throw(RuntimeException) 345 { 346 ::vos::OGuard aGuard( GetMutex() ); 347 348 Throbber* pThrobber( dynamic_cast< Throbber* >( GetWindow() ) ); 349 if ( pThrobber == NULL ) 350 { 351 VCLXWindow::setProperty( i_propertyName, i_value ); 352 return; 353 } 354 355 const sal_uInt16 nPropertyId = GetPropertyId( i_propertyName ); 356 switch ( nPropertyId ) 357 { 358 case BASEPROPERTY_STEP_TIME: 359 { 360 sal_Int32 nStepTime( 0 ); 361 if ( i_value >>= nStepTime ) 362 pThrobber->setStepTime( nStepTime ); 363 break; 364 } 365 case BASEPROPERTY_AUTO_REPEAT: 366 { 367 sal_Bool bRepeat( sal_True ); 368 if ( i_value >>= bRepeat ) 369 pThrobber->setRepeat( bRepeat ); 370 break; 371 } 372 373 case BASEPROPERTY_IMAGE_SCALE_MODE: 374 { 375 sal_Int16 nScaleMode( ImageScaleMode::Anisotropic ); 376 ImageControl* pImageControl = dynamic_cast< ImageControl* >( GetWindow() ); 377 if ( pImageControl && ( i_value >>= nScaleMode ) ) 378 { 379 pImageControl->SetScaleMode( nScaleMode ); 380 } 381 } 382 break; 383 384 default: 385 AnimatedImagesPeer_Base::setProperty( i_propertyName, i_value ); 386 break; 387 } 388 } 389 390 //------------------------------------------------------------------------------------------------------------------ 391 Any SAL_CALL AnimatedImagesPeer::getProperty( const ::rtl::OUString& i_propertyName ) throw(RuntimeException) 392 { 393 ::vos::OGuard aGuard( GetMutex() ); 394 395 Any aReturn; 396 397 Throbber* pThrobber( dynamic_cast< Throbber* >( GetWindow() ) ); 398 if ( pThrobber == NULL ) 399 return VCLXWindow::getProperty( i_propertyName ); 400 401 const sal_uInt16 nPropertyId = GetPropertyId( i_propertyName ); 402 switch ( nPropertyId ) 403 { 404 case BASEPROPERTY_STEP_TIME: 405 aReturn <<= pThrobber->getStepTime(); 406 break; 407 408 case BASEPROPERTY_AUTO_REPEAT: 409 aReturn <<= pThrobber->getRepeat(); 410 break; 411 412 case BASEPROPERTY_IMAGE_SCALE_MODE: 413 { 414 ImageControl const* pImageControl = dynamic_cast< ImageControl* >( GetWindow() ); 415 aReturn <<= ( pImageControl ? pImageControl->GetScaleMode() : ImageScaleMode::Anisotropic ); 416 } 417 break; 418 419 default: 420 aReturn = AnimatedImagesPeer_Base::getProperty( i_propertyName ); 421 break; 422 } 423 424 return aReturn; 425 } 426 427 //------------------------------------------------------------------------------------------------------------------ 428 void AnimatedImagesPeer::ProcessWindowEvent( const VclWindowEvent& i_windowEvent ) 429 { 430 switch ( i_windowEvent.GetId() ) 431 { 432 case VCLEVENT_WINDOW_RESIZE: 433 lcl_updateImageList_nothrow( *m_pData ); 434 break; 435 } 436 437 AnimatedImagesPeer_Base::ProcessWindowEvent( i_windowEvent ); 438 } 439 440 //------------------------------------------------------------------------------------------------------------------ 441 void AnimatedImagesPeer::impl_updateImages_nolck( const Reference< XInterface >& i_animatedImages ) 442 { 443 ::vos::OGuard aGuard( GetMutex() ); 444 445 lcl_updateImageList_nothrow( *m_pData, Reference< XAnimatedImages >( i_animatedImages, UNO_QUERY_THROW ) ); 446 } 447 448 //------------------------------------------------------------------------------------------------------------------ 449 void SAL_CALL AnimatedImagesPeer::elementInserted( const ContainerEvent& i_event ) throw (RuntimeException) 450 { 451 ::vos::OGuard aGuard( GetMutex() ); 452 Reference< XAnimatedImages > xAnimatedImages( i_event.Source, UNO_QUERY_THROW ); 453 454 sal_Int32 nPosition(0); 455 OSL_VERIFY( i_event.Accessor >>= nPosition ); 456 size_t position = size_t( nPosition ); 457 if ( position > m_pData->aCachedImageSets.size() ) 458 { 459 OSL_ENSURE( false, "AnimatedImagesPeer::elementInserted: illegal accessor/index!" ); 460 lcl_updateImageList_nothrow( *m_pData, xAnimatedImages ); 461 } 462 463 Sequence< ::rtl::OUString > aImageURLs; 464 OSL_VERIFY( i_event.Element >>= aImageURLs ); 465 ::std::vector< CachedImage > aImages; 466 lcl_init( aImageURLs, aImages ); 467 m_pData->aCachedImageSets.insert( m_pData->aCachedImageSets.begin() + position, aImages ); 468 lcl_updateImageList_nothrow( *m_pData ); 469 } 470 471 //------------------------------------------------------------------------------------------------------------------ 472 void SAL_CALL AnimatedImagesPeer::elementRemoved( const ContainerEvent& i_event ) throw (RuntimeException) 473 { 474 ::vos::OGuard aGuard( GetMutex() ); 475 Reference< XAnimatedImages > xAnimatedImages( i_event.Source, UNO_QUERY_THROW ); 476 477 sal_Int32 nPosition(0); 478 OSL_VERIFY( i_event.Accessor >>= nPosition ); 479 size_t position = size_t( nPosition ); 480 if ( position >= m_pData->aCachedImageSets.size() ) 481 { 482 OSL_ENSURE( false, "AnimatedImagesPeer::elementRemoved: illegal accessor/index!" ); 483 lcl_updateImageList_nothrow( *m_pData, xAnimatedImages ); 484 } 485 486 m_pData->aCachedImageSets.erase( m_pData->aCachedImageSets.begin() + position ); 487 lcl_updateImageList_nothrow( *m_pData ); 488 } 489 490 //------------------------------------------------------------------------------------------------------------------ 491 void SAL_CALL AnimatedImagesPeer::elementReplaced( const ContainerEvent& i_event ) throw (RuntimeException) 492 { 493 ::vos::OGuard aGuard( GetMutex() ); 494 Reference< XAnimatedImages > xAnimatedImages( i_event.Source, UNO_QUERY_THROW ); 495 496 sal_Int32 nPosition(0); 497 OSL_VERIFY( i_event.Accessor >>= nPosition ); 498 size_t position = size_t( nPosition ); 499 if ( position >= m_pData->aCachedImageSets.size() ) 500 { 501 OSL_ENSURE( false, "AnimatedImagesPeer::elementReplaced: illegal accessor/index!" ); 502 lcl_updateImageList_nothrow( *m_pData, xAnimatedImages ); 503 } 504 505 Sequence< ::rtl::OUString > aImageURLs; 506 OSL_VERIFY( i_event.Element >>= aImageURLs ); 507 ::std::vector< CachedImage > aImages; 508 lcl_init( aImageURLs, aImages ); 509 m_pData->aCachedImageSets[ position ] = aImages; 510 lcl_updateImageList_nothrow( *m_pData ); 511 } 512 513 //------------------------------------------------------------------------------------------------------------------ 514 void SAL_CALL AnimatedImagesPeer::disposing( const EventObject& i_event ) throw (RuntimeException) 515 { 516 VCLXWindow::disposing( i_event ); 517 } 518 519 //------------------------------------------------------------------------------------------------------------------ 520 void SAL_CALL AnimatedImagesPeer::modified( const EventObject& i_event ) throw (RuntimeException) 521 { 522 impl_updateImages_nolck( i_event.Source ); 523 } 524 525 //------------------------------------------------------------------------------------------------------------------ 526 void SAL_CALL AnimatedImagesPeer::dispose( ) throw(RuntimeException) 527 { 528 AnimatedImagesPeer_Base::dispose(); 529 ::vos::OGuard aGuard( GetMutex() ); 530 m_pData->aCachedImageSets.resize(0); 531 } 532 533 //...................................................................................................................... 534 } // namespace toolkit 535 //...................................................................................................................... 536