1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
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.
14  *
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).
20  *
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.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svx.hxx"
30 
31 #include "formfeaturedispatcher.hxx"
32 
33 #include <comphelper/namedvaluecollection.hxx>
34 #include <tools/diagnose_ex.h>
35 
36 //........................................................................
37 namespace svx
38 {
39 //........................................................................
40 
41     using namespace ::com::sun::star::uno;
42     using namespace ::com::sun::star::lang;
43     using namespace ::com::sun::star::frame;
44     using namespace ::com::sun::star::beans;
45     using namespace ::com::sun::star::util;
46     using namespace ::com::sun::star::form::runtime;
47 
48     //====================================================================
49     //= OSingleFeatureDispatcher
50     //====================================================================
51     //--------------------------------------------------------------------
52     OSingleFeatureDispatcher::OSingleFeatureDispatcher( const URL& _rFeatureURL, const sal_Int16 _nFormFeature,
53             const Reference< XFormOperations >& _rxFormOperations, ::osl::Mutex& _rMutex )
54         :m_rMutex( _rMutex )
55         ,m_aStatusListeners( _rMutex )
56         ,m_xFormOperations( _rxFormOperations )
57         ,m_aFeatureURL( _rFeatureURL )
58         ,m_nFormFeature( _nFormFeature )
59         ,m_bLastKnownEnabled( sal_False )
60         ,m_bDisposed( sal_False )
61     {
62     }
63 
64     //--------------------------------------------------------------------
65     void OSingleFeatureDispatcher::dispose()
66     {
67         {
68             ::osl::MutexGuard aGuard( m_rMutex );
69             if ( m_bDisposed )
70                 return;
71         }
72 
73         EventObject aDisposeEvent( *this );
74         m_aStatusListeners.disposeAndClear( aDisposeEvent );
75 
76         {
77             ::osl::MutexGuard aGuard( m_rMutex );
78             m_bDisposed = sal_True;
79         }
80     }
81 
82     //--------------------------------------------------------------------
83     void OSingleFeatureDispatcher::getUnoState( FeatureStateEvent& /* [out] */ _rState ) const
84     {
85         _rState.Source = *const_cast< OSingleFeatureDispatcher* >( this );
86 
87         FeatureState aState( m_xFormOperations->getState( m_nFormFeature ) );
88 
89         _rState.FeatureURL = m_aFeatureURL;
90         _rState.IsEnabled = aState.Enabled;
91         _rState.Requery = sal_False;
92         _rState.State = aState.State;
93     }
94 
95     //--------------------------------------------------------------------
96     void OSingleFeatureDispatcher::updateAllListeners()
97     {
98         ::osl::ClearableMutexGuard aGuard( m_rMutex );
99 
100         FeatureStateEvent aUnoState;
101         getUnoState( aUnoState );
102 
103         if ( ( m_aLastKnownState == aUnoState.State ) && ( m_bLastKnownEnabled == aUnoState.IsEnabled ) )
104             return;
105 
106         m_aLastKnownState = aUnoState.State;
107         m_bLastKnownEnabled = aUnoState.IsEnabled;
108 
109         notifyStatus( NULL, aGuard );
110     }
111 
112     //--------------------------------------------------------------------
113     void OSingleFeatureDispatcher::notifyStatus( const Reference< XStatusListener >& _rxListener, ::osl::ClearableMutexGuard& _rFreeForNotification )
114     {
115         FeatureStateEvent aUnoState;
116         getUnoState( aUnoState );
117 
118         if ( _rxListener.is() )
119         {
120             try
121             {
122                 _rFreeForNotification.clear();
123                 _rxListener->statusChanged( aUnoState );
124             }
125             catch( const Exception& )
126             {
127                 OSL_ENSURE( sal_False, "OSingleFeatureDispatcher::notifyStatus: caught an exception!" );
128             }
129         }
130         else
131         {
132             ::cppu::OInterfaceIteratorHelper aIter( m_aStatusListeners );
133             _rFreeForNotification.clear();
134 
135             while ( aIter.hasMoreElements() )
136             {
137                 try
138                 {
139                     static_cast< XStatusListener* >( aIter.next() )->statusChanged( aUnoState );
140                 }
141                 catch( const DisposedException& )
142                 {
143                     OSL_ENSURE( sal_False, "OSingleFeatureDispatcher::notifyStatus: caught a DisposedException - removing the listener!" );
144                     aIter.remove( );
145                 }
146                 catch( const Exception& )
147                 {
148                     OSL_ENSURE( sal_False, "OSingleFeatureDispatcher::notifyStatus: caught a generic exception while notifying a single listener!" );
149                 }
150             }
151         }
152     }
153 
154     //--------------------------------------------------------------------
155     void SAL_CALL OSingleFeatureDispatcher::dispatch( const URL& _rURL, const Sequence< PropertyValue >& _rArguments ) throw (RuntimeException)
156     {
157         ::osl::ClearableMutexGuard aGuard( m_rMutex );
158         checkAlive();
159 
160         OSL_ENSURE( _rURL.Complete == m_aFeatureURL.Complete, "OSingleFeatureDispatcher::dispatch: not responsible for this URL!" );
161         (void)_rURL;
162 
163         if ( !m_xFormOperations->isEnabled( m_nFormFeature ) )
164             return;
165 
166         // release our mutex before executing the command
167         sal_Int16 nFormFeature( m_nFormFeature );
168         Reference< XFormOperations > xFormOperations( m_xFormOperations );
169         aGuard.clear();
170 
171         try
172         {
173             if ( !_rArguments.getLength() )
174             {
175                 xFormOperations->execute( nFormFeature );
176             }
177             else
178             {   // at the moment we only support one parameter
179                 ::comphelper::NamedValueCollection aArgs( _rArguments );
180                 xFormOperations->executeWithArguments( nFormFeature, aArgs.getNamedValues() );
181             }
182         }
183         catch( const RuntimeException& )
184         {
185             throw;
186         }
187         catch( const Exception& )
188         {
189         	DBG_UNHANDLED_EXCEPTION();
190         }
191     }
192 
193     //--------------------------------------------------------------------
194     void SAL_CALL OSingleFeatureDispatcher::addStatusListener( const Reference< XStatusListener >& _rxControl, const URL& _rURL ) throw (RuntimeException)
195     {
196         (void)_rURL;
197         OSL_ENSURE( _rURL.Complete == m_aFeatureURL.Complete, "OSingleFeatureDispatcher::addStatusListener: unexpected URL!" );
198         OSL_ENSURE( _rxControl.is(), "OSingleFeatureDispatcher::addStatusListener: senseless call!" );
199         if ( !_rxControl.is() )
200             return;
201 
202         ::osl::ClearableMutexGuard aGuard( m_rMutex );
203         if ( m_bDisposed )
204         {
205             EventObject aDisposeEvent( *this );
206             aGuard.clear();
207             _rxControl->disposing( aDisposeEvent );
208             return;
209         }
210 
211         m_aStatusListeners.addInterface( _rxControl );
212 
213         // initially update the status
214         notifyStatus( _rxControl, aGuard );
215     }
216 
217     //--------------------------------------------------------------------
218     void SAL_CALL OSingleFeatureDispatcher::removeStatusListener( const Reference< XStatusListener >& _rxControl, const URL& _rURL ) throw (RuntimeException)
219     {
220         (void)_rURL;
221         OSL_ENSURE( _rURL.Complete == m_aFeatureURL.Complete, "OSingleFeatureDispatcher::removeStatusListener: unexpected URL!" );
222         OSL_ENSURE( _rxControl.is(), "OSingleFeatureDispatcher::removeStatusListener: senseless call!" );
223         if ( !_rxControl.is() )
224             return;
225 
226         ::osl::MutexGuard aGuard( m_rMutex );
227         checkAlive();
228 
229         m_aStatusListeners.removeInterface( _rxControl );
230     }
231 
232     //--------------------------------------------------------------------
233     void OSingleFeatureDispatcher::checkAlive() const SAL_THROW((DisposedException))
234     {
235         if ( m_bDisposed )
236             throw DisposedException( ::rtl::OUString(), *const_cast< OSingleFeatureDispatcher* >( this ) );
237     }
238 
239 //........................................................................
240 }   // namespace svx
241 //........................................................................
242