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 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svtools.hxx"
26 #include <svtools/framestatuslistener.hxx>
27 #include <com/sun/star/frame/XDispatchProvider.hpp>
28 #include <com/sun/star/lang/DisposedException.hpp>
29 #include <vos/mutex.hxx>
30 #include <vcl/svapp.hxx>
31 
32 using namespace ::cppu;
33 using namespace ::com::sun::star::awt;
34 using namespace ::com::sun::star::uno;
35 using namespace ::com::sun::star::util;
36 using namespace ::com::sun::star::beans;
37 using namespace ::com::sun::star::lang;
38 using namespace ::com::sun::star::frame;
39 
40 namespace svt
41 {
42 
FrameStatusListener(const Reference<XMultiServiceFactory> & rServiceManager,const Reference<XFrame> & xFrame)43 FrameStatusListener::FrameStatusListener(
44     const Reference< XMultiServiceFactory >& rServiceManager,
45     const Reference< XFrame >& xFrame ) :
46     OWeakObject()
47     ,   m_bInitialized( sal_True )
48     ,   m_bDisposed( sal_False )
49     ,   m_xFrame( xFrame )
50     ,   m_xServiceManager( rServiceManager )
51 {
52 }
53 
~FrameStatusListener()54 FrameStatusListener::~FrameStatusListener()
55 {
56 }
57 
getFrameInterface() const58 Reference< XFrame > FrameStatusListener::getFrameInterface() const
59 {
60     vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );
61     return m_xFrame;
62 }
63 
getServiceManager() const64 Reference< XMultiServiceFactory > FrameStatusListener::getServiceManager() const
65 {
66     vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );
67     return m_xServiceManager;
68 }
69 
70 // XInterface
queryInterface(const Type & rType)71 Any SAL_CALL FrameStatusListener::queryInterface( const Type& rType )
72 throw ( RuntimeException )
73 {
74 	Any a = ::cppu::queryInterface(
75 				rType ,
76 				static_cast< XComponent* >( this ),
77                 static_cast< XFrameActionListener* >( this ),
78                 static_cast< XStatusListener* >( this ),
79 				static_cast< XEventListener* >( static_cast< XStatusListener* >( this )),
80                 static_cast< XEventListener* >( static_cast< XFrameActionListener* >( this )));
81 
82 	if ( a.hasValue() )
83 		return a;
84 
85 	return OWeakObject::queryInterface( rType );
86 }
87 
acquire()88 void SAL_CALL FrameStatusListener::acquire() throw ()
89 {
90     OWeakObject::acquire();
91 }
92 
release()93 void SAL_CALL FrameStatusListener::release() throw ()
94 {
95     OWeakObject::release();
96 }
97 
98 // XComponent
dispose()99 void SAL_CALL FrameStatusListener::dispose()
100 throw (::com::sun::star::uno::RuntimeException)
101 {
102     Reference< XComponent > xThis( static_cast< OWeakObject* >(this), UNO_QUERY );
103 
104     vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );
105     if ( m_bDisposed )
106         throw DisposedException();
107 
108     Reference< XStatusListener > xStatusListener( static_cast< OWeakObject* >( this ), UNO_QUERY );
109     URLToDispatchMap::iterator pIter = m_aListenerMap.begin();
110     while ( pIter != m_aListenerMap.end() )
111     {
112         try
113         {
114             Reference< XDispatch > xDispatch( pIter->second );
115             Reference< XURLTransformer > xURLTransformer( m_xServiceManager->createInstance(
116                                                             rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
117                                                                 "com.sun.star.util.URLTransformer" ))),
118                                                           UNO_QUERY );
119             com::sun::star::util::URL aTargetURL;
120             aTargetURL.Complete = pIter->first;
121             xURLTransformer->parseStrict( aTargetURL );
122 
123             if ( xDispatch.is() && xStatusListener.is() )
124                 xDispatch->removeStatusListener( xStatusListener, aTargetURL );
125         }
126         catch ( Exception& )
127         {
128         }
129 
130         ++pIter;
131     }
132 
133     m_bDisposed = sal_True;
134 }
135 
addEventListener(const Reference<XEventListener> &)136 void SAL_CALL FrameStatusListener::addEventListener( const Reference< XEventListener >& )
137 throw ( RuntimeException )
138 {
139     // helper class for status updates - no need to support listener
140 }
141 
removeEventListener(const Reference<XEventListener> &)142 void SAL_CALL FrameStatusListener::removeEventListener( const Reference< XEventListener >& )
143 throw ( RuntimeException )
144 {
145     // helper class for status updates - no need to support listener
146 }
147 
148 // XEventListener
disposing(const EventObject & Source)149 void SAL_CALL FrameStatusListener::disposing( const EventObject& Source )
150 throw ( RuntimeException )
151 {
152     Reference< XInterface > xSource( Source.Source );
153 
154     vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );
155 
156     URLToDispatchMap::iterator pIter = m_aListenerMap.begin();
157     while ( pIter != m_aListenerMap.end() )
158     {
159         // Compare references and release dispatch references if they are equal.
160         Reference< XInterface > xIfac( pIter->second, UNO_QUERY );
161         if ( xSource == xIfac )
162             pIter->second.clear();
163     }
164 
165     Reference< XInterface > xIfac( m_xFrame, UNO_QUERY );
166     if ( xIfac == xSource )
167         m_xFrame.clear();
168 }
169 
170 // XStatusListener
statusChanged(const FeatureStateEvent &)171 void SAL_CALL FrameStatusListener::statusChanged( const FeatureStateEvent& )
172 throw ( RuntimeException )
173 {
174     // must be implemented by sub class
175 }
176 
frameAction(const FrameActionEvent & Action)177 void FrameStatusListener::frameAction( const FrameActionEvent& Action )
178 throw ( RuntimeException )
179 {
180     if ( Action.Action == FrameAction_CONTEXT_CHANGED )
181         bindListener();
182 }
183 
addStatusListener(const rtl::OUString & aCommandURL)184 void FrameStatusListener::addStatusListener( const rtl::OUString& aCommandURL )
185 {
186     Reference< XDispatch >       xDispatch;
187     Reference< XStatusListener > xStatusListener;
188     com::sun::star::util::URL    aTargetURL;
189 
190     {
191         vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );
192         URLToDispatchMap::iterator pIter = m_aListenerMap.find( aCommandURL );
193 
194         // Already in the list of status listener. Do nothing.
195         if ( pIter != m_aListenerMap.end() )
196             return;
197 
198         // Check if we are already initialized. Implementation starts adding itself as status listener when
199         // initialize is called.
200         if ( !m_bInitialized )
201         {
202             // Put into the hash_map of status listener. Will be activated when initialized is called
203             m_aListenerMap.insert( URLToDispatchMap::value_type( aCommandURL, Reference< XDispatch >() ));
204             return;
205         }
206         else
207         {
208             // Add status listener directly as initialize has already been called.
209             Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
210             if ( m_xServiceManager.is() && xDispatchProvider.is() )
211             {
212                 Reference< XURLTransformer > xURLTransformer( m_xServiceManager->createInstance(
213                                                                 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.util.URLTransformer" ))),
214                                                             UNO_QUERY );
215                 aTargetURL.Complete = aCommandURL;
216                 xURLTransformer->parseStrict( aTargetURL );
217                 xDispatch = xDispatchProvider->queryDispatch( aTargetURL, ::rtl::OUString(), 0 );
218 
219                 xStatusListener = Reference< XStatusListener >( static_cast< OWeakObject* >( this ), UNO_QUERY );
220                 URLToDispatchMap::iterator aIter = m_aListenerMap.find( aCommandURL );
221                 if ( aIter != m_aListenerMap.end() )
222                 {
223                     Reference< XDispatch > xOldDispatch( aIter->second );
224                     aIter->second = xDispatch;
225 
226                     try
227                     {
228                         if ( xOldDispatch.is() )
229                             xOldDispatch->removeStatusListener( xStatusListener, aTargetURL );
230                     }
231                     catch ( Exception& )
232                     {
233                     }
234                 }
235                 else
236                     m_aListenerMap.insert( URLToDispatchMap::value_type( aCommandURL, xDispatch ));
237             }
238         }
239     }
240 
241     // Call without locked mutex as we are called back from dispatch implementation
242     try
243     {
244         if ( xDispatch.is() )
245             xDispatch->addStatusListener( xStatusListener, aTargetURL );
246     }
247     catch ( Exception& )
248     {
249     }
250 }
251 
removeStatusListener(const rtl::OUString & aCommandURL)252 void FrameStatusListener::removeStatusListener( const rtl::OUString& aCommandURL )
253 {
254     vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );
255 
256     URLToDispatchMap::iterator pIter = m_aListenerMap.find( aCommandURL );
257     if ( pIter != m_aListenerMap.end() )
258     {
259         Reference< XDispatch > xDispatch( pIter->second );
260         Reference< XStatusListener > xStatusListener( static_cast< OWeakObject* >( this ), UNO_QUERY );
261         m_aListenerMap.erase( pIter );
262 
263         try
264         {
265             Reference< XURLTransformer > xURLTransformer( m_xServiceManager->createInstance(
266                                                             rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.util.URLTransformer" ))),
267                                                         UNO_QUERY );
268             com::sun::star::util::URL aTargetURL;
269             aTargetURL.Complete = aCommandURL;
270             xURLTransformer->parseStrict( aTargetURL );
271 
272             if ( xDispatch.is() && xStatusListener.is() )
273                 xDispatch->removeStatusListener( xStatusListener, aTargetURL );
274         }
275         catch ( Exception& )
276         {
277         }
278     }
279 }
280 
bindListener()281 void FrameStatusListener::bindListener()
282 {
283     std::vector< Listener > aDispatchVector;
284     Reference< XStatusListener > xStatusListener;
285 
286     {
287         vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );
288 
289         if ( !m_bInitialized )
290             return;
291 
292         // Collect all registered command URL's and store them temporary
293         Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
294         if ( m_xServiceManager.is() && xDispatchProvider.is() )
295         {
296             xStatusListener = Reference< XStatusListener >( static_cast< OWeakObject* >( this ), UNO_QUERY );
297             URLToDispatchMap::iterator pIter = m_aListenerMap.begin();
298             while ( pIter != m_aListenerMap.end() )
299             {
300                 Reference< XURLTransformer > xURLTransformer( m_xServiceManager->createInstance(
301                                                                 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.util.URLTransformer" ))),
302                                                             UNO_QUERY );
303                 com::sun::star::util::URL aTargetURL;
304                 aTargetURL.Complete = pIter->first;
305                 xURLTransformer->parseStrict( aTargetURL );
306 
307                 Reference< XDispatch > xDispatch( pIter->second );
308                 if ( xDispatch.is() )
309                 {
310                     // We already have a dispatch object => we have to requery.
311                     // Release old dispatch object and remove it as listener
312                     try
313                     {
314                         xDispatch->removeStatusListener( xStatusListener, aTargetURL );
315                     }
316                     catch ( Exception& )
317                     {
318                     }
319                 }
320 
321                 // Query for dispatch object. Old dispatch will be released with this, too.
322                 try
323                 {
324                     xDispatch = xDispatchProvider->queryDispatch( aTargetURL, ::rtl::OUString(), 0 );
325                 }
326                 catch ( Exception& )
327                 {
328                 }
329                 pIter->second = xDispatch;
330 
331                 Listener aListener( aTargetURL, xDispatch );
332                 aDispatchVector.push_back( aListener );
333                 ++pIter;
334             }
335         }
336     }
337 
338     // Call without locked mutex as we are called back from dispatch implementation
339     if ( xStatusListener.is() )
340     {
341         try
342         {
343             for ( sal_uInt32 i = 0; i < aDispatchVector.size(); i++ )
344             {
345                 Listener& rListener = aDispatchVector[i];
346                 if ( rListener.xDispatch.is() )
347                     rListener.xDispatch->addStatusListener( xStatusListener, rListener.aURL );
348             }
349         }
350         catch ( Exception& )
351         {
352         }
353     }
354 }
355 
unbindListener()356 void FrameStatusListener::unbindListener()
357 {
358     vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );
359 
360     if ( !m_bInitialized )
361         return;
362 
363     // Collect all registered command URL's and store them temporary
364     Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
365     if ( m_xServiceManager.is() && xDispatchProvider.is() )
366     {
367         Reference< XStatusListener > xStatusListener( static_cast< OWeakObject* >( this ), UNO_QUERY );
368         URLToDispatchMap::iterator pIter = m_aListenerMap.begin();
369         while ( pIter != m_aListenerMap.end() )
370         {
371             Reference< XURLTransformer > xURLTransformer( m_xServiceManager->createInstance(
372                                                             rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.util.URLTransformer" ))),
373                                                         UNO_QUERY );
374             com::sun::star::util::URL aTargetURL;
375             aTargetURL.Complete = pIter->first;
376             xURLTransformer->parseStrict( aTargetURL );
377 
378             Reference< XDispatch > xDispatch( pIter->second );
379             if ( xDispatch.is() )
380             {
381                 // We already have a dispatch object => we have to requery.
382                 // Release old dispatch object and remove it as listener
383                 try
384                 {
385                     xDispatch->removeStatusListener( xStatusListener, aTargetURL );
386                 }
387                 catch ( Exception& )
388                 {
389                 }
390             }
391             pIter->second.clear();
392             ++pIter;
393         }
394     }
395 }
396 
updateStatus(const rtl::OUString aCommandURL)397 void FrameStatusListener::updateStatus( const rtl::OUString aCommandURL )
398 {
399     Reference< XDispatch > xDispatch;
400     Reference< XStatusListener > xStatusListener;
401     com::sun::star::util::URL aTargetURL;
402 
403     {
404         vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );
405 
406         if ( !m_bInitialized )
407             return;
408 
409         // Try to find a dispatch object for the requested command URL
410         Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
411         xStatusListener = Reference< XStatusListener >( static_cast< OWeakObject* >( this ), UNO_QUERY );
412         if ( m_xServiceManager.is() && xDispatchProvider.is() )
413         {
414             Reference< XURLTransformer > xURLTransformer( m_xServiceManager->createInstance(
415                                                             rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.util.URLTransformer" ))),
416                                                         UNO_QUERY );
417             aTargetURL.Complete = aCommandURL;
418             xURLTransformer->parseStrict( aTargetURL );
419             xDispatch = xDispatchProvider->queryDispatch( aTargetURL, rtl::OUString(), 0 );
420         }
421     }
422 
423     if ( xDispatch.is() && xStatusListener.is() )
424     {
425         // Catch exception as we release our mutex, it is possible that someone else
426         // has already disposed this instance!
427         // Add/remove status listener to get a update status information from the
428         // requested command.
429         try
430         {
431             xDispatch->addStatusListener( xStatusListener, aTargetURL );
432             xDispatch->removeStatusListener( xStatusListener, aTargetURL );
433         }
434         catch ( Exception& )
435         {
436         }
437     }
438 }
439 
440 } // svt
441