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 "AccessibleContextBase.hxx"
21 #include <com/sun/star/accessibility/AccessibleRole.hpp>
22 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
23 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
24 #include <com/sun/star/beans/PropertyChangeEvent.hpp>
25 #include <tools/debug.hxx>
26 #include <tools/gen.hxx>
27 #include <unotools/accessiblestatesethelper.hxx>
28 #include <toolkit/helper/convert.hxx>
29 #include <svl/smplhint.hxx>
30 #include <comphelper/sequence.hxx>
31 #include <comphelper/servicehelper.hxx>
32 #include <cppuhelper/supportsservice.hxx>
33 #include <unotools/accessiblerelationsethelper.hxx>
34 #include <vcl/unohelp.hxx>
35 #include <comphelper/accessibleeventnotifier.hxx>
36 #include <vcl/svapp.hxx>
38 using namespace ::com::sun::star
;
39 using namespace ::com::sun::star::accessibility
;
41 ScAccessibleContextBase::ScAccessibleContextBase(
42 const uno::Reference
<XAccessible
>& rxParent
,
43 const sal_Int16 aRole
)
45 ScAccessibleContextBaseWeakImpl(m_aMutex
),
52 ScAccessibleContextBase::~ScAccessibleContextBase()
54 if (!IsDefunc() && !rBHelper
.bInDispose
)
56 // increment refcount to prevent double call off dtor
57 osl_atomic_increment( &m_refCount
);
58 // call dispose to inform object which have a weak reference to this object
63 void ScAccessibleContextBase::Init()
65 // hold reference to make sure that the destructor is not called
66 uno::Reference
< XAccessibleContext
> xOwnContext(this);
70 uno::Reference
< XAccessibleEventBroadcaster
> xBroadcaster (mxParent
->getAccessibleContext(), uno::UNO_QUERY
);
71 if (xBroadcaster
.is())
72 xBroadcaster
->addAccessibleEventListener(this);
74 msName
= createAccessibleName();
75 msDescription
= createAccessibleDescription();
78 void SAL_CALL
ScAccessibleContextBase::disposing()
80 SolarMutexGuard aGuard
;
81 // CommitDefunc(); not necessary and should not be send, because it cost a lot of time
83 // hold reference to make sure that the destructor is not called
84 uno::Reference
< XAccessibleContext
> xOwnContext(this);
88 sal_Int32
nTemClientId(mnClientId
);
90 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( nTemClientId
, *this );
95 uno::Reference
< XAccessibleEventBroadcaster
> xBroadcaster (mxParent
->getAccessibleContext(), uno::UNO_QUERY
);
96 if (xBroadcaster
.is())
97 xBroadcaster
->removeAccessibleEventListener(this);
101 ScAccessibleContextBaseWeakImpl::disposing();
104 //===== XInterface =====================================================
106 uno::Any SAL_CALL
ScAccessibleContextBase::queryInterface( uno::Type
const & rType
)
107 throw (uno::RuntimeException
, std::exception
)
109 uno::Any
aAny (ScAccessibleContextBaseWeakImpl::queryInterface(rType
));
110 return aAny
.hasValue() ? aAny
: ScAccessibleContextBaseImplEvent::queryInterface(rType
);
113 void SAL_CALL
ScAccessibleContextBase::acquire()
116 ScAccessibleContextBaseWeakImpl::acquire();
119 void SAL_CALL
ScAccessibleContextBase::release()
122 ScAccessibleContextBaseWeakImpl::release();
125 //===== SfxListener =====================================================
127 void ScAccessibleContextBase::Notify( SfxBroadcaster
&, const SfxHint
& rHint
)
129 const SfxSimpleHint
* pSimpleHint
= dynamic_cast<const SfxSimpleHint
*>(&rHint
);
132 if (pSimpleHint
->GetId() == SFX_HINT_DYING
)
134 // it seems the Broadcaster is dying, since the view is dying
140 //===== XAccessible =========================================================
142 uno::Reference
< XAccessibleContext
> SAL_CALL
143 ScAccessibleContextBase::getAccessibleContext()
144 throw (uno::RuntimeException
, std::exception
)
149 //===== XAccessibleComponent ================================================
151 sal_Bool SAL_CALL
ScAccessibleContextBase::containsPoint(const awt::Point
& rPoint
)
152 throw (uno::RuntimeException
, std::exception
)
154 SolarMutexGuard aGuard
;
156 return Rectangle (Point(), GetBoundingBox().GetSize()).IsInside(VCLPoint(rPoint
));
159 uno::Reference
< XAccessible
> SAL_CALL
ScAccessibleContextBase::getAccessibleAtPoint(
160 const awt::Point
& /* rPoint */ )
161 throw (uno::RuntimeException
, std::exception
)
163 OSL_FAIL("not implemented");
164 return uno::Reference
<XAccessible
>();
167 awt::Rectangle SAL_CALL
ScAccessibleContextBase::getBounds( )
168 throw (uno::RuntimeException
, std::exception
)
170 SolarMutexGuard aGuard
;
172 return AWTRectangle(GetBoundingBox());
175 awt::Point SAL_CALL
ScAccessibleContextBase::getLocation( )
176 throw (uno::RuntimeException
, std::exception
)
178 SolarMutexGuard aGuard
;
180 return AWTPoint(GetBoundingBox().TopLeft());
183 awt::Point SAL_CALL
ScAccessibleContextBase::getLocationOnScreen( )
184 throw (uno::RuntimeException
, std::exception
)
186 SolarMutexGuard aGuard
;
188 return AWTPoint(GetBoundingBoxOnScreen().TopLeft());
191 awt::Size SAL_CALL
ScAccessibleContextBase::getSize( )
192 throw (uno::RuntimeException
, std::exception
)
194 SolarMutexGuard aGuard
;
196 return AWTSize(GetBoundingBox().GetSize());
199 bool SAL_CALL
ScAccessibleContextBase::isShowing( )
200 throw (uno::RuntimeException
)
202 SolarMutexGuard aGuard
;
204 bool bShowing(false);
207 uno::Reference
<XAccessibleComponent
> xParentComponent (mxParent
->getAccessibleContext(), uno::UNO_QUERY
);
208 if (xParentComponent
.is())
210 Rectangle
aParentBounds(VCLRectangle(xParentComponent
->getBounds()));
211 Rectangle
aBounds(VCLRectangle(getBounds()));
212 bShowing
= aBounds
.IsOver(aParentBounds
);
218 bool SAL_CALL
ScAccessibleContextBase::isVisible()
219 throw (uno::RuntimeException
, std::exception
)
224 void SAL_CALL
ScAccessibleContextBase::grabFocus( )
225 throw (uno::RuntimeException
, std::exception
)
227 OSL_FAIL("not implemented");
230 sal_Int32 SAL_CALL
ScAccessibleContextBase::getForeground( )
231 throw (uno::RuntimeException
, std::exception
)
236 sal_Int32 SAL_CALL
ScAccessibleContextBase::getBackground( )
237 throw (uno::RuntimeException
, std::exception
)
242 //===== XAccessibleContext ==================================================
244 sal_Int32 SAL_CALL
ScAccessibleContextBase::getAccessibleChildCount()
245 throw (uno::RuntimeException
, std::exception
)
247 OSL_FAIL("should be implemented in the abrevated class");
251 uno::Reference
<XAccessible
> SAL_CALL
252 ScAccessibleContextBase::getAccessibleChild(sal_Int32
/* nIndex */)
253 throw (lang::IndexOutOfBoundsException
, uno::RuntimeException
,
256 OSL_FAIL("should be implemented in the abrevated class");
257 return uno::Reference
<XAccessible
>();
260 uno::Reference
<XAccessible
> SAL_CALL
261 ScAccessibleContextBase::getAccessibleParent()
262 throw (uno::RuntimeException
, std::exception
)
268 ScAccessibleContextBase::getAccessibleIndexInParent()
269 throw (uno::RuntimeException
, std::exception
)
271 SolarMutexGuard aGuard
;
273 // Use a simple but slow solution for now. Optimize later.
274 // Return -1 to indicate that this object's parent does not know about the
276 sal_Int32
nIndex(-1);
278 // Iterate over all the parent's children and search for this object.
281 uno::Reference
<XAccessibleContext
> xParentContext (
282 mxParent
->getAccessibleContext());
283 if (xParentContext
.is())
285 sal_Int32 nChildCount
= xParentContext
->getAccessibleChildCount();
286 for (sal_Int32 i
=0; i
<nChildCount
; ++i
)
288 uno::Reference
<XAccessible
> xChild (xParentContext
->getAccessibleChild (i
));
291 if (xChild
.get() == this)
302 ScAccessibleContextBase::getAccessibleRole()
303 throw (uno::RuntimeException
, std::exception
)
309 ScAccessibleContextBase::getAccessibleDescription()
310 throw (uno::RuntimeException
, std::exception
)
312 SolarMutexGuard aGuard
;
314 if (msDescription
.isEmpty())
316 OUString
sDescription(createAccessibleDescription());
318 if (msDescription
!= sDescription
)
320 AccessibleEventObject aEvent
;
321 aEvent
.EventId
= AccessibleEventId::DESCRIPTION_CHANGED
;
322 aEvent
.Source
= uno::Reference
< XAccessibleContext
>(this);
323 aEvent
.OldValue
<<= msDescription
;
324 aEvent
.NewValue
<<= sDescription
;
326 msDescription
= sDescription
;
328 CommitChange(aEvent
);
331 return msDescription
;
335 ScAccessibleContextBase::getAccessibleName()
336 throw (uno::RuntimeException
, std::exception
)
338 SolarMutexGuard aGuard
;
340 if (msName
.isEmpty())
342 OUString
sName(createAccessibleName());
343 OSL_ENSURE(!sName
.isEmpty(), "We should give always a name.");
347 AccessibleEventObject aEvent
;
348 aEvent
.EventId
= AccessibleEventId::NAME_CHANGED
;
349 aEvent
.Source
= uno::Reference
< XAccessibleContext
>(this);
350 aEvent
.OldValue
<<= msName
;
351 aEvent
.NewValue
<<= sName
;
355 CommitChange(aEvent
);
361 uno::Reference
<XAccessibleRelationSet
> SAL_CALL
362 ScAccessibleContextBase::getAccessibleRelationSet()
363 throw (uno::RuntimeException
, std::exception
)
365 return new utl::AccessibleRelationSetHelper();
368 uno::Reference
<XAccessibleStateSet
> SAL_CALL
369 ScAccessibleContextBase::getAccessibleStateSet()
370 throw (uno::RuntimeException
, std::exception
)
372 return uno::Reference
<XAccessibleStateSet
>();
375 lang::Locale SAL_CALL
376 ScAccessibleContextBase::getLocale()
377 throw (IllegalAccessibleComponentStateException
,
378 uno::RuntimeException
, std::exception
)
380 SolarMutexGuard aGuard
;
384 uno::Reference
<XAccessibleContext
> xParentContext (
385 mxParent
->getAccessibleContext());
386 if (xParentContext
.is())
387 return xParentContext
->getLocale ();
390 // No locale and no parent. Therefore throw exception to indicate this
392 throw IllegalAccessibleComponentStateException ();
395 //===== XAccessibleEventBroadcaster =====================================
398 ScAccessibleContextBase::addAccessibleEventListener(
399 const uno::Reference
<XAccessibleEventListener
>& xListener
)
400 throw (uno::RuntimeException
, std::exception
)
404 SolarMutexGuard aGuard
;
409 mnClientId
= comphelper::AccessibleEventNotifier::registerClient( );
410 comphelper::AccessibleEventNotifier::addEventListener( mnClientId
, xListener
);
416 ScAccessibleContextBase::removeAccessibleEventListener(
417 const uno::Reference
<XAccessibleEventListener
>& xListener
)
418 throw (uno::RuntimeException
, std::exception
)
422 SolarMutexGuard aGuard
;
423 if (!IsDefunc() && mnClientId
)
425 sal_Int32 nListenerCount
= comphelper::AccessibleEventNotifier::removeEventListener( mnClientId
, xListener
);
426 if ( !nListenerCount
)
428 // no listeners anymore
429 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
430 // and at least to us not firing any events anymore, in case somebody calls
431 // NotifyAccessibleEvent, again
432 comphelper::AccessibleEventNotifier::revokeClient( mnClientId
);
439 //===== XAccessibleEventListener ========================================
441 void SAL_CALL
ScAccessibleContextBase::disposing(
442 const lang::EventObject
& rSource
)
443 throw (uno::RuntimeException
, std::exception
)
445 SolarMutexGuard aGuard
;
446 if (rSource
.Source
== mxParent
)
450 void SAL_CALL
ScAccessibleContextBase::notifyEvent(
451 const AccessibleEventObject
& /* aEvent */ )
452 throw (uno::RuntimeException
, std::exception
)
457 OUString SAL_CALL
ScAccessibleContextBase::getImplementationName()
458 throw (uno::RuntimeException
, std::exception
)
460 return OUString("ScAccessibleContextBase");
463 sal_Bool SAL_CALL
ScAccessibleContextBase::supportsService(const OUString
& sServiceName
)
464 throw (uno::RuntimeException
, std::exception
)
466 return cppu::supportsService(this, sServiceName
);
469 uno::Sequence
< OUString
> SAL_CALL
470 ScAccessibleContextBase::getSupportedServiceNames()
471 throw (uno::RuntimeException
, std::exception
)
473 uno::Sequence
<OUString
> aServiceNames(2);
474 OUString
* pServiceNames
= aServiceNames
.getArray();
477 pServiceNames
[0] = "com.sun.star.accessibility.Accessible";
478 pServiceNames
[1] = "com.sun.star.accessibility.AccessibleContext";
481 return aServiceNames
;
484 //===== XTypeProvider =======================================================
486 uno::Sequence
< uno::Type
> SAL_CALL
ScAccessibleContextBase::getTypes()
487 throw (uno::RuntimeException
, std::exception
)
489 return comphelper::concatSequences(ScAccessibleContextBaseWeakImpl::getTypes(), ScAccessibleContextBaseImplEvent::getTypes());
492 uno::Sequence
<sal_Int8
> SAL_CALL
493 ScAccessibleContextBase::getImplementationId()
494 throw (uno::RuntimeException
, std::exception
)
496 return css::uno::Sequence
<sal_Int8
>();
499 //===== internal ============================================================
502 ScAccessibleContextBase::createAccessibleDescription()
503 throw (uno::RuntimeException
)
505 OSL_FAIL("should be implemented in the abrevated class");
509 OUString SAL_CALL
ScAccessibleContextBase::createAccessibleName()
510 throw (uno::RuntimeException
, std::exception
)
512 OSL_FAIL("should be implemented in the abrevated class");
516 void ScAccessibleContextBase::CommitChange(const AccessibleEventObject
& rEvent
) const
519 comphelper::AccessibleEventNotifier::addEvent( mnClientId
, rEvent
);
522 void ScAccessibleContextBase::CommitFocusGained() const
524 AccessibleEventObject aEvent
;
525 aEvent
.EventId
= AccessibleEventId::STATE_CHANGED
;
526 aEvent
.Source
= uno::Reference
< XAccessibleContext
>(const_cast<ScAccessibleContextBase
*>(this));
527 aEvent
.NewValue
<<= AccessibleStateType::FOCUSED
;
529 CommitChange(aEvent
);
531 vcl::unohelper::NotifyAccessibleStateEventGlobally(aEvent
);
534 void ScAccessibleContextBase::CommitFocusLost() const
536 AccessibleEventObject aEvent
;
537 aEvent
.EventId
= AccessibleEventId::STATE_CHANGED
;
538 aEvent
.Source
= uno::Reference
< XAccessibleContext
>(const_cast<ScAccessibleContextBase
*>(this));
539 aEvent
.OldValue
<<= AccessibleStateType::FOCUSED
;
541 CommitChange(aEvent
);
543 vcl::unohelper::NotifyAccessibleStateEventGlobally(aEvent
);
546 Rectangle
ScAccessibleContextBase::GetBoundingBoxOnScreen() const
547 throw (uno::RuntimeException
, std::exception
)
549 OSL_FAIL("not implemented");
553 Rectangle
ScAccessibleContextBase::GetBoundingBox() const
554 throw (uno::RuntimeException
, std::exception
)
556 OSL_FAIL("not implemented");
560 void ScAccessibleContextBase::IsObjectValid() const
561 throw (lang::DisposedException
)
563 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
564 throw lang::DisposedException();
567 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */