LibreOffice Module editeng (master) 1
AccessibleContextBase.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
22#include <com/sun/star/accessibility/XAccessibleEventListener.hpp>
23#include <com/sun/star/accessibility/AccessibleStateType.hpp>
24#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
25#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
26#include <com/sun/star/accessibility/AccessibleEventId.hpp>
27#include <com/sun/star/accessibility/IllegalAccessibleComponentStateException.hpp>
28
32#include <osl/mutex.hxx>
33#include <rtl/ref.hxx>
34
35#include <utility>
36
37using namespace ::com::sun::star;
38using namespace ::com::sun::star::accessibility;
39
40namespace accessibility {
41
42// internal
43
45 uno::Reference<XAccessible> xParent,
46 const sal_Int16 aRole)
47 : WeakComponentImplHelper(m_aMutex),
48 mxParent(std::move(xParent)),
49 meDescriptionOrigin(NotSet),
50 meNameOrigin(NotSet),
51 mnClientId(0),
52 maRole(aRole)
53{
54 // Create the state set.
55 mnStateSet = 0;
56
57 // Set some states. Don't use the SetState method because no events
58 // shall be broadcasted (that is not yet initialized anyway).
59 mnStateSet |= AccessibleStateType::ENABLED;
60 mnStateSet |= AccessibleStateType::SENSITIVE;
61 mnStateSet |= AccessibleStateType::SHOWING;
62 mnStateSet |= AccessibleStateType::VISIBLE;
63 mnStateSet |= AccessibleStateType::FOCUSABLE;
64 mnStateSet |= AccessibleStateType::SELECTABLE;
65
66 // Create the relation set.
67 mxRelationSet = new ::utl::AccessibleRelationSetHelper ();
68}
69
71{
72}
73
74bool AccessibleContextBase::SetState (sal_Int64 aState)
75{
76 ::osl::ClearableMutexGuard aGuard (m_aMutex);
77 if (!(mnStateSet & aState))
78 {
79 mnStateSet |= aState;
80 // Clear the mutex guard so that it is not locked during calls to
81 // listeners.
82 aGuard.clear();
83
84 // Send event for all states except the DEFUNC state.
85 if (aState != AccessibleStateType::DEFUNC)
86 {
87 uno::Any aNewValue;
88 aNewValue <<= aState;
90 AccessibleEventId::STATE_CHANGED,
91 aNewValue,
92 uno::Any(), -1);
93 }
94 return true;
95 }
96 else
97 return false;
98}
99
100
102{
103 ::osl::ClearableMutexGuard aGuard (m_aMutex);
104 if (mnStateSet & aState)
105 {
106 mnStateSet &= ~aState;
107 // Clear the mutex guard so that it is not locked during calls to listeners.
108 aGuard.clear();
109
110 uno::Any aOldValue;
111 aOldValue <<= aState;
113 AccessibleEventId::STATE_CHANGED,
114 uno::Any(),
115 aOldValue, -1);
116 return true;
117 }
118 else
119 return false;
120}
121
122
123bool AccessibleContextBase::GetState (sal_Int64 aState)
124{
125 ::osl::MutexGuard aGuard (m_aMutex);
126 return mnStateSet & aState;
127}
128
129
131 const uno::Reference<XAccessibleRelationSet>& rxNewRelationSet)
132{
133 // Try to emit some meaningful events indicating differing relations in
134 // both sets.
135 typedef std::pair<short int,short int> RD;
136 const RD aRelationDescriptors[] = {
137 RD(AccessibleRelationType::CONTROLLED_BY, AccessibleEventId::CONTROLLED_BY_RELATION_CHANGED),
138 RD(AccessibleRelationType::CONTROLLER_FOR, AccessibleEventId::CONTROLLER_FOR_RELATION_CHANGED),
139 RD(AccessibleRelationType::LABELED_BY, AccessibleEventId::LABELED_BY_RELATION_CHANGED),
140 RD(AccessibleRelationType::LABEL_FOR, AccessibleEventId::LABEL_FOR_RELATION_CHANGED),
141 RD(AccessibleRelationType::MEMBER_OF, AccessibleEventId::MEMBER_OF_RELATION_CHANGED),
142 RD(AccessibleRelationType::INVALID, -1),
143 };
144 for (int i=0; aRelationDescriptors[i].first!=AccessibleRelationType::INVALID; i++)
145 if (mxRelationSet->containsRelation(aRelationDescriptors[i].first)
146 != rxNewRelationSet->containsRelation(aRelationDescriptors[i].first))
147 CommitChange (aRelationDescriptors[i].second, uno::Any(), uno::Any(), -1);
148
149 mxRelationSet = rxNewRelationSet;
150}
151
152
153// XAccessible
154
155uno::Reference< XAccessibleContext> SAL_CALL
157{
158 return this;
159}
160
161
162// XAccessibleContext
163
166sal_Int64 SAL_CALL
168{
169 return 0;
170}
171
172
176uno::Reference<XAccessible> SAL_CALL
178{
180 throw lang::IndexOutOfBoundsException (
181 "no child with index " + OUString::number(nIndex),
182 nullptr);
183}
184
185
186uno::Reference<XAccessible> SAL_CALL
188{
190 return mxParent;
191}
192
193
194sal_Int64 SAL_CALL
196{
198 // Use a simple but slow solution for now. Optimize later.
199
200 // Iterate over all the parent's children and search for this object.
201 if (!mxParent.is())
202 // Return -1 to indicate that this object's parent does not know about the
203 // object.
204 return -1;
205
206 uno::Reference<XAccessibleContext> xParentContext (
207 mxParent->getAccessibleContext());
208 if (xParentContext.is())
209 {
210 sal_Int64 nChildCount = xParentContext->getAccessibleChildCount();
211 for (sal_Int64 i=0; i<nChildCount; i++)
212 {
213 uno::Reference<XAccessible> xChild (xParentContext->getAccessibleChild (i));
214 if (xChild.is())
215 {
216 uno::Reference<XAccessibleContext> xChildContext = xChild->getAccessibleContext();
217 if (xChildContext == static_cast<XAccessibleContext*>(this))
218 return i;
219 }
220 }
221 }
222
223 // Return -1 to indicate that this object's parent does not know about the
224 // object.
225 return -1;
226}
227
228
229sal_Int16 SAL_CALL
231{
233 return maRole;
234}
235
236
237OUString SAL_CALL
239{
241
242 return msDescription;
243}
244
245
246OUString SAL_CALL
248{
250
251 if (meNameOrigin == NotSet)
252 {
253 // Do not send an event because this is the first time it has been
254 // requested.
257 }
258
259 return msName;
260}
261
262
265uno::Reference<XAccessibleRelationSet> SAL_CALL
267{
269
270 // Create a copy of the relation set and return it.
272 static_cast< ::utl::AccessibleRelationSetHelper*>(mxRelationSet.get());
273 if (pRelationSet != nullptr)
274 {
275 return uno::Reference<XAccessibleRelationSet> (
276 new ::utl::AccessibleRelationSetHelper (*pRelationSet));
277 }
278 else
279 return uno::Reference<XAccessibleRelationSet>(nullptr);
280}
281
282
289sal_Int64 SAL_CALL
291{
292 if (rBHelper.bDisposed)
293 {
294 // We are already disposed!
295 // Create a new state set that has only set the DEFUNC state.
296 return AccessibleStateType::DEFUNC;
297 }
298 else
299 {
300 return mnStateSet;
301 }
302}
303
304
305lang::Locale SAL_CALL
307{
309 // Delegate request to parent.
310 if (mxParent.is())
311 {
312 uno::Reference<XAccessibleContext> xParentContext (
313 mxParent->getAccessibleContext());
314 if (xParentContext.is())
315 return xParentContext->getLocale ();
316 }
317
318 // No locale and no parent. Therefore throw exception to indicate this
319 // cluelessness.
320 throw IllegalAccessibleComponentStateException ();
321}
322
323
324// XAccessibleEventListener
325
327 const uno::Reference<XAccessibleEventListener >& rxListener)
328{
329 if (!rxListener.is())
330 return;
331
332 if (rBHelper.bDisposed || rBHelper.bInDispose)
333 {
334 uno::Reference<uno::XInterface> x (static_cast<lang::XComponent *>(this), uno::UNO_QUERY);
335 rxListener->disposing (lang::EventObject (x));
336 }
337 else
338 {
339 if (!mnClientId)
342 }
343}
344
345
347 const uno::Reference<XAccessibleEventListener >& rxListener )
348{
350 if (!(rxListener.is() && mnClientId))
351 return;
352
353 sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( mnClientId, rxListener );
354 if ( !nListenerCount )
355 {
356 // no listeners anymore
357 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
358 // and at least to us not firing any events anymore, in case somebody calls
359 // NotifyAccessibleEvent, again
361 mnClientId = 0;
362 }
363}
364
365// XServiceInfo
367{
368 return "AccessibleContextBase";
369}
370
371sal_Bool SAL_CALL AccessibleContextBase::supportsService (const OUString& sServiceName)
372{
374}
375
376uno::Sequence< OUString > SAL_CALL
378{
379 return {
380 "com.sun.star.accessibility.Accessible",
381 "com.sun.star.accessibility.AccessibleContext"};
382}
383
384
385// XTypeProvider
386
387uno::Sequence<sal_Int8> SAL_CALL
389{
390 return css::uno::Sequence<sal_Int8>();
391}
392
393// internal
394
396{
397 SetState (AccessibleStateType::DEFUNC);
398
399 ::osl::MutexGuard aGuard (m_aMutex);
400
401 // Send a disposing to all listeners.
402 if ( mnClientId )
403 {
405 mnClientId = 0;
406 }
407 mxParent.clear();
408 mxRelationSet.clear();
409}
410
411
413 const OUString& rDescription,
414 StringOrigin eDescriptionOrigin)
415{
416 if (!(eDescriptionOrigin < meDescriptionOrigin
417 || (eDescriptionOrigin == meDescriptionOrigin && msDescription != rDescription)))
418 return;
419
420 uno::Any aOldValue, aNewValue;
421 aOldValue <<= msDescription;
422 aNewValue <<= rDescription;
423
424 msDescription = rDescription;
425 meDescriptionOrigin = eDescriptionOrigin;
426
428 AccessibleEventId::DESCRIPTION_CHANGED,
429 aNewValue,
430 aOldValue, -1);
431}
432
433
435 const OUString& rName,
436 StringOrigin eNameOrigin)
437{
438 if (!(eNameOrigin < meNameOrigin
439 || (eNameOrigin == meNameOrigin && msName != rName)))
440 return;
441
442 uno::Any aOldValue, aNewValue;
443 aOldValue <<= msName;
444 aNewValue <<= rName;
445
446 msName = rName;
447 meNameOrigin = eNameOrigin;
448
450 AccessibleEventId::NAME_CHANGED,
451 aNewValue,
452 aOldValue, -1);
453}
454
455
457{
458 return "Empty Name";
459}
460
461
463 sal_Int16 nEventId,
464 const uno::Any& rNewValue,
465 const uno::Any& rOldValue,
466 sal_Int32 nValueIndex)
467{
468 // Do not call FireEvent and do not even create the event object when no
469 // listener has been registered yet. Creating the event object can
470 // otherwise lead to a crash. See issue 93419 for details.
471 if (mnClientId != 0)
472 {
473 AccessibleEventObject aEvent (
474 static_cast<XAccessibleContext*>(this),
475 nEventId,
476 rNewValue,
477 rOldValue,
478 nValueIndex);
479
481 }
482}
483
484
485void AccessibleContextBase::FireEvent (const AccessibleEventObject& aEvent)
486{
487 if (mnClientId)
489}
490
491
493{
494 if (rBHelper.bDisposed || rBHelper.bInDispose)
495 {
496 throw lang::DisposedException ("object has been already disposed",
497 getXWeak());
498 }
499}
500
501
503{
504 return (rBHelper.bDisposed || rBHelper.bInDispose);
505}
506
507
509{
510 maRole = _nRole;
511}
512
513
514} // end of namespace accessibility
515
516/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
constexpr OUStringLiteral sServiceName
unotools::WeakReference< AnimationNode > mxParent
AnyEventRef aEvent
virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override
Returns an implementation id.
StringOrigin
The origin of the accessible name or description.
virtual OUString SAL_CALL getAccessibleDescription() override
Return this object's description.
virtual bool SetState(sal_Int64 aState)
Set the specified state (turn it on) and send events to all listeners to inform them of the change.
virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext() override
Return the XAccessibleContext.
void ThrowIfDisposed()
Check whether or not the object has been disposed (or is in the state of being disposed).
sal_Int16 maRole
This is the role of this object.
virtual sal_Int64 SAL_CALL getAccessibleStateSet() override
Return the set of current states.
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
Returns a list of all supported services.
virtual bool ResetState(sal_Int64 aState)
Reset the specified state (turn it off) and send events to all listeners to inform them of the change...
StringOrigin meNameOrigin
The origin of the name is used to determine whether new name given to the SetAccessibleName is ignore...
css::uno::Reference< css::accessibility::XAccessible > mxParent
Reference to the parent object.
void FireEvent(const css::accessibility::AccessibleEventObject &aEvent)
virtual sal_Bool SAL_CALL supportsService(const OUString &sServiceName) override
Return whether the specified service is supported by this class.
virtual void SAL_CALL removeAccessibleEventListener(const css::uno::Reference< css::accessibility::XAccessibleEventListener > &xListener) override
css::uno::Reference< css::accessibility::XAccessibleRelationSet > mxRelationSet
The relation set.
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild(sal_Int64 nIndex) override
Return the specified child or throw exception.
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent() override
Return a reference to the parent.
void CommitChange(sal_Int16 aEventId, const css::uno::Any &rNewValue, const css::uno::Any &rOldValue, sal_Int32 nValueIndex)
Call all accessibility event listeners to inform them about the specified event.
virtual void SAL_CALL addAccessibleEventListener(const css::uno::Reference< css::accessibility::XAccessibleEventListener > &xListener) override
AccessibleContextBase(css::uno::Reference< css::accessibility::XAccessible > xParent, const sal_Int16 aRole)
bool IsDisposed() const
Check whether or not the object has been disposed (or is in the state of being disposed).
virtual css::lang::Locale SAL_CALL getLocale() override
Return the parents locale or throw exception if this object has no parent yet/anymore.
virtual OUString CreateAccessibleName()
Create the accessible object's name.
OUString msDescription
Description of this object.
sal_uInt32 mnClientId
client id in the AccessibleEventNotifier queue
void SetAccessibleRole(sal_Int16 _nRole)
sets the role as returned by XaccessibleContext::getAccessibleRole
bool GetState(sal_Int64 aState)
Return the state of the specified state.
virtual void SAL_CALL disposing() override
virtual sal_Int64 SAL_CALL getAccessibleChildCount() override
Return the number of currently visible children.
virtual sal_Int64 SAL_CALL getAccessibleIndexInParent() override
Return this objects index among the parents children.
void SetAccessibleDescription(const OUString &rsDescription, StringOrigin eDescriptionOrigin)
Set a new description and, provided that the new name differs from the old one, broadcast an accessib...
void SetAccessibleName(const OUString &rsName, StringOrigin eNameOrigin)
Set a new description and, provided that the new name differs from the old one, broadcast an accessib...
virtual OUString SAL_CALL getAccessibleName() override
Return the object's current name.
virtual sal_Int16 SAL_CALL getAccessibleRole() override
Return this object's role.
void SetRelationSet(const css::uno::Reference< css::accessibility::XAccessibleRelationSet > &rxRelationSet)
Replace the current relation set with the specified one.
StringOrigin meDescriptionOrigin
The origin of the description is used to determine whether new descriptions given to the SetAccessibl...
virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet() override
Return NULL to indicate that an empty relation set.
virtual OUString SAL_CALL getImplementationName() override
Returns an identifier for the implementation of this object.
static sal_Int32 addEventListener(const TClientId _nClient, const css::uno::Reference< css::accessibility::XAccessibleEventListener > &_rxListener)
static void addEvent(const TClientId _nClient, const css::accessibility::AccessibleEventObject &_rEvent)
static sal_Int32 removeEventListener(const TClientId _nClient, const css::uno::Reference< css::accessibility::XAccessibleEventListener > &_rxListener)
static void revokeClient(const TClientId _nClient)
static void revokeClientNotifyDisposing(const TClientId _nClient, const css::uno::Reference< css::uno::XInterface > &_rxEventSource)
mutable::osl::Mutex m_aMutex
float x
std::mutex m_aMutex
sal_Int32 nIndex
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
int i
unsigned char sal_Bool