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::Exception
;
54 using ::com::sun::star::uno::RuntimeException
;
55 using ::com::sun::star::uno::Any
;
56 using ::com::sun::star::uno::Sequence
;
57 using ::com::sun::star::lang::EventObject
;
58 using ::com::sun::star::container::ContainerEvent
;
59 using ::com::sun::star::awt::XAnimatedImages
;
60 using ::com::sun::star::awt::Size
;
61 using ::com::sun::star::graphic::XGraphicProvider
;
62 using ::com::sun::star::beans::XPropertySet
;
63 using ::com::sun::star::graphic::XGraphic
;
65 namespace ImageScaleMode
= ::com::sun::star::awt::ImageScaleMode
;
68 //= AnimatedImagesPeer_Data
73 mutable Reference
< XGraphic
> xGraphic
;
81 explicit CachedImage( OUString
const& i_imageURL
)
82 :sImageURL( i_imageURL
)
88 struct AnimatedImagesPeer_Data
90 AnimatedImagesPeer
& rAntiImpl
;
91 ::std::vector
< ::std::vector
< CachedImage
> > aCachedImageSets
;
93 explicit AnimatedImagesPeer_Data( AnimatedImagesPeer
& i_antiImpl
)
94 :rAntiImpl( i_antiImpl
)
106 OUString
lcl_getHighContrastURL( OUString
const& i_imageURL
)
108 INetURLObject
aURL( i_imageURL
);
109 if ( aURL
.GetProtocol() != INetProtocol::PrivSoffice
)
111 OSL_VERIFY( aURL
.insertName( "hicontrast", false, 0 ) );
112 return aURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
114 // the private: scheme is not considered to be hierarchical by INetURLObject, so manually insert the
116 const sal_Int32 separatorPos
= i_imageURL
.indexOf( '/' );
117 ENSURE_OR_RETURN( separatorPos
!= -1, "lcl_getHighContrastURL: unsupported URL scheme - cannot automatically determine HC version!", i_imageURL
);
119 OUStringBuffer composer
;
120 composer
.append( i_imageURL
.copy( 0, separatorPos
) );
121 composer
.append( "/hicontrast" );
122 composer
.append( i_imageURL
.copy( separatorPos
) );
123 return composer
.makeStringAndClear();
127 bool lcl_ensureImage_throw( Reference
< XGraphicProvider
> const& i_graphicProvider
, const bool i_isHighContrast
, const CachedImage
& i_cachedImage
)
129 if ( !i_cachedImage
.xGraphic
.is() )
131 ::comphelper::NamedValueCollection aMediaProperties
;
132 if ( i_isHighContrast
)
134 // try (to find) the high-contrast version of the graphic first
135 aMediaProperties
.put( "URL", lcl_getHighContrastURL( i_cachedImage
.sImageURL
) );
136 i_cachedImage
.xGraphic
.set( i_graphicProvider
->queryGraphic( aMediaProperties
.getPropertyValues() ), UNO_QUERY
);
138 if ( !i_cachedImage
.xGraphic
.is() )
140 aMediaProperties
.put( "URL", i_cachedImage
.sImageURL
);
141 i_cachedImage
.xGraphic
.set( i_graphicProvider
->queryGraphic( aMediaProperties
.getPropertyValues() ), UNO_QUERY
);
144 return i_cachedImage
.xGraphic
.is();
148 Size
lcl_getGraphicSizePixel( Reference
< XGraphic
> const& i_graphic
)
153 if ( i_graphic
.is() )
155 const Reference
< XPropertySet
> xGraphicProps( i_graphic
, UNO_QUERY_THROW
);
156 OSL_VERIFY( xGraphicProps
->getPropertyValue("SizePixel") >>= aSizePixel
);
159 catch( const Exception
& )
161 DBG_UNHANDLED_EXCEPTION();
167 void lcl_init( Sequence
< OUString
> const& i_imageURLs
, ::std::vector
< CachedImage
>& o_images
)
170 size_t count
= size_t( i_imageURLs
.getLength() );
171 o_images
.reserve( count
);
172 for ( size_t i
= 0; i
< count
; ++i
)
174 o_images
.push_back( CachedImage( i_imageURLs
[i
] ) );
179 void lcl_updateImageList_nothrow( AnimatedImagesPeer_Data
& i_data
)
181 VclPtr
<Throbber
> pThrobber
= i_data
.rAntiImpl
.GetAsDynamic
<Throbber
>();
187 // collect the image sizes of the different image sets
188 const Reference
< XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
189 const Reference
< XGraphicProvider
> xGraphicProvider( css::graphic::GraphicProvider::create(xContext
) );
191 const bool isHighContrast
= pThrobber
->GetSettings().GetStyleSettings().GetHighContrastMode();
193 sal_Int32 nPreferredSet
= -1;
194 const size_t nImageSetCount
= i_data
.aCachedImageSets
.size();
195 if ( nImageSetCount
< 2 )
197 nPreferredSet
= sal_Int32( nImageSetCount
) - 1;
201 ::std::vector
< Size
> aImageSizes( nImageSetCount
);
202 for ( size_t nImageSet
= 0; nImageSet
< nImageSetCount
; ++nImageSet
)
204 ::std::vector
< CachedImage
> const& rImageSet( i_data
.aCachedImageSets
[ nImageSet
] );
205 if ( ( rImageSet
.empty() )
206 || ( !lcl_ensureImage_throw( xGraphicProvider
, isHighContrast
, rImageSet
[0] ) )
209 aImageSizes
[ nImageSet
] = Size( SAL_MAX_INT32
, SAL_MAX_INT32
);
213 aImageSizes
[ nImageSet
] = lcl_getGraphicSizePixel( rImageSet
[0].xGraphic
);
217 // find the set with the smallest difference between window size and image size
218 const ::Size aWindowSizePixel
= pThrobber
->GetSizePixel();
219 long nMinimalDistance
= ::std::numeric_limits
< long >::max();
220 for ( ::std::vector
< Size
>::const_iterator check
= aImageSizes
.begin();
221 check
!= aImageSizes
.end();
225 if ( ( check
->Width
> aWindowSizePixel
.Width() )
226 || ( check
->Height
> aWindowSizePixel
.Height() )
228 // do not use an image set which doesn't fit into the window
231 const sal_Int64 distance
=
232 ( aWindowSizePixel
.Width() - check
->Width
) * ( aWindowSizePixel
.Width() - check
->Width
)
233 + ( aWindowSizePixel
.Height() - check
->Height
) * ( aWindowSizePixel
.Height() - check
->Height
);
234 if ( distance
< nMinimalDistance
)
236 nMinimalDistance
= distance
;
237 nPreferredSet
= check
- aImageSizes
.begin();
243 std::vector
< Image
> aImages
;
244 if ( ( nPreferredSet
>= 0 ) && ( size_t( nPreferredSet
) < nImageSetCount
) )
247 ::std::vector
< CachedImage
> const& rImageSet( i_data
.aCachedImageSets
[ nPreferredSet
] );
248 aImages
.resize( rImageSet
.size() );
249 sal_Int32 imageIndex
= 0;
250 for ( ::std::vector
< CachedImage
>::const_iterator cachedImage
= rImageSet
.begin();
251 cachedImage
!= rImageSet
.end();
252 ++cachedImage
, ++imageIndex
255 lcl_ensureImage_throw( xGraphicProvider
, isHighContrast
, *cachedImage
);
256 aImages
[ imageIndex
] = Image(cachedImage
->xGraphic
);
259 pThrobber
->setImageList( aImages
);
261 catch( const Exception
& )
263 DBG_UNHANDLED_EXCEPTION();
268 void lcl_updateImageList_nothrow( AnimatedImagesPeer_Data
& i_data
, const Reference
< XAnimatedImages
>& i_images
)
272 const sal_Int32 nImageSetCount
= i_images
->getImageSetCount();
273 i_data
.aCachedImageSets
.resize(0);
274 for ( sal_Int32 set
= 0; set
< nImageSetCount
; ++set
)
276 const Sequence
< OUString
> aImageURLs( i_images
->getImageSet( set
) );
277 ::std::vector
< CachedImage
> aImages
;
278 lcl_init( aImageURLs
, aImages
);
279 i_data
.aCachedImageSets
.push_back( aImages
);
282 lcl_updateImageList_nothrow( i_data
);
284 catch( const Exception
& )
286 DBG_UNHANDLED_EXCEPTION();
292 //= AnimatedImagesPeer
295 AnimatedImagesPeer::AnimatedImagesPeer()
296 :AnimatedImagesPeer_Base()
297 ,m_xData( new AnimatedImagesPeer_Data( *this ) )
302 AnimatedImagesPeer::~AnimatedImagesPeer()
307 void SAL_CALL
AnimatedImagesPeer::startAnimation()
309 SolarMutexGuard aGuard
;
310 VclPtr
<Throbber
> pThrobber
= GetAsDynamic
<Throbber
>();
315 void SAL_CALL
AnimatedImagesPeer::stopAnimation()
317 SolarMutexGuard aGuard
;
318 VclPtr
<Throbber
> pThrobber
= GetAsDynamic
<Throbber
>();
323 sal_Bool SAL_CALL
AnimatedImagesPeer::isAnimationRunning()
325 SolarMutexGuard aGuard
;
326 VclPtr
<Throbber
> pThrobber
= GetAsDynamic
<Throbber
>();
328 return pThrobber
->isRunning();
332 void SAL_CALL
AnimatedImagesPeer::setProperty( const OUString
& i_propertyName
, const Any
& i_value
)
334 SolarMutexGuard aGuard
;
336 VclPtr
<Throbber
> pThrobber
= GetAsDynamic
<Throbber
>();
339 VCLXWindow::setProperty( i_propertyName
, i_value
);
343 const sal_uInt16 nPropertyId
= GetPropertyId( i_propertyName
);
344 switch ( nPropertyId
)
346 case BASEPROPERTY_STEP_TIME
:
348 sal_Int32
nStepTime( 0 );
349 if ( i_value
>>= nStepTime
)
350 pThrobber
->setStepTime( nStepTime
);
353 case BASEPROPERTY_AUTO_REPEAT
:
355 bool bRepeat( true );
356 if ( i_value
>>= bRepeat
)
357 pThrobber
->setRepeat( bRepeat
);
361 case BASEPROPERTY_IMAGE_SCALE_MODE
:
363 sal_Int16
nScaleMode( ImageScaleMode::ANISOTROPIC
);
364 VclPtr
<ImageControl
> pImageControl
= GetAsDynamic
< ImageControl
>();
365 if ( pImageControl
&& ( i_value
>>= nScaleMode
) )
366 pImageControl
->SetScaleMode( nScaleMode
);
371 AnimatedImagesPeer_Base::setProperty( i_propertyName
, i_value
);
377 Any SAL_CALL
AnimatedImagesPeer::getProperty( const OUString
& i_propertyName
)
379 SolarMutexGuard aGuard
;
383 VclPtr
<Throbber
> pThrobber
= GetAsDynamic
<Throbber
>();
385 return VCLXWindow::getProperty( i_propertyName
);
387 const sal_uInt16 nPropertyId
= GetPropertyId( i_propertyName
);
388 switch ( nPropertyId
)
390 case BASEPROPERTY_STEP_TIME
:
391 aReturn
<<= pThrobber
->getStepTime();
394 case BASEPROPERTY_AUTO_REPEAT
:
395 aReturn
<<= pThrobber
->getRepeat();
398 case BASEPROPERTY_IMAGE_SCALE_MODE
:
400 VclPtr
<ImageControl
> pImageControl
= GetAsDynamic
<ImageControl
>();
401 aReturn
<<= ( pImageControl
? pImageControl
->GetScaleMode() : ImageScaleMode::ANISOTROPIC
);
406 aReturn
= AnimatedImagesPeer_Base::getProperty( i_propertyName
);
414 void AnimatedImagesPeer::ProcessWindowEvent( const VclWindowEvent
& i_windowEvent
)
416 if ( i_windowEvent
.GetId() == VclEventId::WindowResize
)
418 lcl_updateImageList_nothrow( *m_xData
);
421 AnimatedImagesPeer_Base::ProcessWindowEvent( i_windowEvent
);
425 void AnimatedImagesPeer::impl_updateImages_nolck( const Reference
< XInterface
>& i_animatedImages
)
427 SolarMutexGuard aGuard
;
429 lcl_updateImageList_nothrow( *m_xData
, Reference
< XAnimatedImages
>( i_animatedImages
, UNO_QUERY_THROW
) );
433 void SAL_CALL
AnimatedImagesPeer::elementInserted( const ContainerEvent
& i_event
)
435 SolarMutexGuard aGuard
;
436 Reference
< XAnimatedImages
> xAnimatedImages( i_event
.Source
, UNO_QUERY_THROW
);
438 sal_Int32
nPosition(0);
439 OSL_VERIFY( i_event
.Accessor
>>= nPosition
);
440 size_t position
= size_t( nPosition
);
441 if ( position
> m_xData
->aCachedImageSets
.size() )
443 OSL_ENSURE( false, "AnimatedImagesPeer::elementInserted: illegal accessor/index!" );
444 lcl_updateImageList_nothrow( *m_xData
, xAnimatedImages
);
447 Sequence
< OUString
> aImageURLs
;
448 OSL_VERIFY( i_event
.Element
>>= aImageURLs
);
449 ::std::vector
< CachedImage
> aImages
;
450 lcl_init( aImageURLs
, aImages
);
451 m_xData
->aCachedImageSets
.insert( m_xData
->aCachedImageSets
.begin() + position
, aImages
);
452 lcl_updateImageList_nothrow( *m_xData
);
456 void SAL_CALL
AnimatedImagesPeer::elementRemoved( const ContainerEvent
& i_event
)
458 SolarMutexGuard aGuard
;
459 Reference
< XAnimatedImages
> xAnimatedImages( i_event
.Source
, UNO_QUERY_THROW
);
461 sal_Int32
nPosition(0);
462 OSL_VERIFY( i_event
.Accessor
>>= nPosition
);
463 size_t position
= size_t( nPosition
);
464 if ( position
>= m_xData
->aCachedImageSets
.size() )
466 OSL_ENSURE( false, "AnimatedImagesPeer::elementRemoved: illegal accessor/index!" );
467 lcl_updateImageList_nothrow( *m_xData
, xAnimatedImages
);
470 m_xData
->aCachedImageSets
.erase( m_xData
->aCachedImageSets
.begin() + position
);
471 lcl_updateImageList_nothrow( *m_xData
);
475 void SAL_CALL
AnimatedImagesPeer::elementReplaced( const ContainerEvent
& i_event
)
477 SolarMutexGuard aGuard
;
478 Reference
< XAnimatedImages
> xAnimatedImages( i_event
.Source
, UNO_QUERY_THROW
);
480 sal_Int32
nPosition(0);
481 OSL_VERIFY( i_event
.Accessor
>>= nPosition
);
482 size_t position
= size_t( nPosition
);
483 if ( position
>= m_xData
->aCachedImageSets
.size() )
485 OSL_ENSURE( false, "AnimatedImagesPeer::elementReplaced: illegal accessor/index!" );
486 lcl_updateImageList_nothrow( *m_xData
, xAnimatedImages
);
489 Sequence
< OUString
> aImageURLs
;
490 OSL_VERIFY( i_event
.Element
>>= aImageURLs
);
491 ::std::vector
< CachedImage
> aImages
;
492 lcl_init( aImageURLs
, aImages
);
493 m_xData
->aCachedImageSets
[ position
] = aImages
;
494 lcl_updateImageList_nothrow( *m_xData
);
498 void SAL_CALL
AnimatedImagesPeer::disposing( const EventObject
& i_event
)
500 VCLXWindow::disposing( i_event
);
504 void SAL_CALL
AnimatedImagesPeer::modified( const EventObject
& i_event
)
506 impl_updateImages_nolck( i_event
.Source
);
510 void SAL_CALL
AnimatedImagesPeer::dispose( )
512 AnimatedImagesPeer_Base::dispose();
513 SolarMutexGuard aGuard
;
514 m_xData
->aCachedImageSets
.resize(0);
518 } // namespace toolkit
521 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */