Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / svtools / source / uno / statusbarcontroller.cxx
blob7ab3a2e29c40dc42d586f5f788e3e1fe82ed6d36
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
29 #include <utility>
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;
44 namespace svt
47 StatusbarController::StatusbarController(
48 const Reference< XComponentContext >& rxContext,
49 const Reference< XFrame >& xFrame,
50 OUString aCommandURL,
51 unsigned short nID ) :
52 OWeakObject()
53 , m_bInitialized( false )
54 , m_bDisposed( false )
55 , m_nID( nID )
56 , m_xFrame( xFrame )
57 , m_xContext( rxContext )
58 , m_aCommandURL(std::move( aCommandURL ))
59 , m_aListenerContainer( m_aMutex )
63 StatusbarController::StatusbarController() :
64 OWeakObject()
65 , m_bInitialized( false )
66 , m_bDisposed( false )
67 , m_nID( 0 )
68 , m_aListenerContainer( m_aMutex )
72 StatusbarController::~StatusbarController()
76 Reference< XFrame > StatusbarController::getFrameInterface() const
78 SolarMutexGuard aSolarMutexGuard;
79 return m_xFrame;
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;
93 // XInterface
94 Any SAL_CALL StatusbarController::queryInterface( const Type& rType )
96 Any a = ::cppu::queryInterface(
97 rType ,
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 ));
105 if ( a.hasValue() )
106 return a;
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;
125 if ( m_bDisposed )
126 throw DisposedException();
128 if ( m_bInitialized )
129 return;
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;
146 if( xMSF.is() )
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;
166 if ( m_bDisposed )
167 throw DisposedException();
170 // Bind all registered listeners to their dispatch objects
171 bindListener();
174 // XComponent
175 void SAL_CALL StatusbarController::dispose()
177 Reference< XComponent > xThis = this;
180 SolarMutexGuard aSolarMutexGuard;
181 if ( m_bDisposed )
182 return;
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 );
203 catch ( Exception& )
208 // clear hash map
209 m_aListenerMap.clear();
211 // release references
212 m_xURLTransformer.clear();
213 m_xContext.clear();
214 m_xFrame.clear();
215 m_xParentWindow.clear();
216 m_xStatusbarItem.clear();
218 m_bDisposed = true;
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 );
231 // XEventListener
232 void SAL_CALL StatusbarController::disposing( const EventObject& Source )
234 SolarMutexGuard aSolarMutexGuard;
236 if ( m_bDisposed )
237 return;
239 Reference< XFrame > xFrame( Source.Source, UNO_QUERY );
240 if ( xFrame.is() )
242 if ( xFrame == m_xFrame )
243 m_xFrame.clear();
244 return;
247 Reference< XDispatch > xDispatch( Source.Source, UNO_QUERY );
248 if ( !xDispatch.is() )
249 return;
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();
259 // XStatusListener
260 void SAL_CALL StatusbarController::statusChanged( const FeatureStateEvent& Event )
262 SolarMutexGuard aSolarMutexGuard;
264 if ( m_bDisposed )
265 return;
267 VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( m_xParentWindow );
268 if ( pWindow && pWindow->GetType() == WindowType::STATUSBAR && m_nID != 0 )
270 OUString aStrValue;
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& )
284 return false;
287 sal_Bool SAL_CALL StatusbarController::mouseMove(
288 const css::awt::MouseEvent& )
290 return false;
293 sal_Bool SAL_CALL StatusbarController::mouseButtonUp(
294 const css::awt::MouseEvent& )
296 return false;
299 void SAL_CALL StatusbarController::command(
300 const css::awt::Point&,
301 ::sal_Int32,
302 sal_Bool,
303 const css::uno::Any& )
307 void SAL_CALL StatusbarController::paint(
308 const css::uno::Reference< css::awt::XGraphics >&,
309 const css::awt::Rectangle&,
310 ::sal_Int32 )
314 void SAL_CALL StatusbarController::click( const css::awt::Point& )
318 void SAL_CALL StatusbarController::doubleClick( const css::awt::Point& )
320 SolarMutexGuard aSolarMutexGuard;
322 if ( m_bDisposed )
323 return;
325 Sequence< PropertyValue > aArgs;
326 execute( 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() )
341 return;
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 >() );
349 return;
351 else
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 );
374 catch ( Exception& )
378 else
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 );
390 catch ( Exception& )
395 void StatusbarController::bindListener()
397 std::vector< Listener > aDispatchVector;
398 Reference< XStatusListener > xStatusListener;
401 SolarMutexGuard aSolarMutexGuard;
403 if ( !m_bInitialized )
404 return;
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 );
427 catch ( Exception& )
432 listener.second.clear();
433 xDispatch.clear();
435 // Query for dispatch object. Old dispatch will be released with this, too.
438 xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
440 catch ( Exception& )
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() )
452 return;
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 );
472 catch ( ... ){}
476 ::tools::Rectangle StatusbarController::getControlRect() const
478 ::tools::Rectangle aRect;
481 SolarMutexGuard aSolarMutexGuard;
483 if ( m_bDisposed )
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 );
494 return aRect;
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;
506 if ( m_bDisposed )
507 throw DisposedException();
509 if ( m_bInitialized &&
510 m_xFrame.is() &&
511 m_xContext.is() &&
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()) )
523 return;
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;
548 if ( m_bDisposed )
549 throw DisposedException();
551 if ( m_bInitialized &&
552 m_xFrame.is() &&
553 m_xContext.is() &&
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;
563 else
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& )
585 } // svt
587 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */