1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include "precompiled_toolkit.hxx"
25 
26 #include "toolkit/controls/animatedimages.hxx"
27 #include "toolkit/helper/servicenames.hxx"
28 #include "toolkit/helper/property.hxx"
29 #include "toolkit/helper/unopropertyarrayhelper.hxx"
30 
31 /** === begin UNO includes === **/
32 #include <com/sun/star/lang/DisposedException.hpp>
33 #include <com/sun/star/awt/VisualEffect.hpp>
34 #include <com/sun/star/awt/ImageScaleMode.hpp>
35 #include <com/sun/star/util/XModifyListener.hpp>
36 /** === end UNO includes === **/
37 
38 //......................................................................................................................
39 namespace toolkit
40 {
41 //......................................................................................................................
42 
43     /** === begin UNO using === **/
44     using ::com::sun::star::uno::Reference;
45     using ::com::sun::star::uno::XInterface;
46     using ::com::sun::star::uno::UNO_QUERY;
47     using ::com::sun::star::uno::UNO_QUERY_THROW;
48     using ::com::sun::star::uno::UNO_SET_THROW;
49     using ::com::sun::star::uno::Exception;
50     using ::com::sun::star::uno::RuntimeException;
51     using ::com::sun::star::uno::Any;
52     using ::com::sun::star::uno::makeAny;
53     using ::com::sun::star::uno::Sequence;
54     using ::com::sun::star::uno::Type;
55     using ::com::sun::star::container::ContainerEvent;
56     using ::com::sun::star::container::XContainerListener;
57     using ::com::sun::star::beans::XPropertySetInfo;
58     using ::com::sun::star::lang::DisposedException;
59     using ::com::sun::star::lang::IndexOutOfBoundsException;
60     using ::com::sun::star::lang::EventObject;
61     using ::com::sun::star::awt::XControlModel;
62     using ::com::sun::star::awt::XAnimatedImages;
63     using ::com::sun::star::lang::IllegalArgumentException;
64     using ::com::sun::star::awt::XWindowPeer;
65     using ::com::sun::star::util::XModifyListener;
66     using ::com::sun::star::awt::XToolkit;
67     using ::com::sun::star::lang::XMultiServiceFactory;
68     /** === end UNO using === **/
69     namespace VisualEffect = ::com::sun::star::awt::VisualEffect;
70     namespace ImageScaleMode = ::com::sun::star::awt::ImageScaleMode;
71 
72     //==================================================================================================================
73     //= AnimatedImagesControl
74     //==================================================================================================================
75     //------------------------------------------------------------------------------------------------------------------
76     AnimatedImagesControl::AnimatedImagesControl( Reference< XMultiServiceFactory > const & i_factory )
77         :AnimatedImagesControl_Base( i_factory )
78     {
79     }
80 
81     //------------------------------------------------------------------------------------------------------------------
82     ::rtl::OUString AnimatedImagesControl::GetComponentServiceName()
83     {
84         return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AnimatedImages" ) );
85     }
86 
87     //------------------------------------------------------------------------------------------------------------------
88     void SAL_CALL AnimatedImagesControl::startAnimation(  ) throw (RuntimeException)
89     {
90         Reference< XAnimation > xAnimation( getPeer(), UNO_QUERY );
91         if ( xAnimation.is() )
92             xAnimation->startAnimation();
93     }
94 
95     //------------------------------------------------------------------------------------------------------------------
96     void SAL_CALL AnimatedImagesControl::stopAnimation(  ) throw (RuntimeException)
97     {
98         Reference< XAnimation > xAnimation( getPeer(), UNO_QUERY );
99         if ( xAnimation.is() )
100             xAnimation->stopAnimation();
101     }
102 
103     //------------------------------------------------------------------------------------------------------------------
104     ::sal_Bool SAL_CALL AnimatedImagesControl::isAnimationRunning(  ) throw (RuntimeException)
105     {
106         Reference< XAnimation > xAnimation( getPeer(), UNO_QUERY );
107         if ( xAnimation.is() )
108             return xAnimation->isAnimationRunning();
109         return sal_False;
110     }
111 
112     //------------------------------------------------------------------------------------------------------------------
113     ::rtl::OUString SAL_CALL AnimatedImagesControl::getImplementationName(  ) throw(RuntimeException)
114     {
115         return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.comp.toolkit.AnimatedImagesControl" ) );
116     }
117 
118     //------------------------------------------------------------------------------------------------------------------
119     Sequence< ::rtl::OUString > SAL_CALL AnimatedImagesControl::getSupportedServiceNames() throw(RuntimeException)
120     {
121         Sequence< ::rtl::OUString > aServices( AnimatedImagesControl_Base::getSupportedServiceNames() );
122         aServices.realloc( aServices.getLength() + 1 );
123         aServices[ aServices.getLength() - 1 ] = ::rtl::OUString::createFromAscii( szServiceName_AnimatedImagesControl );
124         return aServices;
125     }
126 
127     //------------------------------------------------------------------------------------------------------------------
128     namespace
129     {
130         void lcl_updatePeer( Reference< XWindowPeer > const& i_peer, Reference< XControlModel > const& i_model )
131         {
132             const Reference< XModifyListener > xPeerModify( i_peer, UNO_QUERY );
133             if ( xPeerModify.is() )
134             {
135                 EventObject aEvent;
136                 aEvent.Source = i_model;
137                 xPeerModify->modified( aEvent );
138             }
139         }
140     }
141 
142     //------------------------------------------------------------------------------------------------------------------
143     sal_Bool SAL_CALL AnimatedImagesControl::setModel( const Reference< XControlModel >& i_rModel ) throw ( RuntimeException )
144     {
145         const Reference< XAnimatedImages > xOldContainer( getModel(), UNO_QUERY );
146         const Reference< XAnimatedImages > xNewContainer( i_rModel, UNO_QUERY );
147 
148         if ( !AnimatedImagesControl_Base::setModel( i_rModel ) )
149             return sal_False;
150 
151         if ( xOldContainer.is() )
152             xOldContainer->removeContainerListener( this );
153 
154         if ( xNewContainer.is() )
155             xNewContainer->addContainerListener( this );
156 
157         lcl_updatePeer( getPeer(), getModel() );
158 
159         return sal_True;
160     }
161 
162     //------------------------------------------------------------------------------------------------------------------
163     void SAL_CALL AnimatedImagesControl::createPeer( const Reference< XToolkit >& i_toolkit, const Reference< XWindowPeer >& i_parentPeer ) throw(RuntimeException)
164     {
165         AnimatedImagesControl_Base::createPeer( i_toolkit, i_parentPeer );
166 
167         lcl_updatePeer( getPeer(), getModel() );
168     }
169 
170     //------------------------------------------------------------------------------------------------------------------
171     void SAL_CALL AnimatedImagesControl::elementInserted( const ContainerEvent& i_event ) throw (RuntimeException)
172     {
173         const Reference< XContainerListener > xPeerListener( getPeer(), UNO_QUERY );
174         if ( xPeerListener.is() )
175             xPeerListener->elementInserted( i_event );
176     }
177 
178     //------------------------------------------------------------------------------------------------------------------
179     void SAL_CALL AnimatedImagesControl::elementRemoved( const ContainerEvent& i_event ) throw (RuntimeException)
180     {
181         const Reference< XContainerListener > xPeerListener( getPeer(), UNO_QUERY );
182         if ( xPeerListener.is() )
183             xPeerListener->elementRemoved( i_event );
184     }
185 
186     //------------------------------------------------------------------------------------------------------------------
187     void SAL_CALL AnimatedImagesControl::elementReplaced( const ContainerEvent& i_event ) throw (RuntimeException)
188     {
189         const Reference< XContainerListener > xPeerListener( getPeer(), UNO_QUERY );
190         if ( xPeerListener.is() )
191             xPeerListener->elementReplaced( i_event );
192     }
193 
194     //------------------------------------------------------------------------------------------------------------------
195     void SAL_CALL AnimatedImagesControl::disposing( const EventObject& i_event ) throw (RuntimeException)
196     {
197         UnoControlBase::disposing( i_event );
198     }
199 
200     //==================================================================================================================
201     //= AnimatedImagesControlModel_Data
202     //==================================================================================================================
203     struct AnimatedImagesControlModel_Data
204     {
205         ::std::vector< Sequence< ::rtl::OUString > >    aImageSets;
206     };
207 
208     namespace
209     {
210         void lcl_checkIndex( const AnimatedImagesControlModel_Data& i_data, const sal_Int32 i_index, const Reference< XInterface >& i_context,
211             const bool i_forInsert = false )
212         {
213             if ( ( i_index < 0 ) || ( size_t( i_index ) > i_data.aImageSets.size() + ( i_forInsert ? 1 : 0 ) ) )
214                 throw IndexOutOfBoundsException( ::rtl::OUString(), i_context );
215         }
216 
217         void lcl_notify( ::osl::ClearableMutexGuard& i_guard, ::cppu::OBroadcastHelper& i_broadcaseHelper,
218             void ( SAL_CALL XContainerListener::*i_notificationMethod )( const ContainerEvent& ),
219             const sal_Int32 i_accessor, const Sequence< ::rtl::OUString >& i_imageURLs, const Reference< XInterface >& i_context )
220         {
221             ::cppu::OInterfaceContainerHelper* pContainerListeners = i_broadcaseHelper.getContainer( XContainerListener::static_type() );
222             if ( pContainerListeners == NULL )
223                 return;
224 
225             ContainerEvent aEvent;
226             aEvent.Source = i_context;
227             aEvent.Accessor <<= i_accessor;
228             aEvent.Element <<= i_imageURLs;
229 
230             i_guard.clear();
231             pContainerListeners->notifyEach( i_notificationMethod, aEvent );
232         }
233     }
234 
235     //==================================================================================================================
236     //= AnimatedImagesControlModel
237     //==================================================================================================================
238     //------------------------------------------------------------------------------------------------------------------
239     AnimatedImagesControlModel::AnimatedImagesControlModel( Reference< XMultiServiceFactory > const & i_factory )
240         :AnimatedImagesControlModel_Base( i_factory )
241         ,m_pData( new AnimatedImagesControlModel_Data )
242     {
243         ImplRegisterProperty( BASEPROPERTY_AUTO_REPEAT );
244 	    ImplRegisterProperty( BASEPROPERTY_BORDER );
245 	    ImplRegisterProperty( BASEPROPERTY_BORDERCOLOR );
246         ImplRegisterProperty( BASEPROPERTY_BACKGROUNDCOLOR );
247         ImplRegisterProperty( BASEPROPERTY_DEFAULTCONTROL );
248 	    ImplRegisterProperty( BASEPROPERTY_ENABLEVISIBLE );
249 	    ImplRegisterProperty( BASEPROPERTY_HELPTEXT );
250 	    ImplRegisterProperty( BASEPROPERTY_HELPURL );
251 	    ImplRegisterProperty( BASEPROPERTY_IMAGE_SCALE_MODE );
252         ImplRegisterProperty( BASEPROPERTY_STEP_TIME );
253     }
254 
255     //------------------------------------------------------------------------------------------------------------------
256     AnimatedImagesControlModel::AnimatedImagesControlModel( const AnimatedImagesControlModel& i_copySource )
257         :AnimatedImagesControlModel_Base( i_copySource )
258         ,m_pData( new AnimatedImagesControlModel_Data( *i_copySource.m_pData ) )
259     {
260     }
261 
262     //------------------------------------------------------------------------------------------------------------------
263     AnimatedImagesControlModel::~AnimatedImagesControlModel()
264     {
265     }
266 
267     //------------------------------------------------------------------------------------------------------------------
268     UnoControlModel* AnimatedImagesControlModel::Clone() const
269     {
270         return new AnimatedImagesControlModel( *this );
271     }
272 
273     //------------------------------------------------------------------------------------------------------------------
274     Reference< XPropertySetInfo > SAL_CALL AnimatedImagesControlModel::getPropertySetInfo(  ) throw(RuntimeException)
275     {
276         static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
277         return xInfo;
278     }
279 
280     //------------------------------------------------------------------------------------------------------------------
281     ::rtl::OUString SAL_CALL AnimatedImagesControlModel::getServiceName() throw(RuntimeException)
282     {
283         return ::rtl::OUString::createFromAscii( szServiceName_AnimatedImagesControlModel );
284     }
285 
286     //------------------------------------------------------------------------------------------------------------------
287     ::rtl::OUString SAL_CALL AnimatedImagesControlModel::getImplementationName(  ) throw(RuntimeException)
288     {
289         return ::rtl::OUString::createFromAscii( "org.openoffice.comp.toolkit.AnimatedImagesControlModel" );
290     }
291 
292     //------------------------------------------------------------------------------------------------------------------
293     Sequence< ::rtl::OUString > SAL_CALL AnimatedImagesControlModel::getSupportedServiceNames() throw(RuntimeException)
294     {
295         Sequence< ::rtl::OUString > aServiceNames(2);
296         aServiceNames[0] = ::rtl::OUString::createFromAscii( szServiceName_AnimatedImagesControlModel );
297         aServiceNames[1] = ::rtl::OUString::createFromAscii( "com.sun.star.awt.UnoControlModel" );
298         return aServiceNames;
299     }
300 
301     //------------------------------------------------------------------------------------------------------------------
302     void SAL_CALL AnimatedImagesControlModel::setFastPropertyValue_NoBroadcast( sal_Int32 i_handle, const Any& i_value ) throw (Exception)
303     {
304         switch ( i_handle )
305         {
306         case BASEPROPERTY_IMAGE_SCALE_MODE:
307         {
308             sal_Int16 nImageScaleMode( ImageScaleMode::Anisotropic );
309             OSL_VERIFY( i_value >>= nImageScaleMode );  // convertFastPropertyValue ensures that this has the proper type
310             if  (   ( nImageScaleMode != ImageScaleMode::None )
311                 &&  ( nImageScaleMode != ImageScaleMode::Isotropic )
312                 &&  ( nImageScaleMode != ImageScaleMode::Anisotropic )
313                 )
314                 throw IllegalArgumentException( ::rtl::OUString(), *this, 1 );
315         }
316         break;
317         }
318 
319         AnimatedImagesControlModel_Base::setFastPropertyValue_NoBroadcast( i_handle, i_value );
320     }
321 
322     //------------------------------------------------------------------------------------------------------------------
323     Any AnimatedImagesControlModel::ImplGetDefaultValue( sal_uInt16 i_propertyId ) const
324     {
325         switch ( i_propertyId )
326         {
327         case BASEPROPERTY_DEFAULTCONTROL:
328             return makeAny( ::rtl::OUString::createFromAscii( szServiceName_AnimatedImagesControl ) );
329 
330         case BASEPROPERTY_BORDER:
331             return makeAny( VisualEffect::NONE );
332 
333         case BASEPROPERTY_STEP_TIME:
334             return makeAny( (sal_Int32) 100 );
335 
336         case BASEPROPERTY_AUTO_REPEAT:
337             return makeAny( (sal_Bool)sal_True );
338 
339         case BASEPROPERTY_IMAGE_SCALE_MODE:
340             return makeAny( ImageScaleMode::None );
341 
342         default:
343             return UnoControlModel::ImplGetDefaultValue( i_propertyId );
344         }
345     }
346 
347     //------------------------------------------------------------------------------------------------------------------
348     ::cppu::IPropertyArrayHelper& SAL_CALL AnimatedImagesControlModel::getInfoHelper()
349     {
350         static UnoPropertyArrayHelper* pHelper = NULL;
351         if ( !pHelper )
352         {
353             Sequence< sal_Int32 > aIDs = ImplGetPropertyIds();
354             pHelper = new UnoPropertyArrayHelper( aIDs );
355         }
356         return *pHelper;
357     }
358 
359     //------------------------------------------------------------------------------------------------------------------
360     ::sal_Int32 SAL_CALL AnimatedImagesControlModel::getStepTime() throw (RuntimeException)
361     {
362         sal_Int32 nStepTime( 100 );
363         OSL_VERIFY( getPropertyValue( GetPropertyName( BASEPROPERTY_STEP_TIME ) ) >>= nStepTime );
364         return nStepTime;
365     }
366 
367     //------------------------------------------------------------------------------------------------------------------
368     void SAL_CALL AnimatedImagesControlModel::setStepTime( ::sal_Int32 i_stepTime ) throw (RuntimeException)
369     {
370         setPropertyValue( GetPropertyName( BASEPROPERTY_STEP_TIME ), makeAny( i_stepTime ) );
371     }
372 
373     //------------------------------------------------------------------------------------------------------------------
374     ::sal_Bool SAL_CALL AnimatedImagesControlModel::getAutoRepeat() throw (RuntimeException)
375     {
376         sal_Bool bAutoRepeat( sal_True );
377         OSL_VERIFY( getPropertyValue( GetPropertyName( BASEPROPERTY_AUTO_REPEAT ) ) >>= bAutoRepeat );
378         return bAutoRepeat;
379     }
380 
381     //------------------------------------------------------------------------------------------------------------------
382     void SAL_CALL AnimatedImagesControlModel::setAutoRepeat( ::sal_Bool i_autoRepeat ) throw (RuntimeException)
383     {
384         setPropertyValue( GetPropertyName( BASEPROPERTY_AUTO_REPEAT ), makeAny( i_autoRepeat ) );
385     }
386 
387     //------------------------------------------------------------------------------------------------------------------
388     ::sal_Int16 SAL_CALL AnimatedImagesControlModel::getScaleMode() throw (RuntimeException)
389     {
390         sal_Int16 nImageScaleMode( ImageScaleMode::Anisotropic );
391         OSL_VERIFY( getPropertyValue( GetPropertyName( BASEPROPERTY_IMAGE_SCALE_MODE ) ) >>= nImageScaleMode );
392         return nImageScaleMode;
393     }
394 
395     //------------------------------------------------------------------------------------------------------------------
396     void SAL_CALL AnimatedImagesControlModel::setScaleMode( ::sal_Int16 i_scaleMode ) throw (IllegalArgumentException, RuntimeException)
397     {
398         setPropertyValue( GetPropertyName( BASEPROPERTY_IMAGE_SCALE_MODE ), makeAny( i_scaleMode ) );
399     }
400 
401     //------------------------------------------------------------------------------------------------------------------
402     ::sal_Int32 SAL_CALL AnimatedImagesControlModel::getImageSetCount(  ) throw (RuntimeException)
403     {
404 	    ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
405         if ( GetBroadcastHelper().bDisposed || GetBroadcastHelper().bInDispose )
406             throw DisposedException();
407 
408         return m_pData->aImageSets.size();
409     }
410 
411     //------------------------------------------------------------------------------------------------------------------
412     Sequence< ::rtl::OUString > SAL_CALL AnimatedImagesControlModel::getImageSet( ::sal_Int32 i_index ) throw (IndexOutOfBoundsException, RuntimeException)
413     {
414 	    ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
415         if ( GetBroadcastHelper().bDisposed || GetBroadcastHelper().bInDispose )
416             throw DisposedException();
417 
418         lcl_checkIndex( *m_pData, i_index, *this );
419 
420         return m_pData->aImageSets[ i_index ];
421     }
422 
423     //------------------------------------------------------------------------------------------------------------------
424     void SAL_CALL AnimatedImagesControlModel::insertImageSet( ::sal_Int32 i_index, const Sequence< ::rtl::OUString >& i_imageURLs ) throw (IndexOutOfBoundsException, RuntimeException)
425     {
426 	    ::osl::ClearableMutexGuard aGuard( GetMutex() );
427         // sanity checks
428         if ( GetBroadcastHelper().bDisposed || GetBroadcastHelper().bInDispose )
429             throw DisposedException();
430 
431         lcl_checkIndex( *m_pData, i_index, *this, true );
432 
433         // actaul insertion
434         m_pData->aImageSets.insert( m_pData->aImageSets.begin() + i_index, i_imageURLs );
435 
436         // listener notification
437         lcl_notify( aGuard, BrdcstHelper, &XContainerListener::elementInserted, i_index, i_imageURLs, *this );
438     }
439 
440     //------------------------------------------------------------------------------------------------------------------
441     void SAL_CALL AnimatedImagesControlModel::replaceImageSet( ::sal_Int32 i_index, const Sequence< ::rtl::OUString >& i_imageURLs ) throw (IndexOutOfBoundsException, RuntimeException)
442     {
443 	    ::osl::ClearableMutexGuard aGuard( GetMutex() );
444         // sanity checks
445         if ( GetBroadcastHelper().bDisposed || GetBroadcastHelper().bInDispose )
446             throw DisposedException();
447 
448         lcl_checkIndex( *m_pData, i_index, *this );
449 
450         // actaul insertion
451         m_pData->aImageSets[ i_index ] = i_imageURLs;
452 
453         // listener notification
454         lcl_notify( aGuard, BrdcstHelper, &XContainerListener::elementReplaced, i_index, i_imageURLs, *this );
455     }
456 
457     //------------------------------------------------------------------------------------------------------------------
458     void SAL_CALL AnimatedImagesControlModel::removeImageSet( ::sal_Int32 i_index ) throw (IndexOutOfBoundsException, RuntimeException)
459     {
460 	    ::osl::ClearableMutexGuard aGuard( GetMutex() );
461         // sanity checks
462         if ( GetBroadcastHelper().bDisposed || GetBroadcastHelper().bInDispose )
463             throw DisposedException();
464 
465         lcl_checkIndex( *m_pData, i_index, *this );
466 
467         // actual removal
468         ::std::vector< Sequence< ::rtl::OUString > >::iterator removalPos = m_pData->aImageSets.begin() + i_index;
469         Sequence< ::rtl::OUString > aRemovedElement( *removalPos );
470         m_pData->aImageSets.erase( removalPos );
471 
472         // listener notification
473         lcl_notify( aGuard, BrdcstHelper, &XContainerListener::elementRemoved, i_index, aRemovedElement, *this );
474     }
475 
476     //------------------------------------------------------------------------------------------------------------------
477     void SAL_CALL AnimatedImagesControlModel::addContainerListener( const Reference< XContainerListener >& i_listener ) throw (RuntimeException)
478     {
479         BrdcstHelper.addListener( XContainerListener::static_type(), i_listener );
480     }
481 
482     //------------------------------------------------------------------------------------------------------------------
483     void SAL_CALL AnimatedImagesControlModel::removeContainerListener( const Reference< XContainerListener >& i_listener ) throw (RuntimeException)
484     {
485         BrdcstHelper.removeListener( XContainerListener::static_type(), i_listener );
486     }
487 
488 //......................................................................................................................
489 } // namespace toolkit
490 //......................................................................................................................
491