1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
29 #include "toolkit/awt/animatedimagespeer.hxx"
30 #include "toolkit/helper/property.hxx"
32 /** === begin UNO includes === **/
33 #include <com/sun/star/awt/XAnimatedImages.hpp>
34 #include <com/sun/star/awt/Size.hpp>
35 #include <com/sun/star/graphic/GraphicProvider.hpp>
36 #include <com/sun/star/graphic/XGraphicProvider.hpp>
37 #include <com/sun/star/beans/XPropertySet.hpp>
38 #include <com/sun/star/graphic/XGraphic.hpp>
39 #include <com/sun/star/awt/ImageScaleMode.hpp>
40 /** === end UNO includes === **/
42 #include <comphelper/componentcontext.hxx>
43 #include <comphelper/namedvaluecollection.hxx>
44 #include <comphelper/processfactory.hxx>
45 #include <rtl/ustrbuf.hxx>
46 #include <tools/diagnose_ex.h>
47 #include <tools/urlobj.hxx>
48 #include <vcl/throbber.hxx>
49 #include <vcl/svapp.hxx>
53 //......................................................................................................................
56 //......................................................................................................................
58 /** === begin UNO using === **/
59 using ::com::sun::star::uno::XComponentContext
;
60 using ::com::sun::star::uno::Reference
;
61 using ::com::sun::star::uno::XInterface
;
62 using ::com::sun::star::uno::UNO_QUERY
;
63 using ::com::sun::star::uno::UNO_QUERY_THROW
;
64 using ::com::sun::star::uno::UNO_SET_THROW
;
65 using ::com::sun::star::uno::Exception
;
66 using ::com::sun::star::uno::RuntimeException
;
67 using ::com::sun::star::uno::Any
;
68 using ::com::sun::star::uno::makeAny
;
69 using ::com::sun::star::uno::Sequence
;
70 using ::com::sun::star::uno::Type
;
71 using ::com::sun::star::lang::EventObject
;
72 using ::com::sun::star::container::ContainerEvent
;
73 using ::com::sun::star::awt::XAnimatedImages
;
74 using ::com::sun::star::awt::Size
;
75 using ::com::sun::star::lang::XMultiServiceFactory
;
76 using ::com::sun::star::graphic::XGraphicProvider
;
77 using ::com::sun::star::beans::XPropertySet
;
78 using ::com::sun::star::graphic::XGraphic
;
79 /** === end UNO using === **/
80 namespace ImageScaleMode
= ::com::sun::star::awt::ImageScaleMode
;
82 //==================================================================================================================
83 //= AnimatedImagesPeer_Data
84 //==================================================================================================================
87 ::rtl::OUString sImageURL
;
88 mutable Reference
< XGraphic
> xGraphic
;
96 CachedImage( ::rtl::OUString
const& i_imageURL
)
97 :sImageURL( i_imageURL
)
103 struct AnimatedImagesPeer_Data
105 AnimatedImagesPeer
& rAntiImpl
;
106 ::std::vector
< ::std::vector
< CachedImage
> > aCachedImageSets
;
108 AnimatedImagesPeer_Data( AnimatedImagesPeer
& i_antiImpl
)
109 :rAntiImpl( i_antiImpl
)
115 //==================================================================================================================
117 //==================================================================================================================
120 //--------------------------------------------------------------------------------------------------------------
121 ::rtl::OUString
lcl_getHighContrastURL( ::rtl::OUString
const& i_imageURL
)
123 INetURLObject
aURL( i_imageURL
);
124 if ( aURL
.GetProtocol() != INET_PROT_PRIV_SOFFICE
)
126 OSL_VERIFY( aURL
.insertName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "hicontrast" ) ), false, 0 ) );
127 return aURL
.GetMainURL( INetURLObject::NO_DECODE
);
129 // the private: scheme is not considered to be hierarchical by INetURLObject, so manually insert the
131 const sal_Int32 separatorPos
= i_imageURL
.indexOf( '/' );
132 ENSURE_OR_RETURN( separatorPos
!= -1, "lcl_getHighContrastURL: unsipported URL scheme - cannot automatically determine HC version!", i_imageURL
);
134 ::rtl::OUStringBuffer composer
;
135 composer
.append( i_imageURL
.copy( 0, separatorPos
) );
136 composer
.appendAscii( "/hicontrast" );
137 composer
.append( i_imageURL
.copy( separatorPos
) );
138 return composer
.makeStringAndClear();
141 //--------------------------------------------------------------------------------------------------------------
142 bool lcl_ensureImage_throw( Reference
< XGraphicProvider
> const& i_graphicProvider
, const bool i_isHighContrast
, const CachedImage
& i_cachedImage
)
144 if ( !i_cachedImage
.xGraphic
.is() )
146 ::comphelper::NamedValueCollection aMediaProperties
;
147 if ( i_isHighContrast
)
149 // try (to find) the high-contrast version of the graphic first
150 aMediaProperties
.put( "URL", lcl_getHighContrastURL( i_cachedImage
.sImageURL
) );
151 i_cachedImage
.xGraphic
.set( i_graphicProvider
->queryGraphic( aMediaProperties
.getPropertyValues() ), UNO_QUERY
);
153 if ( !i_cachedImage
.xGraphic
.is() )
155 aMediaProperties
.put( "URL", i_cachedImage
.sImageURL
);
156 i_cachedImage
.xGraphic
.set( i_graphicProvider
->queryGraphic( aMediaProperties
.getPropertyValues() ), UNO_QUERY
);
159 return i_cachedImage
.xGraphic
.is();
162 //--------------------------------------------------------------------------------------------------------------
163 Size
lcl_getGraphicSizePixel( Reference
< XGraphic
> const& i_graphic
)
168 if ( i_graphic
.is() )
170 const Reference
< XPropertySet
> xGraphicProps( i_graphic
, UNO_QUERY_THROW
);
171 OSL_VERIFY( xGraphicProps
->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "SizePixel" ) ) ) >>= aSizePixel
);
174 catch( const Exception
& )
176 DBG_UNHANDLED_EXCEPTION();
181 //--------------------------------------------------------------------------------------------------------------
182 void lcl_init( Sequence
< ::rtl::OUString
> const& i_imageURLs
, ::std::vector
< CachedImage
>& o_images
)
185 size_t count
= size_t( i_imageURLs
.getLength() );
186 o_images
.reserve( count
);
187 for ( size_t i
= 0; i
< count
; ++i
)
189 o_images
.push_back( CachedImage( i_imageURLs
[i
] ) );
193 //--------------------------------------------------------------------------------------------------------------
194 void lcl_updateImageList_nothrow( AnimatedImagesPeer_Data
& i_data
)
196 Throbber
* pThrobber
= dynamic_cast< Throbber
* >( i_data
.rAntiImpl
.GetWindow() );
197 if ( pThrobber
== NULL
)
202 // collect the image sizes of the different image sets
203 const Reference
< XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
204 const Reference
< XGraphicProvider
> xGraphicProvider( com::sun::star::graphic::GraphicProvider::create(xContext
) );
206 const bool isHighContrast
= pThrobber
->GetSettings().GetStyleSettings().GetHighContrastMode();
208 sal_Int32 nPreferredSet
= -1;
209 const size_t nImageSetCount
= i_data
.aCachedImageSets
.size();
210 if ( nImageSetCount
< 2 )
212 nPreferredSet
= sal_Int32( nImageSetCount
) - 1;
216 ::std::vector
< Size
> aImageSizes( nImageSetCount
);
217 for ( sal_Int32 nImageSet
= 0; size_t( nImageSet
) < nImageSetCount
; ++nImageSet
)
219 ::std::vector
< CachedImage
> const& rImageSet( i_data
.aCachedImageSets
[ nImageSet
] );
220 if ( ( rImageSet
.empty() )
221 || ( !lcl_ensureImage_throw( xGraphicProvider
, isHighContrast
, rImageSet
[0] ) )
224 aImageSizes
[ nImageSet
] = Size( SAL_MAX_INT32
, SAL_MAX_INT32
);
228 aImageSizes
[ nImageSet
] = lcl_getGraphicSizePixel( rImageSet
[0].xGraphic
);
232 // find the set with the smallest difference between window size and image size
233 const ::Size aWindowSizePixel
= pThrobber
->GetSizePixel();
234 long nMinimalDistance
= ::std::numeric_limits
< long >::max();
235 for ( ::std::vector
< Size
>::const_iterator check
= aImageSizes
.begin();
236 check
!= aImageSizes
.end();
240 if ( ( check
->Width
> aWindowSizePixel
.Width() )
241 || ( check
->Height
> aWindowSizePixel
.Height() )
243 // do not use an image set which doesn't fit into the window
246 const sal_Int64 distance
=
247 ( aWindowSizePixel
.Width() - check
->Width
) * ( aWindowSizePixel
.Width() - check
->Width
)
248 + ( aWindowSizePixel
.Height() - check
->Height
) * ( aWindowSizePixel
.Height() - check
->Height
);
249 if ( distance
< nMinimalDistance
)
251 nMinimalDistance
= distance
;
252 nPreferredSet
= check
- aImageSizes
.begin();
258 Sequence
< Reference
< XGraphic
> > aImages
;
259 if ( ( nPreferredSet
>= 0 ) && ( size_t( nPreferredSet
) < nImageSetCount
) )
262 ::std::vector
< CachedImage
> const& rImageSet( i_data
.aCachedImageSets
[ nPreferredSet
] );
263 aImages
.realloc( rImageSet
.size() );
264 sal_Int32 imageIndex
= 0;
265 for ( ::std::vector
< CachedImage
>::const_iterator cachedImage
= rImageSet
.begin();
266 cachedImage
!= rImageSet
.end();
267 ++cachedImage
, ++imageIndex
270 lcl_ensureImage_throw( xGraphicProvider
, isHighContrast
, *cachedImage
);
271 aImages
[ imageIndex
] = cachedImage
->xGraphic
;
274 pThrobber
->setImageList( aImages
);
276 catch( const Exception
& )
278 DBG_UNHANDLED_EXCEPTION();
282 //--------------------------------------------------------------------------------------------------------------
283 void lcl_updateImageList_nothrow( AnimatedImagesPeer_Data
& i_data
, const Reference
< XAnimatedImages
>& i_images
)
287 const sal_Int32 nImageSetCount
= i_images
->getImageSetCount();
288 i_data
.aCachedImageSets
.resize(0);
289 for ( sal_Int32 set
= 0; set
< nImageSetCount
; ++set
)
291 const Sequence
< ::rtl::OUString
> aImageURLs( i_images
->getImageSet( set
) );
292 ::std::vector
< CachedImage
> aImages
;
293 lcl_init( aImageURLs
, aImages
);
294 i_data
.aCachedImageSets
.push_back( aImages
);
297 lcl_updateImageList_nothrow( i_data
);
299 catch( const Exception
& )
301 DBG_UNHANDLED_EXCEPTION();
306 //==================================================================================================================
307 //= AnimatedImagesPeer
308 //==================================================================================================================
309 //------------------------------------------------------------------------------------------------------------------
310 AnimatedImagesPeer::AnimatedImagesPeer()
311 :AnimatedImagesPeer_Base()
312 ,m_pData( new AnimatedImagesPeer_Data( *this ) )
316 //------------------------------------------------------------------------------------------------------------------
317 AnimatedImagesPeer::~AnimatedImagesPeer()
321 //------------------------------------------------------------------------------------------------------------------
322 void SAL_CALL
AnimatedImagesPeer::startAnimation( ) throw (RuntimeException
)
324 SolarMutexGuard aGuard
;
325 Throbber
* pThrobber( dynamic_cast< Throbber
* >( GetWindow() ) );
326 if ( pThrobber
!= NULL
)
330 //------------------------------------------------------------------------------------------------------------------
331 void SAL_CALL
AnimatedImagesPeer::stopAnimation( ) throw (RuntimeException
)
333 SolarMutexGuard aGuard
;
334 Throbber
* pThrobber( dynamic_cast< Throbber
* >( GetWindow() ) );
335 if ( pThrobber
!= NULL
)
339 //------------------------------------------------------------------------------------------------------------------
340 ::sal_Bool SAL_CALL
AnimatedImagesPeer::isAnimationRunning( ) throw (RuntimeException
)
342 SolarMutexGuard aGuard
;
343 Throbber
* pThrobber( dynamic_cast< Throbber
* >( GetWindow() ) );
344 if ( pThrobber
!= NULL
)
345 return pThrobber
->isRunning();
349 //------------------------------------------------------------------------------------------------------------------
350 void SAL_CALL
AnimatedImagesPeer::setProperty( const ::rtl::OUString
& i_propertyName
, const Any
& i_value
) throw(RuntimeException
)
352 SolarMutexGuard aGuard
;
354 Throbber
* pThrobber( dynamic_cast< Throbber
* >( GetWindow() ) );
355 if ( pThrobber
== NULL
)
357 VCLXWindow::setProperty( i_propertyName
, i_value
);
361 const sal_uInt16 nPropertyId
= GetPropertyId( i_propertyName
);
362 switch ( nPropertyId
)
364 case BASEPROPERTY_STEP_TIME
:
366 sal_Int32
nStepTime( 0 );
367 if ( i_value
>>= nStepTime
)
368 pThrobber
->setStepTime( nStepTime
);
371 case BASEPROPERTY_AUTO_REPEAT
:
373 sal_Bool
bRepeat( sal_True
);
374 if ( i_value
>>= bRepeat
)
375 pThrobber
->setRepeat( bRepeat
);
379 case BASEPROPERTY_IMAGE_SCALE_MODE
:
381 sal_Int16
nScaleMode( ImageScaleMode::Anisotropic
);
382 ImageControl
* pImageControl
= dynamic_cast< ImageControl
* >( GetWindow() );
383 if ( pImageControl
&& ( i_value
>>= nScaleMode
) )
385 pImageControl
->SetScaleMode( nScaleMode
);
391 AnimatedImagesPeer_Base::setProperty( i_propertyName
, i_value
);
396 //------------------------------------------------------------------------------------------------------------------
397 Any SAL_CALL
AnimatedImagesPeer::getProperty( const ::rtl::OUString
& i_propertyName
) throw(RuntimeException
)
399 SolarMutexGuard aGuard
;
403 Throbber
* pThrobber( dynamic_cast< Throbber
* >( GetWindow() ) );
404 if ( pThrobber
== NULL
)
405 return VCLXWindow::getProperty( i_propertyName
);
407 const sal_uInt16 nPropertyId
= GetPropertyId( i_propertyName
);
408 switch ( nPropertyId
)
410 case BASEPROPERTY_STEP_TIME
:
411 aReturn
<<= pThrobber
->getStepTime();
414 case BASEPROPERTY_AUTO_REPEAT
:
415 aReturn
<<= pThrobber
->getRepeat();
418 case BASEPROPERTY_IMAGE_SCALE_MODE
:
420 ImageControl
const* pImageControl
= dynamic_cast< ImageControl
* >( GetWindow() );
421 aReturn
<<= ( pImageControl
? pImageControl
->GetScaleMode() : ImageScaleMode::Anisotropic
);
426 aReturn
= AnimatedImagesPeer_Base::getProperty( i_propertyName
);
433 //------------------------------------------------------------------------------------------------------------------
434 void AnimatedImagesPeer::ProcessWindowEvent( const VclWindowEvent
& i_windowEvent
)
436 switch ( i_windowEvent
.GetId() )
438 case VCLEVENT_WINDOW_RESIZE
:
439 lcl_updateImageList_nothrow( *m_pData
);
443 AnimatedImagesPeer_Base::ProcessWindowEvent( i_windowEvent
);
446 //------------------------------------------------------------------------------------------------------------------
447 void AnimatedImagesPeer::impl_updateImages_nolck( const Reference
< XInterface
>& i_animatedImages
)
449 SolarMutexGuard aGuard
;
451 lcl_updateImageList_nothrow( *m_pData
, Reference
< XAnimatedImages
>( i_animatedImages
, UNO_QUERY_THROW
) );
454 //------------------------------------------------------------------------------------------------------------------
455 void SAL_CALL
AnimatedImagesPeer::elementInserted( const ContainerEvent
& i_event
) throw (RuntimeException
)
457 SolarMutexGuard aGuard
;
458 Reference
< XAnimatedImages
> xAnimatedImages( i_event
.Source
, UNO_QUERY_THROW
);
460 sal_Int32
nPosition(0);
461 OSL_VERIFY( i_event
.Accessor
>>= nPosition
);
462 size_t position
= size_t( nPosition
);
463 if ( position
> m_pData
->aCachedImageSets
.size() )
465 OSL_ENSURE( false, "AnimatedImagesPeer::elementInserted: illegal accessor/index!" );
466 lcl_updateImageList_nothrow( *m_pData
, xAnimatedImages
);
469 Sequence
< ::rtl::OUString
> aImageURLs
;
470 OSL_VERIFY( i_event
.Element
>>= aImageURLs
);
471 ::std::vector
< CachedImage
> aImages
;
472 lcl_init( aImageURLs
, aImages
);
473 m_pData
->aCachedImageSets
.insert( m_pData
->aCachedImageSets
.begin() + position
, aImages
);
474 lcl_updateImageList_nothrow( *m_pData
);
477 //------------------------------------------------------------------------------------------------------------------
478 void SAL_CALL
AnimatedImagesPeer::elementRemoved( const ContainerEvent
& i_event
) throw (RuntimeException
)
480 SolarMutexGuard aGuard
;
481 Reference
< XAnimatedImages
> xAnimatedImages( i_event
.Source
, UNO_QUERY_THROW
);
483 sal_Int32
nPosition(0);
484 OSL_VERIFY( i_event
.Accessor
>>= nPosition
);
485 size_t position
= size_t( nPosition
);
486 if ( position
>= m_pData
->aCachedImageSets
.size() )
488 OSL_ENSURE( false, "AnimatedImagesPeer::elementRemoved: illegal accessor/index!" );
489 lcl_updateImageList_nothrow( *m_pData
, xAnimatedImages
);
492 m_pData
->aCachedImageSets
.erase( m_pData
->aCachedImageSets
.begin() + position
);
493 lcl_updateImageList_nothrow( *m_pData
);
496 //------------------------------------------------------------------------------------------------------------------
497 void SAL_CALL
AnimatedImagesPeer::elementReplaced( const ContainerEvent
& i_event
) throw (RuntimeException
)
499 SolarMutexGuard aGuard
;
500 Reference
< XAnimatedImages
> xAnimatedImages( i_event
.Source
, UNO_QUERY_THROW
);
502 sal_Int32
nPosition(0);
503 OSL_VERIFY( i_event
.Accessor
>>= nPosition
);
504 size_t position
= size_t( nPosition
);
505 if ( position
>= m_pData
->aCachedImageSets
.size() )
507 OSL_ENSURE( false, "AnimatedImagesPeer::elementReplaced: illegal accessor/index!" );
508 lcl_updateImageList_nothrow( *m_pData
, xAnimatedImages
);
511 Sequence
< ::rtl::OUString
> aImageURLs
;
512 OSL_VERIFY( i_event
.Element
>>= aImageURLs
);
513 ::std::vector
< CachedImage
> aImages
;
514 lcl_init( aImageURLs
, aImages
);
515 m_pData
->aCachedImageSets
[ position
] = aImages
;
516 lcl_updateImageList_nothrow( *m_pData
);
519 //------------------------------------------------------------------------------------------------------------------
520 void SAL_CALL
AnimatedImagesPeer::disposing( const EventObject
& i_event
) throw (RuntimeException
)
522 VCLXWindow::disposing( i_event
);
525 //------------------------------------------------------------------------------------------------------------------
526 void SAL_CALL
AnimatedImagesPeer::modified( const EventObject
& i_event
) throw (RuntimeException
)
528 impl_updateImages_nolck( i_event
.Source
);
531 //------------------------------------------------------------------------------------------------------------------
532 void SAL_CALL
AnimatedImagesPeer::dispose( ) throw(RuntimeException
)
534 AnimatedImagesPeer_Base::dispose();
535 SolarMutexGuard aGuard
;
536 m_pData
->aCachedImageSets
.resize(0);
539 //......................................................................................................................
540 } // namespace toolkit
541 //......................................................................................................................
543 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */