Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/vcl/source/accessibility/vclxaccessibletoolbox.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
#include <string.h>
20
21
#include <accessibility/vclxaccessibletoolbox.hxx>
22
#include <accessibility/vclxaccessibletoolboxitem.hxx>
23
24
#include <com/sun/star/accessibility/AccessibleEventId.hpp>
25
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
26
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
27
#include <o3tl/safeint.hxx>
28
#include <vcl/toolbox.hxx>
29
#include <vcl/unohelp.hxx>
30
#include <vcl/vclevent.hxx>
31
#include <comphelper/accessiblecontexthelper.hxx>
32
#include <comphelper/sequence.hxx>
33
34
using namespace ::comphelper;
35
using namespace ::com::sun::star;
36
using namespace ::com::sun::star::uno;
37
using namespace ::com::sun::star::lang;
38
using namespace ::com::sun::star::accessibility;
39
40
// VCLXAccessibleToolBox
41
42
VCLXAccessibleToolBox::VCLXAccessibleToolBox(ToolBox* pToolBox)
43
0
    : ImplInheritanceHelper(pToolBox)
44
0
{
45
0
}
46
47
VCLXAccessibleToolBox::~VCLXAccessibleToolBox()
48
0
{
49
0
}
50
51
VCLXAccessibleToolBoxItem* VCLXAccessibleToolBox::GetItem_Impl( ToolBox::ImplToolItems::size_type _nPos )
52
0
{
53
0
    VCLXAccessibleToolBoxItem* pItem = nullptr;
54
0
    VclPtr< ToolBox > pToolBox = GetAs< ToolBox >();
55
0
    if ( pToolBox )
56
0
    {
57
0
        ToolBoxItemsMap::iterator aIter = m_aAccessibleChildren.find( _nPos );
58
            //TODO: ToolBox::ImplToolItems::size_type -> sal_Int32!
59
        // returns only toolbox buttons, not windows
60
0
        if ( aIter != m_aAccessibleChildren.end()  && aIter->second.is())
61
0
            pItem = aIter->second.get();
62
0
    }
63
64
0
    return pItem;
65
0
}
66
67
void VCLXAccessibleToolBox::UpdateFocus_Impl()
68
0
{
69
0
    VclPtr< ToolBox > pToolBox = GetAs< ToolBox >();
70
0
    if( !pToolBox )
71
0
        return;
72
73
    // submit events only if toolbox has the focus to avoid sending events due to mouse move
74
0
    bool bHasFocus = false;
75
0
    if ( pToolBox->HasFocus() )
76
0
        bHasFocus = true;
77
0
    else
78
0
    {
79
        // check for subtoolbar, i.e. check if our parent is a toolbar
80
0
        ToolBox* pToolBoxParent = dynamic_cast< ToolBox* >( pToolBox->GetParent() );
81
        // subtoolbars never get the focus as key input is just forwarded, so check if the parent toolbar has it
82
0
        if ( pToolBoxParent && pToolBoxParent->HasFocus() )
83
0
            bHasFocus = true;
84
0
    }
85
86
0
    if ( !bHasFocus )
87
0
        return;
88
89
0
    ToolBoxItemId nHighlightItemId = pToolBox->GetHighlightItemId();
90
0
    sal_uInt16 nFocusCount = 0;
91
0
    for ( const auto& [rPos, rxChild] : m_aAccessibleChildren )
92
0
    {
93
0
        ToolBoxItemId nItemId = pToolBox->GetItemId( rPos );
94
95
0
        if ( rxChild.is() )
96
0
        {
97
0
            VCLXAccessibleToolBoxItem* pItem = rxChild.get();
98
0
            if ( pItem->HasFocus() && nItemId != nHighlightItemId )
99
0
            {
100
                // reset the old focused item
101
0
                pItem->SetFocus( false );
102
0
                nFocusCount++;
103
0
            }
104
0
            if ( nItemId == nHighlightItemId )
105
0
            {
106
                // set the new focused item
107
0
                pItem->SetFocus( true );
108
0
                nFocusCount++;
109
0
            }
110
0
        }
111
        // both items changed?
112
0
        if ( nFocusCount > 1 )
113
0
            break;
114
0
    }
115
0
}
116
117
void VCLXAccessibleToolBox::ReleaseFocus_Impl( ToolBox::ImplToolItems::size_type _nPos )
118
0
{
119
0
    VclPtr< ToolBox > pToolBox = GetAs< ToolBox >();
120
0
    if ( pToolBox ) // #107124#, do not check for focus because this message is also handled in losefocus
121
0
    {
122
0
        ToolBoxItemsMap::iterator aIter = m_aAccessibleChildren.find( _nPos );
123
            //TODO: ToolBox::ImplToolItems::size_type -> sal_Int32!
124
0
        if ( aIter != m_aAccessibleChildren.end() && aIter->second.is() )
125
0
        {
126
0
            VCLXAccessibleToolBoxItem* pItem = aIter->second.get();
127
0
            if ( pItem->HasFocus() )
128
0
                pItem->SetFocus( false );
129
0
        }
130
0
    }
131
0
}
132
133
void VCLXAccessibleToolBox::UpdateChecked_Impl( ToolBox::ImplToolItems::size_type _nPos )
134
0
{
135
0
    VclPtr< ToolBox > pToolBox = GetAs< ToolBox >();
136
0
    if ( !pToolBox )
137
0
        return;
138
139
0
    ToolBoxItemId nFocusId = pToolBox->GetItemId( _nPos );
140
0
    VCLXAccessibleToolBoxItem* pFocusItem = nullptr;
141
142
0
    for ( const auto& [rPos, rxChild] : m_aAccessibleChildren )
143
0
    {
144
0
            ToolBoxItemId nItemId = pToolBox->GetItemId( rPos );
145
146
0
            VCLXAccessibleToolBoxItem* pItem = rxChild.get();
147
0
            pItem->SetChecked( pToolBox->IsItemChecked( nItemId ) );
148
0
            if ( nItemId == nFocusId )
149
0
                pFocusItem = pItem;
150
0
    }
151
    //Solution:If the position is not a child item,the focus should not be called
152
0
    if ( pFocusItem && _nPos != ToolBox::ITEM_NOTFOUND )
153
0
        pFocusItem->SetFocus( true );
154
0
}
155
156
void VCLXAccessibleToolBox::UpdateIndeterminate_Impl( ToolBox::ImplToolItems::size_type _nPos )
157
0
{
158
0
    VclPtr< ToolBox > pToolBox = GetAs< ToolBox >();
159
0
    if ( !pToolBox )
160
0
        return;
161
162
0
    ToolBoxItemId nItemId = pToolBox->GetItemId( _nPos );
163
164
0
    ToolBoxItemsMap::iterator aIter = m_aAccessibleChildren.find( _nPos );
165
        //TODO: ToolBox::ImplToolItems::size_type -> sal_Int32!
166
0
    if ( aIter != m_aAccessibleChildren.end() && aIter->second.is() )
167
0
    {
168
0
        VCLXAccessibleToolBoxItem* pItem = aIter->second.get();
169
0
        if ( pItem )
170
0
            pItem->SetIndeterminate( pToolBox->GetItemState( nItemId ) == TRISTATE_INDET );
171
0
    }
172
0
}
173
174
void VCLXAccessibleToolBox::implReleaseToolboxItem( ToolBoxItemsMap::iterator const & _rMapPos,
175
        bool _bNotifyRemoval )
176
0
{
177
0
    rtl::Reference<VCLXAccessibleToolBoxItem> xItemAcc(_rMapPos->second);
178
0
    if ( !xItemAcc.is() )
179
0
        return;
180
181
0
    if ( _bNotifyRemoval )
182
0
    {
183
0
        NotifyAccessibleEvent(AccessibleEventId::CHILD, Any(Reference<XAccessible>(xItemAcc)), Any());
184
0
    }
185
186
0
    xItemAcc->ReleaseToolBox();
187
0
    xItemAcc->dispose();
188
0
}
189
190
void VCLXAccessibleToolBox::UpdateItem_Impl( ToolBox::ImplToolItems::size_type _nPos)
191
0
{
192
0
    if ( _nPos < m_aAccessibleChildren.size() )
193
0
    {
194
0
        UpdateAllItems_Impl();
195
0
        return;
196
0
    }
197
198
0
    VclPtr< ToolBox > pToolBox = GetAs< ToolBox >();
199
0
    if ( !pToolBox )
200
0
        return;
201
202
    // adjust the "index-in-parent"s
203
0
    ToolBoxItemsMap::iterator aIndexAdjust = m_aAccessibleChildren.upper_bound( _nPos );
204
        //TODO: ToolBox::ImplToolItems::size_type -> sal_Int32!
205
0
    while ( m_aAccessibleChildren.end() != aIndexAdjust )
206
0
    {
207
0
        rtl::Reference<VCLXAccessibleToolBoxItem> xItem(aIndexAdjust->second);
208
0
        if (xItem.is())
209
0
        {
210
0
            sal_Int32 nIndex = xItem->getIndexInParent();
211
0
            nIndex++;
212
0
            xItem->setIndexInParent(nIndex);
213
0
        }
214
215
0
        ++aIndexAdjust;
216
0
    }
217
218
    // TODO: we should make this dependent on the existence of event listeners
219
    // with the current implementation, we always create accessible object
220
0
    Any aNewChild( getAccessibleChild( static_cast<sal_Int64>(_nPos) ) );
221
        //TODO: ToolBox::ImplToolItems::size_type -> sal_Int32!
222
0
    NotifyAccessibleEvent( AccessibleEventId::CHILD, Any(), aNewChild );
223
0
}
224
225
void VCLXAccessibleToolBox::UpdateAllItems_Impl()
226
0
{
227
0
    VclPtr< ToolBox > pToolBox = GetAs< ToolBox >();
228
0
    if ( !pToolBox )
229
0
        return;
230
231
    // deregister the old items
232
0
    for ( ToolBoxItemsMap::iterator aIter = m_aAccessibleChildren.begin();
233
0
            aIter != m_aAccessibleChildren.end(); ++aIter )
234
0
    {
235
0
        implReleaseToolboxItem( aIter, true );
236
0
    }
237
0
    m_aAccessibleChildren.clear();
238
239
    // register the new items
240
0
    ToolBox::ImplToolItems::size_type i, nCount = pToolBox->GetItemCount();
241
0
    for ( i = 0; i < nCount; ++i )
242
0
    {
243
0
        Any aNewValue;
244
0
        aNewValue <<= getAccessibleChild(i);
245
0
        NotifyAccessibleEvent( AccessibleEventId::CHILD, Any(), aNewValue );
246
0
    }
247
0
}
248
249
void VCLXAccessibleToolBox::UpdateCustomPopupItemp_Impl( vcl::Window* pWindow, bool bOpen )
250
0
{
251
0
    VclPtr< ToolBox > pToolBox = GetAs< ToolBox >();
252
0
    if( !(pWindow && pToolBox) )
253
0
        return;
254
255
0
    const ToolBoxItemId nDownItem = pToolBox->GetDownItemId();
256
0
    if ( !nDownItem )
257
        // No item is currently in down state.
258
        // Moreover, calling GetItemPos with 0 will find a separator if there is any.
259
0
        return;
260
261
0
    ToolBox::ImplToolItems::size_type nIndex = pToolBox->GetItemPos(nDownItem);
262
0
    if (nIndex == ToolBox::ITEM_NOTFOUND)
263
0
        return; // not found
264
265
0
    rtl::Reference<comphelper::OAccessible> pChild = pWindow->GetAccessible();
266
0
    if (pChild.is())
267
0
    {
268
0
        Reference< XAccessible > xChildItem(getAccessibleChild(nIndex));
269
0
        VCLXAccessibleToolBoxItem* pItem = static_cast< VCLXAccessibleToolBoxItem* >( xChildItem.get() );
270
271
0
        pItem->SetChild(pChild);
272
0
        pItem->NotifyChildEvent(pChild, bOpen);
273
0
    }
274
0
}
275
276
void VCLXAccessibleToolBox::UpdateItemName_Impl( ToolBox::ImplToolItems::size_type _nPos )
277
0
{
278
0
    VCLXAccessibleToolBoxItem* pItem = GetItem_Impl( _nPos );
279
0
    if ( pItem )
280
0
        pItem->NameChanged();
281
0
}
282
283
void VCLXAccessibleToolBox::UpdateItemEnabled_Impl( ToolBox::ImplToolItems::size_type _nPos )
284
0
{
285
0
    VCLXAccessibleToolBoxItem* pItem = GetItem_Impl( _nPos );
286
0
    if ( pItem )
287
0
        pItem->ToggleEnableState();
288
0
}
289
290
void VCLXAccessibleToolBox::HandleSubToolBarEvent( const VclWindowEvent& rVclWindowEvent )
291
0
{
292
0
    vcl::Window* pChildWindow = static_cast<vcl::Window *>(rVclWindowEvent.GetData());
293
0
    VclPtr< ToolBox > pToolBox = GetAs< ToolBox >();
294
0
    if ( !(pChildWindow
295
0
        && pToolBox
296
0
        && pToolBox == pChildWindow->GetParent()
297
0
        && pChildWindow->GetType() == WindowType::TOOLBOX) )
298
0
        return;
299
300
0
    const ToolBoxItemId nCurItemId( pToolBox->GetCurItemId() );
301
0
    if ( !nCurItemId )
302
        // No item is currently active (might happen when opening the overflow popup).
303
        // Moreover, calling GetItemPos with 0 will find a separator if there is any.
304
0
        return;
305
306
0
    ToolBox::ImplToolItems::size_type nIndex = pToolBox->GetItemPos(nCurItemId);
307
0
    if (nIndex == ToolBox::ITEM_NOTFOUND)
308
0
        return; // not found
309
310
0
    Reference< XAccessible > xItem = getAccessibleChild( nIndex );
311
0
    if ( xItem.is() )
312
0
    {
313
0
        rtl::Reference<comphelper::OAccessible> pChild = pChildWindow->GetAccessible();
314
0
        VCLXAccessibleToolBoxItem* pItem =
315
0
            static_cast< VCLXAccessibleToolBoxItem* >( xItem.get() );
316
0
        pItem->SetChild(pChild);
317
0
        pItem->NotifyChildEvent(pChild, true /*_bShow*/);
318
0
    }
319
0
}
320
321
void VCLXAccessibleToolBox::ReleaseSubToolBox( ToolBox* _pSubToolBox )
322
0
{
323
0
    VclPtr< ToolBox > pToolBox = GetAs< ToolBox >();
324
0
    if ( !pToolBox )
325
0
        return;
326
327
0
    ToolBox::ImplToolItems::size_type nIndex = pToolBox->GetItemPos( pToolBox->GetCurItemId() );
328
0
    if ( nIndex == ToolBox::ITEM_NOTFOUND )
329
0
        return; // not found
330
331
0
    Reference< XAccessible > xItem = getAccessibleChild( nIndex );
332
0
    if ( !xItem.is() )
333
0
        return;
334
335
0
    rtl::Reference<comphelper::OAccessible> pChild = _pSubToolBox->GetAccessible();
336
0
    VCLXAccessibleToolBoxItem* pItem =
337
0
        static_cast< VCLXAccessibleToolBoxItem* >( xItem.get() );
338
0
    if (pItem->GetChild() == pChild)
339
0
    {
340
0
        pItem->SetChild({});
341
0
        pItem->NotifyChildEvent(pChild, false);
342
0
    }
343
0
}
344
345
void VCLXAccessibleToolBox::FillAccessibleStateSet( sal_Int64& rStateSet )
346
0
{
347
0
    VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet );
348
349
0
    VclPtr< ToolBox > pToolBox = GetAs< ToolBox >();
350
0
    if ( pToolBox )
351
0
    {
352
0
        rStateSet |= AccessibleStateType::FOCUSABLE;
353
0
        if ( pToolBox->IsHorizontal() )
354
0
            rStateSet |= AccessibleStateType::HORIZONTAL;
355
0
        else
356
0
            rStateSet |= AccessibleStateType::VERTICAL;
357
0
    }
358
0
}
359
360
void VCLXAccessibleToolBox::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
361
0
{
362
    // to prevent an early release of the toolbox (VclEventId::ObjectDying)
363
0
    Reference< XAccessibleContext > xHoldAlive = this;
364
365
0
    switch ( rVclWindowEvent.GetId() )
366
0
    {
367
0
        case VclEventId::ToolboxClick:
368
0
        case VclEventId::ToolboxSelect:
369
0
        {
370
0
            VclPtr< ToolBox > pToolBox = GetAs< ToolBox >();
371
0
            if ( rVclWindowEvent.GetData() )
372
0
            {
373
0
                UpdateChecked_Impl( static_cast<ToolBox::ImplToolItems::size_type>(reinterpret_cast<sal_IntPtr>(rVclWindowEvent.GetData())) );
374
0
                UpdateIndeterminate_Impl( static_cast<ToolBox::ImplToolItems::size_type>(reinterpret_cast<sal_IntPtr>(rVclWindowEvent.GetData())) );
375
0
            }
376
0
            else if( pToolBox->GetItemPos(pToolBox->GetCurItemId()) != ToolBox::ITEM_NOTFOUND )
377
0
            {
378
0
                UpdateChecked_Impl( pToolBox->GetItemPos(pToolBox->GetCurItemId()) );
379
0
                UpdateIndeterminate_Impl( pToolBox->GetItemPos(pToolBox->GetCurItemId()) );
380
0
            }
381
0
            break;
382
0
        }
383
0
        case VclEventId::ToolboxDoubleClick:
384
0
        case VclEventId::ToolboxActivate:
385
0
        case VclEventId::ToolboxDeactivate:
386
        //case VclEventId::ToolboxSelect:
387
0
            break;
388
389
0
        case VclEventId::ToolboxItemUpdated:
390
0
        {
391
0
            if ( rVclWindowEvent.GetData() )
392
0
            {
393
0
                UpdateChecked_Impl( ToolBox::ITEM_NOTFOUND );
394
0
                UpdateIndeterminate_Impl( static_cast<ToolBox::ImplToolItems::size_type>(reinterpret_cast<sal_IntPtr>(rVclWindowEvent.GetData())) );
395
0
            }
396
0
            break;
397
0
        }
398
399
0
        case VclEventId::ToolboxHighlight:
400
0
            UpdateFocus_Impl();
401
0
            break;
402
403
0
        case VclEventId::ToolboxHighlightOff:
404
0
            ReleaseFocus_Impl( static_cast<ToolBox::ImplToolItems::size_type>(reinterpret_cast<sal_IntPtr>(rVclWindowEvent.GetData())) );
405
0
            break;
406
407
0
        case VclEventId::ToolboxItemAdded :
408
0
            UpdateItem_Impl( static_cast<ToolBox::ImplToolItems::size_type>(reinterpret_cast<sal_IntPtr>(rVclWindowEvent.GetData())) );
409
0
            break;
410
411
0
        case VclEventId::ToolboxItemRemoved :
412
0
        case VclEventId::ToolboxAllItemsChanged :
413
0
        {
414
0
            UpdateAllItems_Impl();
415
0
            break;
416
0
        }
417
418
0
        case VclEventId::ToolboxItemWindowChanged:
419
0
        {
420
0
            auto nPos = static_cast<ToolBox::ImplToolItems::size_type>(reinterpret_cast<sal_IntPtr>(rVclWindowEvent.GetData()));
421
0
            ToolBoxItemsMap::iterator aAccessiblePos( m_aAccessibleChildren.find( nPos ) );
422
                //TODO: ToolBox::ImplToolItems::size_type -> sal_Int32!
423
0
            if ( m_aAccessibleChildren.end() != aAccessiblePos )
424
0
            {
425
0
                implReleaseToolboxItem( aAccessiblePos, false );
426
0
                m_aAccessibleChildren.erase (aAccessiblePos);
427
0
            }
428
429
0
            Any aNewValue;
430
0
            aNewValue <<= getAccessibleChild(nPos);
431
0
            NotifyAccessibleEvent( AccessibleEventId::CHILD, Any(), aNewValue );
432
0
            break;
433
0
        }
434
0
        case VclEventId::ToolboxItemTextChanged :
435
0
            UpdateItemName_Impl( static_cast<ToolBox::ImplToolItems::size_type>(reinterpret_cast<sal_IntPtr>(rVclWindowEvent.GetData())) );
436
0
            break;
437
438
0
        case VclEventId::ToolboxItemEnabled :
439
0
        case VclEventId::ToolboxItemDisabled :
440
0
        {
441
0
            UpdateItemEnabled_Impl( static_cast<ToolBox::ImplToolItems::size_type>(reinterpret_cast<sal_IntPtr>(rVclWindowEvent.GetData())) );
442
0
            break;
443
0
        }
444
445
0
        case VclEventId::DropdownOpen:
446
0
        case VclEventId::DropdownClose:
447
0
        {
448
0
            UpdateCustomPopupItemp_Impl( static_cast< vcl::Window* >( rVclWindowEvent.GetData() ), rVclWindowEvent.GetId() == VclEventId::DropdownOpen );
449
0
            break;
450
0
        }
451
452
0
        case VclEventId::ObjectDying :
453
0
        {
454
            // if this toolbox is a subtoolbox, we have to release it from its parent
455
0
            VclPtr< vcl::Window > pWin = GetAs< vcl::Window >();
456
0
            if ( pWin && pWin->GetParent() &&
457
0
                 pWin->GetParent()->GetType() == WindowType::TOOLBOX )
458
0
            {
459
0
                rtl::Reference<comphelper::OAccessible> pParentAcc = pWin->GetParent()->GetAccessible();
460
0
                VCLXAccessibleToolBox* pParent = static_cast<VCLXAccessibleToolBox*>(pParentAcc.get());
461
0
                if ( pParent )
462
0
                    pParent->ReleaseSubToolBox(static_cast<ToolBox *>(pWin.get()));
463
0
            }
464
465
            // dispose all items
466
0
            for ( ToolBoxItemsMap::iterator aIter = m_aAccessibleChildren.begin();
467
0
                  aIter != m_aAccessibleChildren.end(); ++aIter )
468
0
            {
469
0
                implReleaseToolboxItem( aIter, false );
470
0
            }
471
0
            m_aAccessibleChildren.clear();
472
473
0
            [[fallthrough]]; // call base class
474
0
        }
475
476
0
        default:
477
0
            VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent );
478
0
    }
