1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "toolkit/awt/animatedimagespeer.hxx"
22 #include "toolkit/helper/property.hxx"
24 #include <com/sun/star/awt/XAnimatedImages.hpp>
25 #include <com/sun/star/awt/Size.hpp>
26 #include <com/sun/star/graphic/GraphicProvider.hpp>
27 #include <com/sun/star/graphic/XGraphicProvider.hpp>
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <com/sun/star/graphic/XGraphic.hpp>
30 #include <com/sun/star/awt/ImageScaleMode.hpp>
32 #include <comphelper/namedvaluecollection.hxx>
33 #include <comphelper/processfactory.hxx>
34 #include <rtl/ustrbuf.hxx>
35 #include <tools/diagnose_ex.h>
36 #include <tools/urlobj.hxx>
37 #include <vcl/throbber.hxx>
38 #include <vcl/svapp.hxx>
39 #include <vcl/settings.hxx>
48 using ::com::sun::star::uno::XComponentContext
;
49 using ::com::sun::star::uno::Reference
;
50 using ::com::sun::star::uno::XInterface
;
51 using ::com::sun::star::uno::UNO_QUERY
;
52 using ::com::sun::star::uno::UNO_QUERY_THROW
;
53 using ::com::sun::star::uno::UNO_SET_THROW
;
54 using ::com::sun::star::uno::Exception
;
55 using ::com::sun::star::uno::RuntimeException
;
56 using ::com::sun::star::uno::Any
;
57 using ::com::sun::star::uno::makeAny
;
58 using ::com::sun::star::uno::Sequence
;
59 using ::com::sun::star::uno::Type
;
60 using ::com::sun::star::lang::EventObject
;
61 using ::com::sun::star::container::ContainerEvent
;
62 using ::com::sun::star::awt::XAnimatedImages
;
63 using ::com::sun::star::awt::Size
;
64 using ::com::sun::star::lang::XMultiServiceFactory
;
65 using ::com::sun::star::graphic::XGraphicProvider
;
66 using ::com::sun::star::beans::XPropertySet
;
67 using ::com::sun::star::graphic::XGraphic
;
69 namespace ImageScaleMode
= ::com::sun::star::awt::ImageScaleMode
;
72 //= AnimatedImagesPeer_Data
77 mutable Reference
< XGraphic
> xGraphic
;
85 CachedImage( OUString
const& i_imageURL
)
86 :sImageURL( i_imageURL
)
92 struct AnimatedImagesPeer_Data
94 AnimatedImagesPeer
& rAntiImpl
;
95 ::std::vector
< ::std::vector
< CachedImage
> > aCachedImageSets
;
97 AnimatedImagesPeer_Data( AnimatedImagesPeer
& i_antiImpl
)
98 :rAntiImpl( i_antiImpl
)
110 OUString
lcl_getHighContrastURL( OUString
const& i_imageURL
)
112 INetURLObject
aURL( i_imageURL
);
113 if ( aURL
.GetProtocol() != INET_PROT_PRIV_SOFFICE
)
115 OSL_VERIFY( aURL
.insertName( OUString( "hicontrast" ), false, 0 ) );
116 return aURL
.GetMainURL( INetURLObject::NO_DECODE
);
118 // the private: scheme is not considered to be hierarchical by INetURLObject, so manually insert the
120 const sal_Int32 separatorPos
= i_imageURL
.indexOf( '/' );
121 ENSURE_OR_RETURN( separatorPos
!= -1, "lcl_getHighContrastURL: unsipported URL scheme - cannot automatically determine HC version!", i_imageURL
);
123 OUStringBuffer composer
;
124 composer
.append( i_imageURL
.copy( 0, separatorPos
) );
125 composer
.appendAscii( "/hicontrast" );
126 composer
.append( i_imageURL
.copy( separatorPos
) );
127 return composer
.makeStringAndClear();
131 bool lcl_ensureImage_throw( Reference
< XGraphicProvider
> const& i_graphicProvider
, const bool i_isHighContrast
, const CachedImage
& i_cachedImage
)
133 if ( !i_cachedImage
.xGraphic
.is() )
135 ::comphelper::NamedValueCollection aMediaProperties
;
136 if ( i_isHighContrast
)
138 // try (to find) the high-contrast version of the graphic first
139 aMediaProperties
.put( "URL", lcl_getHighContrastURL( i_cachedImage
.sImageURL
) );
140 i_cachedImage
.xGraphic
.set( i_graphicProvider
->queryGraphic( aMediaProperties
.getPropertyValues() ), UNO_QUERY
);
142 if ( !i_cachedImage
.xGraphic
.is() )
144 aMediaProperties
.put( "URL", i_cachedImage
.sImageURL
);
145 i_cachedImage
.xGraphic
.set( i_graphicProvider
->queryGraphic( aMediaProperties
.getPropertyValues() ), UNO_QUERY
);
148 return i_cachedImage
.xGraphic
.is();
152 Size
lcl_getGraphicSizePixel( Reference
< XGraphic
> const& i_graphic
)
157 if ( i_graphic
.is() )
159 const Reference
< XPropertySet
> xGraphicProps( i_graphic
, UNO_QUERY_THROW
);
160 OSL_VERIFY( xGraphicProps
->getPropertyValue("SizePixel") >>= aSizePixel
);
163 catch( const Exception
& )
165 DBG_UNHANDLED_EXCEPTION();
171 void lcl_init( Sequence
< OUString
> const& i_imageURLs
, ::std::vector
< CachedImage
>& o_images
)
174 size_t count
= size_t( i_imageURLs
.getLength() );
175 o_images
.reserve( count
);
176 for ( size_t i
= 0; i
< count
; ++i
)
178 o_images
.push_back( CachedImage( i_imageURLs
[i
] ) );
183 void lcl_updateImageList_nothrow( AnimatedImagesPeer_Data
& i_data
)
185 Throbber
* pThrobber
= dynamic_cast< Throbber
* >( i_data
.rAntiImpl
.GetWindow() );
186 if ( pThrobber
== NULL
)
191 // collect the image sizes of the different image sets
192 const Reference
< XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
193 const Reference
< XGraphicProvider
> xGraphicProvider( com::sun::star::graphic::GraphicProvider::create(xContext
) );
195 const bool isHighContrast
= pThrobber
->GetSettings().GetStyleSettings().GetHighContrastMode();
197 sal_Int32 nPreferredSet
= -1;
198 const size_t nImageSetCount
= i_data
.aCachedImageSets
.size();
199 if ( nImageSetCount
< 2 )
201 nPreferredSet
= sal_Int32( nImageSetCount
) - 1;
205 ::std::vector
< Size
> aImageSizes( nImageSetCount
);
206 for ( sal_Int32 nImageSet
= 0; size_t( nImageSet
) < nImageSetCount
; ++nImageSet
)
208 ::std::vector
< CachedImage
> const& rImageSet( i_data
.aCachedImageSets
[ nImageSet
] );
209 if ( ( rImageSet
.empty() )
210 || ( !lcl_ensureImage_throw( xGraphicProvider
, isHighContrast
, rImageSet
[0] ) )
213 aImageSizes
[ nImageSet
] = Size( SAL_MAX_INT32
, SAL_MAX_INT32
);
217 aImageSizes
[ nImageSet
] = lcl_getGraphicSizePixel( rImageSet
[0].xGraphic
);
221 // find the set with the smallest difference between window size and image size
222 const ::Size aWindowSizePixel
= pThrobber
->GetSizePixel();
223 long nMinimalDistance
= ::std::numeric_limits
< long >::max();
224 for ( ::std::vector
< Size
>::const_iterator check
= aImageSizes
.begin();
225 check
!= aImageSizes
.end();
229 if ( ( check
->Width
> aWindowSizePixel
.Width() )
230 || ( check
->Height
> aWindowSizePixel
.Height() )
232 // do not use an image set which doesn't fit into the window
235 const sal_Int64 distance
=
236 ( aWindowSizePixel
.Width() - check
->Width
) * ( aWindowSizePixel
.Width() - check
->Width
)
237 + ( aWindowSizePixel
.Height() - check
->Height
) * ( aWindowSizePixel
.Height() - check
->Height
);
238 if ( distance
< nMinimalDistance
)
240 nMinimalDistance
= distance
;
241 nPreferredSet
= check
- aImageSizes
.begin();
247 Sequence
< Reference
< XGraphic
> > aImages
;
248 if ( ( nPreferredSet
>= 0 ) && ( size_t( nPreferredSet
) < nImageSetCount
) )
251 ::std::vector
< CachedImage
> const& rImageSet( i_data
.aCachedImageSets
[ nPreferredSet
] );
252 aImages
.realloc( rImageSet
.size() );
253 sal_Int32 imageIndex
= 0;
254 for ( ::std::vector
< CachedImage
>::const_iterator cachedImage
= rImageSet
.begin();
255 cachedImage
!= rImageSet
.end();
256 ++cachedImage
, ++imageIndex
259 lcl_ensureImage_throw( xGraphicProvider
, isHighContrast
, *cachedImage
);
260 aImages
[ imageIndex
] = cachedImage
->xGraphic
;
263 pThrobber
->setImageList( aImages
);
265 catch( const Exception
& )
267 DBG_UNHANDLED_EXCEPTION();
272 void lcl_updateImageList_nothrow( AnimatedImagesPeer_Data
& i_data
, const Reference
< XAnimatedImages
>& i_images
)
276 const sal_Int32 nImageSetCount
= i_images
->getImageSetCount();
277 i_data
.aCachedImageSets
.resize(0);
278 for ( sal_Int32 set
= 0; set
< nImageSetCount
; ++set
)
280 const Sequence
< OUString
> aImageURLs( i_images
->getImageSet( set
) );
281 ::std::vector
< CachedImage
> aImages
;
282 lcl_init( aImageURLs
, aImages
);
283 i_data
.aCachedImageSets
.push_back( aImages
);
286 lcl_updateImageList_nothrow( i_data
);
288 catch( const Exception
& )
290 DBG_UNHANDLED_EXCEPTION();
296 //= AnimatedImagesPeer
299 AnimatedImagesPeer::AnimatedImagesPeer()
300 :AnimatedImagesPeer_Base()
301 ,m_pData( new AnimatedImagesPeer_Data( *this ) )
306 AnimatedImagesPeer::~AnimatedImagesPeer()
311 void SAL_CALL
AnimatedImagesPeer::startAnimation( ) throw (RuntimeException
, std::exception
)
313 SolarMutexGuard aGuard
;
314 Throbber
* pThrobber( dynamic_cast< Throbber
* >( GetWindow() ) );
315 if ( pThrobber
!= NULL
)
320 void SAL_CALL
AnimatedImagesPeer::stopAnimation( ) throw (RuntimeException
, std::exception
)
322 SolarMutexGuard aGuard
;
323 Throbber
* pThrobber( dynamic_cast< Throbber
* >( GetWindow() ) );
324 if ( pThrobber
!= NULL
)
329 sal_Bool SAL_CALL
AnimatedImagesPeer::isAnimationRunning( ) throw (RuntimeException
, std::exception
)
331 SolarMutexGuard aGuard
;
332 Throbber
* pThrobber( dynamic_cast< Throbber
* >( GetWindow() ) );
333 if ( pThrobber
!= NULL
)
334 return pThrobber
->isRunning();
339 void SAL_CALL
AnimatedImagesPeer::setProperty( const OUString
& i_propertyName
, const Any
& i_value
) throw(RuntimeException
, std::exception
)
341 SolarMutexGuard aGuard
;
343 Throbber
* pThrobber( dynamic_cast< Throbber
* >( GetWindow() ) );
344 if ( pThrobber
== NULL
)
346 VCLXWindow::setProperty( i_propertyName
, i_value
);
350 const sal_uInt16 nPropertyId
= GetPropertyId( i_propertyName
);
351 switch ( nPropertyId
)
353 case BASEPROPERTY_STEP_TIME
:
355 sal_Int32
nStepTime( 0 );
356 if ( i_value
>>= nStepTime
)
357 pThrobber
->setStepTime( nStepTime
);
360 case BASEPROPERTY_AUTO_REPEAT
:
362 bool bRepeat( true );
363 if ( i_value
>>= bRepeat
)
364 pThrobber
->setRepeat( bRepeat
);
368 case BASEPROPERTY_IMAGE_SCALE_MODE
:
370 sal_Int16
nScaleMode( ImageScaleMode::ANISOTROPIC
);
371 ImageControl
* pImageControl
= dynamic_cast< ImageControl
* >( GetWindow() );
372 if ( pImageControl
&& ( i_value
>>= nScaleMode
) )
374 pImageControl
->SetScaleMode( nScaleMode
);
380 AnimatedImagesPeer_Base::setProperty( i_propertyName
, i_value
);
386 Any SAL_CALL
AnimatedImagesPeer::getProperty( const OUString
& i_propertyName
) throw(RuntimeException
, std::exception
)
388 SolarMutexGuard aGuard
;
392 Throbber
* pThrobber( dynamic_cast< Throbber
* >( GetWindow() ) );
393 if ( pThrobber
== NULL
)
394 return VCLXWindow::getProperty( i_propertyName
);
396 const sal_uInt16 nPropertyId
= GetPropertyId( i_propertyName
);
397 switch ( nPropertyId
)
399 case BASEPROPERTY_STEP_TIME
:
400 aReturn
<<= pThrobber
->getStepTime();
403 case BASEPROPERTY_AUTO_REPEAT
:
404 aReturn
<<= pThrobber
->getRepeat();
407 case BASEPROPERTY_IMAGE_SCALE_MODE
:
409 ImageControl
const* pImageControl
= dynamic_cast< ImageControl
* >( GetWindow() );
410 aReturn
<<= ( pImageControl
? pImageControl
->GetScaleMode() : ImageScaleMode::ANISOTROPIC
);
415 aReturn
= AnimatedImagesPeer_Base::getProperty( i_propertyName
);
423 void AnimatedImagesPeer::ProcessWindowEvent( const VclWindowEvent
& i_windowEvent
)
425 switch ( i_windowEvent
.GetId() )
427 case VCLEVENT_WINDOW_RESIZE
:
428 lcl_updateImageList_nothrow( *m_pData
);
432 AnimatedImagesPeer_Base::ProcessWindowEvent( i_windowEvent
);
436 void AnimatedImagesPeer::impl_updateImages_nolck( const Reference
< XInterface
>& i_animatedImages
)
438 SolarMutexGuard aGuard
;
440 lcl_updateImageList_nothrow( *m_pData
, Reference
< XAnimatedImages
>( i_animatedImages
, UNO_QUERY_THROW
) );
444 void SAL_CALL
AnimatedImagesPeer::elementInserted( const ContainerEvent
& i_event
) throw (RuntimeException
, std::exception
)
446 SolarMutexGuard aGuard
;
447 Reference
< XAnimatedImages
> xAnimatedImages( i_event
.Source
, UNO_QUERY_THROW
);
449 sal_Int32
nPosition(0);
450 OSL_VERIFY( i_event
.Accessor
>>= nPosition
);
451 size_t position
= size_t( nPosition
);
452 if ( position
> m_pData
->aCachedImageSets
.size() )
454 OSL_ENSURE( false, "AnimatedImagesPeer::elementInserted: illegal accessor/index!" );
455 lcl_updateImageList_nothrow( *m_pData
, xAnimatedImages
);
458 Sequence
< OUString
> aImageURLs
;
459 OSL_VERIFY( i_event
.Element
>>= aImageURLs
);
460 ::std::vector
< CachedImage
> aImages
;
461 lcl_init( aImageURLs
, aImages
);
462 m_pData
->aCachedImageSets
.insert( m_pData
->aCachedImageSets
.begin() + position
, aImages
);
463 lcl_updateImageList_nothrow( *m_pData
);
467 void SAL_CALL
AnimatedImagesPeer::elementRemoved( const ContainerEvent
& i_event
) throw (RuntimeException
, std::exception
)
469 SolarMutexGuard aGuard
;
470 Reference
< XAnimatedImages
> xAnimatedImages( i_event
.Source
, UNO_QUERY_THROW
);
472 sal_Int32
nPosition(0);
473 OSL_VERIFY( i_event
.Accessor
>>= nPosition
);
474 size_t position
= size_t( nPosition
);
475 if ( position
>= m_pData
->aCachedImageSets
.size() )
477 OSL_ENSURE( false, "AnimatedImagesPeer::elementRemoved: illegal accessor/index!" );
478 lcl_updateImageList_nothrow( *m_pData
, xAnimatedImages
);
481 m_pData
->aCachedImageSets
.erase( m_pData
->aCachedImageSets
.begin() + position
);
482 lcl_updateImageList_nothrow( *m_pData
);
486 void SAL_CALL
AnimatedImagesPeer::elementReplaced( const ContainerEvent
& i_event
) throw (RuntimeException
, std::exception
)
488 SolarMutexGuard aGuard
;
489 Reference
< XAnimatedImages
> xAnimatedImages( i_event
.Source
, UNO_QUERY_THROW
);
491 sal_Int32
nPosition(0);
492 OSL_VERIFY( i_event
.Accessor
>>= nPosition
);
493 size_t position
= size_t( nPosition
);
494 if ( position
>= m_pData
->aCachedImageSets
.size() )
496 OSL_ENSURE( false, "AnimatedImagesPeer::elementReplaced: illegal accessor/index!" );
497 lcl_updateImageList_nothrow( *m_pData
, xAnimatedImages
);
500 Sequence
< OUString
> aImageURLs
;
501 OSL_VERIFY( i_event
.Element
>>= aImageURLs
);
502 ::std::vector
< CachedImage
> aImages
;
503 lcl_init( aImageURLs
, aImages
);
504 m_pData
->aCachedImageSets
[ position
] = aImages
;
505 lcl_updateImageList_nothrow( *m_pData
);
509 void SAL_CALL
AnimatedImagesPeer::disposing( const EventObject
& i_event
) throw (RuntimeException
, std::exception
)
511 VCLXWindow::disposing( i_event
);
515 void SAL_CALL
AnimatedImagesPeer::modified( const EventObject
& i_event
) throw (RuntimeException
, std::exception
)
517 impl_updateImages_nolck( i_event
.Source
);
521 void SAL_CALL
AnimatedImagesPeer::dispose( ) throw(RuntimeException
, std::exception
)
523 AnimatedImagesPeer_Base::dispose();
524 SolarMutexGuard aGuard
;
525 m_pData
->aCachedImageSets
.resize(0);
529 } // namespace toolkit
532 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */