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