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() != INetProtocol::PrivSoffice
)
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 VclPtr
<Throbber
> pThrobber
= i_data
.rAntiImpl
.GetAsDynamic
<Throbber
>();
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_xData( new AnimatedImagesPeer_Data( *this ) )
306 AnimatedImagesPeer::~AnimatedImagesPeer()
311 void SAL_CALL
AnimatedImagesPeer::startAnimation() throw (RuntimeException
, std::exception
)
313 SolarMutexGuard aGuard
;
314 VclPtr
<Throbber
> pThrobber
= GetAsDynamic
<Throbber
>();
319 void SAL_CALL
AnimatedImagesPeer::stopAnimation() throw (RuntimeException
, std::exception
)
321 SolarMutexGuard aGuard
;
322 VclPtr
<Throbber
> pThrobber
= GetAsDynamic
<Throbber
>();
327 sal_Bool SAL_CALL
AnimatedImagesPeer::isAnimationRunning() throw (RuntimeException
, std::exception
)
329 SolarMutexGuard aGuard
;
330 VclPtr
<Throbber
> pThrobber
= GetAsDynamic
<Throbber
>();
332 return pThrobber
->isRunning();
336 void SAL_CALL
AnimatedImagesPeer::setProperty( const OUString
& i_propertyName
, const Any
& i_value
) throw(RuntimeException
, std::exception
)
338 SolarMutexGuard aGuard
;
340 VclPtr
<Throbber
> pThrobber
= GetAsDynamic
<Throbber
>();
343 VCLXWindow::setProperty( i_propertyName
, i_value
);
347 const sal_uInt16 nPropertyId
= GetPropertyId( i_propertyName
);
348 switch ( nPropertyId
)
350 case BASEPROPERTY_STEP_TIME
:
352 sal_Int32
nStepTime( 0 );
353 if ( i_value
>>= nStepTime
)
354 pThrobber
->setStepTime( nStepTime
);
357 case BASEPROPERTY_AUTO_REPEAT
:
359 bool bRepeat( true );
360 if ( i_value
>>= bRepeat
)
361 pThrobber
->setRepeat( bRepeat
);
365 case BASEPROPERTY_IMAGE_SCALE_MODE
:
367 sal_Int16
nScaleMode( ImageScaleMode::ANISOTROPIC
);
368 VclPtr
<ImageControl
> pImageControl
= GetAsDynamic
< ImageControl
>();
369 if ( pImageControl
&& ( i_value
>>= nScaleMode
) )
370 pImageControl
->SetScaleMode( nScaleMode
);
375 AnimatedImagesPeer_Base::setProperty( i_propertyName
, i_value
);
381 Any SAL_CALL
AnimatedImagesPeer::getProperty( const OUString
& i_propertyName
) throw(RuntimeException
, std::exception
)
383 SolarMutexGuard aGuard
;
387 VclPtr
<Throbber
> pThrobber
= GetAsDynamic
<Throbber
>();
389 return VCLXWindow::getProperty( i_propertyName
);
391 const sal_uInt16 nPropertyId
= GetPropertyId( i_propertyName
);
392 switch ( nPropertyId
)
394 case BASEPROPERTY_STEP_TIME
:
395 aReturn
<<= pThrobber
->getStepTime();
398 case BASEPROPERTY_AUTO_REPEAT
:
399 aReturn
<<= pThrobber
->getRepeat();
402 case BASEPROPERTY_IMAGE_SCALE_MODE
:
404 VclPtr
<ImageControl
> pImageControl
= GetAsDynamic
<ImageControl
>();
405 aReturn
<<= ( pImageControl
? pImageControl
->GetScaleMode() : ImageScaleMode::ANISOTROPIC
);
410 aReturn
= AnimatedImagesPeer_Base::getProperty( i_propertyName
);
418 void AnimatedImagesPeer::ProcessWindowEvent( const VclWindowEvent
& i_windowEvent
)
420 switch ( i_windowEvent
.GetId() )
422 case VCLEVENT_WINDOW_RESIZE
:
423 lcl_updateImageList_nothrow( *m_xData
);
427 AnimatedImagesPeer_Base::ProcessWindowEvent( i_windowEvent
);
431 void AnimatedImagesPeer::impl_updateImages_nolck( const Reference
< XInterface
>& i_animatedImages
)
433 SolarMutexGuard aGuard
;
435 lcl_updateImageList_nothrow( *m_xData
, Reference
< XAnimatedImages
>( i_animatedImages
, UNO_QUERY_THROW
) );
439 void SAL_CALL
AnimatedImagesPeer::elementInserted( const ContainerEvent
& i_event
) throw (RuntimeException
, std::exception
)
441 SolarMutexGuard aGuard
;
442 Reference
< XAnimatedImages
> xAnimatedImages( i_event
.Source
, UNO_QUERY_THROW
);
444 sal_Int32
nPosition(0);
445 OSL_VERIFY( i_event
.Accessor
>>= nPosition
);
446 size_t position
= size_t( nPosition
);
447 if ( position
> m_xData
->aCachedImageSets
.size() )
449 OSL_ENSURE( false, "AnimatedImagesPeer::elementInserted: illegal accessor/index!" );
450 lcl_updateImageList_nothrow( *m_xData
, xAnimatedImages
);
453 Sequence
< OUString
> aImageURLs
;
454 OSL_VERIFY( i_event
.Element
>>= aImageURLs
);
455 ::std::vector
< CachedImage
> aImages
;
456 lcl_init( aImageURLs
, aImages
);
457 m_xData
->aCachedImageSets
.insert( m_xData
->aCachedImageSets
.begin() + position
, aImages
);
458 lcl_updateImageList_nothrow( *m_xData
);
462 void SAL_CALL
AnimatedImagesPeer::elementRemoved( const ContainerEvent
& i_event
) throw (RuntimeException
, std::exception
)
464 SolarMutexGuard aGuard
;
465 Reference
< XAnimatedImages
> xAnimatedImages( i_event
.Source
, UNO_QUERY_THROW
);
467 sal_Int32
nPosition(0);
468 OSL_VERIFY( i_event
.Accessor
>>= nPosition
);
469 size_t position
= size_t( nPosition
);
470 if ( position
>= m_xData
->aCachedImageSets
.size() )
472 OSL_ENSURE( false, "AnimatedImagesPeer::elementRemoved: illegal accessor/index!" );
473 lcl_updateImageList_nothrow( *m_xData
, xAnimatedImages
);
476 m_xData
->aCachedImageSets
.erase( m_xData
->aCachedImageSets
.begin() + position
);
477 lcl_updateImageList_nothrow( *m_xData
);
481 void SAL_CALL
AnimatedImagesPeer::elementReplaced( const ContainerEvent
& i_event
) throw (RuntimeException
, std::exception
)
483 SolarMutexGuard aGuard
;
484 Reference
< XAnimatedImages
> xAnimatedImages( i_event
.Source
, UNO_QUERY_THROW
);
486 sal_Int32
nPosition(0);
487 OSL_VERIFY( i_event
.Accessor
>>= nPosition
);
488 size_t position
= size_t( nPosition
);
489 if ( position
>= m_xData
->aCachedImageSets
.size() )
491 OSL_ENSURE( false, "AnimatedImagesPeer::elementReplaced: illegal accessor/index!" );
492 lcl_updateImageList_nothrow( *m_xData
, xAnimatedImages
);
495 Sequence
< OUString
> aImageURLs
;
496 OSL_VERIFY( i_event
.Element
>>= aImageURLs
);
497 ::std::vector
< CachedImage
> aImages
;
498 lcl_init( aImageURLs
, aImages
);
499 m_xData
->aCachedImageSets
[ position
] = aImages
;
500 lcl_updateImageList_nothrow( *m_xData
);
504 void SAL_CALL
AnimatedImagesPeer::disposing( const EventObject
& i_event
) throw (RuntimeException
, std::exception
)
506 VCLXWindow::disposing( i_event
);
510 void SAL_CALL
AnimatedImagesPeer::modified( const EventObject
& i_event
) throw (RuntimeException
, std::exception
)
512 impl_updateImages_nolck( i_event
.Source
);
516 void SAL_CALL
AnimatedImagesPeer::dispose( ) throw(RuntimeException
, std::exception
)
518 AnimatedImagesPeer_Base::dispose();
519 SolarMutexGuard aGuard
;
520 m_xData
->aCachedImageSets
.resize(0);
524 } // namespace toolkit
527 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */