Coverage Report

Created: 2026-08-14 10:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/vcl/source/accessibility/vclxaccessiblelistitem.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 <accessibility/vclxaccessiblelistitem.hxx>
21
#include <accessibility/IComboListBoxHelper.hxx>
22
#include <com/sun/star/awt/Rectangle.hpp>
23
24
#include <com/sun/star/accessibility/AccessibleEventId.hpp>
25
#include <com/sun/star/accessibility/AccessibleRole.hpp>
26
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
27
#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
28
#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
29
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
30
#include <cppuhelper/supportsservice.hxx>
31
#include <utility>
32
#include <vcl/svapp.hxx>
33
#include <vcl/toolkit/lstbox.hxx>
34
#include <vcl/unohelp.hxx>
35
#include <vcl/unohelp2.hxx>
36
#include <vcl/settings.hxx>
37
#include <unotools/accessiblerelationsethelper.hxx>
38
#include <i18nlangtag/languagetag.hxx>
39
40
namespace
41
{
42
    /// @throws css::lang::IndexOutOfBoundsException
43
    void checkIndex_Impl( sal_Int32 _nIndex, std::u16string_view _sText )
44
0
    {
45
0
        if ( _nIndex < 0 || _nIndex > static_cast<sal_Int32>(_sText.size()) )
46
0
            throw css::lang::IndexOutOfBoundsException();
47
0
    }
48
}
49
50
// class VCLXAccessibleListItem ------------------------------------------
51
52
using namespace ::com::sun::star::accessibility;
53
using namespace ::com::sun::star::uno;
54
using namespace ::com::sun::star::beans;
55
using namespace ::com::sun::star::lang;
56
using namespace ::com::sun::star;
57
58
59
// Ctor() and Dtor()
60
61
VCLXAccessibleListItem::VCLXAccessibleListItem(sal_Int32 _nIndexInParent,
62
                                               rtl::Reference<VCLXAccessibleList> _xParent)
63
0
    : m_nIndexInParent(_nIndexInParent)
64
0
    , m_bSelected(false)
65
0
    , m_bVisible(false)
66
0
    , m_xParent(std::move(_xParent))
67
0
{
68
0
    assert(m_xParent.is());
69
0
    IComboListBoxHelper* pListBoxHelper = m_xParent->getListBoxHelper();
70
0
    if (pListBoxHelper)
71
0
        m_sEntryText = pListBoxHelper->GetEntry(_nIndexInParent);
72
0
}
73
74
void VCLXAccessibleListItem::SetSelected( bool _bSelected )
75
0
{
76
0
    if ( m_bSelected != _bSelected )
77
0
    {
78
0
        Any aOldValue;
79
0
        Any aNewValue;
80
0
        if ( m_bSelected )
81
0
            aOldValue <<= AccessibleStateType::SELECTED;
82
0
        else
83
0
            aNewValue <<= AccessibleStateType::SELECTED;
84
0
        m_bSelected = _bSelected;
85
0
        NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
86
0
    }
87
0
}
88
89
void VCLXAccessibleListItem::SetVisible( bool _bVisible )
90
0
{
91
0
    if ( m_bVisible != _bVisible )
92
0
    {
93
0
        Any aOldValue, aNewValue;
94
0
        m_bVisible = _bVisible;
95
0
        (_bVisible ? aNewValue : aOldValue ) <<= AccessibleStateType::VISIBLE;
96
0
        NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
97
0
        (_bVisible ? aNewValue : aOldValue ) <<= AccessibleStateType::SHOWING;
98
0
        NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
99
0
    }
100
0
}
101
102
void VCLXAccessibleListItem::NotifyAccessibleEvent( sal_Int16 _nEventId,
103
                                                    const css::uno::Any& _aOldValue,
104
                                                    const css::uno::Any& _aNewValue )
105
0
{
106
0
    comphelper::OAccessible::NotifyAccessibleEvent(_nEventId, _aOldValue, _aNewValue);
107
0
}
108
109
// OCommonAccessibleText
110
111
OUString VCLXAccessibleListItem::implGetText()
112
0
{
113
0
    return m_sEntryText;
114
0
}
115
116
Locale VCLXAccessibleListItem::implGetLocale()
117
0
{
118
0
    return Application::GetSettings().GetLanguageTag().getLocale();
119
0
}
120
121
void VCLXAccessibleListItem::implGetSelection( sal_Int32& nStartIndex, sal_Int32& nEndIndex )
122
0
{
123
0
    nStartIndex = 0;
124
0
    nEndIndex = 0;
125
0
}
126
127
awt::Rectangle VCLXAccessibleListItem::implGetBounds()
128
0
{
129
0
    tools::Rectangle aRect;
130
0
    IComboListBoxHelper* pListBoxHelper = m_xParent.is() ? m_xParent->getListBoxHelper() : nullptr;
131
0
    if (pListBoxHelper)
132
0
    {
133
0
        aRect = pListBoxHelper->GetBoundingRectangle(m_nIndexInParent);
134
        // convert position relative to the combobox/listbox (parent's parent) to position relative
135
        // to direct parent by subtracting parent's relative position in the combobox/listbox
136
0
        aRect -= vcl::unohelper::ConvertToVCLPoint(m_xParent->getLocation());
137
0
    }
138
139
0
    return vcl::unohelper::ConvertToAWTRect(aRect);
140
0
}
141
142
// XComponent
143
144
void SAL_CALL VCLXAccessibleListItem::disposing()
145
0
{
146
0
    m_sEntryText.clear();
147
0
    m_xParent = nullptr;
148
149
0
    OAccessible::disposing();
150
0
}
151
152
// XServiceInfo
153
154
OUString VCLXAccessibleListItem::getImplementationName()
155
0
{
156
0
    return u"com.sun.star.comp.toolkit.AccessibleListItem"_ustr;
157
0
}
158
159
sal_Bool VCLXAccessibleListItem::supportsService( const OUString& rServiceName )
160
0
{
161
0
    return cppu::supportsService(this, rServiceName);
162
0
}
163
164
Sequence< OUString > VCLXAccessibleListItem::getSupportedServiceNames()
165
0
{
166
0
    return {u"com.sun.star.accessibility.AccessibleContext"_ustr};
167
0
}
168
169
// XAccessibleContext
170
171
sal_Int64 SAL_CALL VCLXAccessibleListItem::getAccessibleChildCount(  )
172
0
{
173
0
    return 0;
174
0
}
175
176
Reference< XAccessible > SAL_CALL VCLXAccessibleListItem::getAccessibleChild( sal_Int64 )
177
0
{
178
0
    return Reference< XAccessible >();
179
0
}
180
181
Reference< XAccessible > SAL_CALL VCLXAccessibleListItem::getAccessibleParent(  )
182
0
{
183
0
    SolarMutexGuard aSolarGuard;
184
185
0
    return m_xParent;
186
0
}
187
188
sal_Int64 SAL_CALL VCLXAccessibleListItem::getAccessibleIndexInParent(  )
189
0
{
190
0
    return m_nIndexInParent;
191
0
}
192
193
sal_Int16 SAL_CALL VCLXAccessibleListItem::getAccessibleRole(  )
194
0
{
195
0
    return AccessibleRole::LIST_ITEM;
196
    //  return AccessibleRole::LABEL;
197
0
}
198
199
OUString SAL_CALL VCLXAccessibleListItem::getAccessibleDescription(  )
200
0
{
201
    // no description for every item
202
0
    return OUString();
203
0
}
204
205
OUString SAL_CALL VCLXAccessibleListItem::getAccessibleName(  )
206
0
{
207
0
    SolarMutexGuard aSolarGuard;
208
209
    // entry text == accessible name
210
0
    return m_sEntryText;
211
0
}
212
213
Reference< XAccessibleRelationSet > SAL_CALL VCLXAccessibleListItem::getAccessibleRelationSet(  )
214
0
{
215
0
    return new utl::AccessibleRelationSetHelper;
216
0
}
217
218
sal_Int64 SAL_CALL VCLXAccessibleListItem::getAccessibleStateSet(  )
219
0
{
220
0
    SolarMutexGuard aSolarGuard;
221
222
0
    sal_Int64 nStateSet = 0;
223
224
0
    if (isAlive())
225
0
    {
226
0
        nStateSet |= AccessibleStateType::TRANSIENT;
227
228
0
        IComboListBoxHelper* pListBoxHelper = m_xParent.is() ? m_xParent->getListBoxHelper() : nullptr;
229
0
        if (pListBoxHelper && pListBoxHelper->IsEnabled())
230
0
        {
231
0
            nStateSet |= AccessibleStateType::SELECTABLE;
232
0
            nStateSet |= AccessibleStateType::ENABLED;
233
0
            nStateSet |= AccessibleStateType::SENSITIVE;
234
0
        }
235
236
0
        if ( m_bSelected )
237
0
            nStateSet |= AccessibleStateType::SELECTED;
238
0
        if ( m_bVisible )
239
0
        {
240
0
            nStateSet |= AccessibleStateType::VISIBLE;
241
0
            nStateSet |= AccessibleStateType::SHOWING;
242
0
        }
243
0
    }
244
0
    else
245
0
        nStateSet |= AccessibleStateType::DEFUNC;
246
247
0
    return nStateSet;
248
0
}
249
250
Locale SAL_CALL VCLXAccessibleListItem::getLocale(  )
251
0
{
252
0
    SolarMutexGuard aSolarGuard;
253
254
0
    return implGetLocale();
255
0
}
256
257
// XAccessibleComponent
258
259
Reference< XAccessible > SAL_CALL VCLXAccessibleListItem::getAccessibleAtPoint( const awt::Point& )
260
0
{
261
0
    return Reference< XAccessible >();
262
0
}
263
264
void SAL_CALL VCLXAccessibleListItem::grabFocus(  )
265
0
{
266
    // no focus for each item
267
0
}
268
269
// XAccessibleText
270
271
sal_Int32 SAL_CALL VCLXAccessibleListItem::getCaretPosition()
272
0
{
273
0
    return -1;
274
0
}
275
276
sal_Bool SAL_CALL VCLXAccessibleListItem::setCaretPosition( sal_Int32 nIndex )
277
0
{
278
0
    SolarMutexGuard aSolarGuard;
279
280
0
    if ( !implIsValidRange( nIndex, nIndex, m_sEntryText.getLength() ) )
281
0
        throw IndexOutOfBoundsException();
282
283
0
    return false;
284
0
}
285
286
sal_Unicode SAL_CALL VCLXAccessibleListItem::getCharacter( sal_Int32 nIndex )
287
0
{
288
0
    SolarMutexGuard aSolarGuard;
289
290
0
    return OCommonAccessibleText::implGetCharacter( m_sEntryText, nIndex );
291
0
}
292
293
Sequence< PropertyValue > SAL_CALL VCLXAccessibleListItem::getCharacterAttributes( sal_Int32 nIndex, const Sequence< OUString >& )
294
0
{
295
0
    SolarMutexGuard aSolarGuard;
296
297
0
    if ( !implIsValidIndex( nIndex, m_sEntryText.getLength() ) )
298
0
        throw IndexOutOfBoundsException();
299
300
0
    return Sequence< PropertyValue >();
301
0
}
302
303
awt::Rectangle SAL_CALL VCLXAccessibleListItem::getCharacterBounds( sal_Int32 nIndex )
304
0
{
305
0
    SolarMutexGuard aSolarGuard;
306
307
0
    if ( !implIsValidIndex( nIndex, m_sEntryText.getLength() ) )
308
0
        throw IndexOutOfBoundsException();
309
310
0
    awt::Rectangle aBounds( 0, 0, 0, 0 );
311
0
    IComboListBoxHelper* pListBoxHelper = m_xParent.is() ? m_xParent->getListBoxHelper() : nullptr;
312
0
    if (pListBoxHelper)
313
0
    {
314
0
        tools::Rectangle aCharRect = pListBoxHelper->GetEntryCharacterBounds( m_nIndexInParent, nIndex );
315
0
        tools::Rectangle aItemRect = pListBoxHelper->GetBoundingRectangle(m_nIndexInParent);
316
0
        aCharRect.Move( -aItemRect.Left(), -aItemRect.Top() );
317
0
        aBounds = vcl::unohelper::ConvertToAWTRect(aCharRect);
318
0
    }
319
320
0
    return aBounds;
321
0
}
322
323
sal_Int32 SAL_CALL VCLXAccessibleListItem::getCharacterCount()
324
0
{
325
0
    SolarMutexGuard aSolarGuard;
326
327
0
    return m_sEntryText.getLength();
328
0
}
329
330
sal_Int32 SAL_CALL VCLXAccessibleListItem::getIndexAtPoint( const awt::Point& aPoint )
331
0
{
332
0
    SolarMutexGuard aSolarGuard;
333
334
0
    sal_Int32 nIndex = -1;
335
0
    IComboListBoxHelper* pListBoxHelper = m_xParent.is() ? m_xParent->getListBoxHelper() : nullptr;
336
0
    if (pListBoxHelper)
337
0
    {
338
0
        sal_Int32 nPos = LISTBOX_ENTRY_NOTFOUND;
339
0
        tools::Rectangle aItemRect = pListBoxHelper->GetBoundingRectangle(m_nIndexInParent);
340
0
        Point aPnt(vcl::unohelper::ConvertToVCLPoint(aPoint));
341
0
        aPnt += aItemRect.TopLeft();
342
0
        sal_Int32 nI = pListBoxHelper->GetIndexForPoint( aPnt, nPos );
343
0
        if ( nI != -1 && m_nIndexInParent == nPos )
344
0
            nIndex = nI;
345
0
    }
346
0
    return nIndex;
347
0
}
348
349
OUString SAL_CALL VCLXAccessibleListItem::getSelectedText()
350
0
{
351
0
    return OUString();
352
0
}
353
354
sal_Int32 SAL_CALL VCLXAccessibleListItem::getSelectionStart()
355
0
{
356
0
    return 0;
357
0
}
358
359
sal_Int32 SAL_CALL VCLXAccessibleListItem::getSelectionEnd()
360
0
{
361
0
    return 0;
362
0
}
363
364
sal_Bool SAL_CALL VCLXAccessibleListItem::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
365
0
{
366
0
    SolarMutexGuard aSolarGuard;
367
368
0
    if ( !implIsValidRange( nStartIndex, nEndIndex, m_sEntryText.getLength() ) )
369
0
        throw IndexOutOfBoundsException();
370
371
0
    return false;
372
0
}
373
374
OUString SAL_CALL VCLXAccessibleListItem::getText()
375
0
{
376
0
    SolarMutexGuard aSolarGuard;
377
378
0
    return m_sEntryText;
379
0
}
380
381
OUString VCLXAccessibleListItem::getTextRangeImpl(sal_Int32 nStartIndex, sal_Int32 nEndIndex)
382
0
{
383
0
    return OCommonAccessibleText::implGetTextRange(m_sEntryText, nStartIndex, nEndIndex);
384
0
}
385
386
OUString SAL_CALL VCLXAccessibleListItem::getTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
387
0
{
388
0
    SolarMutexGuard aSolarGuard;
389
390
0
    return getTextRangeImpl(nStartIndex, nEndIndex);
391
0
}
392
393
css::accessibility::TextSegment SAL_CALL VCLXAccessibleListItem::getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType )
394
0
{
395
0
    SolarMutexGuard aSolarGuard;
396
397
0
    return OCommonAccessibleText::getTextAtIndex( nIndex, aTextType );
398
0
}
399
400
css::accessibility::TextSegment SAL_CALL VCLXAccessibleListItem::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType )
401
0
{
402
0
    SolarMutexGuard aSolarGuard;
403
404
0
    return OCommonAccessibleText::getTextBeforeIndex( nIndex, aTextType );
405
0
}
406
407
css::accessibility::TextSegment SAL_CALL VCLXAccessibleListItem::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType )
408
0
{
409
0
    SolarMutexGuard aSolarGuard;
410
411
0
    return OCommonAccessibleText::getTextBehindIndex( nIndex, aTextType );
412
0
}
413
414
sal_Bool SAL_CALL VCLXAccessibleListItem::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
415
0
{
416
0
    SolarMutexGuard aSolarGuard;
417
418
0
    checkIndex_Impl( nStartIndex, m_sEntryText );
419
0
    checkIndex_Impl( nEndIndex, m_sEntryText );
420
421
0
    bool bRet = false;
422
0
    IComboListBoxHelper* pListBoxHelper = m_xParent.is() ? m_xParent->getListBoxHelper() : nullptr;
423
0
    if (pListBoxHelper)
424
0
    {
425
0
        Reference< datatransfer::clipboard::XClipboard > xClipboard = pListBoxHelper->GetClipboard();
426
0
        if ( xClipboard.is() )
427
0
        {
428
0
            OUString sText(getTextRangeImpl(nStartIndex, nEndIndex));
429
0
            rtl::Reference<vcl::unohelper::TextDataObject> pDataObj = new vcl::unohelper::TextDataObject( sText );
430
431
0
            SolarMutexReleaser aReleaser;
432
0
            xClipboard->setContents( pDataObj, nullptr );
433
0
            Reference< datatransfer::clipboard::XFlushableClipboard > xFlushableClipboard( xClipboard, uno::UNO_QUERY );
434
0
            if( xFlushableClipboard.is() )
435
0
                xFlushableClipboard->flushClipboard();
436
437
0
            bRet = true;
438
0
        }
439
0
    }
440
441
0
    return bRet;
442
0
}
443
444
sal_Bool VCLXAccessibleListItem::scrollSubstringTo( sal_Int32, sal_Int32, AccessibleScrollType )
445
0
{
446
0
    return false;
447
0
}
448
449
// AF (Oct. 29 2002): Return black as constant foreground color.  This is an
450
// initial implementation and has to be substituted by code that determines
451
// the color that is actually used.
452
sal_Int32 SAL_CALL VCLXAccessibleListItem::getForeground()
453
0
{
454
0
    return sal_Int32(COL_BLACK);
455
0
}
456
457
// AF (Oct. 29 2002): Return white as constant background color.  This is an
458
// initial implementation and has to be substituted by code that determines
459
// the color that is actually used.
460
sal_Int32 SAL_CALL VCLXAccessibleListItem::getBackground()
461
0
{
462
0
    return sal_Int32(COL_WHITE);
463
0
}
464
465
466
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */