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/lang/XMultiServiceFactory.hpp>
26 #include <com/sun/star/frame/XLayoutManager.hpp>
27 #include <com/sun/star/util/URLTransformer.hpp>
28 #include <osl/mutex.hxx>
29 #include <vcl/svapp.hxx>
30 #include <vcl/window.hxx>
31 #include <vcl/status.hxx>
32 #include <svtools/imgdef.hxx>
33 #include <svtools/miscopt.hxx>
34 #include <toolkit/helper/vclunohelper.hxx>
35 #include <comphelper/processfactory.hxx>
37 using namespace ::cppu
;
38 using namespace ::com::sun::star::awt
;
39 using namespace ::com::sun::star::uno
;
40 using namespace ::com::sun::star::util
;
41 using namespace ::com::sun::star::beans
;
42 using namespace ::com::sun::star::lang
;
43 using namespace ::com::sun::star::frame
;
48 StatusbarController::StatusbarController(
49 const Reference
< XComponentContext
>& rxContext
,
50 const Reference
< XFrame
>& xFrame
,
51 const OUString
& aCommandURL
,
52 unsigned short nID
) :
54 , m_bInitialized( sal_False
)
55 , m_bDisposed( sal_False
)
58 , m_xContext( rxContext
)
59 , m_aCommandURL( aCommandURL
)
60 , m_aListenerContainer( m_aMutex
)
64 StatusbarController::StatusbarController() :
66 , m_bInitialized( sal_False
)
67 , m_bDisposed( sal_False
)
69 , m_aListenerContainer( m_aMutex
)
73 StatusbarController::~StatusbarController()
77 Reference
< XFrame
> StatusbarController::getFrameInterface() const
79 SolarMutexGuard aSolarMutexGuard
;
83 Reference
< XURLTransformer
> StatusbarController::getURLTransformer() const
85 SolarMutexGuard aSolarMutexGuard
;
86 if ( !m_xURLTransformer
.is() && m_xContext
.is() )
88 m_xURLTransformer
= com::sun::star::util::URLTransformer::create( m_xContext
);
91 return m_xURLTransformer
;
95 Any SAL_CALL
StatusbarController::queryInterface( const Type
& rType
)
96 throw ( RuntimeException
)
98 Any a
= ::cppu::queryInterface(
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 static_cast< XUpdatable
* >( this ));
110 return OWeakObject::queryInterface( rType
);
113 void SAL_CALL
StatusbarController::acquire() throw ()
115 OWeakObject::acquire();
118 void SAL_CALL
StatusbarController::release() throw ()
120 OWeakObject::release();
123 void SAL_CALL
StatusbarController::initialize( const Sequence
< Any
>& aArguments
)
124 throw ( Exception
, RuntimeException
)
126 bool bInitialized( true );
129 SolarMutexGuard aSolarMutexGuard
;
132 throw DisposedException();
134 bInitialized
= m_bInitialized
;
139 SolarMutexGuard aSolarMutexGuard
;
140 m_bInitialized
= sal_True
;
142 PropertyValue aPropValue
;
143 for ( int i
= 0; i
< aArguments
.getLength(); i
++ )
145 if ( aArguments
[i
] >>= aPropValue
)
147 if ( aPropValue
.Name
== "Frame" )
148 aPropValue
.Value
>>= m_xFrame
;
149 else if ( aPropValue
.Name
== "CommandURL" )
150 aPropValue
.Value
>>= m_aCommandURL
;
151 else if ( aPropValue
.Name
== "ServiceManager" )
153 Reference
<XMultiServiceFactory
> xMSF
;
154 aPropValue
.Value
>>= xMSF
;
156 m_xContext
= comphelper::getComponentContext(xMSF
);
158 else if ( aPropValue
.Name
== "ParentWindow" )
159 aPropValue
.Value
>>= m_xParentWindow
;
160 else if ( aPropValue
.Name
== "Identifier" )
161 aPropValue
.Value
>>= m_nID
;
162 else if ( aPropValue
.Name
== "StatusbarItem" )
163 aPropValue
.Value
>>= m_xStatusbarItem
;
167 if ( !m_aCommandURL
.isEmpty() )
168 m_aListenerMap
.insert( URLToDispatchMap::value_type( m_aCommandURL
, Reference
< XDispatch
>() ));
172 void SAL_CALL
StatusbarController::update()
173 throw ( RuntimeException
)
176 SolarMutexGuard aSolarMutexGuard
;
178 throw DisposedException();
181 // Bind all registered listeners to their dispatch objects
186 void SAL_CALL
StatusbarController::dispose()
187 throw (::com::sun::star::uno::RuntimeException
)
189 Reference
< XComponent
> xThis( static_cast< OWeakObject
* >(this), UNO_QUERY
);
192 SolarMutexGuard aSolarMutexGuard
;
194 throw DisposedException();
197 com::sun::star::lang::EventObject
aEvent( xThis
);
198 m_aListenerContainer
.disposeAndClear( aEvent
);
200 SolarMutexGuard aSolarMutexGuard
;
201 Reference
< XStatusListener
> xStatusListener( static_cast< OWeakObject
* >( this ), UNO_QUERY
);
202 Reference
< XURLTransformer
> xURLTransformer
= getURLTransformer();
203 URLToDispatchMap::iterator pIter
= m_aListenerMap
.begin();
204 com::sun::star::util::URL aTargetURL
;
205 while ( pIter
!= m_aListenerMap
.end() )
209 Reference
< XDispatch
> xDispatch( pIter
->second
);
210 aTargetURL
.Complete
= pIter
->first
;
211 xURLTransformer
->parseStrict( aTargetURL
);
213 if ( xDispatch
.is() && xStatusListener
.is() )
214 xDispatch
->removeStatusListener( xStatusListener
, aTargetURL
);
224 m_aListenerMap
.clear();
226 // release references
227 m_xURLTransformer
.clear();
230 m_xParentWindow
.clear();
231 m_xStatusbarItem
.clear();
233 m_bDisposed
= sal_True
;
236 void SAL_CALL
StatusbarController::addEventListener( const Reference
< XEventListener
>& xListener
)
237 throw ( RuntimeException
)
239 m_aListenerContainer
.addInterface( ::getCppuType( ( const Reference
< XEventListener
>* ) NULL
), xListener
);
242 void SAL_CALL
StatusbarController::removeEventListener( const Reference
< XEventListener
>& aListener
)
243 throw ( RuntimeException
)
245 m_aListenerContainer
.removeInterface( ::getCppuType( ( const Reference
< XEventListener
>* ) NULL
), aListener
);
249 void SAL_CALL
StatusbarController::disposing( const EventObject
& Source
)
250 throw ( RuntimeException
)
252 SolarMutexGuard aSolarMutexGuard
;
257 Reference
< XFrame
> xFrame( Source
.Source
, UNO_QUERY
);
260 if ( xFrame
== m_xFrame
)
265 Reference
< XDispatch
> xDispatch( Source
.Source
, UNO_QUERY
);
266 if ( !xDispatch
.is() )
269 URLToDispatchMap::iterator pIter
= m_aListenerMap
.begin();
270 while ( pIter
!= m_aListenerMap
.end() )
272 // Compare references and release dispatch references if they are equal.
273 if ( xDispatch
== pIter
->second
)
274 pIter
->second
.clear();
280 void SAL_CALL
StatusbarController::statusChanged( const FeatureStateEvent
& Event
)
281 throw ( RuntimeException
)
283 SolarMutexGuard aSolarMutexGuard
;
288 Window
* pWindow
= VCLUnoHelper::GetWindow( m_xParentWindow
);
289 if ( pWindow
&& pWindow
->GetType() == WINDOW_STATUSBAR
&& m_nID
!= 0 )
292 StatusBar
* pStatusBar
= (StatusBar
*)pWindow
;
294 if ( Event
.State
>>= aStrValue
)
295 pStatusBar
->SetItemText( m_nID
, aStrValue
);
296 else if ( !Event
.State
.hasValue() )
297 pStatusBar
->SetItemText( m_nID
, "" );
301 // XStatusbarController
302 ::sal_Bool SAL_CALL
StatusbarController::mouseButtonDown(
303 const ::com::sun::star::awt::MouseEvent
& )
304 throw (::com::sun::star::uno::RuntimeException
)
309 ::sal_Bool SAL_CALL
StatusbarController::mouseMove(
310 const ::com::sun::star::awt::MouseEvent
& )
311 throw (::com::sun::star::uno::RuntimeException
)
316 ::sal_Bool SAL_CALL
StatusbarController::mouseButtonUp(
317 const ::com::sun::star::awt::MouseEvent
& )
318 throw (::com::sun::star::uno::RuntimeException
)
323 void SAL_CALL
StatusbarController::command(
324 const ::com::sun::star::awt::Point
&,
327 const ::com::sun::star::uno::Any
& )
328 throw (::com::sun::star::uno::RuntimeException
)
332 void SAL_CALL
StatusbarController::paint(
333 const ::com::sun::star::uno::Reference
< ::com::sun::star::awt::XGraphics
>&,
334 const ::com::sun::star::awt::Rectangle
&,
336 throw (::com::sun::star::uno::RuntimeException
)
340 void SAL_CALL
StatusbarController::click( const ::com::sun::star::awt::Point
& )
341 throw (::com::sun::star::uno::RuntimeException
)
345 void SAL_CALL
StatusbarController::doubleClick( const ::com::sun::star::awt::Point
& ) throw (::com::sun::star::uno::RuntimeException
)
347 SolarMutexGuard aSolarMutexGuard
;
352 Sequence
< PropertyValue
> aArgs
;
356 void StatusbarController::addStatusListener( const OUString
& aCommandURL
)
358 Reference
< XDispatch
> xDispatch
;
359 Reference
< XStatusListener
> xStatusListener
;
360 com::sun::star::util::URL aTargetURL
;
363 SolarMutexGuard aSolarMutexGuard
;
364 URLToDispatchMap::iterator pIter
= m_aListenerMap
.find( aCommandURL
);
366 // Already in the list of status listener. Do nothing.
367 if ( pIter
!= m_aListenerMap
.end() )
370 // Check if we are already initialized. Implementation starts adding itself as status listener when
371 // intialize is called.
372 if ( !m_bInitialized
)
374 // Put into the boost::unordered_map of status listener. Will be activated when initialized is called
375 m_aListenerMap
.insert( URLToDispatchMap::value_type( aCommandURL
, Reference
< XDispatch
>() ));
380 // Add status listener directly as intialize has already been called.
381 Reference
< XDispatchProvider
> xDispatchProvider( m_xFrame
, UNO_QUERY
);
382 if ( m_xContext
.is() && xDispatchProvider
.is() )
384 Reference
< XURLTransformer
> xURLTransformer
= getURLTransformer();
385 aTargetURL
.Complete
= aCommandURL
;
386 xURLTransformer
->parseStrict( aTargetURL
);
387 xDispatch
= xDispatchProvider
->queryDispatch( aTargetURL
, OUString(), 0 );
389 xStatusListener
= Reference
< XStatusListener
>( static_cast< OWeakObject
* >( this ), UNO_QUERY
);
390 URLToDispatchMap::iterator aIter
= m_aListenerMap
.find( aCommandURL
);
391 if ( aIter
!= m_aListenerMap
.end() )
393 Reference
< XDispatch
> xOldDispatch( aIter
->second
);
394 aIter
->second
= xDispatch
;
398 if ( xOldDispatch
.is() )
399 xOldDispatch
->removeStatusListener( xStatusListener
, aTargetURL
);
406 m_aListenerMap
.insert( URLToDispatchMap::value_type( aCommandURL
, xDispatch
));
411 // Call without locked mutex as we are called back from dispatch implementation
414 if ( xDispatch
.is() )
415 xDispatch
->addStatusListener( xStatusListener
, aTargetURL
);
422 void StatusbarController::bindListener()
424 std::vector
< Listener
> aDispatchVector
;
425 Reference
< XStatusListener
> xStatusListener
;
428 SolarMutexGuard aSolarMutexGuard
;
430 if ( !m_bInitialized
)
433 // Collect all registered command URL's and store them temporary
434 Reference
< XDispatchProvider
> xDispatchProvider( m_xFrame
, UNO_QUERY
);
435 if ( m_xContext
.is() && xDispatchProvider
.is() )
437 xStatusListener
= Reference
< XStatusListener
>( static_cast< OWeakObject
* >( this ), UNO_QUERY
);
438 URLToDispatchMap::iterator pIter
= m_aListenerMap
.begin();
439 while ( pIter
!= m_aListenerMap
.end() )
441 Reference
< XURLTransformer
> xURLTransformer
= getURLTransformer();
442 com::sun::star::util::URL aTargetURL
;
443 aTargetURL
.Complete
= pIter
->first
;
444 xURLTransformer
->parseStrict( aTargetURL
);
446 Reference
< XDispatch
> xDispatch( pIter
->second
);
447 if ( xDispatch
.is() )
449 // We already have a dispatch object => we have to requery.
450 // Release old dispatch object and remove it as listener
453 xDispatch
->removeStatusListener( xStatusListener
, aTargetURL
);
460 pIter
->second
.clear();
463 // Query for dispatch object. Old dispatch will be released with this, too.
466 xDispatch
= xDispatchProvider
->queryDispatch( aTargetURL
, OUString(), 0 );
471 pIter
->second
= xDispatch
;
473 Listener
aListener( aTargetURL
, xDispatch
);
474 aDispatchVector
.push_back( aListener
);
480 // Call without locked mutex as we are called back from dispatch implementation
481 if ( !xStatusListener
.is() )
484 for ( sal_uInt32 i
= 0; i
< aDispatchVector
.size(); i
++ )
488 Listener
& rListener
= aDispatchVector
[i
];
489 if ( rListener
.xDispatch
.is() )
490 rListener
.xDispatch
->addStatusListener( xStatusListener
, rListener
.aURL
);
491 else if ( rListener
.aURL
.Complete
== m_aCommandURL
)
493 // Send status changed for the main URL, if we cannot get a valid dispatch object.
494 // UI disables the button. Catch exception as we release our mutex, it is possible
495 // that someone else already disposed this instance!
496 FeatureStateEvent aFeatureStateEvent
;
497 aFeatureStateEvent
.IsEnabled
= sal_False
;
498 aFeatureStateEvent
.FeatureURL
= rListener
.aURL
;
499 aFeatureStateEvent
.State
= Any();
500 xStatusListener
->statusChanged( aFeatureStateEvent
);
507 ::Rectangle
StatusbarController::getControlRect() const
512 SolarMutexGuard aSolarMutexGuard
;
515 throw DisposedException();
517 if ( m_xParentWindow
.is() )
519 StatusBar
* pStatusBar
= dynamic_cast< StatusBar
* >( VCLUnoHelper::GetWindow( m_xParentWindow
));
520 if ( pStatusBar
&& pStatusBar
->GetType() == WINDOW_STATUSBAR
)
521 aRect
= pStatusBar
->GetItemRect( m_nID
);
528 void StatusbarController::execute( const ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>& aArgs
)
530 Reference
< XDispatch
> xDispatch
;
531 Reference
< XURLTransformer
> xURLTransformer
;
532 OUString aCommandURL
;
535 SolarMutexGuard aSolarMutexGuard
;
538 throw DisposedException();
540 if ( m_bInitialized
&&
543 !m_aCommandURL
.isEmpty() )
545 xURLTransformer
= getURLTransformer();
546 aCommandURL
= m_aCommandURL
;
547 URLToDispatchMap::iterator pIter
= m_aListenerMap
.find( m_aCommandURL
);
548 if ( pIter
!= m_aListenerMap
.end() )
549 xDispatch
= pIter
->second
;
553 if ( xDispatch
.is() && xURLTransformer
.is() )
557 com::sun::star::util::URL aTargetURL
;
559 aTargetURL
.Complete
= aCommandURL
;
560 xURLTransformer
->parseStrict( aTargetURL
);
561 xDispatch
->dispatch( aTargetURL
, aArgs
);
563 catch ( DisposedException
& )
569 void StatusbarController::execute(
570 const OUString
& aCommandURL
,
571 const Sequence
< ::com::sun::star::beans::PropertyValue
>& aArgs
)
573 Reference
< XDispatch
> xDispatch
;
574 com::sun::star::util::URL aTargetURL
;
577 SolarMutexGuard aSolarMutexGuard
;
580 throw DisposedException();
582 if ( m_bInitialized
&&
585 !m_aCommandURL
.isEmpty() )
587 Reference
< XURLTransformer
> xURLTransformer( getURLTransformer() );
588 aTargetURL
.Complete
= aCommandURL
;
589 xURLTransformer
->parseStrict( aTargetURL
);
591 URLToDispatchMap::iterator pIter
= m_aListenerMap
.find( aCommandURL
);
592 if ( pIter
!= m_aListenerMap
.end() )
593 xDispatch
= pIter
->second
;
596 Reference
< ::com::sun::star::frame::XDispatchProvider
> xDispatchProvider(
597 m_xFrame
->getController(), UNO_QUERY
);
598 if ( xDispatchProvider
.is() )
599 xDispatch
= xDispatchProvider
->queryDispatch( aTargetURL
, OUString(), 0 );
604 if ( xDispatch
.is() )
608 xDispatch
->dispatch( aTargetURL
, aArgs
);
610 catch ( DisposedException
& )
618 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */