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