479
0
}
480
481
void VCLXAccessibleToolBox::ProcessWindowChildEvent( const VclWindowEvent& rVclWindowEvent )
482
0
{
483
0
    switch ( rVclWindowEvent.GetId() )
484
0
    {
485
0
        case VclEventId::WindowShow:  // send create on show for direct accessible children
486
0
        {
487
0
            Reference< XAccessible > xReturn = GetItemWindowAccessible(rVclWindowEvent);
488
0
            if ( xReturn.is() )
489
0
                NotifyAccessibleEvent( AccessibleEventId::CHILD, Any(), Any(xReturn) );
490
0
            else
491
0
                HandleSubToolBarEvent( rVclWindowEvent );
492
0
        }
493
0
        break;
494
495
0
        default:
496
0
           VCLXAccessibleComponent::ProcessWindowChildEvent( rVclWindowEvent );
497
498
0
    }
499
0
}
500
501
// XComponent
502
void SAL_CALL VCLXAccessibleToolBox::disposing()
503
0
{
504
0
    VCLXAccessibleComponent::disposing();
505
506
    // release the items
507
0
    for ( ToolBoxItemsMap::iterator aIter = m_aAccessibleChildren.begin();
508
0
          aIter != m_aAccessibleChildren.end(); ++aIter )
509
0
    {
510
0
        implReleaseToolboxItem( aIter, false );
511
0
    }
512
0
    m_aAccessibleChildren.clear();
513
0
}
514
515
// XServiceInfo
516
OUString VCLXAccessibleToolBox::getImplementationName()
517
0
{
518
0
    return u"com.sun.star.comp.toolkit.AccessibleToolBox"_ustr;
519
0
}
520
521
Sequence< OUString > VCLXAccessibleToolBox::getSupportedServiceNames()
522
0
{
523
0
    return comphelper::concatSequences(VCLXAccessibleComponent::getSupportedServiceNames(),
524
0
                                       std::initializer_list<OUString>{u"com.sun.star.accessibility.AccessibleToolBox"_ustr});
525
0
}
526
527
// XAccessibleContext
528
sal_Int64 SAL_CALL VCLXAccessibleToolBox::getAccessibleChildCount(  )
529
0
{
530
0
    comphelper::OExternalLockGuard aGuard( this );
531
0
    return implGetAccessibleChildCount();
532
0
}
533
534
 sal_Int64 VCLXAccessibleToolBox::implGetAccessibleChildCount(  )
535
0
 {
536
0
    sal_Int64 nCount = 0;
537
0
    VclPtr< ToolBox > pToolBox = GetAs< ToolBox >();
538
0
    if ( pToolBox )
539
0
        nCount = pToolBox->GetItemCount();
540
541
0
    return nCount;
542
0
}
543
544
Reference< XAccessible > SAL_CALL VCLXAccessibleToolBox::getAccessibleChild( sal_Int64 i )
545
0
{
546
0
    comphelper::OExternalLockGuard aGuard( this );
547
548
0
    VclPtr< ToolBox > pToolBox = GetAs< ToolBox >();
549
0
    if ( (!pToolBox) || i < 0 || o3tl::make_unsigned(i) >= pToolBox->GetItemCount() )
550
0
        throw IndexOutOfBoundsException();
551
552
0
    rtl::Reference< VCLXAccessibleToolBoxItem > xChild;
553
    // search for the child
554
0
    ToolBoxItemsMap::iterator aIter = m_aAccessibleChildren.find(i);
555
0
    if ( m_aAccessibleChildren.end() == aIter )
556
0
    {
557
0
        ToolBoxItemId nItemId = pToolBox->GetItemId( i );
558
0
        ToolBoxItemId nHighlightItemId = pToolBox->GetHighlightItemId();
559
0
        vcl::Window* pItemWindow = pToolBox->GetItemWindow( nItemId );
560
        // not found -> create a new child
561
0
        xChild = new VCLXAccessibleToolBoxItem( pToolBox, i );
562
0
        if ( pItemWindow )
563
0
        {
564
0
            rtl::Reference<comphelper::OAccessible> pInnerAcc = pItemWindow->GetAccessible();
565
0
            if (pInnerAcc.is()) // else child is being disposed - avoid crashing
566
0
            {
567
0
                pItemWindow->SetAccessibleParent(xChild);
568
0
                xChild->SetChild(pInnerAcc);
569
0
            }
570
0
        }
571
0
        if ( nHighlightItemId > ToolBoxItemId(0) && nItemId == nHighlightItemId )
572
0
            xChild->SetFocus( true );
573
0
        if ( pToolBox->IsItemChecked( nItemId ) )
574
0
            xChild->SetChecked( true );
575
0
        if ( pToolBox->GetItemState( nItemId ) == TRISTATE_INDET )
576
0
            xChild->SetIndeterminate( true );
577
0
        m_aAccessibleChildren.emplace( i, xChild );
578
0
    }
579
0
    else
580
0
    {
581
        // found it
582
0
        xChild = aIter->second;
583
0
    }
584
0
    return xChild;
585
0
}
586
587
Reference< XAccessible > SAL_CALL VCLXAccessibleToolBox::getAccessibleAtPoint( const awt::Point& _rPoint )
588
0
{
589
0
    comphelper::OExternalLockGuard aGuard( this );
590
591
0
    Reference< XAccessible > xAccessible;
592
0
    VclPtr< ToolBox > pToolBox = GetAs< ToolBox >();
593
0
    if ( pToolBox )
594
0
    {
595
0
        ToolBox::ImplToolItems::size_type nItemPos
596
0
            = pToolBox->GetItemPos(vcl::unohelper::ConvertToVCLPoint(_rPoint));
597
0
        if ( nItemPos != ToolBox::ITEM_NOTFOUND )
598
0
            xAccessible = getAccessibleChild( nItemPos );
599
0
    }
600
601
0
    return xAccessible;
602
0
}
603
604
Reference< XAccessible > VCLXAccessibleToolBox::GetItemWindowAccessible( const VclWindowEvent& rVclWindowEvent )
605
0
{
606
0
    Reference< XAccessible > xReturn;
607
0
    vcl::Window* pChildWindow = static_cast<vcl::Window *>(rVclWindowEvent.GetData());
608
0
    VclPtr< ToolBox > pToolBox = GetAs< ToolBox >();
609
0
    if ( pChildWindow && pToolBox )
610
0
    {
611
0
        ToolBox::ImplToolItems::size_type nCount = pToolBox->GetItemCount();
612
0
        for (ToolBox::ImplToolItems::size_type i = 0 ; i < nCount && !xReturn.is() ; ++i)
613
0
        {
614
0
            ToolBoxItemId nItemId = pToolBox->GetItemId( i );
615
0
            vcl::Window* pItemWindow = pToolBox->GetItemWindow( nItemId );
616
0
            if ( pItemWindow == pChildWindow )
617
0
                xReturn = getAccessibleChild(i);
618
0
        }
619
0
    }
620
0
    return xReturn;
621
0
}
622
623
Reference< XAccessible > VCLXAccessibleToolBox::GetChildAccessible( const VclWindowEvent& rVclWindowEvent )
624
0
{
625
0
    Reference< XAccessible > xReturn = GetItemWindowAccessible(rVclWindowEvent);
626
627
0
    if ( !xReturn.is() )
628
0
        xReturn = VCLXAccessibleComponent::GetChildAccessible(rVclWindowEvent);
629
0
    return xReturn;
630
0
}
631
632
// XAccessibleSelection
633
void VCLXAccessibleToolBox::selectAccessibleChild( sal_Int64 nChildIndex )
634
0
{
635
0
    OExternalLockGuard aGuard( this );
636
637
0
    VclPtr< ToolBox > pToolBox = GetAs< ToolBox >();
638
0
    if ( (!pToolBox) || nChildIndex < 0 || o3tl::make_unsigned(nChildIndex) >= pToolBox->GetItemCount() )
639
0
        throw IndexOutOfBoundsException();
640
641
0
    pToolBox->ChangeHighlight( nChildIndex );
642
0
}
643
644
sal_Bool VCLXAccessibleToolBox::isAccessibleChildSelected( sal_Int64 nChildIndex )
645
0
{
646
0
    OExternalLockGuard aGuard( this );
647
0
    VclPtr< ToolBox > pToolBox = GetAs< ToolBox >();
648
0
    if ( (!pToolBox) || nChildIndex < 0 || o3tl::make_unsigned(nChildIndex) >= pToolBox->GetItemCount() )
649
0
        throw IndexOutOfBoundsException();
650
651
0
    if ( pToolBox->GetHighlightItemId() == pToolBox->GetItemId( nChildIndex ) )
652
0
        return true;
653
0
    else
654
0
        return false;
655
0
}
656
657
void VCLXAccessibleToolBox::clearAccessibleSelection(  )
658
0
{
659
0
    OExternalLockGuard aGuard( this );
660
0
    VclPtr< ToolBox > pToolBox = GetAs< ToolBox >();
661
0
    pToolBox -> LoseFocus();
662
0
}
663
664
void VCLXAccessibleToolBox::selectAllAccessibleChildren(  )
665
0
{
666
0
    OExternalLockGuard aGuard( this );
667
    // intentionally empty. makes no sense for a toolbox
668
0
}
669
670
sal_Int64 VCLXAccessibleToolBox::getSelectedAccessibleChildCount(  )
671
0
{
672
0
    OExternalLockGuard aGuard( this );
673
674
0
    sal_Int64 nRet = 0;
675
0
    VclPtr< ToolBox > pToolBox = GetAs< ToolBox >();
676
0
    if (pToolBox)
677
0
    {
678
0
        ToolBoxItemId nHighlightItemId = pToolBox->GetHighlightItemId();
679
0
        for ( size_t i = 0, nCount = pToolBox->GetItemCount(); i < nCount; i++ )
680
0
        {
681
0
            if ( nHighlightItemId == pToolBox->GetItemId( i ) )
682
0
            {
683
0
                nRet = 1;
684
0
                break; // a toolbox can only have (n)one selected child
685
0
            }
686
0
        }
687
0
    }
688
689
0
    return nRet;
690
0
}
691
692
Reference< XAccessible > VCLXAccessibleToolBox::getSelectedAccessibleChild( sal_Int64 nSelectedChildIndex )
693
0
{
694
0
    OExternalLockGuard aGuard( this );
695
0
    if ( nSelectedChildIndex != 0 )
696
0
        throw IndexOutOfBoundsException();
697
698
0
    Reference< XAccessible > xChild;
699
0
    VclPtr< ToolBox > pToolBox = GetAs< ToolBox >();
700
0
    if (pToolBox)
701
0
    {
702
0
        ToolBoxItemId nHighlightItemId = pToolBox->GetHighlightItemId();
703
0
        for (ToolBox::ImplToolItems::size_type i = 0, nCount = pToolBox->GetItemCount(); i < nCount; i++ )
704
0
        {
705
0
            if ( nHighlightItemId == pToolBox->GetItemId( i ) )
706
0
            {
707
0
                xChild = getAccessibleChild( i );
708
0
                break;
709
0
            }
710
0
        }
711
0
    }
712
713
0
    if (!xChild)
714
0
        throw IndexOutOfBoundsException();
715
716
0
    return xChild;
717
0
}
718
719
void VCLXAccessibleToolBox::deselectAccessibleChild( sal_Int64 nChildIndex )
720
0
{
721
0
    OExternalLockGuard aGuard( this );
722
0
    if ( nChildIndex < 0 || nChildIndex >= implGetAccessibleChildCount() )
723
0
        throw IndexOutOfBoundsException();
724
0
    clearAccessibleSelection(); // a toolbox can only have (n)one selected child
725
0
}
726
727
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */