LibreOffice Module svtools (master) 1
statusbarcontroller.cxx
Go to the documentation of this file.
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
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>
29#include <utility>
30#include <vcl/svapp.hxx>
31#include <vcl/window.hxx>
32#include <vcl/status.hxx>
35
36using namespace ::cppu;
37using namespace css::awt;
38using namespace css::uno;
39using namespace css::util;
40using namespace css::beans;
41using namespace css::lang;
42using namespace css::frame;
43
44namespace svt
45{
46
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 )
60{
61}
62
63StatusbarController::StatusbarController() :
64 OWeakObject()
65 , m_bInitialized( false )
66 , m_bDisposed( false )
67 , m_nID( 0 )
68 , m_aListenerContainer( m_aMutex )
69{
70}
71
73{
74}
75
77{
78 SolarMutexGuard aSolarMutexGuard;
79 return m_xFrame;
80}
81
83{
84 SolarMutexGuard aSolarMutexGuard;
85 if ( !m_xURLTransformer.is() && m_xContext.is() )
86 {
87 m_xURLTransformer = css::util::URLTransformer::create( m_xContext );
88 }
89
90 return m_xURLTransformer;
91}
92
93// XInterface
95{
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 ));
104
105 if ( a.hasValue() )
106 return a;
107
108 return OWeakObject::queryInterface( rType );
109}
110
111void SAL_CALL StatusbarController::acquire() noexcept
112{
113 OWeakObject::acquire();
114}
115
116void SAL_CALL StatusbarController::release() noexcept
117{
118 OWeakObject::release();
119}
120
121void SAL_CALL StatusbarController::initialize( const Sequence< Any >& aArguments )
122{
123 SolarMutexGuard aSolarMutexGuard;
124
125 if ( m_bDisposed )
126 throw DisposedException();
127
128 if ( m_bInitialized )
129 return;
130
131 m_bInitialized = true;
132
133 PropertyValue aPropValue;
134 for ( const auto& rArgument : aArguments )
135 {
136 if ( rArgument >>= aPropValue )
137 {
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" )
143 {
145 aPropValue.Value >>= xMSF;
146 if( xMSF.is() )
148 }
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;
155 }
156 }
157
158 if ( !m_aCommandURL.isEmpty() )
160}
161
163{
164 {
165 SolarMutexGuard aSolarMutexGuard;
166 if ( m_bDisposed )
167 throw DisposedException();
168 }
169
170 // Bind all registered listeners to their dispatch objects
171 bindListener();
172}
173
174// XComponent
176{
177 Reference< XComponent > xThis = this;
178
179 {
180 SolarMutexGuard aSolarMutexGuard;
181 if ( m_bDisposed )
182 return;
183 }
184
185 css::lang::EventObject aEvent( xThis );
187
188 SolarMutexGuard aSolarMutexGuard;
189 Reference< XStatusListener > xStatusListener = this;
191 css::util::URL aTargetURL;
192 for (auto const& listener : m_aListenerMap)
193 {
194 try
195 {
196 Reference< XDispatch > xDispatch(listener.second);
197 aTargetURL.Complete = listener.first;
198 xURLTransformer->parseStrict( aTargetURL );
199
200 if ( xDispatch.is() && xStatusListener.is() )
201 xDispatch->removeStatusListener( xStatusListener, aTargetURL );
202 }
203 catch ( Exception& )
204 {
205 }
206 }
207
208 // clear hash map
209 m_aListenerMap.clear();
210
211 // release references
212 m_xURLTransformer.clear();
213 m_xContext.clear();
214 m_xFrame.clear();
215 m_xParentWindow.clear();
216 m_xStatusbarItem.clear();
217
218 m_bDisposed = true;
219}
220
222{
224}
225
227{
229}
230
231// XEventListener
232void SAL_CALL StatusbarController::disposing( const EventObject& Source )
233{
234 SolarMutexGuard aSolarMutexGuard;
235
236 if ( m_bDisposed )
237 return;
238
239 Reference< XFrame > xFrame( Source.Source, UNO_QUERY );
240 if ( xFrame.is() )
241 {
242 if ( xFrame == m_xFrame )
243 m_xFrame.clear();
244 return;
245 }
246
247 Reference< XDispatch > xDispatch( Source.Source, UNO_QUERY );
248 if ( !xDispatch.is() )
249 return;
250
251 for (auto & listener : m_aListenerMap)
252 {
253 // Compare references and release dispatch references if they are equal.
254 if ( xDispatch == listener.second )
255 listener.second.clear();
256 }
257}
258
259// XStatusListener
260void SAL_CALL StatusbarController::statusChanged( const FeatureStateEvent& Event )
261{
262 SolarMutexGuard aSolarMutexGuard;
263
264 if ( m_bDisposed )
265 return;
266
268 if ( pWindow && pWindow->GetType() == WindowType::STATUSBAR && m_nID != 0 )
269 {
270 OUString aStrValue;
271 StatusBar* pStatusBar = static_cast<StatusBar *>(pWindow.get());
272
273 if ( Event.State >>= aStrValue )
274 pStatusBar->SetItemText( m_nID, aStrValue );
275 else if ( !Event.State.hasValue() )
276 pStatusBar->SetItemText( m_nID, "" );
277 }
278}
279
280// XStatusbarController
282 const css::awt::MouseEvent& )
283{
284 return false;
285}
286
288 const css::awt::MouseEvent& )
289{
290 return false;
291}
292
294 const css::awt::MouseEvent& )
295{
296 return false;
297}
298
300 const css::awt::Point&,
301 ::sal_Int32,
302 sal_Bool,
303 const css::uno::Any& )
304{
305}
306
308 const css::uno::Reference< css::awt::XGraphics >&,
309 const css::awt::Rectangle&,
310 ::sal_Int32 )
311{
312}
313
314void SAL_CALL StatusbarController::click( const css::awt::Point& )
315{
316}
317
318void SAL_CALL StatusbarController::doubleClick( const css::awt::Point& )
319{
320 SolarMutexGuard aSolarMutexGuard;
321
322 if ( m_bDisposed )
323 return;
324
326 execute( aArgs );
327}
328
329void StatusbarController::addStatusListener( const OUString& aCommandURL )
330{
332 Reference< XStatusListener > xStatusListener;
333 css::util::URL aTargetURL;
334
335 {
336 SolarMutexGuard aSolarMutexGuard;
337 URLToDispatchMap::iterator pIter = m_aListenerMap.find( aCommandURL );
338
339 // Already in the list of status listener. Do nothing.
340 if ( pIter != m_aListenerMap.end() )
341 return;
342
343 // Check if we are already initialized. Implementation starts adding itself as status listener when
344 // initialize is called.
345 if ( !m_bInitialized )
346 {
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;
350 }
351 else
352 {
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() )
356 {
358 aTargetURL.Complete = aCommandURL;
359 xURLTransformer->parseStrict( aTargetURL );
360 xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
361
362 xStatusListener = this;
363 URLToDispatchMap::iterator aIter = m_aListenerMap.find( aCommandURL );
364 if ( aIter != m_aListenerMap.end() )
365 {
366 Reference< XDispatch > xOldDispatch( aIter->second );
367 aIter->second = xDispatch;
368
369 try
370 {
371 if ( xOldDispatch.is() )
372 xOldDispatch->removeStatusListener( xStatusListener, aTargetURL );
373 }
374 catch ( Exception& )
375 {
376 }
377 }
378 else
379 m_aListenerMap.emplace( aCommandURL, xDispatch );
380 }
381 }
382 }
383
384 // Call without locked mutex as we are called back from dispatch implementation
385 try
386 {
387 if ( xDispatch.is() )
388 xDispatch->addStatusListener( xStatusListener, aTargetURL );
389 }
390 catch ( Exception& )
391 {
392 }
393}
394
396{
397 std::vector< Listener > aDispatchVector;
398 Reference< XStatusListener > xStatusListener;
399
400 {
401 SolarMutexGuard aSolarMutexGuard;
402
403 if ( !m_bInitialized )
404 return;
405
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() )
409 {
410 xStatusListener = this;
411 for (auto & listener : m_aListenerMap)
412 {
414 css::util::URL aTargetURL;
415 aTargetURL.Complete = listener.first;
416 xURLTransformer->parseStrict( aTargetURL );
417
418 Reference< XDispatch > xDispatch(listener.second);
419 if ( xDispatch.is() )
420 {
421 // We already have a dispatch object => we have to requery.
422 // Release old dispatch object and remove it as listener
423 try
424 {
425 xDispatch->removeStatusListener( xStatusListener, aTargetURL );
426 }
427 catch ( Exception& )
428 {
429 }
430 }
431
432 listener.second.clear();
433 xDispatch.clear();
434
435 // Query for dispatch object. Old dispatch will be released with this, too.
436 try
437 {
438 xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
439 }
440 catch ( Exception& )
441 {
442 }
443 listener.second = xDispatch;
444
445 aDispatchVector.push_back( Listener( std::move(aTargetURL), xDispatch ) );
446 }
447 }
448 }
449
450 // Call without locked mutex as we are called back from dispatch implementation
451 if ( !xStatusListener.is() )
452 return;
453
454 for (Listener & rListener : aDispatchVector)
455 {
456 try
457 {
458 if ( rListener.xDispatch.is() )
459 rListener.xDispatch->addStatusListener( xStatusListener, rListener.aURL );
460 else if ( rListener.aURL.Complete == m_aCommandURL )
461 {
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 );
470 }
471 }
472 catch ( ... ){}
473 }
474}
475
477{
478 ::tools::Rectangle aRect;
479
480 {
481 SolarMutexGuard aSolarMutexGuard;
482
483 if ( m_bDisposed )
484 throw DisposedException();
485
486 if ( m_xParentWindow.is() )
487 {
488 VclPtr< StatusBar > pStatusBar = dynamic_cast< StatusBar* >( VCLUnoHelper::GetWindow( m_xParentWindow ) );
489 if ( pStatusBar && pStatusBar->GetType() == WindowType::STATUSBAR )
490 aRect = pStatusBar->GetItemRect( m_nID );
491 }
492 }
493
494 return aRect;
495}
496
497void StatusbarController::execute( const css::uno::Sequence< css::beans::PropertyValue >& aArgs )
498{
500 Reference< XURLTransformer > xURLTransformer;
501 OUString aCommandURL;
502
503 {
504 SolarMutexGuard aSolarMutexGuard;
505
506 if ( m_bDisposed )
507 throw DisposedException();
508
509 if ( m_bInitialized &&
510 m_xFrame.is() &&
511 m_xContext.is() &&
512 !m_aCommandURL.isEmpty() )
513 {
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;
519 }
520 }
521
522 if ( !(xDispatch.is() && xURLTransformer.is()) )
523 return;
524
525 try
526 {
527 css::util::URL aTargetURL;
528
529 aTargetURL.Complete = aCommandURL;
530 xURLTransformer->parseStrict( aTargetURL );
531 xDispatch->dispatch( aTargetURL, aArgs );
532 }
533 catch ( DisposedException& )
534 {
535 }
536}
537
539 const OUString& aCommandURL,
541{
543 css::util::URL aTargetURL;
544
545 {
546 SolarMutexGuard aSolarMutexGuard;
547
548 if ( m_bDisposed )
549 throw DisposedException();
550
551 if ( m_bInitialized &&
552 m_xFrame.is() &&
553 m_xContext.is() &&
554 !m_aCommandURL.isEmpty() )
555 {
557 aTargetURL.Complete = aCommandURL;
558 xURLTransformer->parseStrict( aTargetURL );
559
560 URLToDispatchMap::iterator pIter = m_aListenerMap.find( aCommandURL );
561 if ( pIter != m_aListenerMap.end() )
562 xDispatch = pIter->second;
563 else
564 {
566 m_xFrame->getController(), UNO_QUERY );
567 if ( xDispatchProvider.is() )
568 xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
569 }
570 }
571 }
572
573 if ( xDispatch.is() )
574 {
575 try
576 {
577 xDispatch->dispatch( aTargetURL, aArgs );
578 }
579 catch ( DisposedException& )
580 {
581 }
582 }
583}
584
585} // svt
586
587/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XComponentContext > m_xContext
css::uno::Reference< css::lang::XComponent > m_xFrame
AnyEventRef aEvent
void SetItemText(sal_uInt16 nItemId, const OUString &rText, int nCharsWidth=-1)
static vcl::Window * GetWindow(const css::uno::Reference< css::awt::XWindow > &rxWindow)
reference_type * get() const
sal_Int32 removeInterface(const css::uno::Type &rKey, const css::uno::Reference< css::uno::XInterface > &rxIFace)
sal_Int32 addInterface(const css::uno::Type &rKey, const css::uno::Reference< css::uno::XInterface > &r)
void disposeAndClear(const css::lang::EventObject &rEvt)
virtual void SAL_CALL removeEventListener(const css::uno::Reference< css::lang::XEventListener > &aListener) override
::tools::Rectangle getControlRect() const
virtual void SAL_CALL command(const css::awt::Point &aPos, ::sal_Int32 nCommand, sal_Bool bMouseEvent, const css::uno::Any &aData) override
virtual void SAL_CALL release() noexcept override
css::uno::Reference< css::awt::XWindow > m_xParentWindow
virtual ~StatusbarController() override
css::uno::Reference< css::frame::XFrame > m_xFrame
virtual void SAL_CALL paint(const css::uno::Reference< css::awt::XGraphics > &xGraphics, const css::awt::Rectangle &rOutputRectangle, ::sal_Int32 nStyle) override
virtual void SAL_CALL disposing(const css::lang::EventObject &Source) override
virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent &Event) override
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &aType) override
void addStatusListener(const OUString &aCommandURL)
css::uno::Reference< css::uno::XComponentContext > m_xContext
virtual void SAL_CALL addEventListener(const css::uno::Reference< css::lang::XEventListener > &xListener) override
css::uno::Reference< css::util::XURLTransformer > m_xURLTransformer
container for ALL Listener
css::uno::Reference< css::ui::XStatusbarItem > m_xStatusbarItem
virtual void SAL_CALL click(const css::awt::Point &aPos) override
css::uno::Reference< css::util::XURLTransformer > getURLTransformer() const
virtual void SAL_CALL initialize(const css::uno::Sequence< css::uno::Any > &aArguments) override
comphelper::OMultiTypeInterfaceContainerHelper2 m_aListenerContainer
virtual sal_Bool SAL_CALL mouseButtonUp(const css::awt::MouseEvent &aMouseEvent) override
virtual sal_Bool SAL_CALL mouseButtonDown(const css::awt::MouseEvent &aMouseEvent) override
virtual void SAL_CALL update() override
virtual void SAL_CALL doubleClick(const css::awt::Point &aPos) override
virtual void SAL_CALL acquire() noexcept override
void execute(const css::uno::Sequence< css::beans::PropertyValue > &aArgs)
virtual sal_Bool SAL_CALL mouseMove(const css::awt::MouseEvent &aMouseEvent) override
css::uno::Reference< css::frame::XFrame > getFrameInterface() const
virtual void SAL_CALL dispose() override
Reference< XDispatch > xDispatch
bool m_bDisposed
std::mutex m_aMutex
Sequence< PropertyValue > aArguments
uno_Any a
@ Exception
Reference< XComponentContext > getComponentContext(Reference< XMultiServiceFactory > const &factory)
Type
Reference< XFrame > xFrame
unsigned char sal_Bool
OUString aTargetURL