Line data Source code
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 :
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 <cppuhelper/queryinterface.hxx>
29 : #include <osl/mutex.hxx>
30 : #include <vcl/svapp.hxx>
31 : #include <vcl/window.hxx>
32 : #include <vcl/status.hxx>
33 : #include <svtools/imgdef.hxx>
34 : #include <svtools/miscopt.hxx>
35 : #include <toolkit/helper/vclunohelper.hxx>
36 : #include <comphelper/processfactory.hxx>
37 :
38 : using namespace ::cppu;
39 : using namespace ::com::sun::star::awt;
40 : using namespace ::com::sun::star::uno;
41 : using namespace ::com::sun::star::util;
42 : using namespace ::com::sun::star::beans;
43 : using namespace ::com::sun::star::lang;
44 : using namespace ::com::sun::star::frame;
45 :
46 : namespace svt
47 : {
48 :
49 1013 : StatusbarController::StatusbarController(
50 : const Reference< XComponentContext >& rxContext,
51 : const Reference< XFrame >& xFrame,
52 : const OUString& aCommandURL,
53 : unsigned short nID ) :
54 : OWeakObject()
55 : , m_bInitialized( false )
56 : , m_bDisposed( false )
57 : , m_nID( nID )
58 : , m_xFrame( xFrame )
59 : , m_xContext( rxContext )
60 : , m_aCommandURL( aCommandURL )
61 1013 : , m_aListenerContainer( m_aMutex )
62 : {
63 1013 : }
64 :
65 5445 : StatusbarController::StatusbarController() :
66 : OWeakObject()
67 : , m_bInitialized( false )
68 : , m_bDisposed( false )
69 : , m_nID( 0 )
70 5445 : , m_aListenerContainer( m_aMutex )
71 : {
72 5445 : }
73 :
74 7125 : StatusbarController::~StatusbarController()
75 : {
76 7125 : }
77 :
78 972 : Reference< XFrame > StatusbarController::getFrameInterface() const
79 : {
80 972 : SolarMutexGuard aSolarMutexGuard;
81 972 : return m_xFrame;
82 : }
83 :
84 14629 : Reference< XURLTransformer > StatusbarController::getURLTransformer() const
85 : {
86 14629 : SolarMutexGuard aSolarMutexGuard;
87 14629 : if ( !m_xURLTransformer.is() && m_xContext.is() )
88 : {
89 6458 : m_xURLTransformer = com::sun::star::util::URLTransformer::create( m_xContext );
90 : }
91 :
92 14629 : return m_xURLTransformer;
93 : }
94 :
95 : // XInterface
96 27792 : Any SAL_CALL StatusbarController::queryInterface( const Type& rType )
97 : throw ( RuntimeException, std::exception )
98 : {
99 : Any a = ::cppu::queryInterface(
100 : rType ,
101 : static_cast< XStatusbarController* >( this ),
102 : static_cast< XStatusListener* >( this ),
103 : static_cast< XEventListener* >( this ),
104 : static_cast< XInitialization* >( this ),
105 : static_cast< XComponent* >( this ),
106 27792 : static_cast< XUpdatable* >( this ));
107 :
108 27792 : if ( a.hasValue() )
109 27784 : return a;
110 :
111 8 : return OWeakObject::queryInterface( rType );
112 : }
113 :
114 20933 : void SAL_CALL StatusbarController::acquire() throw ()
115 : {
116 20933 : OWeakObject::acquire();
117 20933 : }
118 :
119 20933 : void SAL_CALL StatusbarController::release() throw ()
120 : {
121 20933 : OWeakObject::release();
122 20933 : }
123 :
124 6458 : void SAL_CALL StatusbarController::initialize( const Sequence< Any >& aArguments )
125 : throw ( Exception, RuntimeException, std::exception )
126 : {
127 6458 : bool bInitialized( true );
128 :
129 : {
130 6458 : SolarMutexGuard aSolarMutexGuard;
131 :
132 6458 : if ( m_bDisposed )
133 0 : throw DisposedException();
134 :
135 6458 : bInitialized = m_bInitialized;
136 : }
137 :
138 6458 : if ( !bInitialized )
139 : {
140 6458 : SolarMutexGuard aSolarMutexGuard;
141 6458 : m_bInitialized = true;
142 :
143 12916 : PropertyValue aPropValue;
144 52010 : for ( int i = 0; i < aArguments.getLength(); i++ )
145 : {
146 45552 : if ( aArguments[i] >>= aPropValue )
147 : {
148 45552 : if ( aPropValue.Name == "Frame" )
149 6458 : aPropValue.Value >>= m_xFrame;
150 39094 : else if ( aPropValue.Name == "CommandURL" )
151 6804 : aPropValue.Value >>= m_aCommandURL;
152 32290 : else if ( aPropValue.Name == "ServiceManager" )
153 : {
154 6458 : Reference<XMultiServiceFactory> xMSF;
155 6458 : aPropValue.Value >>= xMSF;
156 6458 : if( xMSF.is() )
157 6458 : m_xContext = comphelper::getComponentContext(xMSF);
158 : }
159 25832 : else if ( aPropValue.Name == "ParentWindow" )
160 6458 : aPropValue.Value >>= m_xParentWindow;
161 19374 : else if ( aPropValue.Name == "Identifier" )
162 6458 : aPropValue.Value >>= m_nID;
163 12916 : else if ( aPropValue.Name == "StatusbarItem" )
164 6458 : aPropValue.Value >>= m_xStatusbarItem;
165 : }
166 : }
167 :
168 6458 : if ( !m_aCommandURL.isEmpty() )
169 12916 : m_aListenerMap.insert( URLToDispatchMap::value_type( m_aCommandURL, Reference< XDispatch >() ));
170 : }
171 6458 : }
172 :
173 6458 : void SAL_CALL StatusbarController::update()
174 : throw ( RuntimeException, std::exception )
175 : {
176 : {
177 6458 : SolarMutexGuard aSolarMutexGuard;
178 6458 : if ( m_bDisposed )
179 0 : throw DisposedException();
180 : }
181 :
182 : // Bind all registered listeners to their dispatch objects
183 6458 : bindListener();
184 6458 : }
185 :
186 : // XComponent
187 6458 : void SAL_CALL StatusbarController::dispose()
188 : throw (::com::sun::star::uno::RuntimeException, std::exception)
189 : {
190 6458 : Reference< XComponent > xThis( static_cast< OWeakObject* >(this), UNO_QUERY );
191 :
192 : {
193 6458 : SolarMutexGuard aSolarMutexGuard;
194 6458 : if ( m_bDisposed )
195 0 : throw DisposedException();
196 : }
197 :
198 12916 : com::sun::star::lang::EventObject aEvent( xThis );
199 6458 : m_aListenerContainer.disposeAndClear( aEvent );
200 :
201 12916 : SolarMutexGuard aSolarMutexGuard;
202 12916 : Reference< XStatusListener > xStatusListener( static_cast< OWeakObject* >( this ), UNO_QUERY );
203 12916 : Reference< XURLTransformer > xURLTransformer = getURLTransformer();
204 6458 : URLToDispatchMap::iterator pIter = m_aListenerMap.begin();
205 12916 : com::sun::star::util::URL aTargetURL;
206 21087 : while ( pIter != m_aListenerMap.end() )
207 : {
208 : try
209 : {
210 8171 : Reference< XDispatch > xDispatch( pIter->second );
211 8171 : aTargetURL.Complete = pIter->first;
212 8171 : xURLTransformer->parseStrict( aTargetURL );
213 :
214 8171 : if ( xDispatch.is() && xStatusListener.is() )
215 7699 : xDispatch->removeStatusListener( xStatusListener, aTargetURL );
216 : }
217 0 : catch ( Exception& )
218 : {
219 : }
220 :
221 8171 : ++pIter;
222 : }
223 :
224 : // clear hash map
225 6458 : m_aListenerMap.clear();
226 :
227 : // release references
228 6458 : m_xURLTransformer.clear();
229 6458 : m_xContext.clear();
230 6458 : m_xFrame.clear();
231 6458 : m_xParentWindow.clear();
232 6458 : m_xStatusbarItem.clear();
233 :
234 12916 : m_bDisposed = true;
235 6458 : }
236 :
237 0 : void SAL_CALL StatusbarController::addEventListener( const Reference< XEventListener >& xListener )
238 : throw ( RuntimeException, std::exception )
239 : {
240 0 : m_aListenerContainer.addInterface( cppu::UnoType<XEventListener>::get(), xListener );
241 0 : }
242 :
243 0 : void SAL_CALL StatusbarController::removeEventListener( const Reference< XEventListener >& aListener )
244 : throw ( RuntimeException, std::exception )
245 : {
246 0 : m_aListenerContainer.removeInterface( cppu::UnoType<XEventListener>::get(), aListener );
247 0 : }
248 :
249 : // XEventListener
250 0 : void SAL_CALL StatusbarController::disposing( const EventObject& Source )
251 : throw ( RuntimeException, std::exception )
252 : {
253 0 : SolarMutexGuard aSolarMutexGuard;
254 :
255 0 : if ( m_bDisposed )
256 0 : return;
257 :
258 0 : Reference< XFrame > xFrame( Source.Source, UNO_QUERY );
259 0 : if ( xFrame.is() )
260 : {
261 0 : if ( xFrame == m_xFrame )
262 0 : m_xFrame.clear();
263 0 : return;
264 : }
265 :
266 0 : Reference< XDispatch > xDispatch( Source.Source, UNO_QUERY );
267 0 : if ( !xDispatch.is() )
268 0 : return;
269 :
270 0 : URLToDispatchMap::iterator pIter = m_aListenerMap.begin();
271 0 : while ( pIter != m_aListenerMap.end() )
272 : {
273 : // Compare references and release dispatch references if they are equal.
274 0 : if ( xDispatch == pIter->second )
275 0 : pIter->second.clear();
276 0 : ++pIter;
277 0 : }
278 : }
279 :
280 : // XStatusListener
281 2532 : void SAL_CALL StatusbarController::statusChanged( const FeatureStateEvent& Event )
282 : throw ( RuntimeException, std::exception )
283 : {
284 2532 : SolarMutexGuard aSolarMutexGuard;
285 :
286 2532 : if ( m_bDisposed )
287 2532 : return;
288 :
289 2532 : vcl::Window* pWindow = VCLUnoHelper::GetWindow( m_xParentWindow );
290 2532 : if ( pWindow && pWindow->GetType() == WINDOW_STATUSBAR && m_nID != 0 )
291 : {
292 2532 : OUString aStrValue;
293 2532 : StatusBar* pStatusBar = static_cast<StatusBar *>(pWindow);
294 :
295 2532 : if ( Event.State >>= aStrValue )
296 2313 : pStatusBar->SetItemText( m_nID, aStrValue );
297 219 : else if ( !Event.State.hasValue() )
298 219 : pStatusBar->SetItemText( m_nID, "" );
299 2532 : }
300 : }
301 :
302 : // XStatusbarController
303 0 : sal_Bool SAL_CALL StatusbarController::mouseButtonDown(
304 : const ::com::sun::star::awt::MouseEvent& )
305 : throw (::com::sun::star::uno::RuntimeException, std::exception)
306 : {
307 0 : return sal_False;
308 : }
309 :
310 0 : sal_Bool SAL_CALL StatusbarController::mouseMove(
311 : const ::com::sun::star::awt::MouseEvent& )
312 : throw (::com::sun::star::uno::RuntimeException, std::exception)
313 : {
314 0 : return sal_False;
315 : }
316 :
317 0 : sal_Bool SAL_CALL StatusbarController::mouseButtonUp(
318 : const ::com::sun::star::awt::MouseEvent& )
319 : throw (::com::sun::star::uno::RuntimeException, std::exception)
320 : {
321 0 : return sal_False;
322 : }
323 :
324 0 : void SAL_CALL StatusbarController::command(
325 : const ::com::sun::star::awt::Point&,
326 : ::sal_Int32,
327 : sal_Bool,
328 : const ::com::sun::star::uno::Any& )
329 : throw (::com::sun::star::uno::RuntimeException, std::exception)
330 : {
331 0 : }
332 :
333 50 : void SAL_CALL StatusbarController::paint(
334 : const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XGraphics >&,
335 : const ::com::sun::star::awt::Rectangle&,
336 : ::sal_Int32 )
337 : throw (::com::sun::star::uno::RuntimeException, std::exception)
338 : {
339 50 : }
340 :
341 0 : void SAL_CALL StatusbarController::click( const ::com::sun::star::awt::Point& )
342 : throw (::com::sun::star::uno::RuntimeException, std::exception)
343 : {
344 0 : }
345 :
346 0 : void SAL_CALL StatusbarController::doubleClick( const ::com::sun::star::awt::Point& ) throw (::com::sun::star::uno::RuntimeException, std::exception)
347 : {
348 0 : SolarMutexGuard aSolarMutexGuard;
349 :
350 0 : if ( m_bDisposed )
351 0 : return;
352 :
353 0 : Sequence< PropertyValue > aArgs;
354 0 : execute( aArgs );
355 : }
356 :
357 1713 : void StatusbarController::addStatusListener( const OUString& aCommandURL )
358 : {
359 1713 : Reference< XDispatch > xDispatch;
360 1713 : Reference< XStatusListener > xStatusListener;
361 1713 : com::sun::star::util::URL aTargetURL;
362 :
363 : {
364 1713 : SolarMutexGuard aSolarMutexGuard;
365 1713 : URLToDispatchMap::iterator pIter = m_aListenerMap.find( aCommandURL );
366 :
367 : // Already in the list of status listener. Do nothing.
368 1713 : if ( pIter != m_aListenerMap.end() )
369 0 : return;
370 :
371 : // Check if we are already initialized. Implementation starts adding itself as status listener when
372 : // intialize is called.
373 1713 : if ( !m_bInitialized )
374 : {
375 : // Put into the unordered_map of status listener. Will be activated when initialized is called
376 1713 : m_aListenerMap.insert( URLToDispatchMap::value_type( aCommandURL, Reference< XDispatch >() ));
377 1713 : return;
378 : }
379 : else
380 : {
381 : // Add status listener directly as intialize has already been called.
382 0 : Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
383 0 : if ( m_xContext.is() && xDispatchProvider.is() )
384 : {
385 0 : Reference< XURLTransformer > xURLTransformer = getURLTransformer();
386 0 : aTargetURL.Complete = aCommandURL;
387 0 : xURLTransformer->parseStrict( aTargetURL );
388 0 : xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
389 :
390 0 : xStatusListener = Reference< XStatusListener >( static_cast< OWeakObject* >( this ), UNO_QUERY );
391 0 : URLToDispatchMap::iterator aIter = m_aListenerMap.find( aCommandURL );
392 0 : if ( aIter != m_aListenerMap.end() )
393 : {
394 0 : Reference< XDispatch > xOldDispatch( aIter->second );
395 0 : aIter->second = xDispatch;
396 :
397 : try
398 : {
399 0 : if ( xOldDispatch.is() )
400 0 : xOldDispatch->removeStatusListener( xStatusListener, aTargetURL );
401 : }
402 0 : catch ( Exception& )
403 : {
404 0 : }
405 : }
406 : else
407 0 : m_aListenerMap.insert( URLToDispatchMap::value_type( aCommandURL, xDispatch ));
408 0 : }
409 0 : }
410 : }
411 :
412 : // Call without locked mutex as we are called back from dispatch implementation
413 : try
414 : {
415 0 : if ( xDispatch.is() )
416 0 : xDispatch->addStatusListener( xStatusListener, aTargetURL );
417 : }
418 0 : catch ( Exception& )
419 : {
420 0 : }
421 : }
422 :
423 6458 : void StatusbarController::bindListener()
424 : {
425 6458 : std::vector< Listener > aDispatchVector;
426 12916 : Reference< XStatusListener > xStatusListener;
427 :
428 : {
429 6458 : SolarMutexGuard aSolarMutexGuard;
430 :
431 6458 : if ( !m_bInitialized )
432 0 : return;
433 :
434 : // Collect all registered command URL's and store them temporary
435 12916 : Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
436 6458 : if ( m_xContext.is() && xDispatchProvider.is() )
437 : {
438 6458 : xStatusListener = Reference< XStatusListener >( static_cast< OWeakObject* >( this ), UNO_QUERY );
439 6458 : URLToDispatchMap::iterator pIter = m_aListenerMap.begin();
440 21087 : while ( pIter != m_aListenerMap.end() )
441 : {
442 8171 : Reference< XURLTransformer > xURLTransformer = getURLTransformer();
443 16342 : com::sun::star::util::URL aTargetURL;
444 8171 : aTargetURL.Complete = pIter->first;
445 8171 : xURLTransformer->parseStrict( aTargetURL );
446 :
447 16342 : Reference< XDispatch > xDispatch( pIter->second );
448 8171 : if ( xDispatch.is() )
449 : {
450 : // We already have a dispatch object => we have to requery.
451 : // Release old dispatch object and remove it as listener
452 : try
453 : {
454 0 : xDispatch->removeStatusListener( xStatusListener, aTargetURL );
455 : }
456 0 : catch ( Exception& )
457 : {
458 : }
459 : }
460 :
461 8171 : pIter->second.clear();
462 8171 : xDispatch.clear();
463 :
464 : // Query for dispatch object. Old dispatch will be released with this, too.
465 : try
466 : {
467 8171 : xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
468 : }
469 0 : catch ( Exception& )
470 : {
471 : }
472 8171 : pIter->second = xDispatch;
473 :
474 16342 : Listener aListener( aTargetURL, xDispatch );
475 8171 : aDispatchVector.push_back( aListener );
476 8171 : ++pIter;
477 8171 : }
478 6458 : }
479 : }
480 :
481 : // Call without locked mutex as we are called back from dispatch implementation
482 6458 : if ( !xStatusListener.is() )
483 0 : return;
484 :
485 14629 : for ( size_t i = 0; i < aDispatchVector.size(); i++ )
486 : {
487 : try
488 : {
489 8171 : Listener& rListener = aDispatchVector[i];
490 8171 : if ( rListener.xDispatch.is() )
491 7699 : rListener.xDispatch->addStatusListener( xStatusListener, rListener.aURL );
492 472 : else if ( rListener.aURL.Complete == m_aCommandURL )
493 : {
494 : // Send status changed for the main URL, if we cannot get a valid dispatch object.
495 : // UI disables the button. Catch exception as we release our mutex, it is possible
496 : // that someone else already disposed this instance!
497 0 : FeatureStateEvent aFeatureStateEvent;
498 0 : aFeatureStateEvent.IsEnabled = sal_False;
499 0 : aFeatureStateEvent.FeatureURL = rListener.aURL;
500 0 : aFeatureStateEvent.State = Any();
501 0 : xStatusListener->statusChanged( aFeatureStateEvent );
502 : }
503 : }
504 0 : catch ( ... ){}
505 6458 : }
506 : }
507 :
508 16841 : ::Rectangle StatusbarController::getControlRect() const
509 : {
510 16841 : ::Rectangle aRect;
511 :
512 : {
513 16841 : SolarMutexGuard aSolarMutexGuard;
514 :
515 16841 : if ( m_bDisposed )
516 0 : throw DisposedException();
517 :
518 16841 : if ( m_xParentWindow.is() )
519 : {
520 16841 : VclPtr< StatusBar > pStatusBar = dynamic_cast< StatusBar* >( VCLUnoHelper::GetWindow( m_xParentWindow ).get() );
521 16841 : if ( pStatusBar && pStatusBar->GetType() == WINDOW_STATUSBAR )
522 16841 : aRect = pStatusBar->GetItemRect( m_nID );
523 16841 : }
524 : }
525 :
526 16841 : return aRect;
527 : }
528 :
529 0 : void StatusbarController::execute( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aArgs )
530 : {
531 0 : Reference< XDispatch > xDispatch;
532 0 : Reference< XURLTransformer > xURLTransformer;
533 0 : OUString aCommandURL;
534 :
535 : {
536 0 : SolarMutexGuard aSolarMutexGuard;
537 :
538 0 : if ( m_bDisposed )
539 0 : throw DisposedException();
540 :
541 0 : if ( m_bInitialized &&
542 0 : m_xFrame.is() &&
543 0 : m_xContext.is() &&
544 0 : !m_aCommandURL.isEmpty() )
545 : {
546 0 : xURLTransformer = getURLTransformer();
547 0 : aCommandURL = m_aCommandURL;
548 0 : URLToDispatchMap::iterator pIter = m_aListenerMap.find( m_aCommandURL );
549 0 : if ( pIter != m_aListenerMap.end() )
550 0 : xDispatch = pIter->second;
551 0 : }
552 : }
553 :
554 0 : if ( xDispatch.is() && xURLTransformer.is() )
555 : {
556 : try
557 : {
558 0 : com::sun::star::util::URL aTargetURL;
559 :
560 0 : aTargetURL.Complete = aCommandURL;
561 0 : xURLTransformer->parseStrict( aTargetURL );
562 0 : xDispatch->dispatch( aTargetURL, aArgs );
563 : }
564 0 : catch ( DisposedException& )
565 : {
566 : }
567 0 : }
568 0 : }
569 :
570 0 : void StatusbarController::execute(
571 : const OUString& aCommandURL,
572 : const Sequence< ::com::sun::star::beans::PropertyValue >& aArgs )
573 : {
574 0 : Reference< XDispatch > xDispatch;
575 0 : com::sun::star::util::URL aTargetURL;
576 :
577 : {
578 0 : SolarMutexGuard aSolarMutexGuard;
579 :
580 0 : if ( m_bDisposed )
581 0 : throw DisposedException();
582 :
583 0 : if ( m_bInitialized &&
584 0 : m_xFrame.is() &&
585 0 : m_xContext.is() &&
586 0 : !m_aCommandURL.isEmpty() )
587 : {
588 0 : Reference< XURLTransformer > xURLTransformer( getURLTransformer() );
589 0 : aTargetURL.Complete = aCommandURL;
590 0 : xURLTransformer->parseStrict( aTargetURL );
591 :
592 0 : URLToDispatchMap::iterator pIter = m_aListenerMap.find( aCommandURL );
593 0 : if ( pIter != m_aListenerMap.end() )
594 0 : xDispatch = pIter->second;
595 : else
596 : {
597 : Reference< ::com::sun::star::frame::XDispatchProvider > xDispatchProvider(
598 0 : m_xFrame->getController(), UNO_QUERY );
599 0 : if ( xDispatchProvider.is() )
600 0 : xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
601 0 : }
602 0 : }
603 : }
604 :
605 0 : if ( xDispatch.is() )
606 : {
607 : try
608 : {
609 0 : xDispatch->dispatch( aTargetURL, aArgs );
610 : }
611 0 : catch ( DisposedException& )
612 : {
613 : }
614 0 : }
615 0 : }
616 :
617 : } // svt
618 :
619 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|