Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <svtools/statusbarcontroller.hxx>
21 : #include <com/sun/star/beans/PropertyValue.hpp>
22 : #include <com/sun/star/beans/XPropertySet.hpp>
23 : #include <com/sun/star/frame/XDispatchProvider.hpp>
24 : #include <com/sun/star/lang/DisposedException.hpp>
25 : #include <com/sun/star/frame/XLayoutManager.hpp>
26 : #include <com/sun/star/util/URLTransformer.hpp>
27 : #include <osl/mutex.hxx>
28 : #include <vcl/svapp.hxx>
29 : #include <vcl/window.hxx>
30 : #include <vcl/status.hxx>
31 : #include <svtools/imgdef.hxx>
32 : #include <svtools/miscopt.hxx>
33 : #include <toolkit/unohlp.hxx>
34 : #include <comphelper/processfactory.hxx>
35 :
36 : using namespace ::cppu;
37 : using namespace ::com::sun::star::awt;
38 : using namespace ::com::sun::star::uno;
39 : using namespace ::com::sun::star::util;
40 : using namespace ::com::sun::star::beans;
41 : using namespace ::com::sun::star::lang;
42 : using namespace ::com::sun::star::frame;
43 : using namespace ::com::sun::star::frame;
44 :
45 : namespace svt
46 : {
47 :
48 0 : StatusbarController::StatusbarController(
49 : const Reference< XMultiServiceFactory >& rServiceManager,
50 : const Reference< XFrame >& xFrame,
51 : const ::rtl::OUString& aCommandURL,
52 : unsigned short nID ) :
53 : OWeakObject()
54 : , m_bInitialized( sal_False )
55 : , m_bDisposed( sal_False )
56 : , m_nID( nID )
57 : , m_xFrame( xFrame )
58 : , m_xServiceManager( rServiceManager )
59 : , m_aCommandURL( aCommandURL )
60 0 : , m_aListenerContainer( m_aMutex )
61 : {
62 0 : }
63 :
64 0 : StatusbarController::StatusbarController() :
65 : OWeakObject()
66 : , m_bInitialized( sal_False )
67 : , m_bDisposed( sal_False )
68 : , m_nID( 0 )
69 0 : , m_aListenerContainer( m_aMutex )
70 : {
71 0 : }
72 :
73 0 : StatusbarController::~StatusbarController()
74 : {
75 0 : }
76 :
77 0 : Reference< XFrame > StatusbarController::getFrameInterface() const
78 : {
79 0 : SolarMutexGuard aSolarMutexGuard;
80 0 : return m_xFrame;
81 : }
82 :
83 0 : Reference< XURLTransformer > StatusbarController::getURLTransformer() const
84 : {
85 0 : SolarMutexGuard aSolarMutexGuard;
86 0 : if ( !m_xURLTransformer.is() && m_xServiceManager.is() )
87 : {
88 0 : m_xURLTransformer = com::sun::star::util::URLTransformer::create( ::comphelper::getComponentContext(m_xServiceManager) );
89 : }
90 :
91 0 : return m_xURLTransformer;
92 : }
93 :
94 : // XInterface
95 0 : Any SAL_CALL StatusbarController::queryInterface( const Type& rType )
96 : throw ( RuntimeException )
97 : {
98 : Any a = ::cppu::queryInterface(
99 : rType ,
100 : static_cast< XStatusbarController* >( this ),
101 : static_cast< XStatusListener* >( this ),
102 : static_cast< XEventListener* >( this ),
103 : static_cast< XInitialization* >( this ),
104 : static_cast< XComponent* >( this ),
105 0 : static_cast< XUpdatable* >( this ));
106 :
107 0 : if ( a.hasValue() )
108 0 : return a;
109 :
110 0 : return OWeakObject::queryInterface( rType );
111 : }
112 :
113 0 : void SAL_CALL StatusbarController::acquire() throw ()
114 : {
115 0 : OWeakObject::acquire();
116 0 : }
117 :
118 0 : void SAL_CALL StatusbarController::release() throw ()
119 : {
120 0 : OWeakObject::release();
121 0 : }
122 :
123 0 : void SAL_CALL StatusbarController::initialize( const Sequence< Any >& aArguments )
124 : throw ( Exception, RuntimeException )
125 : {
126 0 : bool bInitialized( true );
127 :
128 : {
129 0 : SolarMutexGuard aSolarMutexGuard;
130 :
131 0 : if ( m_bDisposed )
132 0 : throw DisposedException();
133 :
134 0 : bInitialized = m_bInitialized;
135 : }
136 :
137 0 : if ( !bInitialized )
138 : {
139 0 : SolarMutexGuard aSolarMutexGuard;
140 0 : m_bInitialized = sal_True;
141 :
142 0 : PropertyValue aPropValue;
143 0 : for ( int i = 0; i < aArguments.getLength(); i++ )
144 : {
145 0 : if ( aArguments[i] >>= aPropValue )
146 : {
147 0 : if ( aPropValue.Name == "Frame" )
148 0 : aPropValue.Value >>= m_xFrame;
149 0 : else if ( aPropValue.Name == "CommandURL" )
150 0 : aPropValue.Value >>= m_aCommandURL;
151 0 : else if ( aPropValue.Name == "ServiceManager" )
152 0 : aPropValue.Value >>= m_xServiceManager;
153 0 : else if ( aPropValue.Name == "ParentWindow" )
154 0 : aPropValue.Value >>= m_xParentWindow;
155 0 : else if ( aPropValue.Name == "Identifier" )
156 0 : aPropValue.Value >>= m_nID;
157 : }
158 : }
159 :
160 0 : if ( !m_aCommandURL.isEmpty() )
161 0 : m_aListenerMap.insert( URLToDispatchMap::value_type( m_aCommandURL, Reference< XDispatch >() ));
162 : }
163 0 : }
164 :
165 0 : void SAL_CALL StatusbarController::update()
166 : throw ( RuntimeException )
167 : {
168 : {
169 0 : SolarMutexGuard aSolarMutexGuard;
170 0 : if ( m_bDisposed )
171 0 : throw DisposedException();
172 : }
173 :
174 : // Bind all registered listeners to their dispatch objects
175 0 : bindListener();
176 0 : }
177 :
178 : // XComponent
179 0 : void SAL_CALL StatusbarController::dispose()
180 : throw (::com::sun::star::uno::RuntimeException)
181 : {
182 0 : Reference< XComponent > xThis( static_cast< OWeakObject* >(this), UNO_QUERY );
183 :
184 : {
185 0 : SolarMutexGuard aSolarMutexGuard;
186 0 : if ( m_bDisposed )
187 0 : throw DisposedException();
188 : }
189 :
190 0 : com::sun::star::lang::EventObject aEvent( xThis );
191 0 : m_aListenerContainer.disposeAndClear( aEvent );
192 :
193 0 : SolarMutexGuard aSolarMutexGuard;
194 0 : Reference< XStatusListener > xStatusListener( static_cast< OWeakObject* >( this ), UNO_QUERY );
195 0 : Reference< XURLTransformer > xURLTransformer = getURLTransformer();
196 0 : URLToDispatchMap::iterator pIter = m_aListenerMap.begin();
197 0 : com::sun::star::util::URL aTargetURL;
198 0 : while ( pIter != m_aListenerMap.end() )
199 : {
200 : try
201 : {
202 0 : Reference< XDispatch > xDispatch( pIter->second );
203 0 : aTargetURL.Complete = pIter->first;
204 0 : xURLTransformer->parseStrict( aTargetURL );
205 :
206 0 : if ( xDispatch.is() && xStatusListener.is() )
207 0 : xDispatch->removeStatusListener( xStatusListener, aTargetURL );
208 : }
209 0 : catch ( Exception& )
210 : {
211 : }
212 :
213 0 : ++pIter;
214 : }
215 :
216 : // clear hash map
217 0 : m_aListenerMap.clear();
218 :
219 : // release references
220 0 : m_xURLTransformer.clear();
221 0 : m_xServiceManager.clear();
222 0 : m_xFrame.clear();
223 0 : m_xParentWindow.clear();
224 :
225 0 : m_bDisposed = sal_True;
226 0 : }
227 :
228 0 : void SAL_CALL StatusbarController::addEventListener( const Reference< XEventListener >& xListener )
229 : throw ( RuntimeException )
230 : {
231 0 : m_aListenerContainer.addInterface( ::getCppuType( ( const Reference< XEventListener >* ) NULL ), xListener );
232 0 : }
233 :
234 0 : void SAL_CALL StatusbarController::removeEventListener( const Reference< XEventListener >& aListener )
235 : throw ( RuntimeException )
236 : {
237 0 : m_aListenerContainer.removeInterface( ::getCppuType( ( const Reference< XEventListener >* ) NULL ), aListener );
238 0 : }
239 :
240 : // XEventListener
241 0 : void SAL_CALL StatusbarController::disposing( const EventObject& Source )
242 : throw ( RuntimeException )
243 : {
244 0 : Reference< XInterface > xSource( Source.Source );
245 :
246 0 : SolarMutexGuard aSolarMutexGuard;
247 :
248 0 : if ( m_bDisposed )
249 0 : return;
250 :
251 0 : URLToDispatchMap::iterator pIter = m_aListenerMap.begin();
252 0 : while ( pIter != m_aListenerMap.end() )
253 : {
254 : // Compare references and release dispatch references if they are equal.
255 0 : Reference< XInterface > xIfac( pIter->second, UNO_QUERY );
256 0 : if ( xSource == xIfac )
257 0 : pIter->second.clear();
258 0 : ++pIter;
259 0 : }
260 :
261 0 : Reference< XInterface > xIfac( m_xFrame, UNO_QUERY );
262 0 : if ( xIfac == xSource )
263 0 : m_xFrame.clear();
264 : }
265 :
266 : // XStatusListener
267 0 : void SAL_CALL StatusbarController::statusChanged( const FeatureStateEvent& Event )
268 : throw ( RuntimeException )
269 : {
270 0 : SolarMutexGuard aSolarMutexGuard;
271 :
272 0 : if ( m_bDisposed )
273 0 : return;
274 :
275 0 : Window* pWindow = VCLUnoHelper::GetWindow( m_xParentWindow );
276 0 : if ( pWindow && pWindow->GetType() == WINDOW_STATUSBAR && m_nID != 0 )
277 : {
278 0 : rtl::OUString aStrValue;
279 0 : StatusBar* pStatusBar = (StatusBar *)pWindow;
280 :
281 0 : if ( Event.State >>= aStrValue )
282 0 : pStatusBar->SetItemText( m_nID, aStrValue );
283 0 : else if ( !Event.State.hasValue() )
284 0 : pStatusBar->SetItemText( m_nID, String() );
285 0 : }
286 : }
287 :
288 : // XStatusbarController
289 0 : ::sal_Bool SAL_CALL StatusbarController::mouseButtonDown(
290 : const ::com::sun::star::awt::MouseEvent& )
291 : throw (::com::sun::star::uno::RuntimeException)
292 : {
293 0 : return sal_False;
294 : }
295 :
296 0 : ::sal_Bool SAL_CALL StatusbarController::mouseMove(
297 : const ::com::sun::star::awt::MouseEvent& )
298 : throw (::com::sun::star::uno::RuntimeException)
299 : {
300 0 : return sal_False;
301 : }
302 :
303 0 : ::sal_Bool SAL_CALL StatusbarController::mouseButtonUp(
304 : const ::com::sun::star::awt::MouseEvent& )
305 : throw (::com::sun::star::uno::RuntimeException)
306 : {
307 0 : return sal_False;
308 : }
309 :
310 0 : void SAL_CALL StatusbarController::command(
311 : const ::com::sun::star::awt::Point&,
312 : ::sal_Int32,
313 : ::sal_Bool,
314 : const ::com::sun::star::uno::Any& )
315 : throw (::com::sun::star::uno::RuntimeException)
316 : {
317 0 : }
318 :
319 0 : void SAL_CALL StatusbarController::paint(
320 : const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XGraphics >&,
321 : const ::com::sun::star::awt::Rectangle&,
322 : ::sal_Int32,
323 : ::sal_Int32 )
324 : throw (::com::sun::star::uno::RuntimeException)
325 : {
326 0 : }
327 :
328 0 : void SAL_CALL StatusbarController::click()
329 : throw (::com::sun::star::uno::RuntimeException)
330 : {
331 0 : }
332 :
333 0 : void SAL_CALL StatusbarController::doubleClick() throw (::com::sun::star::uno::RuntimeException)
334 : {
335 0 : SolarMutexGuard aSolarMutexGuard;
336 :
337 0 : if ( m_bDisposed )
338 0 : return;
339 :
340 0 : Sequence< PropertyValue > aArgs;
341 0 : execute( aArgs );
342 : }
343 :
344 0 : void StatusbarController::addStatusListener( const rtl::OUString& aCommandURL )
345 : {
346 0 : Reference< XDispatch > xDispatch;
347 0 : Reference< XStatusListener > xStatusListener;
348 0 : com::sun::star::util::URL aTargetURL;
349 :
350 : {
351 0 : SolarMutexGuard aSolarMutexGuard;
352 0 : URLToDispatchMap::iterator pIter = m_aListenerMap.find( aCommandURL );
353 :
354 : // Already in the list of status listener. Do nothing.
355 0 : if ( pIter != m_aListenerMap.end() )
356 : return;
357 :
358 : // Check if we are already initialized. Implementation starts adding itself as status listener when
359 : // intialize is called.
360 0 : if ( !m_bInitialized )
361 : {
362 : // Put into the boost::unordered_map of status listener. Will be activated when initialized is called
363 0 : m_aListenerMap.insert( URLToDispatchMap::value_type( aCommandURL, Reference< XDispatch >() ));
364 : return;
365 : }
366 : else
367 : {
368 : // Add status listener directly as intialize has already been called.
369 0 : Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
370 0 : if ( m_xServiceManager.is() && xDispatchProvider.is() )
371 : {
372 0 : Reference< XURLTransformer > xURLTransformer = getURLTransformer();
373 0 : aTargetURL.Complete = aCommandURL;
374 0 : xURLTransformer->parseStrict( aTargetURL );
375 0 : xDispatch = xDispatchProvider->queryDispatch( aTargetURL, ::rtl::OUString(), 0 );
376 :
377 0 : xStatusListener = Reference< XStatusListener >( static_cast< OWeakObject* >( this ), UNO_QUERY );
378 0 : URLToDispatchMap::iterator aIter = m_aListenerMap.find( aCommandURL );
379 0 : if ( aIter != m_aListenerMap.end() )
380 : {
381 0 : Reference< XDispatch > xOldDispatch( aIter->second );
382 0 : aIter->second = xDispatch;
383 :
384 : try
385 : {
386 0 : if ( xOldDispatch.is() )
387 0 : xOldDispatch->removeStatusListener( xStatusListener, aTargetURL );
388 : }
389 0 : catch ( Exception& )
390 : {
391 0 : }
392 : }
393 : else
394 0 : m_aListenerMap.insert( URLToDispatchMap::value_type( aCommandURL, xDispatch ));
395 0 : }
396 0 : }
397 : }
398 :
399 : // Call without locked mutex as we are called back from dispatch implementation
400 : try
401 : {
402 0 : if ( xDispatch.is() )
403 0 : xDispatch->addStatusListener( xStatusListener, aTargetURL );
404 : }
405 0 : catch ( Exception& )
406 : {
407 0 : }
408 : }
409 :
410 0 : void StatusbarController::bindListener()
411 : {
412 0 : std::vector< Listener > aDispatchVector;
413 0 : Reference< XStatusListener > xStatusListener;
414 :
415 : {
416 0 : SolarMutexGuard aSolarMutexGuard;
417 :
418 0 : if ( !m_bInitialized )
419 0 : return;
420 :
421 : // Collect all registered command URL's and store them temporary
422 0 : Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
423 0 : if ( m_xServiceManager.is() && xDispatchProvider.is() )
424 : {
425 0 : xStatusListener = Reference< XStatusListener >( static_cast< OWeakObject* >( this ), UNO_QUERY );
426 0 : URLToDispatchMap::iterator pIter = m_aListenerMap.begin();
427 0 : while ( pIter != m_aListenerMap.end() )
428 : {
429 0 : Reference< XURLTransformer > xURLTransformer = getURLTransformer();
430 0 : com::sun::star::util::URL aTargetURL;
431 0 : aTargetURL.Complete = pIter->first;
432 0 : xURLTransformer->parseStrict( aTargetURL );
433 :
434 0 : Reference< XDispatch > xDispatch( pIter->second );
435 0 : if ( xDispatch.is() )
436 : {
437 : // We already have a dispatch object => we have to requery.
438 : // Release old dispatch object and remove it as listener
439 : try
440 : {
441 0 : xDispatch->removeStatusListener( xStatusListener, aTargetURL );
442 : }
443 0 : catch ( Exception& )
444 : {
445 : }
446 : }
447 :
448 0 : pIter->second.clear();
449 0 : xDispatch.clear();
450 :
451 : // Query for dispatch object. Old dispatch will be released with this, too.
452 : try
453 : {
454 0 : xDispatch = xDispatchProvider->queryDispatch( aTargetURL, ::rtl::OUString(), 0 );
455 : }
456 0 : catch ( Exception& )
457 : {
458 : }
459 0 : pIter->second = xDispatch;
460 :
461 0 : Listener aListener( aTargetURL, xDispatch );
462 0 : aDispatchVector.push_back( aListener );
463 0 : ++pIter;
464 0 : }
465 0 : }
466 : }
467 :
468 : // Call without locked mutex as we are called back from dispatch implementation
469 0 : if ( xStatusListener.is() )
470 : {
471 : try
472 : {
473 0 : for ( sal_uInt32 i = 0; i < aDispatchVector.size(); i++ )
474 : {
475 0 : Listener& rListener = aDispatchVector[i];
476 0 : if ( rListener.xDispatch.is() )
477 0 : rListener.xDispatch->addStatusListener( xStatusListener, rListener.aURL );
478 0 : else if ( rListener.aURL.Complete == m_aCommandURL )
479 : {
480 : try
481 : {
482 : // Send status changed for the main URL, if we cannot get a valid dispatch object.
483 : // UI disables the button. Catch exception as we release our mutex, it is possible
484 : // that someone else already disposed this instance!
485 0 : FeatureStateEvent aFeatureStateEvent;
486 0 : aFeatureStateEvent.IsEnabled = sal_False;
487 0 : aFeatureStateEvent.FeatureURL = rListener.aURL;
488 0 : aFeatureStateEvent.State = Any();
489 0 : xStatusListener->statusChanged( aFeatureStateEvent );
490 : }
491 0 : catch ( Exception& )
492 : {
493 : }
494 : }
495 : }
496 : }
497 0 : catch ( Exception& )
498 : {
499 : }
500 0 : }
501 : }
502 :
503 0 : ::Rectangle StatusbarController::getControlRect() const
504 : {
505 0 : ::Rectangle aRect;
506 :
507 : {
508 0 : SolarMutexGuard aSolarMutexGuard;
509 :
510 0 : if ( m_bDisposed )
511 0 : throw DisposedException();
512 :
513 0 : if ( m_xParentWindow.is() )
514 : {
515 0 : StatusBar* pStatusBar = dynamic_cast< StatusBar* >( VCLUnoHelper::GetWindow( m_xParentWindow ));
516 0 : if ( pStatusBar && pStatusBar->GetType() == WINDOW_STATUSBAR )
517 0 : aRect = pStatusBar->GetItemRect( m_nID );
518 0 : }
519 : }
520 :
521 0 : return aRect;
522 : }
523 :
524 0 : void StatusbarController::execute( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aArgs )
525 : {
526 0 : Reference< XDispatch > xDispatch;
527 0 : Reference< XURLTransformer > xURLTransformer;
528 0 : rtl::OUString aCommandURL;
529 :
530 : {
531 0 : SolarMutexGuard aSolarMutexGuard;
532 :
533 0 : if ( m_bDisposed )
534 0 : throw DisposedException();
535 :
536 0 : if ( m_bInitialized &&
537 0 : m_xFrame.is() &&
538 0 : m_xServiceManager.is() &&
539 0 : !m_aCommandURL.isEmpty() )
540 : {
541 0 : xURLTransformer = getURLTransformer();
542 0 : aCommandURL = m_aCommandURL;
543 0 : URLToDispatchMap::iterator pIter = m_aListenerMap.find( m_aCommandURL );
544 0 : if ( pIter != m_aListenerMap.end() )
545 0 : xDispatch = pIter->second;
546 0 : }
547 : }
548 :
549 0 : if ( xDispatch.is() && xURLTransformer.is() )
550 : {
551 : try
552 : {
553 0 : com::sun::star::util::URL aTargetURL;
554 :
555 0 : aTargetURL.Complete = aCommandURL;
556 0 : xURLTransformer->parseStrict( aTargetURL );
557 0 : xDispatch->dispatch( aTargetURL, aArgs );
558 : }
559 0 : catch ( DisposedException& )
560 : {
561 : }
562 0 : }
563 0 : }
564 :
565 0 : void StatusbarController::execute(
566 : const rtl::OUString& aCommandURL,
567 : const Sequence< ::com::sun::star::beans::PropertyValue >& aArgs )
568 : {
569 0 : Reference< XDispatch > xDispatch;
570 0 : com::sun::star::util::URL aTargetURL;
571 :
572 : {
573 0 : SolarMutexGuard aSolarMutexGuard;
574 :
575 0 : if ( m_bDisposed )
576 0 : throw DisposedException();
577 :
578 0 : if ( m_bInitialized &&
579 0 : m_xFrame.is() &&
580 0 : m_xServiceManager.is() &&
581 0 : !m_aCommandURL.isEmpty() )
582 : {
583 0 : Reference< XURLTransformer > xURLTransformer( getURLTransformer() );
584 0 : aTargetURL.Complete = aCommandURL;
585 0 : xURLTransformer->parseStrict( aTargetURL );
586 :
587 0 : URLToDispatchMap::iterator pIter = m_aListenerMap.find( aCommandURL );
588 0 : if ( pIter != m_aListenerMap.end() )
589 0 : xDispatch = pIter->second;
590 : else
591 : {
592 : Reference< ::com::sun::star::frame::XDispatchProvider > xDispatchProvider(
593 0 : m_xFrame->getController(), UNO_QUERY );
594 0 : if ( xDispatchProvider.is() )
595 0 : xDispatch = xDispatchProvider->queryDispatch( aTargetURL, ::rtl::OUString(), 0 );
596 0 : }
597 0 : }
598 : }
599 :
600 0 : if ( xDispatch.is() )
601 : {
602 : try
603 : {
604 0 : xDispatch->dispatch( aTargetURL, aArgs );
605 : }
606 0 : catch ( DisposedException& )
607 : {
608 : }
609 0 : }
610 0 : }
611 :
612 : } // svt
613 :
614 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|