Coverage Report

Created: 2026-04-09 11:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svtools/source/control/accessibletabbarpagelist.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 "accessibletabbarpagelist.hxx"
21
22
#include <svtools/tabbar.hxx>
23
#include <com/sun/star/accessibility/AccessibleEventId.hpp>
24
#include <com/sun/star/accessibility/AccessibleRole.hpp>
25
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
26
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
27
#include <comphelper/accessiblecontexthelper.hxx>
28
#include <cppuhelper/supportsservice.hxx>
29
#include <o3tl/safeint.hxx>
30
#include <unotools/accessiblerelationsethelper.hxx>
31
#include <vcl/svapp.hxx>
32
#include <vcl/settings.hxx>
33
#include <vcl/unohelp.hxx>
34
#include <vcl/vclevent.hxx>
35
#include <i18nlangtag/languagetag.hxx>
36
37
38
namespace accessibility
39
{
40
41
using namespace ::com::sun::star::accessibility;
42
using namespace ::com::sun::star::uno;
43
using namespace ::com::sun::star::lang;
44
using namespace ::com::sun::star;
45
using namespace ::comphelper;
46
47
48
AccessibleTabBarPageList::AccessibleTabBarPageList( TabBar* pTabBar, sal_Int32 nIndexInParent )
49
0
    :ImplInheritanceHelper( pTabBar )
50
0
    ,m_nIndexInParent( nIndexInParent )
51
0
{
52
0
    if ( m_pTabBar )
53
0
        m_aAccessibleChildren.assign( m_pTabBar->GetPageCount(), rtl::Reference< AccessibleTabBarPage >() );
54
0
}
55
56
57
void AccessibleTabBarPageList::UpdateShowing( bool bShowing )
58
0
{
59
0
    for (const rtl::Reference<AccessibleTabBarPage>& xChild : m_aAccessibleChildren)
60
0
    {
61
0
        if ( xChild.is() )
62
0
            xChild->SetShowing( bShowing );
63
0
    }
64
0
}
65
66
67
void AccessibleTabBarPageList::UpdateSelected( sal_Int32 i, bool bSelected )
68
0
{
69
0
    NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() );
70
71
0
    if ( i >= 0 && o3tl::make_unsigned(i) < m_aAccessibleChildren.size() )
72
0
    {
73
0
        rtl::Reference< AccessibleTabBarPage > xChild( m_aAccessibleChildren[i] );
74
0
        if ( xChild.is() )
75
0
            xChild->SetSelected( bSelected );
76
0
    }
77
0
}
78
79
80
void AccessibleTabBarPageList::UpdatePageText( sal_Int32 i )
81
0
{
82
0
    if ( i < 0 || o3tl::make_unsigned(i) >= m_aAccessibleChildren.size() )
83
0
        return;
84
85
0
    if ( m_pTabBar )
86
0
    {
87
0
        rtl::Reference< AccessibleTabBarPage > pAccessibleTabBarPage( m_aAccessibleChildren[i] );
88
0
        if ( pAccessibleTabBarPage.is() )
89
0
        {
90
0
            OUString sPageText = m_pTabBar->GetPageText( m_pTabBar->GetPageId( static_cast<sal_uInt16>(i) ) );
91
0
            pAccessibleTabBarPage->SetPageText( sPageText );
92
0
        }
93
0
    }
94
0
}
95
96
97
void AccessibleTabBarPageList::InsertChild( sal_Int32 i )
98
0
{
99
0
    if ( i < 0 || o3tl::make_unsigned(i) > m_aAccessibleChildren.size() )
100
0
        return;
101
102
    // insert entry in child list
103
0
    m_aAccessibleChildren.insert( m_aAccessibleChildren.begin() + i, rtl::Reference< AccessibleTabBarPage >() );
104
105
    // send accessible child event
106
0
    Reference< XAccessible > xChild( getAccessibleChild( i ) );
107
0
    if ( xChild.is() )
108
0
    {
109
0
        Any aOldValue, aNewValue;
110
0
        aNewValue <<= xChild;
111
0
        NotifyAccessibleEvent( AccessibleEventId::CHILD, aOldValue, aNewValue );
112
0
    }
113
0
}
114
115
116
void AccessibleTabBarPageList::RemoveChild( sal_Int32 i )
117
0
{
118
0
    if ( i < 0 || o3tl::make_unsigned(i) >= m_aAccessibleChildren.size() )
119
0
        return;
120
121
    // get the accessible of the removed page
122
0
    rtl::Reference< AccessibleTabBarPage > xChild( m_aAccessibleChildren[i] );
123
124
    // remove entry in child list
125
0
    m_aAccessibleChildren.erase( m_aAccessibleChildren.begin() + i );
126
127
    // send accessible child event
128
0
    if ( xChild.is() )
129
0
    {
130
0
        Any aOldValue, aNewValue;
131
0
        aOldValue <<= uno::Reference<XAccessible>(xChild);
132
0
        NotifyAccessibleEvent( AccessibleEventId::CHILD, aOldValue, aNewValue );
133
134
0
        xChild->dispose();
135
0
    }
136
0
}
137
138
139
void AccessibleTabBarPageList::MoveChild( sal_Int32 i, sal_Int32 j )
140
0
{
141
0
    if ( !(i >= 0 && o3tl::make_unsigned(i) < m_aAccessibleChildren.size() &&
142
0
         j >= 0 && o3tl::make_unsigned(j) <= m_aAccessibleChildren.size()) )
143
0
        return;
144
145
0
    if ( i < j )
146
0
        --j;
147
148
    // get the accessible of the moved page
149
0
    rtl::Reference< AccessibleTabBarPage > xChild( m_aAccessibleChildren[i] );
150
151
    // remove entry in child list at old position
152
0
    m_aAccessibleChildren.erase( m_aAccessibleChildren.begin() + i );
153
154
    // insert entry in child list at new position
155
0
    m_aAccessibleChildren.insert( m_aAccessibleChildren.begin() + j, xChild );
156
0
}
157
158
159
void AccessibleTabBarPageList::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
160
0
{
161
0
     switch ( rVclWindowEvent.GetId() )
162
0
     {
163
0
        case VclEventId::WindowEnabled:
164
0
        {
165
0
            Any aNewValue;
166
0
            aNewValue <<= AccessibleStateType::SENSITIVE;
167
0
            NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, Any(), aNewValue );
168
0
            aNewValue <<= AccessibleStateType::ENABLED;
169
0
            NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, Any(), aNewValue );
170
0
        }
171
0
        break;
172
0
        case VclEventId::WindowDisabled:
173
0
        {
174
0
            Any aOldValue;
175
0
            aOldValue <<= AccessibleStateType::ENABLED;
176
0
            NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, Any() );
177
0
            aOldValue <<= AccessibleStateType::SENSITIVE;
178
0
            NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, Any() );
179
0
        }
180
0
        break;
181
0
        case VclEventId::WindowShow:
182
0
        {
183
0
            Any aOldValue, aNewValue;
184
0
            aNewValue <<= AccessibleStateType::SHOWING;
185
0
            NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
186
0
            UpdateShowing( true );
187
0
        }
188
0
        break;
189
0
        case VclEventId::WindowHide:
190
0
        {
191
0
            Any aOldValue, aNewValue;
192
0
            aOldValue <<= AccessibleStateType::SHOWING;
193
0
            NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
194
0
            UpdateShowing( false );
195
0
        }
196
0
        break;
197
0
        case VclEventId::TabbarPageSelected:
198
0
        {
199
            // do nothing
200
0
        }
201
0
        break;
202
0
        case VclEventId::TabbarPageActivated:
203
0
        {
204
0
            if ( m_pTabBar )
205
0
            {
206
0
                sal_uInt16 nPageId = static_cast<sal_uInt16>(reinterpret_cast<sal_IntPtr>(rVclWindowEvent.GetData()));
207
0
                sal_uInt16 nPagePos = m_pTabBar->GetPagePos( nPageId );
208
0
                UpdateSelected( nPagePos, true );
209
0
            }
210
0
        }
211
0
        break;
212
0
        case VclEventId::TabbarPageDeactivated:
213
0
        {
214
0
            if ( m_pTabBar )
215
0
            {
216
0
                sal_uInt16 nPageId = static_cast<sal_uInt16>(reinterpret_cast<sal_IntPtr>(rVclWindowEvent.GetData()));
217
0
                sal_uInt16 nPagePos = m_pTabBar->GetPagePos( nPageId );
218
0
                UpdateSelected( nPagePos, false );
219
0
            }
220
0
        }
221
0
        break;
222
0
        case VclEventId::TabbarPageInserted:
223
0
        {
224
0
            if ( m_pTabBar )
225
0
            {
226
0
                sal_uInt16 nPageId = static_cast<sal_uInt16>(reinterpret_cast<sal_IntPtr>(rVclWindowEvent.GetData()));
227
0
                sal_uInt16 nPagePos = m_pTabBar->GetPagePos( nPageId );
228
0
                InsertChild( nPagePos );
229
0
            }
230
0
        }
231
0
        break;
232
0
        case VclEventId::TabbarPageRemoved:
233
0
        {
234
0
            if ( m_pTabBar )
235
0
            {
236
0
                sal_uInt16 nPageId = static_cast<sal_uInt16>(reinterpret_cast<sal_IntPtr>(rVclWindowEvent.GetData()));
237
238
0
                OExternalLockGuard aGuard( this );
239
240
0
                if ( nPageId == TabBar::PAGE_NOT_FOUND )
241
0
                {
242
0
                    for ( sal_Int32 i = m_aAccessibleChildren.size() - 1; i >= 0; --i )
243
0
                        RemoveChild( i );
244
0
                }
245
0
                else
246
0
                {
247
0
                    for ( sal_Int64 i = 0, nCount = m_aAccessibleChildren.size(); i < nCount; ++i )
248
0
                    {
249
0
                        sal_uInt16 nChildPageId = m_pTabBar->GetPageId( static_cast<sal_uInt16>(i) );
250
0
                        if (nPageId == nChildPageId)
251
0
                        {
252
0
                            RemoveChild( i );
253
0
                            break;
254
0
                        }
255
0
                    }
256
0
                }
257
0
            }
258
0
        }
259
0
        break;
260
0
        case VclEventId::TabbarPageMoved:
261
0
        {
262
0
            Pair* pPair = static_cast<Pair*>(rVclWindowEvent.GetData());
263
0
            if ( pPair )
264
0
                MoveChild( pPair->A(), pPair->B() );
265
0
        }
266
0
        break;
267
0
        case VclEventId::TabbarPageTextChanged:
268
0
        {
269
0
            sal_uInt16 nPageId = static_cast<sal_uInt16>(reinterpret_cast<sal_IntPtr>(rVclWindowEvent.GetData()));
270
0
            sal_uInt16 nPagePos = m_pTabBar->GetPagePos( nPageId );
271
0
            UpdatePageText( nPagePos );
272
0
        }
273
0
        break;
274
0
        default:
275
0
        {
276
0
            AccessibleTabBarBase::ProcessWindowEvent( rVclWindowEvent );
277
0
        }
278
0
        break;
279
0
    }
280
0
}
281
282
283
void AccessibleTabBarPageList::FillAccessibleStateSet( sal_Int64& rStateSet )
284
0
{
285
0
    if ( !m_pTabBar )
286
0
        return;
287
288
0
    if ( m_pTabBar->IsEnabled() )
289
0
    {
290
0
        rStateSet |= AccessibleStateType::ENABLED;
291
0
        rStateSet |= AccessibleStateType::SENSITIVE;
292
0
    }
293
294
0
    rStateSet |= AccessibleStateType::VISIBLE;
295
296
0
    if ( m_pTabBar->IsVisible() )
297
0
        rStateSet |= AccessibleStateType::SHOWING;
298
0
}
299
300
// OAccessible
301
302
awt::Rectangle AccessibleTabBarPageList::implGetBounds()
303
0
{
304
0
    awt::Rectangle aBounds;
305
0
    if ( m_pTabBar )
306
0
        aBounds = vcl::unohelper::ConvertToAWTRect(m_pTabBar->GetPageArea());
307
308
0
    return aBounds;
309
0
}
310
311
312
// XComponent
313
314
315
void AccessibleTabBarPageList::disposing()
316
0
{
317
0
    AccessibleTabBarBase::disposing();
318
319
    // dispose all children
320
0
    for (const rtl::Reference<AccessibleTabBarPage>& xComponent : m_aAccessibleChildren)
321
0
    {
322
0
        if ( xComponent.is() )
323
0
            xComponent->dispose();
324
0
    }
325
0
    m_aAccessibleChildren.clear();
326
0
}
327
328
329
// XServiceInfo
330
331
332
OUString AccessibleTabBarPageList::getImplementationName()
333
0
{
334
0
    return u"com.sun.star.comp.svtools.AccessibleTabBarPageList"_ustr;
335
0
}
336
337
338
sal_Bool AccessibleTabBarPageList::supportsService( const OUString& rServiceName )
339
0
{
340
0
    return cppu::supportsService(this, rServiceName);
341
0
}
342
343
344
Sequence< OUString > AccessibleTabBarPageList::getSupportedServiceNames()
345
0
{
346
0
    return { u"com.sun.star.awt.AccessibleTabBarPageList"_ustr };
347
0
}
348
349
// XAccessibleContext
350
351
sal_Int64 AccessibleTabBarPageList::getAccessibleChildCount()
352
0
{
353
0
    OExternalLockGuard aGuard( this );
354
355
0
    return m_aAccessibleChildren.size();
356
0
}
357
358
359
Reference< XAccessible > AccessibleTabBarPageList::getAccessibleChild( sal_Int64 i )
360
0
{
361
0
    OExternalLockGuard aGuard( this );
362
363
0
    return getAccessibleChildImpl(i);
364
0
}
365
366
rtl::Reference< AccessibleTabBarPage > AccessibleTabBarPageList::getAccessibleChildImpl( sal_Int64 i )
367
0
{
368
0
    if ( i < 0 || i >= getAccessibleChildCount() )
369
0
        throw IndexOutOfBoundsException();
370
371
0
    rtl::Reference< AccessibleTabBarPage > xChild = m_aAccessibleChildren[i];
372
0
    if ( !xChild.is() )
373
0
    {
374
0
        if ( m_pTabBar )
375
0
        {
376
0
            sal_uInt16 nPageId = m_pTabBar->GetPageId( static_cast<sal_uInt16>(i) );
377
378
0
            xChild = new AccessibleTabBarPage( m_pTabBar, nPageId, this );
379
380
            // insert into child list
381
0
            m_aAccessibleChildren[i] = xChild;
382
0
        }
383
0
    }
384
385
0
    return xChild;
386
0
}
387
388
389
Reference< XAccessible > AccessibleTabBarPageList::getAccessibleParent(  )
390
0
{
391
0
    OExternalLockGuard aGuard( this );
392
393
0
    Reference< XAccessible > xParent;
394
0
    if ( m_pTabBar )
395
0
        xParent = m_pTabBar->GetAccessible();
396
397
0
    return xParent;
398
0
}
399
400
401
sal_Int64 AccessibleTabBarPageList::getAccessibleIndexInParent(  )
402
0
{
403
0
    OExternalLockGuard aGuard( this );
404
405
0
    return m_nIndexInParent;
406
0
}
407
408
409
sal_Int16 AccessibleTabBarPageList::getAccessibleRole(  )
410
0
{
411
0
    return AccessibleRole::PAGE_TAB_LIST;
412
0
}
413
414
415
OUString AccessibleTabBarPageList::getAccessibleDescription( )
416
0
{
417
0
    return OUString();
418
0
}
419
420
421
OUString AccessibleTabBarPageList::getAccessibleName(  )
422
0
{
423
0
    return OUString();
424
0
}
425
426
427
Reference< XAccessibleRelationSet > AccessibleTabBarPageList::getAccessibleRelationSet(  )
428
0
{
429
0
    OExternalLockGuard aGuard( this );
430
431
0
    return new utl::AccessibleRelationSetHelper;
432
0
}
433
434
435
sal_Int64 AccessibleTabBarPageList::getAccessibleStateSet(  )
436
0
{
437
0
    OExternalLockGuard aGuard( this );
438
439
0
    sal_Int64 nStateSet = 0;
440
441
0
    if ( !rBHelper.bDisposed && !rBHelper.bInDispose )
442
0
    {
443
0
        FillAccessibleStateSet( nStateSet );
444
0
    }
445
0
    else
446
0
    {
447
0
        nStateSet |= AccessibleStateType::DEFUNC;
448
0
    }
449
450
0
    return nStateSet;
451
0
}
452
453
454
Locale AccessibleTabBarPageList::getLocale(  )
455
0
{
456
0
    OExternalLockGuard aGuard( this );
457
458
0
    return Application::GetSettings().GetLanguageTag().getLocale();
459
0
}
460
461
462
// XAccessibleComponent
463
464
465
Reference< XAccessible > AccessibleTabBarPageList::getAccessibleAtPoint( const awt::Point& rPoint )
466
0
{
467
0
    OExternalLockGuard aGuard( this );
468
469
0
    Point aPos = vcl::unohelper::ConvertToVCLPoint(rPoint);
470
0
    for ( size_t i = 0; i < m_aAccessibleChildren.size(); ++i )
471
0
    {
472
0
        rtl::Reference< AccessibleTabBarPage > xAcc = getAccessibleChildImpl( i );
473
0
        if ( xAcc.is() )
474
0
        {
475
0
            tools::Rectangle aRect = vcl::unohelper::ConvertToVCLRect(xAcc->getBounds());
476
0
            if (aRect.Contains(aPos))
477
0
                return xAcc;
478
0
        }
479
0
    }
480
481
0
    return nullptr;
482
0
}
483
484
485
void AccessibleTabBarPageList::grabFocus(  )
486
0
{
487
    // no focus
488
0
}
489
490
491
sal_Int32 AccessibleTabBarPageList::getForeground(  )
492
0
{
493
0
    OExternalLockGuard aGuard( this );
494
495
0
    sal_Int32 nColor = 0;
496
0
    Reference< XAccessible > xParent = getAccessibleParent();
497
0
    if ( xParent.is() )
498
0
    {
499
0
        Reference< XAccessibleComponent > xParentComp( xParent->getAccessibleContext(), UNO_QUERY );
500
0
        if ( xParentComp.is() )
501
0
            nColor = xParentComp->getForeground();
502
0
    }
503
504
0
    return nColor;
505
0
}
506
507
508
sal_Int32 AccessibleTabBarPageList::getBackground(  )
509
0
{
510
0
    OExternalLockGuard aGuard( this );
511
512
0
    sal_Int32 nColor = 0;
513
0
    Reference< XAccessible > xParent = getAccessibleParent();
514
0
    if ( xParent.is() )
515
0
    {
516
0
        Reference< XAccessibleComponent > xParentComp( xParent->getAccessibleContext(), UNO_QUERY );
517
0
        if ( xParentComp.is() )
518
0
            nColor = xParentComp->getBackground();
519
0
    }
520
521
0
    return nColor;
522
0
}
523
524
// XAccessibleSelection
525
526
527
void AccessibleTabBarPageList::selectAccessibleChild( sal_Int64 nChildIndex )
528
0
{
529
0
    OExternalLockGuard aGuard( this );
530
531
0
    if ( nChildIndex < 0 || nChildIndex >= getAccessibleChildCount() )
532
0
        throw IndexOutOfBoundsException();
533
534
0
    if ( m_pTabBar )
535
0
    {
536
0
        m_pTabBar->SetCurPageId( m_pTabBar->GetPageId( static_cast<sal_uInt16>(nChildIndex) ) );
537
0
        m_pTabBar->PaintImmediately();
538
0
        m_pTabBar->ActivatePage();
539
0
        m_pTabBar->Select();
540
0
    }
541
0
}
542
543
544
sal_Bool AccessibleTabBarPageList::isAccessibleChildSelected( sal_Int64 nChildIndex )
545
0
{
546
0
    OExternalLockGuard aGuard( this );
547
548
0
    if ( nChildIndex < 0 || nChildIndex >= getAccessibleChildCount() )
549
0
        throw IndexOutOfBoundsException();
550
551
0
    bool bSelected = false;
552
0
    if ( m_pTabBar && m_pTabBar->GetCurPageId() == m_pTabBar->GetPageId( static_cast<sal_uInt16>(nChildIndex) ) )
553
0
        bSelected = true;
554
555
0
    return bSelected;
556
0
}
557
558
559
void AccessibleTabBarPageList::clearAccessibleSelection(  )
560
0
{
561
    // This method makes no sense in a TabBar, and so does nothing.
562
0
}
563
564
565
void AccessibleTabBarPageList::selectAllAccessibleChildren(  )
566
0
{
567
0
    selectAccessibleChild( 0 );
568
0
}
569
570
571
sal_Int64 AccessibleTabBarPageList::getSelectedAccessibleChildCount(  )
572
0
{
573
0
    return 1;
574
0
}
575
576
577
Reference< XAccessible > AccessibleTabBarPageList::getSelectedAccessibleChild( sal_Int64 nSelectedChildIndex )
578
0
{
579
0
    OExternalLockGuard aGuard( this );
580
581
0
    if ( nSelectedChildIndex < 0 || nSelectedChildIndex >= getSelectedAccessibleChildCount() )
582
0
        throw IndexOutOfBoundsException();
583
584
0
    Reference< XAccessible > xChild;
585
586
0
    for ( sal_Int64 i = 0, j = 0, nCount = getAccessibleChildCount(); i < nCount; i++ )
587
0
    {
588
0
        if ( isAccessibleChildSelected( i ) && ( j++ == nSelectedChildIndex ) )
589
0
        {
590
0
            xChild = getAccessibleChild( i );
591
0
            break;
592
0
        }
593
0
    }
594
595
0
    return xChild;
596
0
}
597
598
599
void AccessibleTabBarPageList::deselectAccessibleChild( sal_Int64 nChildIndex )
600
0
{
601
0
    OExternalLockGuard aGuard( this );
602
603
0
    if ( nChildIndex < 0 || nChildIndex >= getAccessibleChildCount() )
604
0
        throw IndexOutOfBoundsException();
605
606
    // This method makes no sense in a TabBar, and so does nothing.
607
0
}
608
609
610
}   // namespace accessibility
611
612
613
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */