| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| #include "precompiled_toolkit.hxx" |
| |
| #include "toolkit/awt/animatedimagespeer.hxx" |
| #include "toolkit/helper/property.hxx" |
| |
| /** === begin UNO includes === **/ |
| #include <com/sun/star/awt/XAnimatedImages.hpp> |
| #include <com/sun/star/awt/Size.hpp> |
| #include <com/sun/star/graphic/XGraphicProvider.hpp> |
| #include <com/sun/star/beans/XPropertySet.hpp> |
| #include <com/sun/star/graphic/XGraphic.hpp> |
| #include <com/sun/star/awt/ImageScaleMode.hpp> |
| /** === end UNO includes === **/ |
| |
| #include <comphelper/componentcontext.hxx> |
| #include <comphelper/namedvaluecollection.hxx> |
| #include <comphelper/processfactory.hxx> |
| #include <rtl/ustrbuf.hxx> |
| #include <tools/diagnose_ex.h> |
| #include <tools/urlobj.hxx> |
| #include <vcl/throbber.hxx> |
| |
| #include <limits> |
| |
| //...................................................................................................................... |
| namespace toolkit |
| { |
| //...................................................................................................................... |
| |
| /** === begin UNO using === **/ |
| using ::com::sun::star::uno::Reference; |
| using ::com::sun::star::uno::XInterface; |
| using ::com::sun::star::uno::UNO_QUERY; |
| using ::com::sun::star::uno::UNO_QUERY_THROW; |
| using ::com::sun::star::uno::UNO_SET_THROW; |
| using ::com::sun::star::uno::Exception; |
| using ::com::sun::star::uno::RuntimeException; |
| using ::com::sun::star::uno::Any; |
| using ::com::sun::star::uno::makeAny; |
| using ::com::sun::star::uno::Sequence; |
| using ::com::sun::star::uno::Type; |
| using ::com::sun::star::lang::EventObject; |
| using ::com::sun::star::container::ContainerEvent; |
| using ::com::sun::star::awt::XAnimatedImages; |
| using ::com::sun::star::awt::Size; |
| using ::com::sun::star::lang::XMultiServiceFactory; |
| using ::com::sun::star::graphic::XGraphicProvider; |
| using ::com::sun::star::beans::XPropertySet; |
| using ::com::sun::star::graphic::XGraphic; |
| /** === end UNO using === **/ |
| namespace ImageScaleMode = ::com::sun::star::awt::ImageScaleMode; |
| |
| //================================================================================================================== |
| //= AnimatedImagesPeer_Data |
| //================================================================================================================== |
| struct CachedImage |
| { |
| ::rtl::OUString sImageURL; |
| mutable Reference< XGraphic > xGraphic; |
| |
| CachedImage() |
| :sImageURL() |
| ,xGraphic() |
| { |
| } |
| |
| CachedImage( ::rtl::OUString const& i_imageURL ) |
| :sImageURL( i_imageURL ) |
| ,xGraphic() |
| { |
| } |
| }; |
| |
| struct AnimatedImagesPeer_Data |
| { |
| AnimatedImagesPeer& rAntiImpl; |
| ::std::vector< ::std::vector< CachedImage > > aCachedImageSets; |
| |
| AnimatedImagesPeer_Data( AnimatedImagesPeer& i_antiImpl ) |
| :rAntiImpl( i_antiImpl ) |
| ,aCachedImageSets() |
| { |
| } |
| }; |
| |
| //================================================================================================================== |
| //= helper |
| //================================================================================================================== |
| namespace |
| { |
| //-------------------------------------------------------------------------------------------------------------- |
| bool lcl_ensureImage_throw( Reference< XGraphicProvider > const& i_graphicProvider, const bool i_isHighContrast, const CachedImage& i_cachedImage ) |
| { |
| if ( !i_cachedImage.xGraphic.is() ) |
| { |
| ::comphelper::NamedValueCollection aMediaProperties; |
| if ( i_isHighContrast ) |
| { |
| // try (to find) the high-contrast version of the graphic first |
| INetURLObject aURL( i_cachedImage.sImageURL ); |
| if ( aURL.GetProtocol() != INET_PROT_PRIV_SOFFICE ) |
| { |
| rtl::OUString sURL( i_cachedImage.sImageURL ); |
| const sal_Int32 separatorPos = sURL.lastIndexOf( '/' ); |
| if ( separatorPos != -1 ) |
| { |
| ::rtl::OUStringBuffer composer; |
| composer.append( sURL.copy( 0, separatorPos ) ); |
| composer.appendAscii( RTL_CONSTASCII_STRINGPARAM( "/hicontrast" ) ); |
| composer.append( sURL.copy( separatorPos ) ); |
| |
| aMediaProperties.put( "URL", composer.makeStringAndClear() ); |
| i_cachedImage.xGraphic.set( i_graphicProvider->queryGraphic( aMediaProperties.getPropertyValues() ), UNO_QUERY ); |
| } |
| } |
| } |
| if ( !i_cachedImage.xGraphic.is() ) |
| { |
| aMediaProperties.put( "URL", i_cachedImage.sImageURL ); |
| i_cachedImage.xGraphic.set( i_graphicProvider->queryGraphic( aMediaProperties.getPropertyValues() ), UNO_QUERY ); |
| } |
| } |
| return i_cachedImage.xGraphic.is(); |
| } |
| |
| //-------------------------------------------------------------------------------------------------------------- |
| Size lcl_getGraphicSizePixel( Reference< XGraphic > const& i_graphic ) |
| { |
| Size aSizePixel; |
| try |
| { |
| if ( i_graphic.is() ) |
| { |
| const Reference< XPropertySet > xGraphicProps( i_graphic, UNO_QUERY_THROW ); |
| OSL_VERIFY( xGraphicProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "SizePixel" ) ) ) >>= aSizePixel ); |
| } |
| } |
| catch( const Exception& ) |
| { |
| DBG_UNHANDLED_EXCEPTION(); |
| } |
| return aSizePixel; |
| } |
| |
| //-------------------------------------------------------------------------------------------------------------- |
| void lcl_init( Sequence< ::rtl::OUString > const& i_imageURLs, ::std::vector< CachedImage >& o_images ) |
| { |
| o_images.resize(0); |
| size_t count = size_t( i_imageURLs.getLength() ); |
| o_images.reserve( count ); |
| for ( size_t i = 0; i < count; ++i ) |
| { |
| o_images.push_back( CachedImage( i_imageURLs[i] ) ); |
| } |
| } |
| |
| //-------------------------------------------------------------------------------------------------------------- |
| void lcl_updateImageList_nothrow( AnimatedImagesPeer_Data& i_data ) |
| { |
| Throbber* pThrobber = dynamic_cast< Throbber* >( i_data.rAntiImpl.GetWindow() ); |
| if ( pThrobber == NULL ) |
| return; |
| |
| try |
| { |
| // collect the image sizes of the different image sets |
| const ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() ); |
| const Reference< XGraphicProvider > xGraphicProvider( aContext.createComponent( "com.sun.star.graphic.GraphicProvider" ), UNO_QUERY_THROW ); |
| |
| const bool isHighContrast = pThrobber->GetSettings().GetStyleSettings().GetHighContrastMode(); |
| |
| sal_Int32 nPreferredSet = -1; |
| const size_t nImageSetCount = i_data.aCachedImageSets.size(); |
| if ( nImageSetCount < 2 ) |
| { |
| nPreferredSet = sal_Int32( nImageSetCount ) - 1; |
| } |
| else |
| { |
| ::std::vector< Size > aImageSizes( nImageSetCount ); |
| for ( sal_Int32 nImageSet = 0; size_t( nImageSet ) < nImageSetCount; ++nImageSet ) |
| { |
| ::std::vector< CachedImage > const& rImageSet( i_data.aCachedImageSets[ nImageSet ] ); |
| if ( ( rImageSet.empty() ) |
| || ( !lcl_ensureImage_throw( xGraphicProvider, isHighContrast, rImageSet[0] ) ) |
| ) |
| { |
| aImageSizes[ nImageSet ] = Size( ::std::numeric_limits< long >::max(), ::std::numeric_limits< long >::max() ); |
| } |
| else |
| { |
| aImageSizes[ nImageSet ] = lcl_getGraphicSizePixel( rImageSet[0].xGraphic ); |
| } |
| } |
| |
| // find the set with the smallest difference between window size and image size |
| const ::Size aWindowSizePixel = pThrobber->GetSizePixel(); |
| long nMinimalDistance = ::std::numeric_limits< long >::max(); |
| for ( ::std::vector< Size >::const_iterator check = aImageSizes.begin(); |
| check != aImageSizes.end(); |
| ++check |
| ) |
| { |
| if ( ( check->Width > aWindowSizePixel.Width() ) |
| || ( check->Height > aWindowSizePixel.Height() ) |
| ) |
| // do not use an image set which doesn't fit into the window |
| continue; |
| |
| const sal_Int64 distance = |
| ( aWindowSizePixel.Width() - check->Width ) * ( aWindowSizePixel.Width() - check->Width ) |
| + ( aWindowSizePixel.Height() - check->Height ) * ( aWindowSizePixel.Height() - check->Height ); |
| if ( distance < nMinimalDistance ) |
| { |
| nMinimalDistance = distance; |
| nPreferredSet = check - aImageSizes.begin(); |
| } |
| } |
| } |
| |
| // found a set? |
| Sequence< Reference< XGraphic > > aImages; |
| if ( ( nPreferredSet >= 0 ) && ( size_t( nPreferredSet ) < nImageSetCount ) ) |
| { |
| // => set the images |
| ::std::vector< CachedImage > const& rImageSet( i_data.aCachedImageSets[ nPreferredSet ] ); |
| aImages.realloc( rImageSet.size() ); |
| sal_Int32 imageIndex = 0; |
| for ( ::std::vector< CachedImage >::const_iterator cachedImage = rImageSet.begin(); |
| cachedImage != rImageSet.end(); |
| ++cachedImage, ++imageIndex |
| ) |
| { |
| lcl_ensureImage_throw( xGraphicProvider, isHighContrast, *cachedImage ); |
| aImages[ imageIndex ] = cachedImage->xGraphic; |
| } |
| } |
| pThrobber->setImageList( aImages ); |
| } |
| catch( const Exception& ) |
| { |
| DBG_UNHANDLED_EXCEPTION(); |
| } |
| } |
| |
| //-------------------------------------------------------------------------------------------------------------- |
| void lcl_updateImageList_nothrow( AnimatedImagesPeer_Data& i_data, const Reference< XAnimatedImages >& i_images ) |
| { |
| try |
| { |
| const sal_Int32 nImageSetCount = i_images->getImageSetCount(); |
| i_data.aCachedImageSets.resize(0); |
| for ( sal_Int32 set = 0; set < nImageSetCount; ++set ) |
| { |
| const Sequence< ::rtl::OUString > aImageURLs( i_images->getImageSet( set ) ); |
| ::std::vector< CachedImage > aImages; |
| lcl_init( aImageURLs, aImages ); |
| i_data.aCachedImageSets.push_back( aImages ); |
| } |
| |
| lcl_updateImageList_nothrow( i_data ); |
| } |
| catch( const Exception& ) |
| { |
| DBG_UNHANDLED_EXCEPTION(); |
| } |
| } |
| } |
| |
| //================================================================================================================== |
| //= AnimatedImagesPeer |
| //================================================================================================================== |
| //------------------------------------------------------------------------------------------------------------------ |
| AnimatedImagesPeer::AnimatedImagesPeer() |
| :AnimatedImagesPeer_Base() |
| ,m_pData( new AnimatedImagesPeer_Data( *this ) ) |
| { |
| } |
| |
| //------------------------------------------------------------------------------------------------------------------ |
| AnimatedImagesPeer::~AnimatedImagesPeer() |
| { |
| } |
| |
| //------------------------------------------------------------------------------------------------------------------ |
| void SAL_CALL AnimatedImagesPeer::startAnimation( ) throw (RuntimeException) |
| { |
| ::vos::OGuard aGuard( GetMutex() ); |
| Throbber* pThrobber( dynamic_cast< Throbber* >( GetWindow() ) ); |
| if ( pThrobber != NULL) |
| pThrobber->start(); |
| } |
| |
| //------------------------------------------------------------------------------------------------------------------ |
| void SAL_CALL AnimatedImagesPeer::stopAnimation( ) throw (RuntimeException) |
| { |
| ::vos::OGuard aGuard( GetMutex() ); |
| Throbber* pThrobber( dynamic_cast< Throbber* >( GetWindow() ) ); |
| if ( pThrobber != NULL) |
| pThrobber->stop(); |
| } |
| |
| //------------------------------------------------------------------------------------------------------------------ |
| ::sal_Bool SAL_CALL AnimatedImagesPeer::isAnimationRunning( ) throw (RuntimeException) |
| { |
| ::vos::OGuard aGuard( GetMutex() ); |
| Throbber* pThrobber( dynamic_cast< Throbber* >( GetWindow() ) ); |
| if ( pThrobber != NULL) |
| return pThrobber->isRunning(); |
| return sal_False; |
| } |
| |
| //------------------------------------------------------------------------------------------------------------------ |
| void SAL_CALL AnimatedImagesPeer::setProperty( const ::rtl::OUString& i_propertyName, const Any& i_value ) throw(RuntimeException) |
| { |
| ::vos::OGuard aGuard( GetMutex() ); |
| |
| Throbber* pThrobber( dynamic_cast< Throbber* >( GetWindow() ) ); |
| if ( pThrobber == NULL ) |
| { |
| VCLXWindow::setProperty( i_propertyName, i_value ); |
| return; |
| } |
| |
| const sal_uInt16 nPropertyId = GetPropertyId( i_propertyName ); |
| switch ( nPropertyId ) |
| { |
| case BASEPROPERTY_STEP_TIME: |
| { |
| sal_Int32 nStepTime( 0 ); |
| if ( i_value >>= nStepTime ) |
| pThrobber->setStepTime( nStepTime ); |
| break; |
| } |
| case BASEPROPERTY_AUTO_REPEAT: |
| { |
| sal_Bool bRepeat( sal_True ); |
| if ( i_value >>= bRepeat ) |
| pThrobber->setRepeat( bRepeat ); |
| break; |
| } |
| |
| case BASEPROPERTY_IMAGE_SCALE_MODE: |
| { |
| sal_Int16 nScaleMode( ImageScaleMode::ANISOTROPIC ); |
| ImageControl* pImageControl = dynamic_cast< ImageControl* >( GetWindow() ); |
| if ( pImageControl && ( i_value >>= nScaleMode ) ) |
| { |
| pImageControl->SetScaleMode( nScaleMode ); |
| } |
| } |
| break; |
| |
| default: |
| AnimatedImagesPeer_Base::setProperty( i_propertyName, i_value ); |
| break; |
| } |
| } |
| |
| //------------------------------------------------------------------------------------------------------------------ |
| Any SAL_CALL AnimatedImagesPeer::getProperty( const ::rtl::OUString& i_propertyName ) throw(RuntimeException) |
| { |
| ::vos::OGuard aGuard( GetMutex() ); |
| |
| Any aReturn; |
| |
| Throbber* pThrobber( dynamic_cast< Throbber* >( GetWindow() ) ); |
| if ( pThrobber == NULL ) |
| return VCLXWindow::getProperty( i_propertyName ); |
| |
| const sal_uInt16 nPropertyId = GetPropertyId( i_propertyName ); |
| switch ( nPropertyId ) |
| { |
| case BASEPROPERTY_STEP_TIME: |
| aReturn <<= pThrobber->getStepTime(); |
| break; |
| |
| case BASEPROPERTY_AUTO_REPEAT: |
| aReturn <<= pThrobber->getRepeat(); |
| break; |
| |
| case BASEPROPERTY_IMAGE_SCALE_MODE: |
| { |
| ImageControl const* pImageControl = dynamic_cast< ImageControl* >( GetWindow() ); |
| aReturn <<= ( pImageControl ? pImageControl->GetScaleMode() : ImageScaleMode::ANISOTROPIC ); |
| } |
| break; |
| |
| default: |
| aReturn = AnimatedImagesPeer_Base::getProperty( i_propertyName ); |
| break; |
| } |
| |
| return aReturn; |
| } |
| |
| //------------------------------------------------------------------------------------------------------------------ |
| void AnimatedImagesPeer::ProcessWindowEvent( const VclWindowEvent& i_windowEvent ) |
| { |
| switch ( i_windowEvent.GetId() ) |
| { |
| case VCLEVENT_WINDOW_RESIZE: |
| lcl_updateImageList_nothrow( *m_pData ); |
| break; |
| } |
| |
| AnimatedImagesPeer_Base::ProcessWindowEvent( i_windowEvent ); |
| } |
| |
| //------------------------------------------------------------------------------------------------------------------ |
| void AnimatedImagesPeer::impl_updateImages_nolck( const Reference< XInterface >& i_animatedImages ) |
| { |
| ::vos::OGuard aGuard( GetMutex() ); |
| |
| lcl_updateImageList_nothrow( *m_pData, Reference< XAnimatedImages >( i_animatedImages, UNO_QUERY_THROW ) ); |
| } |
| |
| //------------------------------------------------------------------------------------------------------------------ |
| void SAL_CALL AnimatedImagesPeer::elementInserted( const ContainerEvent& i_event ) throw (RuntimeException) |
| { |
| ::vos::OGuard aGuard( GetMutex() ); |
| Reference< XAnimatedImages > xAnimatedImages( i_event.Source, UNO_QUERY_THROW ); |
| |
| sal_Int32 nPosition(0); |
| OSL_VERIFY( i_event.Accessor >>= nPosition ); |
| size_t position = size_t( nPosition ); |
| if ( position > m_pData->aCachedImageSets.size() ) |
| { |
| OSL_ENSURE( false, "AnimatedImagesPeer::elementInserted: illegal accessor/index!" ); |
| lcl_updateImageList_nothrow( *m_pData, xAnimatedImages ); |
| } |
| |
| Sequence< ::rtl::OUString > aImageURLs; |
| OSL_VERIFY( i_event.Element >>= aImageURLs ); |
| ::std::vector< CachedImage > aImages; |
| lcl_init( aImageURLs, aImages ); |
| m_pData->aCachedImageSets.insert( m_pData->aCachedImageSets.begin() + position, aImages ); |
| lcl_updateImageList_nothrow( *m_pData ); |
| } |
| |
| //------------------------------------------------------------------------------------------------------------------ |
| void SAL_CALL AnimatedImagesPeer::elementRemoved( const ContainerEvent& i_event ) throw (RuntimeException) |
| { |
| ::vos::OGuard aGuard( GetMutex() ); |
| Reference< XAnimatedImages > xAnimatedImages( i_event.Source, UNO_QUERY_THROW ); |
| |
| sal_Int32 nPosition(0); |
| OSL_VERIFY( i_event.Accessor >>= nPosition ); |
| size_t position = size_t( nPosition ); |
| if ( position >= m_pData->aCachedImageSets.size() ) |
| { |
| OSL_ENSURE( false, "AnimatedImagesPeer::elementRemoved: illegal accessor/index!" ); |
| lcl_updateImageList_nothrow( *m_pData, xAnimatedImages ); |
| } |
| |
| m_pData->aCachedImageSets.erase( m_pData->aCachedImageSets.begin() + position ); |
| lcl_updateImageList_nothrow( *m_pData ); |
| } |
| |
| //------------------------------------------------------------------------------------------------------------------ |
| void SAL_CALL AnimatedImagesPeer::elementReplaced( const ContainerEvent& i_event ) throw (RuntimeException) |
| { |
| ::vos::OGuard aGuard( GetMutex() ); |
| Reference< XAnimatedImages > xAnimatedImages( i_event.Source, UNO_QUERY_THROW ); |
| |
| sal_Int32 nPosition(0); |
| OSL_VERIFY( i_event.Accessor >>= nPosition ); |
| size_t position = size_t( nPosition ); |
| if ( position >= m_pData->aCachedImageSets.size() ) |
| { |
| OSL_ENSURE( false, "AnimatedImagesPeer::elementReplaced: illegal accessor/index!" ); |
| lcl_updateImageList_nothrow( *m_pData, xAnimatedImages ); |
| } |
| |
| Sequence< ::rtl::OUString > aImageURLs; |
| OSL_VERIFY( i_event.Element >>= aImageURLs ); |
| ::std::vector< CachedImage > aImages; |
| lcl_init( aImageURLs, aImages ); |
| m_pData->aCachedImageSets[ position ] = aImages; |
| lcl_updateImageList_nothrow( *m_pData ); |
| } |
| |
| //------------------------------------------------------------------------------------------------------------------ |
| void SAL_CALL AnimatedImagesPeer::disposing( const EventObject& i_event ) throw (RuntimeException) |
| { |
| VCLXWindow::disposing( i_event ); |
| } |
| |
| //------------------------------------------------------------------------------------------------------------------ |
| void SAL_CALL AnimatedImagesPeer::modified( const EventObject& i_event ) throw (RuntimeException) |
| { |
| impl_updateImages_nolck( i_event.Source ); |
| } |
| |
| //------------------------------------------------------------------------------------------------------------------ |
| void SAL_CALL AnimatedImagesPeer::dispose( ) throw(RuntimeException) |
| { |
| AnimatedImagesPeer_Base::dispose(); |
| ::vos::OGuard aGuard( GetMutex() ); |
| m_pData->aCachedImageSets.resize(0); |
| } |
| |
| //...................................................................................................................... |
| } // namespace toolkit |
| //...................................................................................................................... |