Gtk-WARNING gtktreestore.c:1047: Invalid column number 1 added to iter
[LibreOffice.git] / toolkit / source / awt / animatedimagespeer.cxx
blob8c4be5b324c2fa5a0a5097a18bae002f04d55898
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <awt/animatedimagespeer.hxx>
22 #include <helper/property.hxx>
24 #include <com/sun/star/awt/Size.hpp>
25 #include <com/sun/star/graphic/GraphicProvider.hpp>
26 #include <com/sun/star/graphic/XGraphicProvider.hpp>
27 #include <com/sun/star/beans/XPropertySet.hpp>
28 #include <com/sun/star/awt/ImageScaleMode.hpp>
30 #include <comphelper/namedvaluecollection.hxx>
31 #include <comphelper/processfactory.hxx>
32 #include <o3tl/safeint.hxx>
33 #include <comphelper/diagnose_ex.hxx>
34 #include <tools/urlobj.hxx>
35 #include <vcl/toolkit/throbber.hxx>
36 #include <vcl/svapp.hxx>
37 #include <vcl/settings.hxx>
39 #include <limits>
40 #include <string_view>
42 namespace toolkit
46 using ::com::sun::star::uno::XComponentContext;
47 using ::com::sun::star::uno::Reference;
48 using ::com::sun::star::uno::XInterface;
49 using ::com::sun::star::uno::UNO_QUERY_THROW;
50 using ::com::sun::star::uno::Exception;
51 using ::com::sun::star::uno::Any;
52 using ::com::sun::star::uno::Sequence;
53 using ::com::sun::star::lang::EventObject;
54 using ::com::sun::star::container::ContainerEvent;
55 using ::com::sun::star::awt::XAnimatedImages;
56 using ::com::sun::star::awt::Size;
57 using ::com::sun::star::graphic::XGraphicProvider;
58 using ::com::sun::star::beans::XPropertySet;
59 using ::com::sun::star::graphic::XGraphic;
61 namespace ImageScaleMode = ::com::sun::star::awt::ImageScaleMode;
63 //= helper
65 namespace
68 OUString lcl_getHighContrastURL( OUString const& i_imageURL )
70 INetURLObject aURL( i_imageURL );
71 if ( aURL.GetProtocol() != INetProtocol::PrivSoffice )
73 OSL_VERIFY( aURL.insertName( u"sifr", false, 0 ) );
74 return aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
76 // the private: scheme is not considered to be hierarchical by INetURLObject, so manually insert the
77 // segment
78 const sal_Int32 separatorPos = i_imageURL.indexOf( '/' );
79 ENSURE_OR_RETURN( separatorPos != -1, "lcl_getHighContrastURL: unsupported URL scheme - cannot automatically determine HC version!", i_imageURL );
81 OUString composer = OUString::Concat(i_imageURL.subView(0, separatorPos)) + "/sifr" +
82 i_imageURL.subView(separatorPos);
83 return composer;
87 bool lcl_ensureImage_throw( Reference< XGraphicProvider > const& i_graphicProvider, const bool i_isHighContrast, const AnimatedImagesPeer::CachedImage& i_cachedImage )
89 if ( !i_cachedImage.xGraphic.is() )
91 ::comphelper::NamedValueCollection aMediaProperties;
92 if ( i_isHighContrast )
94 // try (to find) the high-contrast version of the graphic first
95 aMediaProperties.put( u"URL"_ustr, lcl_getHighContrastURL( i_cachedImage.sImageURL ) );
96 i_cachedImage.xGraphic = i_graphicProvider->queryGraphic( aMediaProperties.getPropertyValues() );
98 if ( !i_cachedImage.xGraphic.is() )
100 aMediaProperties.put( u"URL"_ustr, i_cachedImage.sImageURL );
101 i_cachedImage.xGraphic = i_graphicProvider->queryGraphic( aMediaProperties.getPropertyValues() );
104 return i_cachedImage.xGraphic.is();
108 Size lcl_getGraphicSizePixel( Reference< XGraphic > const& i_graphic )
110 Size aSizePixel;
113 if ( i_graphic.is() )
115 const Reference< XPropertySet > xGraphicProps( i_graphic, UNO_QUERY_THROW );
116 OSL_VERIFY( xGraphicProps->getPropertyValue(u"SizePixel"_ustr) >>= aSizePixel );
119 catch( const Exception& )
121 DBG_UNHANDLED_EXCEPTION("toolkit");
123 return aSizePixel;
127 void lcl_init( Sequence< OUString > const& i_imageURLs, ::std::vector< AnimatedImagesPeer::CachedImage >& o_images )
129 o_images.resize(0);
130 size_t count = size_t( i_imageURLs.getLength() );
131 o_images.reserve( count );
132 for ( const auto& rImageURL : i_imageURLs )
134 o_images.emplace_back( AnimatedImagesPeer::CachedImage{ rImageURL, nullptr } );
142 //= AnimatedImagesPeer
145 AnimatedImagesPeer::AnimatedImagesPeer()
150 AnimatedImagesPeer::~AnimatedImagesPeer()
155 void SAL_CALL AnimatedImagesPeer::startAnimation()
157 SolarMutexGuard aGuard;
158 VclPtr<Throbber> pThrobber = GetAsDynamic<Throbber>();
159 if (pThrobber)
160 pThrobber->start();
163 void SAL_CALL AnimatedImagesPeer::stopAnimation()
165 SolarMutexGuard aGuard;
166 VclPtr<Throbber> pThrobber = GetAsDynamic<Throbber>();
167 if (pThrobber)
168 pThrobber->stop();
171 sal_Bool SAL_CALL AnimatedImagesPeer::isAnimationRunning()
173 SolarMutexGuard aGuard;
174 VclPtr<Throbber> pThrobber = GetAsDynamic<Throbber>();
175 if (pThrobber)
176 return pThrobber->isRunning();
177 return false;
180 void SAL_CALL AnimatedImagesPeer::setProperty( const OUString& i_propertyName, const Any& i_value )
182 SolarMutexGuard aGuard;
184 VclPtr<Throbber> pThrobber = GetAsDynamic<Throbber>();
185 if ( !pThrobber )
187 VCLXWindow::setProperty( i_propertyName, i_value );
188 return;
191 const sal_uInt16 nPropertyId = GetPropertyId( i_propertyName );
192 switch ( nPropertyId )
194 case BASEPROPERTY_STEP_TIME:
196 sal_Int32 nStepTime( 0 );
197 if ( i_value >>= nStepTime )
198 pThrobber->setStepTime( nStepTime );
199 break;
201 case BASEPROPERTY_AUTO_REPEAT:
203 bool bRepeat( true );
204 if ( i_value >>= bRepeat )
205 pThrobber->setRepeat( bRepeat );
206 break;
209 case BASEPROPERTY_IMAGE_SCALE_MODE:
211 sal_Int16 nScaleMode( ImageScaleMode::ANISOTROPIC );
212 VclPtr<ImageControl> pImageControl = GetAsDynamic< ImageControl >();
213 if ( pImageControl && ( i_value >>= nScaleMode ) )
214 pImageControl->SetScaleMode( nScaleMode );
216 break;
218 default:
219 AnimatedImagesPeer_Base::setProperty( i_propertyName, i_value );
220 break;
225 Any SAL_CALL AnimatedImagesPeer::getProperty( const OUString& i_propertyName )
227 SolarMutexGuard aGuard;
229 Any aReturn;
231 VclPtr<Throbber> pThrobber = GetAsDynamic<Throbber>();
232 if ( !pThrobber )
233 return VCLXWindow::getProperty( i_propertyName );
235 const sal_uInt16 nPropertyId = GetPropertyId( i_propertyName );
236 switch ( nPropertyId )
238 case BASEPROPERTY_STEP_TIME:
239 aReturn <<= pThrobber->getStepTime();
240 break;
242 case BASEPROPERTY_AUTO_REPEAT:
243 aReturn <<= pThrobber->getRepeat();
244 break;
246 case BASEPROPERTY_IMAGE_SCALE_MODE:
248 VclPtr<ImageControl> pImageControl = GetAsDynamic<ImageControl>();
249 aReturn <<= ( pImageControl ? pImageControl->GetScaleMode() : ImageScaleMode::ANISOTROPIC );
251 break;
253 default:
254 aReturn = AnimatedImagesPeer_Base::getProperty( i_propertyName );
255 break;
258 return aReturn;
262 void AnimatedImagesPeer::ProcessWindowEvent( const VclWindowEvent& i_windowEvent )
264 if ( i_windowEvent.GetId() == VclEventId::WindowResize )
266 updateImageList_nothrow();
269 AnimatedImagesPeer_Base::ProcessWindowEvent( i_windowEvent );
273 void AnimatedImagesPeer::impl_updateImages_nolck( const Reference< XInterface >& i_animatedImages )
275 SolarMutexGuard aGuard;
277 updateImageList_nothrow( Reference< XAnimatedImages >( i_animatedImages, UNO_QUERY_THROW ) );
281 void SAL_CALL AnimatedImagesPeer::elementInserted( const ContainerEvent& i_event )
283 SolarMutexGuard aGuard;
284 Reference< XAnimatedImages > xAnimatedImages( i_event.Source, UNO_QUERY_THROW );
286 sal_Int32 nPosition(0);
287 OSL_VERIFY( i_event.Accessor >>= nPosition );
288 size_t position = size_t( nPosition );
289 if ( position > maCachedImageSets.size() )
291 OSL_ENSURE( false, "AnimatedImagesPeer::elementInserted: illegal accessor/index!" );
292 updateImageList_nothrow( xAnimatedImages );
295 Sequence< OUString > aImageURLs;
296 OSL_VERIFY( i_event.Element >>= aImageURLs );
297 ::std::vector< CachedImage > aImages;
298 lcl_init( aImageURLs, aImages );
299 maCachedImageSets.insert( maCachedImageSets.begin() + position, aImages );
300 updateImageList_nothrow();
304 void SAL_CALL AnimatedImagesPeer::elementRemoved( const ContainerEvent& i_event )
306 SolarMutexGuard aGuard;
307 Reference< XAnimatedImages > xAnimatedImages( i_event.Source, UNO_QUERY_THROW );
309 sal_Int32 nPosition(0);
310 OSL_VERIFY( i_event.Accessor >>= nPosition );
311 size_t position = size_t( nPosition );
312 if ( position >= maCachedImageSets.size() )
314 OSL_ENSURE( false, "AnimatedImagesPeer::elementRemoved: illegal accessor/index!" );
315 updateImageList_nothrow( xAnimatedImages );
318 maCachedImageSets.erase( maCachedImageSets.begin() + position );
319 updateImageList_nothrow();
323 void SAL_CALL AnimatedImagesPeer::elementReplaced( const ContainerEvent& i_event )
325 SolarMutexGuard aGuard;
326 Reference< XAnimatedImages > xAnimatedImages( i_event.Source, UNO_QUERY_THROW );
328 sal_Int32 nPosition(0);
329 OSL_VERIFY( i_event.Accessor >>= nPosition );
330 size_t position = size_t( nPosition );
331 if ( position >= maCachedImageSets.size() )
333 OSL_ENSURE( false, "AnimatedImagesPeer::elementReplaced: illegal accessor/index!" );
334 updateImageList_nothrow( xAnimatedImages );
337 Sequence< OUString > aImageURLs;
338 OSL_VERIFY( i_event.Element >>= aImageURLs );
339 ::std::vector< CachedImage > aImages;
340 lcl_init( aImageURLs, aImages );
341 maCachedImageSets[ position ] = std::move(aImages);
342 updateImageList_nothrow();
346 void SAL_CALL AnimatedImagesPeer::disposing( const EventObject& i_event )
348 VCLXWindow::disposing( i_event );
352 void SAL_CALL AnimatedImagesPeer::modified( const EventObject& i_event )
354 impl_updateImages_nolck( i_event.Source );
358 void SAL_CALL AnimatedImagesPeer::dispose( )
360 AnimatedImagesPeer_Base::dispose();
361 SolarMutexGuard aGuard;
362 maCachedImageSets.resize(0);
365 void AnimatedImagesPeer::updateImageList_nothrow()
367 VclPtr<Throbber> pThrobber = GetAsDynamic<Throbber>();
368 if ( !pThrobber )
369 return;
373 // collect the image sizes of the different image sets
374 const Reference< XComponentContext >& xContext( ::comphelper::getProcessComponentContext() );
375 const Reference< XGraphicProvider > xGraphicProvider( css::graphic::GraphicProvider::create(xContext) );
377 const bool isHighContrast = pThrobber->GetSettings().GetStyleSettings().GetHighContrastMode();
379 sal_Int32 nPreferredSet = -1;
380 const size_t nImageSetCount = maCachedImageSets.size();
381 if ( nImageSetCount < 2 )
383 nPreferredSet = sal_Int32( nImageSetCount ) - 1;
385 else
387 ::std::vector< Size > aImageSizes( nImageSetCount );
388 for ( size_t nImageSet = 0; nImageSet < nImageSetCount; ++nImageSet )
390 ::std::vector< CachedImage > const& rImageSet( maCachedImageSets[ nImageSet ] );
391 if ( ( rImageSet.empty() )
392 || ( !lcl_ensureImage_throw( xGraphicProvider, isHighContrast, rImageSet[0] ) )
395 aImageSizes[ nImageSet ] = Size( SAL_MAX_INT32, SAL_MAX_INT32 );
397 else
399 aImageSizes[ nImageSet ] = lcl_getGraphicSizePixel( rImageSet[0].xGraphic );
403 // find the set with the smallest difference between window size and image size
404 const ::Size aWindowSizePixel = pThrobber->GetSizePixel();
405 tools::Long nMinimalDistance = ::std::numeric_limits< tools::Long >::max();
406 for ( ::std::vector< Size >::const_iterator check = aImageSizes.begin();
407 check != aImageSizes.end();
408 ++check
411 if ( ( check->Width > aWindowSizePixel.Width() )
412 || ( check->Height > aWindowSizePixel.Height() )
414 // do not use an image set which doesn't fit into the window
415 continue;
417 const sal_Int64 distance =
418 ( aWindowSizePixel.Width() - check->Width ) * ( aWindowSizePixel.Width() - check->Width )
419 + ( aWindowSizePixel.Height() - check->Height ) * ( aWindowSizePixel.Height() - check->Height );
420 if ( distance < nMinimalDistance )
422 nMinimalDistance = distance;
423 nPreferredSet = check - aImageSizes.begin();
428 // found a set?
429 std::vector< Image > aImages;
430 if ( ( nPreferredSet >= 0 ) && ( o3tl::make_unsigned( nPreferredSet ) < nImageSetCount ) )
432 // => set the images
433 ::std::vector< CachedImage > const& rImageSet( maCachedImageSets[ nPreferredSet ] );
434 aImages.resize( rImageSet.size() );
435 sal_Int32 imageIndex = 0;
436 for ( const auto& rCachedImage : rImageSet )
438 lcl_ensureImage_throw( xGraphicProvider, isHighContrast, rCachedImage );
439 aImages[ imageIndex++ ] = Image(rCachedImage.xGraphic);
442 pThrobber->setImageList( std::move(aImages) );
444 catch( const Exception& )
446 DBG_UNHANDLED_EXCEPTION("toolkit");
451 void AnimatedImagesPeer::updateImageList_nothrow( const Reference< XAnimatedImages >& i_images )
455 const sal_Int32 nImageSetCount = i_images->getImageSetCount();
456 maCachedImageSets.resize(0);
457 for ( sal_Int32 set = 0; set < nImageSetCount; ++set )
459 const Sequence< OUString > aImageURLs( i_images->getImageSet( set ) );
460 ::std::vector< CachedImage > aImages;
461 lcl_init( aImageURLs, aImages );
462 maCachedImageSets.push_back( aImages );
465 updateImageList_nothrow();
467 catch( const Exception& )
469 DBG_UNHANDLED_EXCEPTION("toolkit");
473 } // namespace toolkit
476 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */