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/AccessibleEventId.hpp>
22 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
23 #include <com/sun/star/accessibility/IllegalAccessibleComponentStateException.hpp>
24 #include <tools/gen.hxx>
25 #include <tools/color.hxx>
26 #include <toolkit/helper/vclunohelper.hxx>
27 #include <svl/hint.hxx>
28 #include <comphelper/sequence.hxx>
29 #include <cppuhelper/supportsservice.hxx>
30 #include <unotools/accessiblerelationsethelper.hxx>
32 #include <vcl/unohelp.hxx>
33 #include <comphelper/accessibleeventnotifier.hxx>
34 #include <vcl/svapp.hxx>
36 using namespace ::com::sun::star
;
37 using namespace ::com::sun::star::accessibility
;
40 The listener is an internal class to prevent reference-counting cycles and therefore memory leaks.
42 typedef cppu::WeakComponentImplHelper
<
43 css::accessibility::XAccessibleEventListener
44 > ScAccessibleContextBaseEventListenerWeakImpl
;
45 class ScAccessibleContextBase::ScAccessibleContextBaseEventListener
: public cppu::BaseMutex
, public ScAccessibleContextBaseEventListenerWeakImpl
48 ScAccessibleContextBaseEventListener(ScAccessibleContextBase
& rBase
)
49 : ScAccessibleContextBaseEventListenerWeakImpl(m_aMutex
), mrBase(rBase
) {}
51 using WeakComponentImplHelperBase::disposing
;
53 ///===== XAccessibleEventListener ========================================
55 virtual void SAL_CALL
disposing( const lang::EventObject
& rSource
) override
57 SolarMutexGuard aGuard
;
58 if (rSource
.Source
== mrBase
.mxParent
)
64 const css::accessibility::AccessibleEventObject
& /*aEvent*/ ) override
{}
66 ScAccessibleContextBase
& mrBase
;
70 ScAccessibleContextBase::ScAccessibleContextBase(
71 uno::Reference
<XAccessible
> xParent
,
72 const sal_Int16 aRole
)
74 ScAccessibleContextBaseWeakImpl(m_aMutex
),
75 mxParent(std::move(xParent
)),
81 ScAccessibleContextBase::~ScAccessibleContextBase()
83 if (!IsDefunc() && !rBHelper
.bInDispose
)
85 // increment refcount to prevent double call off dtor
86 osl_atomic_increment( &m_refCount
);
87 // call dispose to inform object which have a weak reference to this object
92 void ScAccessibleContextBase::Init()
94 // hold reference to make sure that the destructor is not called
95 uno::Reference
< XAccessibleContext
> xKeepAlive(this);
99 uno::Reference
< XAccessibleEventBroadcaster
> xBroadcaster (mxParent
->getAccessibleContext(), uno::UNO_QUERY
);
100 if (xBroadcaster
.is())
102 if (!mxEventListener
)
103 mxEventListener
= new ScAccessibleContextBaseEventListener(*this);
104 xBroadcaster
->addAccessibleEventListener(mxEventListener
);
107 msName
= createAccessibleName();
108 msDescription
= createAccessibleDescription();
111 void SAL_CALL
ScAccessibleContextBase::disposing()
113 SolarMutexGuard aGuard
;
114 // CommitDefunc(); not necessary and should not be send, because it cost a lot of time
116 // hold reference to make sure that the destructor is not called
117 uno::Reference
< XAccessibleContext
> xKeepAlive(this);
121 sal_Int32
nTemClientId(mnClientId
);
123 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( nTemClientId
, *this );
128 uno::Reference
< XAccessibleEventBroadcaster
> xBroadcaster (mxParent
->getAccessibleContext(), uno::UNO_QUERY
);
129 if (xBroadcaster
&& mxEventListener
)
130 xBroadcaster
->removeAccessibleEventListener(mxEventListener
);
136 //===== SfxListener =====================================================
138 void ScAccessibleContextBase::Notify( SfxBroadcaster
&, const SfxHint
& rHint
)
140 if (rHint
.GetId() == SfxHintId::Dying
)
142 // it seems the Broadcaster is dying, since the view is dying
147 //===== XAccessible =========================================================
149 uno::Reference
< XAccessibleContext
> SAL_CALL
150 ScAccessibleContextBase::getAccessibleContext()
155 //===== XAccessibleComponent ================================================
157 sal_Bool SAL_CALL
ScAccessibleContextBase::containsPoint(const awt::Point
& rPoint
)
159 SolarMutexGuard aGuard
;
161 return tools::Rectangle(Point(), GetBoundingBox().GetSize())
162 .Contains(vcl::unohelper::ConvertToVCLPoint(rPoint
));
165 uno::Reference
< XAccessible
> SAL_CALL
ScAccessibleContextBase::getAccessibleAtPoint(
166 const awt::Point
& /* rPoint */ )
168 OSL_FAIL("not implemented");
169 return uno::Reference
<XAccessible
>();
172 awt::Rectangle SAL_CALL
ScAccessibleContextBase::getBounds( )
174 SolarMutexGuard aGuard
;
176 return vcl::unohelper::ConvertToAWTRect(GetBoundingBox());
179 awt::Point SAL_CALL
ScAccessibleContextBase::getLocation( )
181 SolarMutexGuard aGuard
;
183 return vcl::unohelper::ConvertToAWTPoint(GetBoundingBox().TopLeft());
186 awt::Point SAL_CALL
ScAccessibleContextBase::getLocationOnScreen( )
188 SolarMutexGuard aGuard
;
190 return vcl::unohelper::ConvertToAWTPoint(GetBoundingBoxOnScreen().TopLeft());
193 awt::Size SAL_CALL
ScAccessibleContextBase::getSize( )
195 SolarMutexGuard aGuard
;
197 return vcl::unohelper::ConvertToAWTSize(GetBoundingBox().GetSize());
200 bool ScAccessibleContextBase::isShowing( )
202 SolarMutexGuard aGuard
;
204 bool bShowing(false);
207 uno::Reference
<XAccessibleComponent
> xParentComponent (mxParent
->getAccessibleContext(), uno::UNO_QUERY
);
208 if (xParentComponent
.is())
210 tools::Rectangle
aParentBounds(
211 vcl::unohelper::ConvertToVCLRect(xParentComponent
->getBounds()));
212 tools::Rectangle
aBounds(vcl::unohelper::ConvertToVCLRect(getBounds()));
213 bShowing
= aBounds
.Overlaps(aParentBounds
);
219 bool ScAccessibleContextBase::isVisible()
224 void SAL_CALL
ScAccessibleContextBase::grabFocus( )
226 OSL_FAIL("not implemented");
229 sal_Int32 SAL_CALL
ScAccessibleContextBase::getForeground( )
231 return sal_Int32(COL_BLACK
);
234 sal_Int32 SAL_CALL
ScAccessibleContextBase::getBackground( )
236 return sal_Int32(COL_WHITE
);
239 //===== XAccessibleContext ==================================================
241 sal_Int64 SAL_CALL
ScAccessibleContextBase::getAccessibleChildCount()
243 OSL_FAIL("should be implemented in the abrevated class");
247 uno::Reference
<XAccessible
> SAL_CALL
248 ScAccessibleContextBase::getAccessibleChild(sal_Int64
/* nIndex */)
250 OSL_FAIL("should be implemented in the abrevated class");
251 return uno::Reference
<XAccessible
>();
254 uno::Reference
<XAccessible
> SAL_CALL
255 ScAccessibleContextBase::getAccessibleParent()
261 ScAccessibleContextBase::getAccessibleIndexInParent()
263 SolarMutexGuard aGuard
;
265 // Use a simple but slow solution for now. Optimize later.
266 // Return -1 to indicate that this object's parent does not know about the
268 sal_Int64
nIndex(-1);
270 // Iterate over all the parent's children and search for this object.
273 uno::Reference
<XAccessibleContext
> xParentContext (
274 mxParent
->getAccessibleContext());
275 if (xParentContext
.is())
277 sal_Int64 nChildCount
= xParentContext
->getAccessibleChildCount();
278 for (sal_Int64 i
=0; i
<nChildCount
; ++i
)
280 uno::Reference
<XAccessible
> xChild (xParentContext
->getAccessibleChild (i
));
281 if (xChild
.is() && xChild
.get() == this)
291 ScAccessibleContextBase::getAccessibleRole()
297 ScAccessibleContextBase::getAccessibleDescription()
299 SolarMutexGuard aGuard
;
301 if (msDescription
.isEmpty())
303 OUString
sDescription(createAccessibleDescription());
305 if (msDescription
!= sDescription
)
307 AccessibleEventObject aEvent
;
308 aEvent
.EventId
= AccessibleEventId::DESCRIPTION_CHANGED
;
309 aEvent
.Source
= uno::Reference
< XAccessibleContext
>(this);
310 aEvent
.OldValue
<<= msDescription
;
311 aEvent
.NewValue
<<= sDescription
;
313 msDescription
= sDescription
;
315 CommitChange(aEvent
);
318 return msDescription
;
322 ScAccessibleContextBase::getAccessibleName()
324 SolarMutexGuard aGuard
;
326 if (msName
.isEmpty())
328 OUString
sName(createAccessibleName());
329 OSL_ENSURE(!sName
.isEmpty(), "We should give always a name.");
333 AccessibleEventObject aEvent
;
334 aEvent
.EventId
= AccessibleEventId::NAME_CHANGED
;
335 aEvent
.Source
= uno::Reference
< XAccessibleContext
>(this);
336 aEvent
.OldValue
<<= msName
;
337 aEvent
.NewValue
<<= sName
;
341 CommitChange(aEvent
);
347 uno::Reference
<XAccessibleRelationSet
> SAL_CALL
348 ScAccessibleContextBase::getAccessibleRelationSet()
350 return new utl::AccessibleRelationSetHelper();
353 sal_Int64 SAL_CALL
ScAccessibleContextBase::getAccessibleStateSet()
358 lang::Locale SAL_CALL
359 ScAccessibleContextBase::getLocale()
361 SolarMutexGuard aGuard
;
365 uno::Reference
<XAccessibleContext
> xParentContext (
366 mxParent
->getAccessibleContext());
367 if (xParentContext
.is())
368 return xParentContext
->getLocale ();
371 // No locale and no parent. Therefore throw exception to indicate this
373 throw IllegalAccessibleComponentStateException ();
376 //===== XAccessibleEventBroadcaster =====================================
379 ScAccessibleContextBase::addAccessibleEventListener(
380 const uno::Reference
<XAccessibleEventListener
>& xListener
)
384 SolarMutexGuard aGuard
;
389 mnClientId
= comphelper::AccessibleEventNotifier::registerClient( );
390 comphelper::AccessibleEventNotifier::addEventListener( mnClientId
, xListener
);
396 ScAccessibleContextBase::removeAccessibleEventListener(
397 const uno::Reference
<XAccessibleEventListener
>& xListener
)
402 SolarMutexGuard aGuard
;
403 if (IsDefunc() || !mnClientId
)
406 sal_Int32 nListenerCount
= comphelper::AccessibleEventNotifier::removeEventListener( mnClientId
, xListener
);
407 if ( !nListenerCount
)
409 // no listeners anymore
410 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
411 // and at least to us not firing any events anymore, in case somebody calls
412 // NotifyAccessibleEvent, again
413 comphelper::AccessibleEventNotifier::revokeClient( mnClientId
);
419 OUString SAL_CALL
ScAccessibleContextBase::getImplementationName()
421 return u
"ScAccessibleContextBase"_ustr
;
424 sal_Bool SAL_CALL
ScAccessibleContextBase::supportsService(const OUString
& sServiceName
)
426 return cppu::supportsService(this, sServiceName
);
429 uno::Sequence
< OUString
> SAL_CALL
430 ScAccessibleContextBase::getSupportedServiceNames()
432 return {u
"com.sun.star.accessibility.Accessible"_ustr
,
433 u
"com.sun.star.accessibility.AccessibleContext"_ustr
};
436 //===== internal ============================================================
439 ScAccessibleContextBase::createAccessibleDescription()
441 OSL_FAIL("should be implemented in the abrevated class");
445 OUString
ScAccessibleContextBase::createAccessibleName()
447 OSL_FAIL("should be implemented in the abrevated class");
451 void ScAccessibleContextBase::CommitChange(const AccessibleEventObject
& rEvent
) const
454 comphelper::AccessibleEventNotifier::addEvent( mnClientId
, rEvent
);
457 void ScAccessibleContextBase::CommitFocusGained() const
459 AccessibleEventObject aEvent
;
460 aEvent
.EventId
= AccessibleEventId::STATE_CHANGED
;
461 aEvent
.Source
= uno::Reference
< XAccessibleContext
>(const_cast<ScAccessibleContextBase
*>(this));
462 aEvent
.NewValue
<<= AccessibleStateType::FOCUSED
;
464 CommitChange(aEvent
);
467 void ScAccessibleContextBase::CommitFocusLost() const
469 AccessibleEventObject aEvent
;
470 aEvent
.EventId
= AccessibleEventId::STATE_CHANGED
;
471 aEvent
.Source
= uno::Reference
< XAccessibleContext
>(const_cast<ScAccessibleContextBase
*>(this));
472 aEvent
.OldValue
<<= AccessibleStateType::FOCUSED
;
474 CommitChange(aEvent
);
477 AbsoluteScreenPixelRectangle
ScAccessibleContextBase::GetBoundingBoxOnScreen() const
479 OSL_FAIL("not implemented");
480 return AbsoluteScreenPixelRectangle();
483 tools::Rectangle
ScAccessibleContextBase::GetBoundingBox() const
485 OSL_FAIL("not implemented");
486 return tools::Rectangle();
489 void ScAccessibleContextBase::IsObjectValid() const
491 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
492 throw lang::DisposedException();
495 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */