1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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/helper/vclunohelper.hxx>
34 #include <comphelper/processfactory.hxx>
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
;
47 StatusbarController::StatusbarController(
48 const Reference
< XMultiServiceFactory
>& rServiceManager
,
49 const Reference
< XFrame
>& xFrame
,
50 const OUString
& aCommandURL
,
51 unsigned short nID
) :
53 , m_bInitialized( sal_False
)
54 , m_bDisposed( sal_False
)
57 , m_xServiceManager( rServiceManager
)
58 , m_aCommandURL( aCommandURL
)
59 , m_aListenerContainer( m_aMutex
)
63 StatusbarController::StatusbarController() :
65 , m_bInitialized( sal_False
)
66 , m_bDisposed( sal_False
)
68 , m_aListenerContainer( m_aMutex
)
72 StatusbarController::~StatusbarController()
76 Reference
< XFrame
> StatusbarController::getFrameInterface() const
78 SolarMutexGuard aSolarMutexGuard
;
82 Reference
< XURLTransformer
> StatusbarController::getURLTransformer() const
84 SolarMutexGuard aSolarMutexGuard
;
85 if ( !m_xURLTransformer
.is() && m_xServiceManager
.is() )
87 m_xURLTransformer
= com::sun::star::util::URLTransformer::create( ::comphelper::getComponentContext(m_xServiceManager
) );
90 return m_xURLTransformer
;
94 Any SAL_CALL
StatusbarController::queryInterface( const Type
& rType
)
95 throw ( RuntimeException
)
97 Any a
= ::cppu::queryInterface(
99 static_cast< XStatusbarController
* >( this ),
100 static_cast< XStatusListener
* >( this ),
101 static_cast< XEventListener
* >( this ),
102 static_cast< XInitialization
* >( this ),
103 static_cast< XComponent
* >( this ),
104 static_cast< XUpdatable
* >( this ));
109 return OWeakObject::queryInterface( rType
);
112 void SAL_CALL
StatusbarController::acquire() throw ()
114 OWeakObject::acquire();
117 void SAL_CALL
StatusbarController::release() throw ()
119 OWeakObject::release();
122 void SAL_CALL
StatusbarController::initialize( const Sequence
< Any
>& aArguments
)
123 throw ( Exception
, RuntimeException
)
125 bool bInitialized( true );
128 SolarMutexGuard aSolarMutexGuard
;
131 throw DisposedException();
133 bInitialized
= m_bInitialized
;
138 SolarMutexGuard aSolarMutexGuard
;
139 m_bInitialized
= sal_True
;
141 PropertyValue aPropValue
;
142 for ( int i
= 0; i
< aArguments
.getLength(); i
++ )
144 if ( aArguments
[i
] >>= aPropValue
)
146 if ( aPropValue
.Name
== "Frame" )
147 aPropValue
.Value
>>= m_xFrame
;
148 else if ( aPropValue
.Name
== "CommandURL" )
149 aPropValue
.Value
>>= m_aCommandURL
;
150 else if ( aPropValue
.Name
== "ServiceManager" )
151 aPropValue
.Value
>>= m_xServiceManager
;
152 else if ( aPropValue
.Name
== "ParentWindow" )
153 aPropValue
.Value
>>= m_xParentWindow
;
154 else if ( aPropValue
.Name
== "Identifier" )
155 aPropValue
.Value
>>= m_nID
;
156 else if ( aPropValue
.Name
== "StatusbarItem" )
157 aPropValue
.Value
>>= m_xStatusbarItem
;
161 if ( !m_aCommandURL
.isEmpty() )
162 m_aListenerMap
.insert( URLToDispatchMap::value_type( m_aCommandURL
, Reference
< XDispatch
>() ));
166 void SAL_CALL
StatusbarController::update()
167 throw ( RuntimeException
)
170 SolarMutexGuard aSolarMutexGuard
;
172 throw DisposedException();
175 // Bind all registered listeners to their dispatch objects
180 void SAL_CALL
StatusbarController::dispose()
181 throw (::com::sun::star::uno::RuntimeException
)
183 Reference
< XComponent
> xThis( static_cast< OWeakObject
* >(this), UNO_QUERY
);
186 SolarMutexGuard aSolarMutexGuard
;
188 throw DisposedException();
191 com::sun::star::lang::EventObject
aEvent( xThis
);
192 m_aListenerContainer
.disposeAndClear( aEvent
);
194 SolarMutexGuard aSolarMutexGuard
;
195 Reference
< XStatusListener
> xStatusListener( static_cast< OWeakObject
* >( this ), UNO_QUERY
);
196 Reference
< XURLTransformer
> xURLTransformer
= getURLTransformer();
197 URLToDispatchMap::iterator pIter
= m_aListenerMap
.begin();
198 com::sun::star::util::URL aTargetURL
;
199 while ( pIter
!= m_aListenerMap
.end() )
203 Reference
< XDispatch
> xDispatch( pIter
->second
);
204 aTargetURL
.Complete
= pIter
->first
;
205 xURLTransformer
->parseStrict( aTargetURL
);
207 if ( xDispatch
.is() && xStatusListener
.is() )
208 xDispatch
->removeStatusListener( xStatusListener
, aTargetURL
);
218 m_aListenerMap
.clear();
220 // release references
221 m_xURLTransformer
.clear();
222 m_xServiceManager
.clear();
224 m_xParentWindow
.clear();
225 m_xStatusbarItem
.clear();
227 m_bDisposed
= sal_True
;
230 void SAL_CALL
StatusbarController::addEventListener( const Reference
< XEventListener
>& xListener
)
231 throw ( RuntimeException
)
233 m_aListenerContainer
.addInterface( ::getCppuType( ( const Reference
< XEventListener
>* ) NULL
), xListener
);
236 void SAL_CALL
StatusbarController::removeEventListener( const Reference
< XEventListener
>& aListener
)
237 throw ( RuntimeException
)
239 m_aListenerContainer
.removeInterface( ::getCppuType( ( const Reference
< XEventListener
>* ) NULL
), aListener
);
243 void SAL_CALL
StatusbarController::disposing( const EventObject
& Source
)
244 throw ( RuntimeException
)
246 SolarMutexGuard aSolarMutexGuard
;
251 Reference
< XFrame
> xFrame( Source
.Source
, UNO_QUERY
);
254 if ( xFrame
== m_xFrame
)
259 Reference
< XDispatch
> xDispatch( Source
.Source
, UNO_QUERY
);
260 if ( !xDispatch
.is() )
263 URLToDispatchMap::iterator pIter
= m_aListenerMap
.begin();
264 while ( pIter
!= m_aListenerMap
.end() )
266 // Compare references and release dispatch references if they are equal.
267 if ( xDispatch
== pIter
->second
)
268 pIter
->second
.clear();
274 void SAL_CALL
StatusbarController::statusChanged( const FeatureStateEvent
& Event
)
275 throw ( RuntimeException
)
277 SolarMutexGuard aSolarMutexGuard
;
282 Window
* pWindow
= VCLUnoHelper::GetWindow( m_xParentWindow
);
283 if ( pWindow
&& pWindow
->GetType() == WINDOW_STATUSBAR
&& m_nID
!= 0 )
286 StatusBar
* pStatusBar
= (StatusBar
*)pWindow
;
288 if ( Event
.State
>>= aStrValue
)
289 pStatusBar
->SetItemText( m_nID
, aStrValue
);
290 else if ( !Event
.State
.hasValue() )
291 pStatusBar
->SetItemText( m_nID
, String() );
295 // XStatusbarController
296 ::sal_Bool SAL_CALL
StatusbarController::mouseButtonDown(
297 const ::com::sun::star::awt::MouseEvent
& )
298 throw (::com::sun::star::uno::RuntimeException
)
303 ::sal_Bool SAL_CALL
StatusbarController::mouseMove(
304 const ::com::sun::star::awt::MouseEvent
& )
305 throw (::com::sun::star::uno::RuntimeException
)
310 ::sal_Bool SAL_CALL
StatusbarController::mouseButtonUp(
311 const ::com::sun::star::awt::MouseEvent
& )
312 throw (::com::sun::star::uno::RuntimeException
)
317 void SAL_CALL
StatusbarController::command(
318 const ::com::sun::star::awt::Point
&,
321 const ::com::sun::star::uno::Any
& )
322 throw (::com::sun::star::uno::RuntimeException
)
326 void SAL_CALL
StatusbarController::paint(
327 const ::com::sun::star::uno::Reference
< ::com::sun::star::awt::XGraphics
>&,
328 const ::com::sun::star::awt::Rectangle
&,
330 throw (::com::sun::star::uno::RuntimeException
)
334 void SAL_CALL
StatusbarController::click( const ::com::sun::star::awt::Point
& )
335 throw (::com::sun::star::uno::RuntimeException
)
339 void SAL_CALL
StatusbarController::doubleClick( const ::com::sun::star::awt::Point
& ) throw (::com::sun::star::uno::RuntimeException
)
341 SolarMutexGuard aSolarMutexGuard
;
346 Sequence
< PropertyValue
> aArgs
;
350 void StatusbarController::addStatusListener( const OUString
& aCommandURL
)
352 Reference
< XDispatch
> xDispatch
;
353 Reference
< XStatusListener
> xStatusListener
;
354 com::sun::star::util::URL aTargetURL
;
357 SolarMutexGuard aSolarMutexGuard
;
358 URLToDispatchMap::iterator pIter
= m_aListenerMap
.find( aCommandURL
);
360 // Already in the list of status listener. Do nothing.
361 if ( pIter
!= m_aListenerMap
.end() )
364 // Check if we are already initialized. Implementation starts adding itself as status listener when
365 // intialize is called.
366 if ( !m_bInitialized
)
368 // Put into the boost::unordered_map of status listener. Will be activated when initialized is called
369 m_aListenerMap
.insert( URLToDispatchMap::value_type( aCommandURL
, Reference
< XDispatch
>() ));
374 // Add status listener directly as intialize has already been called.
375 Reference
< XDispatchProvider
> xDispatchProvider( m_xFrame
, UNO_QUERY
);
376 if ( m_xServiceManager
.is() && xDispatchProvider
.is() )
378 Reference
< XURLTransformer
> xURLTransformer
= getURLTransformer();
379 aTargetURL
.Complete
= aCommandURL
;
380 xURLTransformer
->parseStrict( aTargetURL
);
381 xDispatch
= xDispatchProvider
->queryDispatch( aTargetURL
, OUString(), 0 );
383 xStatusListener
= Reference
< XStatusListener
>( static_cast< OWeakObject
* >( this ), UNO_QUERY
);
384 URLToDispatchMap::iterator aIter
= m_aListenerMap
.find( aCommandURL
);
385 if ( aIter
!= m_aListenerMap
.end() )
387 Reference
< XDispatch
> xOldDispatch( aIter
->second
);
388 aIter
->second
= xDispatch
;
392 if ( xOldDispatch
.is() )
393 xOldDispatch
->removeStatusListener( xStatusListener
, aTargetURL
);
400 m_aListenerMap
.insert( URLToDispatchMap::value_type( aCommandURL
, xDispatch
));
405 // Call without locked mutex as we are called back from dispatch implementation
408 if ( xDispatch
.is() )
409 xDispatch
->addStatusListener( xStatusListener
, aTargetURL
);
416 void StatusbarController::bindListener()
418 std::vector
< Listener
> aDispatchVector
;
419 Reference
< XStatusListener
> xStatusListener
;
422 SolarMutexGuard aSolarMutexGuard
;
424 if ( !m_bInitialized
)
427 // Collect all registered command URL's and store them temporary
428 Reference
< XDispatchProvider
> xDispatchProvider( m_xFrame
, UNO_QUERY
);
429 if ( m_xServiceManager
.is() && xDispatchProvider
.is() )
431 xStatusListener
= Reference
< XStatusListener
>( static_cast< OWeakObject
* >( this ), UNO_QUERY
);
432 URLToDispatchMap::iterator pIter
= m_aListenerMap
.begin();
433 while ( pIter
!= m_aListenerMap
.end() )
435 Reference
< XURLTransformer
> xURLTransformer
= getURLTransformer();
436 com::sun::star::util::URL aTargetURL
;
437 aTargetURL
.Complete
= pIter
->first
;
438 xURLTransformer
->parseStrict( aTargetURL
);
440 Reference
< XDispatch
> xDispatch( pIter
->second
);
441 if ( xDispatch
.is() )
443 // We already have a dispatch object => we have to requery.
444 // Release old dispatch object and remove it as listener
447 xDispatch
->removeStatusListener( xStatusListener
, aTargetURL
);
454 pIter
->second
.clear();
457 // Query for dispatch object. Old dispatch will be released with this, too.
460 xDispatch
= xDispatchProvider
->queryDispatch( aTargetURL
, OUString(), 0 );
465 pIter
->second
= xDispatch
;
467 Listener
aListener( aTargetURL
, xDispatch
);
468 aDispatchVector
.push_back( aListener
);
474 // Call without locked mutex as we are called back from dispatch implementation
475 if ( !xStatusListener
.is() )
478 for ( sal_uInt32 i
= 0; i
< aDispatchVector
.size(); i
++ )
482 Listener
& rListener
= aDispatchVector
[i
];
483 if ( rListener
.xDispatch
.is() )
484 rListener
.xDispatch
->addStatusListener( xStatusListener
, rListener
.aURL
);
485 else if ( rListener
.aURL
.Complete
== m_aCommandURL
)
487 // Send status changed for the main URL, if we cannot get a valid dispatch object.
488 // UI disables the button. Catch exception as we release our mutex, it is possible
489 // that someone else already disposed this instance!
490 FeatureStateEvent aFeatureStateEvent
;
491 aFeatureStateEvent
.IsEnabled
= sal_False
;
492 aFeatureStateEvent
.FeatureURL
= rListener
.aURL
;
493 aFeatureStateEvent
.State
= Any();
494 xStatusListener
->statusChanged( aFeatureStateEvent
);
501 ::Rectangle
StatusbarController::getControlRect() const
506 SolarMutexGuard aSolarMutexGuard
;
509 throw DisposedException();
511 if ( m_xParentWindow
.is() )
513 StatusBar
* pStatusBar
= dynamic_cast< StatusBar
* >( VCLUnoHelper::GetWindow( m_xParentWindow
));
514 if ( pStatusBar
&& pStatusBar
->GetType() == WINDOW_STATUSBAR
)
515 aRect
= pStatusBar
->GetItemRect( m_nID
);
522 void StatusbarController::execute( const ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>& aArgs
)
524 Reference
< XDispatch
> xDispatch
;
525 Reference
< XURLTransformer
> xURLTransformer
;
526 OUString aCommandURL
;
529 SolarMutexGuard aSolarMutexGuard
;
532 throw DisposedException();
534 if ( m_bInitialized
&&
536 m_xServiceManager
.is() &&
537 !m_aCommandURL
.isEmpty() )
539 xURLTransformer
= getURLTransformer();
540 aCommandURL
= m_aCommandURL
;
541 URLToDispatchMap::iterator pIter
= m_aListenerMap
.find( m_aCommandURL
);
542 if ( pIter
!= m_aListenerMap
.end() )
543 xDispatch
= pIter
->second
;
547 if ( xDispatch
.is() && xURLTransformer
.is() )
551 com::sun::star::util::URL aTargetURL
;
553 aTargetURL
.Complete
= aCommandURL
;
554 xURLTransformer
->parseStrict( aTargetURL
);
555 xDispatch
->dispatch( aTargetURL
, aArgs
);
557 catch ( DisposedException
& )
563 void StatusbarController::execute(
564 const OUString
& aCommandURL
,
565 const Sequence
< ::com::sun::star::beans::PropertyValue
>& aArgs
)
567 Reference
< XDispatch
> xDispatch
;
568 com::sun::star::util::URL aTargetURL
;
571 SolarMutexGuard aSolarMutexGuard
;
574 throw DisposedException();
576 if ( m_bInitialized
&&
578 m_xServiceManager
.is() &&
579 !m_aCommandURL
.isEmpty() )
581 Reference
< XURLTransformer
> xURLTransformer( getURLTransformer() );
582 aTargetURL
.Complete
= aCommandURL
;
583 xURLTransformer
->parseStrict( aTargetURL
);
585 URLToDispatchMap::iterator pIter
= m_aListenerMap
.find( aCommandURL
);
586 if ( pIter
!= m_aListenerMap
.end() )
587 xDispatch
= pIter
->second
;
590 Reference
< ::com::sun::star::frame::XDispatchProvider
> xDispatchProvider(
591 m_xFrame
->getController(), UNO_QUERY
);
592 if ( xDispatchProvider
.is() )
593 xDispatch
= xDispatchProvider
->queryDispatch( aTargetURL
, OUString(), 0 );
598 if ( xDispatch
.is() )
602 xDispatch
->dispatch( aTargetURL
, aArgs
);
604 catch ( DisposedException
& )
612 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */