Coverage Report

Created: 2026-08-14 10:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/editeng/source/accessibility/AccessibleContextBase.cxx
Line
Count
Source
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 <editeng/AccessibleContextBase.hxx>
21
22
#include <com/sun/star/accessibility/XAccessibleSelection.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
29
#include <unotools/accessiblerelationsethelper.hxx>
30
#include <cppuhelper/supportsservice.hxx>
31
#include <osl/mutex.hxx>
32
#include <rtl/ref.hxx>
33
#include <tools/color.hxx>
34
35
#include <utility>
36
37
using namespace ::com::sun::star;
38
using namespace ::com::sun::star::accessibility;
39
40
namespace accessibility {
41
42
// internal
43
44
AccessibleContextBase::AccessibleContextBase (
45
        uno::Reference<XAccessible> xParent,
46
        const sal_Int16 aRole)
47
0
    :   mxParent(std::move(xParent)),
48
0
        meDescriptionOrigin(NotSet),
49
0
        meNameOrigin(NotSet),
50
0
        maRole(aRole)
51
0
{
52
    // Create the state set.
53
0
    mnStateSet = 0;
54
55
    // Set some states.  Don't use the SetState method because no events
56
    // shall be broadcasted (that is not yet initialized anyway).
57
0
    mnStateSet |= AccessibleStateType::ENABLED;
58
0
    mnStateSet |= AccessibleStateType::SENSITIVE;
59
0
    mnStateSet |= AccessibleStateType::SHOWING;
60
0
    mnStateSet |= AccessibleStateType::VISIBLE;
61
0
    mnStateSet |= AccessibleStateType::FOCUSABLE;
62
0
    mnStateSet |= AccessibleStateType::SELECTABLE;
63
64
    // Create the relation set.
65
0
    mxRelationSet = new ::utl::AccessibleRelationSetHelper ();
66
0
}
67
68
AccessibleContextBase::~AccessibleContextBase()
69
0
{
70
0
}
71
72
bool AccessibleContextBase::SetState (sal_Int64 aState)
73
0
{
74
0
    ::osl::ClearableMutexGuard aGuard (m_aMutex);
75
0
    if (!(mnStateSet & aState))
76
0
    {
77
0
        mnStateSet |= aState;
78
        // Clear the mutex guard so that it is not locked during calls to
79
        // listeners.
80
0
        aGuard.clear();
81
82
        // Send event for all states except the DEFUNC state.
83
0
        if (aState != AccessibleStateType::DEFUNC)
84
0
        {
85
0
            uno::Any aNewValue;
86
0
            aNewValue <<= aState;
87
0
            CommitChange(
88
0
                AccessibleEventId::STATE_CHANGED,
89
0
                aNewValue,
90
0
                uno::Any(), -1);
91
0
        }
92
0
        return true;
93
0
    }
94
0
    else
95
0
        return false;
96
0
}
97
98
99
bool AccessibleContextBase::ResetState (sal_Int64 aState)
100
0
{
101
0
    ::osl::ClearableMutexGuard aGuard (m_aMutex);
102
0
    if (mnStateSet & aState)
103
0
    {
104
0
        mnStateSet &= ~aState;
105
        // Clear the mutex guard so that it is not locked during calls to listeners.
106
0
        aGuard.clear();
107
108
0
        uno::Any aOldValue;
109
0
        aOldValue <<= aState;
110
0
        CommitChange(
111
0
            AccessibleEventId::STATE_CHANGED,
112
0
            uno::Any(),
113
0
            aOldValue, -1);
114
0
        return true;
115
0
    }
116
0
    else
117
0
        return false;
118
0
}
119
120
121
bool AccessibleContextBase::GetState (sal_Int64 aState)
122
0
{
123
0
    ::osl::MutexGuard aGuard (m_aMutex);
124
0
    return mnStateSet & aState;
125
0
}
126
127
128
void AccessibleContextBase::SetRelationSet (
129
    const rtl::Reference<utl::AccessibleRelationSetHelper>& rxNewRelationSet)
130
0
{
131
    // Try to emit some meaningful events indicating differing relations in
132
    // both sets.
133
0
    const std::pair<AccessibleRelationType, short int> aRelationDescriptors[] = {
134
0
        { AccessibleRelationType_CONTROLLED_BY, AccessibleEventId::CONTROLLED_BY_RELATION_CHANGED },
135
0
        { AccessibleRelationType_CONTROLLER_FOR, AccessibleEventId::CONTROLLER_FOR_RELATION_CHANGED },
136
0
        { AccessibleRelationType_LABELED_BY, AccessibleEventId::LABELED_BY_RELATION_CHANGED },
137
0
        { AccessibleRelationType_LABEL_FOR, AccessibleEventId::LABEL_FOR_RELATION_CHANGED },
138
0
        { AccessibleRelationType_MEMBER_OF, AccessibleEventId::MEMBER_OF_RELATION_CHANGED },
139
0
    };
140
0
    for (const std::pair<AccessibleRelationType, short int>& rPair : aRelationDescriptors)
141
0
    {
142
0
        if (mxRelationSet->containsRelation(rPair.first)
143
0
            != rxNewRelationSet->containsRelation(rPair.first))
144
0
            CommitChange(rPair.second, uno::Any(), uno::Any(), -1);
145
0
    }
146
147
0
    mxRelationSet = rxNewRelationSet;
148
0
}
149
150
// XAccessibleContext
151
152
/** No children.
153
*/
154
sal_Int64 SAL_CALL
155
       AccessibleContextBase::getAccessibleChildCount()
156
0
{
157
0
    return 0;
158
0
}
159
160
161
/** Forward the request to the shape.  Return the requested shape or throw
162
    an exception for a wrong index.
163
*/
164
uno::Reference<XAccessible> SAL_CALL
165
    AccessibleContextBase::getAccessibleChild (sal_Int64 nIndex)
166
0
{
167
0
    ensureAlive();
168
0
    throw lang::IndexOutOfBoundsException (
169
0
        "no child with index " + OUString::number(nIndex),
170
0
        nullptr);
171
0
}
172
173
174
uno::Reference<XAccessible> SAL_CALL
175
       AccessibleContextBase::getAccessibleParent()
176
0
{
177
0
    ensureAlive();
178
0
    return mxParent;
179
0
}
180
181
sal_Int16 SAL_CALL
182
    AccessibleContextBase::getAccessibleRole()
183
0
{
184
0
    ensureAlive();
185
0
    return maRole;
186
0
}
187
188
189
OUString SAL_CALL
190
       AccessibleContextBase::getAccessibleDescription()
191
0
{
192
0
    ensureAlive();
193
194
0
    return msDescription;
195
0
}
196
197
198
OUString SAL_CALL
199
       AccessibleContextBase::getAccessibleName()
200
0
{
201
0
    ensureAlive();
202
203
0
    if (meNameOrigin == NotSet)
204
0
    {
205
        // Do not send an event because this is the first time it has been
206
        // requested.
207
0
        msName = CreateAccessibleName();
208
0
        meNameOrigin = AutomaticallyCreated;
209
0
    }
210
211
0
    return msName;
212
0
}
213
214
215
/** Return a copy of the relation set.
216
*/
217
uno::Reference<XAccessibleRelationSet> SAL_CALL
218
       AccessibleContextBase::getAccessibleRelationSet()
219
0
{
220
0
    ensureAlive();
221
222
    // Create a copy of the relation set and return it.
223
0
    if (mxRelationSet)
224
0
    {
225
0
        return mxRelationSet->Clone();
226
0
    }
227
0
    else
228
0
        return uno::Reference<XAccessibleRelationSet>(nullptr);
229
0
}
230
231
232
/** Return a copy of the state set.
233
    Possible states are:
234
        ENABLED
235
        SHOWING
236
        VISIBLE
237
*/
238
sal_Int64 SAL_CALL
239
    AccessibleContextBase::getAccessibleStateSet()
240
0
{
241
0
    if (rBHelper.bDisposed)
242
0
    {
243
        // We are already disposed!
244
        // Create a new state set that has only set the DEFUNC state.
245
0
        return AccessibleStateType::DEFUNC;
246
0
    }
247
0
    else
248
0
    {
249
0
        return mnStateSet;
250
0
    }
251
0
}
252
253
254
lang::Locale SAL_CALL
255
       AccessibleContextBase::getLocale()
256
0
{
257
0
    ensureAlive();
258
    // Delegate request to parent.
259
0
    if (mxParent.is())
260
0
    {
261
0
        uno::Reference<XAccessibleContext> xParentContext (
262
0
            mxParent->getAccessibleContext());
263
0
        if (xParentContext.is())
264
0
            return xParentContext->getLocale ();
265
0
    }
266
267
    //  No locale and no parent.  Therefore throw exception to indicate this
268
    //  cluelessness.
269
0
    throw IllegalAccessibleComponentStateException ();
270
0
}
271
272
// XAccessibleComponent
273
274
uno::Reference<XAccessible > SAL_CALL
275
AccessibleContextBase::getAccessibleAtPoint (
276
    const awt::Point& /*aPoint*/)
277
0
{
278
0
    return uno::Reference<XAccessible>();
279
0
}
280
281
void SAL_CALL AccessibleContextBase::grabFocus()
282
0
{
283
0
    uno::Reference<XAccessibleSelection> xSelection(getAccessibleParent(), uno::UNO_QUERY);
284
0
    if (xSelection.is())
285
0
    {
286
        // Do a single selection on this object.
287
0
        xSelection->clearAccessibleSelection();
288
0
        xSelection->selectAccessibleChild (getAccessibleIndexInParent());
289
0
    }
290
0
}
291
292
293
sal_Int32 SAL_CALL AccessibleContextBase::getForeground()
294
0
{
295
0
    return sal_Int32(COL_BLACK);
296
0
}
297
298
299
sal_Int32 SAL_CALL AccessibleContextBase::getBackground()
300
0
{
301
0
    return sal_Int32(COL_WHITE);
302
0
}
303
304
// XServiceInfo
305
OUString SAL_CALL AccessibleContextBase::getImplementationName()
306
0
{
307
0
    return u"AccessibleContextBase"_ustr;
308
0
}
309
310
sal_Bool SAL_CALL AccessibleContextBase::supportsService (const OUString& sServiceName)
311
0
{
312
0
    return cppu::supportsService(this, sServiceName);
313
0
}
314
315
uno::Sequence< OUString > SAL_CALL
316
       AccessibleContextBase::getSupportedServiceNames()
317
0
{
318
0
    return {
319
0
        u"com.sun.star.accessibility.AccessibleContext"_ustr};
320
0
}
321
322
void SAL_CALL AccessibleContextBase::disposing()
323
0
{
324
0
    SetState (AccessibleStateType::DEFUNC);
325
326
0
    ::osl::MutexGuard aGuard (m_aMutex);
327
328
0
    comphelper::OAccessible::disposing();
329
330
0
    mxParent.clear();
331
0
    mxRelationSet.clear();
332
0
}
333
334
335
void AccessibleContextBase::SetAccessibleDescription (
336
    const OUString& rDescription,
337
    StringOrigin eDescriptionOrigin)
338
0
{
339
0
    if (!(eDescriptionOrigin < meDescriptionOrigin
340
0
        || (eDescriptionOrigin == meDescriptionOrigin && msDescription != rDescription)))
341
0
        return;
342
343
0
    uno::Any aOldValue, aNewValue;
344
0
    aOldValue <<= msDescription;
345
0
    aNewValue <<= rDescription;
346
347
0
    msDescription = rDescription;
348
0
    meDescriptionOrigin = eDescriptionOrigin;
349
350
0
    CommitChange(
351
0
        AccessibleEventId::DESCRIPTION_CHANGED,
352
0
        aNewValue,
353
0
        aOldValue, -1);
354
0
}
355
356
357
void AccessibleContextBase::SetAccessibleName (
358
    const OUString& rName,
359
    StringOrigin eNameOrigin)
360
0
{
361
0
    if (!(eNameOrigin < meNameOrigin
362
0
        || (eNameOrigin == meNameOrigin && msName != rName)))
363
0
        return;
364
365
0
    uno::Any aOldValue, aNewValue;
366
0
    aOldValue <<= msName;
367
0
    aNewValue <<= rName;
368
369
0
    msName = rName;
370
0
    meNameOrigin = eNameOrigin;
371
372
0
    CommitChange(
373
0
        AccessibleEventId::NAME_CHANGED,
374
0
        aNewValue,
375
0
        aOldValue, -1);
376
0
}
377
378
379
OUString AccessibleContextBase::CreateAccessibleName()
380
0
{
381
0
    return u"Empty Name"_ustr;
382
0
}
383
384
385
void AccessibleContextBase::CommitChange (
386
    sal_Int16 nEventId,
387
    const uno::Any& rNewValue,
388
    const uno::Any& rOldValue,
389
    sal_Int32 nValueIndex)
390
0
{
391
0
    NotifyAccessibleEvent(nEventId, rOldValue, rNewValue, nValueIndex);
392
0
}
393
394
bool AccessibleContextBase::IsDisposed() const
395
0
{
396
0
    return !isAlive();
397
0
}
398
399
400
void AccessibleContextBase::SetAccessibleRole( sal_Int16 _nRole )
401
0
{
402
0
    maRole = _nRole;
403
0
}
404
405
406
} // end of namespace accessibility
407
408
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */