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/frame/XDispatchProvider.hpp>
23 #include <com/sun/star/frame/XFrame.hpp>
24 #include <com/sun/star/lang/DisposedException.hpp>
25 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
26 #include <com/sun/star/util/URLTransformer.hpp>
27 #include <com/sun/star/ui/XStatusbarItem.hpp>
28 #include <cppuhelper/queryinterface.hxx>
30 #include <vcl/svapp.hxx>
31 #include <vcl/window.hxx>
32 #include <vcl/status.hxx>
33 #include <toolkit/helper/vclunohelper.hxx>
34 #include <comphelper/processfactory.hxx>
36 using namespace ::cppu
;
37 using namespace css::awt
;
38 using namespace css::uno
;
39 using namespace css::util
;
40 using namespace css::beans
;
41 using namespace css::lang
;
42 using namespace css::frame
;
47 StatusbarController::StatusbarController(
48 const Reference
< XComponentContext
>& rxContext
,
49 const Reference
< XFrame
>& xFrame
,
51 unsigned short nID
) :
53 , m_bInitialized( false )
54 , m_bDisposed( false )
57 , m_xContext( rxContext
)
58 , m_aCommandURL(std::move( aCommandURL
))
59 , m_aListenerContainer( m_aMutex
)
63 StatusbarController::StatusbarController() :
65 , m_bInitialized( false )
66 , m_bDisposed( 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_xContext
.is() )
87 m_xURLTransformer
= css::util::URLTransformer::create( m_xContext
);
90 return m_xURLTransformer
;
94 Any SAL_CALL
StatusbarController::queryInterface( const Type
& rType
)
96 Any a
= ::cppu::queryInterface(
98 static_cast< XStatusbarController
* >( this ),
99 static_cast< XStatusListener
* >( this ),
100 static_cast< XEventListener
* >( this ),
101 static_cast< XInitialization
* >( this ),
102 static_cast< XComponent
* >( this ),
103 static_cast< XUpdatable
* >( this ));
108 return OWeakObject::queryInterface( rType
);
111 void SAL_CALL
StatusbarController::acquire() noexcept
113 OWeakObject::acquire();
116 void SAL_CALL
StatusbarController::release() noexcept
118 OWeakObject::release();
121 void SAL_CALL
StatusbarController::initialize( const Sequence
< Any
>& aArguments
)
123 SolarMutexGuard aSolarMutexGuard
;
126 throw DisposedException();
128 if ( m_bInitialized
)
131 m_bInitialized
= true;
133 PropertyValue aPropValue
;
134 for ( const auto& rArgument
: aArguments
)
136 if ( rArgument
>>= aPropValue
)
138 if ( aPropValue
.Name
== "Frame" )
139 aPropValue
.Value
>>= m_xFrame
;
140 else if ( aPropValue
.Name
== "CommandURL" )
141 aPropValue
.Value
>>= m_aCommandURL
;
142 else if ( aPropValue
.Name
== "ServiceManager" )
144 Reference
<XMultiServiceFactory
> xMSF
;
145 aPropValue
.Value
>>= xMSF
;
147 m_xContext
= comphelper::getComponentContext(xMSF
);
149 else if ( aPropValue
.Name
== "ParentWindow" )
150 aPropValue
.Value
>>= m_xParentWindow
;
151 else if ( aPropValue
.Name
== "Identifier" )
152 aPropValue
.Value
>>= m_nID
;
153 else if ( aPropValue
.Name
== "StatusbarItem" )
154 aPropValue
.Value
>>= m_xStatusbarItem
;
158 if ( !m_aCommandURL
.isEmpty() )
159 m_aListenerMap
.emplace( m_aCommandURL
, Reference
< XDispatch
>() );
162 void SAL_CALL
StatusbarController::update()
165 SolarMutexGuard aSolarMutexGuard
;
167 throw DisposedException();
170 // Bind all registered listeners to their dispatch objects
175 void SAL_CALL
StatusbarController::dispose()
177 Reference
< XComponent
> xThis
= this;
180 SolarMutexGuard aSolarMutexGuard
;
185 css::lang::EventObject
aEvent( xThis
);
186 m_aListenerContainer
.disposeAndClear( aEvent
);
188 SolarMutexGuard aSolarMutexGuard
;
189 Reference
< XStatusListener
> xStatusListener
= this;
190 Reference
< XURLTransformer
> xURLTransformer
= getURLTransformer();
191 css::util::URL aTargetURL
;
192 for (auto const& listener
: m_aListenerMap
)
196 Reference
< XDispatch
> xDispatch(listener
.second
);
197 aTargetURL
.Complete
= listener
.first
;
198 xURLTransformer
->parseStrict( aTargetURL
);
200 if ( xDispatch
.is() && xStatusListener
.is() )
201 xDispatch
->removeStatusListener( xStatusListener
, aTargetURL
);
209 m_aListenerMap
.clear();
211 // release references
212 m_xURLTransformer
.clear();
215 m_xParentWindow
.clear();
216 m_xStatusbarItem
.clear();
221 void SAL_CALL
StatusbarController::addEventListener( const Reference
< XEventListener
>& xListener
)
223 m_aListenerContainer
.addInterface( cppu::UnoType
<XEventListener
>::get(), xListener
);
226 void SAL_CALL
StatusbarController::removeEventListener( const Reference
< XEventListener
>& aListener
)
228 m_aListenerContainer
.removeInterface( cppu::UnoType
<XEventListener
>::get(), aListener
);
232 void SAL_CALL
StatusbarController::disposing( const EventObject
& Source
)
234 SolarMutexGuard aSolarMutexGuard
;
239 Reference
< XFrame
> xFrame( Source
.Source
, UNO_QUERY
);
242 if ( xFrame
== m_xFrame
)
247 Reference
< XDispatch
> xDispatch( Source
.Source
, UNO_QUERY
);
248 if ( !xDispatch
.is() )
251 for (auto & listener
: m_aListenerMap
)
253 // Compare references and release dispatch references if they are equal.
254 if ( xDispatch
== listener
.second
)
255 listener
.second
.clear();
260 void SAL_CALL
StatusbarController::statusChanged( const FeatureStateEvent
& Event
)
262 SolarMutexGuard aSolarMutexGuard
;
267 VclPtr
<vcl::Window
> pWindow
= VCLUnoHelper::GetWindow( m_xParentWindow
);
268 if ( pWindow
&& pWindow
->GetType() == WindowType::STATUSBAR
&& m_nID
!= 0 )
271 StatusBar
* pStatusBar
= static_cast<StatusBar
*>(pWindow
.get());
273 if ( Event
.State
>>= aStrValue
)
274 pStatusBar
->SetItemText( m_nID
, aStrValue
);
275 else if ( !Event
.State
.hasValue() )
276 pStatusBar
->SetItemText( m_nID
, "" );
280 // XStatusbarController
281 sal_Bool SAL_CALL
StatusbarController::mouseButtonDown(
282 const css::awt::MouseEvent
& )
287 sal_Bool SAL_CALL
StatusbarController::mouseMove(
288 const css::awt::MouseEvent
& )
293 sal_Bool SAL_CALL
StatusbarController::mouseButtonUp(
294 const css::awt::MouseEvent
& )
299 void SAL_CALL
StatusbarController::command(
300 const css::awt::Point
&,
303 const css::uno::Any
& )
307 void SAL_CALL
StatusbarController::paint(
308 const css::uno::Reference
< css::awt::XGraphics
>&,
309 const css::awt::Rectangle
&,
314 void SAL_CALL
StatusbarController::click( const css::awt::Point
& )
318 void SAL_CALL
StatusbarController::doubleClick( const css::awt::Point
& )
320 SolarMutexGuard aSolarMutexGuard
;
325 Sequence
< PropertyValue
> aArgs
;
329 void StatusbarController::addStatusListener( const OUString
& aCommandURL
)
331 Reference
< XDispatch
> xDispatch
;
332 Reference
< XStatusListener
> xStatusListener
;
333 css::util::URL aTargetURL
;
336 SolarMutexGuard aSolarMutexGuard
;
337 URLToDispatchMap::iterator pIter
= m_aListenerMap
.find( aCommandURL
);
339 // Already in the list of status listener. Do nothing.
340 if ( pIter
!= m_aListenerMap
.end() )
343 // Check if we are already initialized. Implementation starts adding itself as status listener when
344 // initialize is called.
345 if ( !m_bInitialized
)
347 // Put into the unordered_map of status listener. Will be activated when initialized is called
348 m_aListenerMap
.emplace( aCommandURL
, Reference
< XDispatch
>() );
353 // Add status listener directly as initialize has already been called.
354 Reference
< XDispatchProvider
> xDispatchProvider( m_xFrame
, UNO_QUERY
);
355 if ( m_xContext
.is() && xDispatchProvider
.is() )
357 Reference
< XURLTransformer
> xURLTransformer
= getURLTransformer();
358 aTargetURL
.Complete
= aCommandURL
;
359 xURLTransformer
->parseStrict( aTargetURL
);
360 xDispatch
= xDispatchProvider
->queryDispatch( aTargetURL
, OUString(), 0 );
362 xStatusListener
= this;
363 URLToDispatchMap::iterator aIter
= m_aListenerMap
.find( aCommandURL
);
364 if ( aIter
!= m_aListenerMap
.end() )
366 Reference
< XDispatch
> xOldDispatch( aIter
->second
);
367 aIter
->second
= xDispatch
;
371 if ( xOldDispatch
.is() )
372 xOldDispatch
->removeStatusListener( xStatusListener
, aTargetURL
);
379 m_aListenerMap
.emplace( aCommandURL
, xDispatch
);
384 // Call without locked mutex as we are called back from dispatch implementation
387 if ( xDispatch
.is() )
388 xDispatch
->addStatusListener( xStatusListener
, aTargetURL
);
395 void StatusbarController::bindListener()
397 std::vector
< Listener
> aDispatchVector
;
398 Reference
< XStatusListener
> xStatusListener
;
401 SolarMutexGuard aSolarMutexGuard
;
403 if ( !m_bInitialized
)
406 // Collect all registered command URL's and store them temporary
407 Reference
< XDispatchProvider
> xDispatchProvider( m_xFrame
, UNO_QUERY
);
408 if ( m_xContext
.is() && xDispatchProvider
.is() )
410 xStatusListener
= this;
411 for (auto & listener
: m_aListenerMap
)
413 Reference
< XURLTransformer
> xURLTransformer
= getURLTransformer();
414 css::util::URL aTargetURL
;
415 aTargetURL
.Complete
= listener
.first
;
416 xURLTransformer
->parseStrict( aTargetURL
);
418 Reference
< XDispatch
> xDispatch(listener
.second
);
419 if ( xDispatch
.is() )
421 // We already have a dispatch object => we have to requery.
422 // Release old dispatch object and remove it as listener
425 xDispatch
->removeStatusListener( xStatusListener
, aTargetURL
);
432 listener
.second
.clear();
435 // Query for dispatch object. Old dispatch will be released with this, too.
438 xDispatch
= xDispatchProvider
->queryDispatch( aTargetURL
, OUString(), 0 );
443 listener
.second
= xDispatch
;
445 aDispatchVector
.push_back( Listener( std::move(aTargetURL
), xDispatch
) );
450 // Call without locked mutex as we are called back from dispatch implementation
451 if ( !xStatusListener
.is() )
454 for (Listener
& rListener
: aDispatchVector
)
458 if ( rListener
.xDispatch
.is() )
459 rListener
.xDispatch
->addStatusListener( xStatusListener
, rListener
.aURL
);
460 else if ( rListener
.aURL
.Complete
== m_aCommandURL
)
462 // Send status changed for the main URL, if we cannot get a valid dispatch object.
463 // UI disables the button. Catch exception as we release our mutex, it is possible
464 // that someone else already disposed this instance!
465 FeatureStateEvent aFeatureStateEvent
;
466 aFeatureStateEvent
.IsEnabled
= false;
467 aFeatureStateEvent
.FeatureURL
= rListener
.aURL
;
468 aFeatureStateEvent
.State
= Any();
469 xStatusListener
->statusChanged( aFeatureStateEvent
);
476 ::tools::Rectangle
StatusbarController::getControlRect() const
478 ::tools::Rectangle aRect
;
481 SolarMutexGuard aSolarMutexGuard
;
484 throw DisposedException();
486 if ( m_xParentWindow
.is() )
488 VclPtr
< StatusBar
> pStatusBar
= dynamic_cast< StatusBar
* >( VCLUnoHelper::GetWindow( m_xParentWindow
) );
489 if ( pStatusBar
&& pStatusBar
->GetType() == WindowType::STATUSBAR
)
490 aRect
= pStatusBar
->GetItemRect( m_nID
);
497 void StatusbarController::execute( const css::uno::Sequence
< css::beans::PropertyValue
>& aArgs
)
499 Reference
< XDispatch
> xDispatch
;
500 Reference
< XURLTransformer
> xURLTransformer
;
501 OUString aCommandURL
;
504 SolarMutexGuard aSolarMutexGuard
;
507 throw DisposedException();
509 if ( m_bInitialized
&&
512 !m_aCommandURL
.isEmpty() )
514 xURLTransformer
= getURLTransformer();
515 aCommandURL
= m_aCommandURL
;
516 URLToDispatchMap::iterator pIter
= m_aListenerMap
.find( m_aCommandURL
);
517 if ( pIter
!= m_aListenerMap
.end() )
518 xDispatch
= pIter
->second
;
522 if ( !(xDispatch
.is() && xURLTransformer
.is()) )
527 css::util::URL aTargetURL
;
529 aTargetURL
.Complete
= aCommandURL
;
530 xURLTransformer
->parseStrict( aTargetURL
);
531 xDispatch
->dispatch( aTargetURL
, aArgs
);
533 catch ( DisposedException
& )
538 void StatusbarController::execute(
539 const OUString
& aCommandURL
,
540 const Sequence
< css::beans::PropertyValue
>& aArgs
)
542 Reference
< XDispatch
> xDispatch
;
543 css::util::URL aTargetURL
;
546 SolarMutexGuard aSolarMutexGuard
;
549 throw DisposedException();
551 if ( m_bInitialized
&&
554 !m_aCommandURL
.isEmpty() )
556 Reference
< XURLTransformer
> xURLTransformer( getURLTransformer() );
557 aTargetURL
.Complete
= aCommandURL
;
558 xURLTransformer
->parseStrict( aTargetURL
);
560 URLToDispatchMap::iterator pIter
= m_aListenerMap
.find( aCommandURL
);
561 if ( pIter
!= m_aListenerMap
.end() )
562 xDispatch
= pIter
->second
;
565 Reference
< css::frame::XDispatchProvider
> xDispatchProvider(
566 m_xFrame
->getController(), UNO_QUERY
);
567 if ( xDispatchProvider
.is() )
568 xDispatch
= xDispatchProvider
->queryDispatch( aTargetURL
, OUString(), 0 );
573 if ( xDispatch
.is() )
577 xDispatch
->dispatch( aTargetURL
, aArgs
);
579 catch ( DisposedException
& )
587 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */