Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/vcl/source/window/accessibility.cxx
Line
Count
Source (jump to first uncovered line)
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 <vcl/layout.hxx>
21
#include <vcl/toolkit/fixed.hxx>
22
#include <vcl/window.hxx>
23
#include <vcl/menu.hxx>
24
#include <vcl/mnemonic.hxx>
25
#include <vcl/accessibility/vclxaccessiblecomponent.hxx>
26
#include <vcl/wrkwin.hxx>
27
#include <comphelper/lok.hxx>
28
29
#include <accessibility/floatingwindowaccessible.hxx>
30
#include <accessibility/vclxaccessiblefixedtext.hxx>
31
#include <accessibility/vclxaccessiblestatusbar.hxx>
32
#include <accessibility/vclxaccessibletabcontrol.hxx>
33
#include <accessibility/vclxaccessibletabpagewindow.hxx>
34
#include <window.h>
35
#include <brdwin.hxx>
36
37
#include <com/sun/star/accessibility/XAccessible.hpp>
38
#include <com/sun/star/accessibility/AccessibleRole.hpp>
39
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
40
#include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
41
#include <com/sun/star/awt/XVclWindowPeer.hpp>
42
43
#include <sal/log.hxx>
44
45
using namespace ::com::sun::star::uno;
46
using namespace ::com::sun::star::datatransfer::clipboard;
47
using namespace ::com::sun::star::datatransfer::dnd;
48
using namespace ::com::sun::star;
49
50
51
ImplAccessibleInfos::ImplAccessibleInfos()
52
0
{
53
0
    nAccessibleRole = accessibility::AccessibleRole::UNKNOWN;
54
0
    pLabeledByWindow = nullptr;
55
0
    pLabelForWindow = nullptr;
56
0
}
57
58
ImplAccessibleInfos::~ImplAccessibleInfos()
59
0
{
60
0
}
61
62
namespace vcl {
63
64
css::uno::Reference< css::accessibility::XAccessible > Window::GetAccessible( bool bCreate )
65
0
{
66
    // do not optimize hierarchy for the top level border win (ie, when there is no parent)
67
    /* // do not optimize accessible hierarchy at all to better reflect real VCL hierarchy
68
    if ( GetParent() && ( GetType() == WindowType::BORDERWINDOW ) && ( GetChildCount() == 1 ) )
69
    //if( !ImplIsAccessibleCandidate() )
70
    {
71
        vcl::Window* pChild = GetAccessibleChildWindow( 0 );
72
        if ( pChild )
73
            return pChild->GetAccessible();
74
    }
75
    */
76
0
    if ( !mpWindowImpl )
77
0
        return css::uno::Reference< css::accessibility::XAccessible >();
78
0
    if (!mpWindowImpl->mxAccessible.is() && !mpWindowImpl->mbInDispose && bCreate)
79
0
        mpWindowImpl->mxAccessible = CreateAccessible();
80
81
0
    return mpWindowImpl->mxAccessible;
82
0
}
83
84
namespace {
85
86
bool hasFloatingChild(vcl::Window *pWindow)
87
0
{
88
0
    vcl::Window * pChild = pWindow->GetAccessibleChildWindow(0);
89
0
    return pChild && pChild->GetType() == WindowType::FLOATINGWINDOW;
90
0
}
91
};
92
93
css::uno::Reference< css::accessibility::XAccessible > Window::CreateAccessible()
94
0
{
95
0
    const WindowType eType = GetType();
96
97
0
    if (eType == WindowType::STATUSBAR)
98
0
        return new VCLXAccessibleStatusBar(this);
99
100
0
    if (eType == WindowType::TABCONTROL)
101
0
        return new VCLXAccessibleTabControl(this);
102
103
0
    if (eType == WindowType::TABPAGE && GetAccessibleParentWindow() && GetAccessibleParentWindow()->GetType() == WindowType::TABCONTROL)
104
0
        return new VCLXAccessibleTabPageWindow(this);
105
106
0
    if (eType == WindowType::FLOATINGWINDOW)
107
0
        return new FloatingWindowAccessible(this);
108
109
0
    if (eType == WindowType::BORDERWINDOW && hasFloatingChild(this))
110
0
        return new FloatingWindowAccessible(this);
111
112
0
    if ((eType == WindowType::HELPTEXTWINDOW) || (eType == WindowType::FIXEDLINE))
113
0
        return new VCLXAccessibleFixedText(this);
114
115
0
    return new VCLXAccessibleComponent(this);
116
0
}
117
118
void Window::SetAccessible(const rtl::Reference<comphelper::OAccessible>& rpAccessible)
119
0
{
120
0
    if (!mpWindowImpl)
121
0
        return;
122
123
0
    mpWindowImpl->mxAccessible = rpAccessible;
124
0
}
125
126
// skip all border windows that are not top level frames
127
bool Window::ImplIsAccessibleCandidate() const
128
0
{
129
0
    if( !mpWindowImpl->mbBorderWin )
130
0
        return true;
131
132
0
    return IsNativeFrame();
133
0
}
134
135
vcl::Window* Window::GetAccessibleParentWindow() const
136
0
{
137
0
    if (!mpWindowImpl || IsNativeFrame())
138
0
        return nullptr;
139
140
0
    if (IsTopWindow())
141
0
    {
142
        // if "top-level" has native border window parent, report it;
143
        // but don't report parent otherwise (which could e.g. be
144
        // a dialog's parent window that's otherwise a separate window and
145
        // doesn't consider the top level its a11y child either)
146
0
        if (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->IsNativeFrame())
147
0
            return mpWindowImpl->mpBorderWindow;
148
0
        return nullptr;
149
0
    }
150
151
0
    vcl::Window* pParent = mpWindowImpl->mpParent;
152
0
    if( GetType() == WindowType::MENUBARWINDOW )
153
0
    {
154
        // report the menubar as a child of THE workwindow
155
0
        vcl::Window *pWorkWin = GetParent()->mpWindowImpl->mpFirstChild;
156
0
        while( pWorkWin && (pWorkWin == this) )
157
0
            pWorkWin = pWorkWin->mpWindowImpl->mpNext;
158
0
        pParent = pWorkWin;
159
0
    }
160
    // If this is a floating window which has a native border window, then that border should be reported as
161
    // the accessible parent
162
0
    else if( GetType() == WindowType::FLOATINGWINDOW &&
163
0
        mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame )
164
0
    {
165
0
        pParent = mpWindowImpl->mpBorderWindow;
166
0
    }
167
0
    else if( pParent && !pParent->ImplIsAccessibleCandidate() )
168
0
    {
169
0
        pParent = pParent->mpWindowImpl->mpParent;
170
0
    }
171
0
    return pParent;
172
0
}
173
174
sal_uInt16 Window::GetAccessibleChildWindowCount()
175
0
{
176
0
    if (!mpWindowImpl)
177
0
        return 0;
178
179
0
    sal_uInt16 nChildren = 0;
180
0
    vcl::Window* pChild = mpWindowImpl->mpFirstChild;
181
0
    while( pChild )
182
0
    {
183
0
        if( pChild->IsVisible() )
184
0
            nChildren++;
185
0
        pChild = pChild->mpWindowImpl->mpNext;
186
0
    }
187
188
    // report the menubarwindow as a child of THE workwindow
189
0
    if( GetType() == WindowType::BORDERWINDOW )
190
0
    {
191
0
        ImplBorderWindow *pBorderWindow = static_cast<ImplBorderWindow*>(this);
192
0
        if( pBorderWindow->mpMenuBarWindow &&
193
0
            pBorderWindow->mpMenuBarWindow->IsVisible()
194
0
            )
195
0
            --nChildren;
196
0
    }
197
0
    else if( GetType() == WindowType::WORKWINDOW )
198
0
    {
199
0
        WorkWindow *pWorkWindow = static_cast<WorkWindow*>(this);
200
0
        if( pWorkWindow->GetMenuBar() &&
201
0
            pWorkWindow->GetMenuBar()->GetWindow() &&
202
0
            pWorkWindow->GetMenuBar()->GetWindow()->IsVisible()
203
0
            )
204
0
            ++nChildren;
205
0
    }
206
207
0
    return nChildren;
208
0
}
209
210
vcl::Window* Window::GetAccessibleChildWindow( sal_uInt16 n )
211
0
{
212
    // report the menubarwindow as the first child of THE workwindow
213
0
    if( GetType() == WindowType::WORKWINDOW && static_cast<WorkWindow *>(this)->GetMenuBar() )
214
0
    {
215
0
        if( n == 0 )
216
0
        {
217
0
            MenuBar *pMenuBar = static_cast<WorkWindow *>(this)->GetMenuBar();
218
0
            if( pMenuBar->GetWindow() && pMenuBar->GetWindow()->IsVisible() )
219
0
                return pMenuBar->GetWindow();
220
0
        }
221
0
        else
222
0
            --n;
223
0
    }
224
225
    // transform n to child number including invisible children
226
0
    sal_uInt16 nChildren = n;
227
0
    vcl::Window* pChild = mpWindowImpl->mpFirstChild;
228
0
    while( pChild )
229
0
    {
230
0
        if( pChild->IsVisible() )
231
0
        {
232
0
            if( ! nChildren )
233
0
                break;
234
0
            nChildren--;
235
0
        }
236
0
        pChild = pChild->mpWindowImpl->mpNext;
237
0
    }
238
239
0
    if( GetType() == WindowType::BORDERWINDOW && pChild && pChild->GetType() == WindowType::MENUBARWINDOW )
240
0
    {
241
0
        do pChild = pChild->mpWindowImpl->mpNext; while( pChild && ! pChild->IsVisible() );
242
0
        SAL_WARN_IF( !pChild, "vcl", "GetAccessibleChildWindow(): wrong index in border window");
243
0
    }
244
245
0
    if ( pChild && ( pChild->GetType() == WindowType::BORDERWINDOW ) && ( pChild->GetChildCount() == 1 ) )
246
0
    {
247
0
        pChild = pChild->GetChild( 0 );
248
0
    }
249
0
    return pChild;
250
0
}
251
252
void Window::SetAccessibleParent(const css::uno::Reference<css::accessibility::XAccessible>& rxParent)
253
0
{
254
0
    if (!mpWindowImpl->mpAccessibleInfos)
255
0
        mpWindowImpl->mpAccessibleInfos.reset(new ImplAccessibleInfos);
256
257
0
    mpWindowImpl->mpAccessibleInfos->xAccessibleParent = rxParent;
258
0
}
259
260
css::uno::Reference<css::accessibility::XAccessible> Window::GetAccessibleParent() const
261
0
{
262
0
    if (!mpWindowImpl)
263
0
        return nullptr;
264
265
0
    if (mpWindowImpl->mpAccessibleInfos && mpWindowImpl->mpAccessibleInfos->xAccessibleParent.is())
266
0
        return mpWindowImpl->mpAccessibleInfos->xAccessibleParent;
267
268
0
    if (vcl::Window* pAccessibleParentWin = GetAccessibleParentWindow())
269
0
        return pAccessibleParentWin->GetAccessible();
270
271
0
    return nullptr;
272
0
}
273
274
void Window::SetAccessibleRole( sal_uInt16 nRole )
275
0
{
276
0
    if ( !mpWindowImpl->mpAccessibleInfos )
277
0
        mpWindowImpl->mpAccessibleInfos.reset( new ImplAccessibleInfos );
278
279
0
    SAL_WARN_IF( mpWindowImpl->mpAccessibleInfos->nAccessibleRole != accessibility::AccessibleRole::UNKNOWN, "vcl", "AccessibleRole already set!" );
280
0
    mpWindowImpl->mpAccessibleInfos->nAccessibleRole = nRole;
281
0
}
282
283
sal_uInt16 Window::getDefaultAccessibleRole() const
284
0
{
285
0
    sal_uInt16 nRole = accessibility::AccessibleRole::UNKNOWN;
286
0
    switch (GetType())
287
0
    {
288
0
        case WindowType::MESSBOX:
289
0
        case WindowType::INFOBOX:
290
0
        case WindowType::WARNINGBOX:
291
0
        case WindowType::ERRORBOX:
292
0
        case WindowType::QUERYBOX:
293
0
            nRole = accessibility::AccessibleRole::ALERT;
294
0
            break;
295
296
0
        case WindowType::MODELESSDIALOG:
297
0
        case WindowType::TABDIALOG:
298
0
        case WindowType::BUTTONDIALOG:
299
0
        case WindowType::DIALOG:
300
0
            nRole = accessibility::AccessibleRole::DIALOG;
301
0
            break;
302
303
0
        case WindowType::PUSHBUTTON:
304
0
        case WindowType::OKBUTTON:
305
0
        case WindowType::CANCELBUTTON:
306
0
        case WindowType::HELPBUTTON:
307
0
        case WindowType::IMAGEBUTTON:
308
0
        case WindowType::MOREBUTTON:
309
0
            nRole = accessibility::AccessibleRole::PUSH_BUTTON;
310
0
            break;
311
0
        case WindowType::MENUBUTTON:
312
0
            nRole = accessibility::AccessibleRole::BUTTON_MENU;
313
0
            break;
314
315
0
        case WindowType::RADIOBUTTON:
316
0
            nRole = accessibility::AccessibleRole::RADIO_BUTTON;
317
0
            break;
318
0
        case WindowType::TRISTATEBOX:
319
0
        case WindowType::CHECKBOX:
320
0
            nRole = accessibility::AccessibleRole::CHECK_BOX;
321
0
            break;
322
323
0
        case WindowType::MULTILINEEDIT:
324
0
            nRole = accessibility::AccessibleRole::SCROLL_PANE;
325
0
            break;
326
327
0
        case WindowType::PATTERNFIELD:
328
0
        case WindowType::EDIT:
329
0
            nRole = static_cast<Edit const*>(this)->IsPassword()
330
0
                        ? accessibility::AccessibleRole::PASSWORD_TEXT
331
0
                        : accessibility::AccessibleRole::TEXT;
332
0
            break;
333
334
0
        case WindowType::PATTERNBOX:
335
0
        case WindowType::NUMERICBOX:
336
0
        case WindowType::METRICBOX:
337
0
        case WindowType::CURRENCYBOX:
338
0
        case WindowType::LONGCURRENCYBOX:
339
0
        case WindowType::COMBOBOX:
340
0
            nRole = accessibility::AccessibleRole::COMBO_BOX;
341
0
            break;
342
343
0
        case WindowType::LISTBOX:
344
0
        case WindowType::MULTILISTBOX:
345
0
            nRole = accessibility::AccessibleRole::LIST;
346
0
            break;
347
348
0
        case WindowType::TREELISTBOX:
349
0
            nRole = accessibility::AccessibleRole::TREE;
350
0
            break;
351
352
0
        case WindowType::FIXEDTEXT:
353
0
            nRole = accessibility::AccessibleRole::LABEL;
354
0
            break;
355
0
        case WindowType::FIXEDLINE:
356
0
            if (!GetText().isEmpty())
357
0
                nRole = accessibility::AccessibleRole::LABEL;
358
0
            else
359
0
                nRole = accessibility::AccessibleRole::SEPARATOR;
360
0
            break;
361
362
0
        case WindowType::FIXEDBITMAP:
363
0
        case WindowType::FIXEDIMAGE:
364
0
            nRole = accessibility::AccessibleRole::ICON;
365
0
            break;
366
0
        case WindowType::GROUPBOX:
367
0
            nRole = accessibility::AccessibleRole::GROUP_BOX;
368
0
            break;
369
0
        case WindowType::SCROLLBAR:
370
0
            nRole = accessibility::AccessibleRole::SCROLL_BAR;
371
0
            break;
372
373
0
        case WindowType::SLIDER:
374
0
        case WindowType::SPLITTER:
375
0
        case WindowType::SPLITWINDOW:
376
0
            nRole = accessibility::AccessibleRole::SPLIT_PANE;
377
0
            break;
378
379
0
        case WindowType::DATEBOX:
380
0
        case WindowType::TIMEBOX:
381
0
        case WindowType::DATEFIELD:
382
0
        case WindowType::TIMEFIELD:
383
0
            nRole = accessibility::AccessibleRole::DATE_EDITOR;
384
0
            break;
385
386
0
        case WindowType::METRICFIELD:
387
0
        case WindowType::CURRENCYFIELD:
388
0
        case WindowType::SPINBUTTON:
389
0
        case WindowType::SPINFIELD:
390
0
        case WindowType::FORMATTEDFIELD:
391
0
            nRole = accessibility::AccessibleRole::SPIN_BOX;
392
0
            break;
393
394
0
        case WindowType::TOOLBOX:
395
0
            nRole = accessibility::AccessibleRole::TOOL_BAR;
396
0
            break;
397
0
        case WindowType::STATUSBAR:
398
0
            nRole = accessibility::AccessibleRole::STATUS_BAR;
399
0
            break;
400
401
0
        case WindowType::TABPAGE:
402
0
            nRole = accessibility::AccessibleRole::PANEL;
403
0
            break;
404
0
        case WindowType::TABCONTROL:
405
0
            nRole = accessibility::AccessibleRole::PAGE_TAB_LIST;
406
0
            break;
407
408
0
        case WindowType::DOCKINGWINDOW:
409
0
            nRole = (mpWindowImpl->mbFrame) ? accessibility::AccessibleRole::FRAME
410
0
                                            : accessibility::AccessibleRole::PANEL;
411
0
            break;
412
413
0
        case WindowType::FLOATINGWINDOW:
414
0
            nRole = (mpWindowImpl->mbFrame
415
0
                     || (mpWindowImpl->mpBorderWindow
416
0
                         && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame)
417
0
                     || (GetStyle() & WB_OWNERDRAWDECORATION))
418
0
                        ? accessibility::AccessibleRole::FRAME
419
0
                        : accessibility::AccessibleRole::WINDOW;
420
0
            break;
421
422
0
        case WindowType::WORKWINDOW:
423
0
            nRole = accessibility::AccessibleRole::ROOT_PANE;
424
0
            break;
425
426
0
        case WindowType::SCROLLBARBOX:
427
0
            nRole = accessibility::AccessibleRole::FILLER;
428
0
            break;
429
430
0
        case WindowType::HELPTEXTWINDOW:
431
0
            nRole = accessibility::AccessibleRole::TOOL_TIP;
432
0
            break;
433
434
0
        case WindowType::PROGRESSBAR:
435
0
            nRole = accessibility::AccessibleRole::PROGRESS_BAR;
436
0
            break;
437
438
0
        case WindowType::RULER:
439
0
            nRole = accessibility::AccessibleRole::RULER;
440
0
            break;
441
442
0
        case WindowType::SCROLLWINDOW:
443
0
            nRole = accessibility::AccessibleRole::SCROLL_PANE;
444
0
            break;
445
446
0
        case WindowType::WINDOW:
447
0
        case WindowType::CONTROL:
448
0
        case WindowType::BORDERWINDOW:
449
0
        case WindowType::SYSTEMCHILDWINDOW:
450
0
        default:
451
0
            if (IsNativeFrame())
452
0
                nRole = accessibility::AccessibleRole::FRAME;
453
0
            else if (IsScrollable())
454
0
                nRole = accessibility::AccessibleRole::SCROLL_PANE;
455
0
            else if (this->ImplGetWindow()->IsMenuFloatingWindow())
456
                // #106002#, contextmenus are windows (i.e. toplevel)
457
0
                nRole = accessibility::AccessibleRole::WINDOW;
458
0
            else
459
                // #104051# WINDOW seems to be a bad default role, use LAYEREDPANE instead
460
                // a WINDOW is interpreted as a top-level window, which is typically not the case
461
                //nRole = accessibility::AccessibleRole::WINDOW;
462
0
                nRole = accessibility::AccessibleRole::PANEL;
463
0
    }
464
0
    return nRole;
465
0
}
466
467
sal_uInt16 Window::GetAccessibleRole() const
468
0
{
469
0
    if (!mpWindowImpl)
470
0
        return accessibility::AccessibleRole::UNKNOWN;
471
472
0
    sal_uInt16 nRole = mpWindowImpl->mpAccessibleInfos
473
0
                           ? mpWindowImpl->mpAccessibleInfos->nAccessibleRole
474
0
                           : accessibility::AccessibleRole::UNKNOWN;
475
0
    if (nRole == accessibility::AccessibleRole::UNKNOWN)
476
0
        nRole = getDefaultAccessibleRole();
477
0
    return nRole;
478
0
}
479
480
void Window::SetAccessibleName( const OUString& rName )
481
0
{
482
0
    if ( !mpWindowImpl->mpAccessibleInfos )
483
0
        mpWindowImpl->mpAccessibleInfos.reset( new ImplAccessibleInfos );
484
485
0
    OUString oldName = GetAccessibleName();
486
487
0
    mpWindowImpl->mpAccessibleInfos->pAccessibleName = rName;
488
489
0
    CallEventListeners( VclEventId::WindowFrameTitleChanged, &oldName );
490
0
}
491
492
OUString Window::GetAccessibleName() const
493
0
{
494
0
    if (!mpWindowImpl)
495
0
        return OUString();
496
497
0
    if (mpWindowImpl->mpAccessibleInfos && mpWindowImpl->mpAccessibleInfos->pAccessibleName)
498
0
        return *mpWindowImpl->mpAccessibleInfos->pAccessibleName;
499
0
    return getDefaultAccessibleName();
500
0
}
501
502
OUString Window::getDefaultAccessibleName() const
503
0
{
504
0
    OUString aAccessibleName;
505
0
    switch ( GetType() )
506
0
    {
507
0
        case WindowType::MULTILINEEDIT:
508
0
        case WindowType::PATTERNFIELD:
509
0
        case WindowType::METRICFIELD:
510
0
        case WindowType::CURRENCYFIELD:
511
0
        case WindowType::EDIT:
512
513
0
        case WindowType::DATEBOX:
514
0
        case WindowType::TIMEBOX:
515
0
        case WindowType::CURRENCYBOX:
516
0
        case WindowType::LONGCURRENCYBOX:
517
0
        case WindowType::DATEFIELD:
518
0
        case WindowType::TIMEFIELD:
519
0
        case WindowType::SPINFIELD:
520
0
        case WindowType::FORMATTEDFIELD:
521
522
0
        case WindowType::COMBOBOX:
523
0
        case WindowType::LISTBOX:
524
0
        case WindowType::MULTILISTBOX:
525
0
        case WindowType::TREELISTBOX:
526
0
        case WindowType::METRICBOX:
527
0
        {
528
0
            vcl::Window *pLabel = GetAccessibleRelationLabeledBy();
529
0
            if ( pLabel && pLabel != this )
530
0
                aAccessibleName = pLabel->GetText();
531
0
            if (aAccessibleName.isEmpty())
532
0
                aAccessibleName = GetQuickHelpText();
533
0
            if (aAccessibleName.isEmpty())
534
0
                aAccessibleName = GetText();
535
0
        }
536
0
        break;
537
538
0
        case WindowType::IMAGEBUTTON:
539
0
        case WindowType::PUSHBUTTON:
540
0
            aAccessibleName = GetText();
541
0
            if (aAccessibleName.isEmpty())
542
0
            {
543
0
                aAccessibleName = GetQuickHelpText();
544
0
                if (aAccessibleName.isEmpty())
545
0
                    aAccessibleName = GetHelpText();
546
0
            }
547
0
        break;
548
549
0
        case WindowType::TOOLBOX:
550
0
            aAccessibleName = GetText();
551
0
            break;
552
553
0
        case WindowType::MOREBUTTON:
554
0
            aAccessibleName = mpWindowImpl->maText;
555
0
            break;
556
557
0
        default:
558
0
            aAccessibleName = GetText();
559
0
            break;
560
0
    }
561
562
0
    return removeMnemonicFromString( aAccessibleName );
563
0
}
564
565
void Window::SetAccessibleDescription( const OUString& rDescription )
566
0
{
567
0
    if ( ! mpWindowImpl->mpAccessibleInfos )
568
0
        mpWindowImpl->mpAccessibleInfos.reset( new ImplAccessibleInfos );
569
570
0
    std::optional<OUString>& rCurrentDescription = mpWindowImpl->mpAccessibleInfos->pAccessibleDescription;
571
0
    SAL_WARN_IF( rCurrentDescription && *rCurrentDescription != rDescription, "vcl", "AccessibleDescription already set" );
572
0
    rCurrentDescription = rDescription;
573
0
}
574
575
OUString Window::GetAccessibleDescription() const
576
0
{
577
0
    if (!mpWindowImpl)
578
0
        return OUString();
579
580
0
    OUString aAccessibleDescription;
581
0
    if ( mpWindowImpl->mpAccessibleInfos && mpWindowImpl->mpAccessibleInfos->pAccessibleDescription )
582
0
    {
583
0
        aAccessibleDescription = *mpWindowImpl->mpAccessibleInfos->pAccessibleDescription;
584
0
    }
585
0
    else
586
0
    {
587
        // Special code for help text windows. ZT asks the border window for the
588
        // description so we have to forward this request to our inner window.
589
0
        const vcl::Window* pWin = this->ImplGetWindow();
590
0
        if ( pWin->GetType() == WindowType::HELPTEXTWINDOW )
591
0
            aAccessibleDescription = pWin->GetHelpText();
592
0
        else
593
0
            aAccessibleDescription = GetHelpText();
594
0
    }
595
596
0
    return aAccessibleDescription;
597
0
}
598
599
void Window::SetAccessibleRelationLabeledBy( vcl::Window* pLabeledBy )
600
0
{
601
0
    if ( !mpWindowImpl->mpAccessibleInfos )
602
0
        mpWindowImpl->mpAccessibleInfos.reset( new ImplAccessibleInfos );
603
0
    mpWindowImpl->mpAccessibleInfos->pLabeledByWindow = pLabeledBy;
604
0
}
605
606
void Window::SetAccessibleRelationLabelFor( vcl::Window* pLabelFor )
607
0
{
608
0
    if ( !mpWindowImpl->mpAccessibleInfos )
609
0
        mpWindowImpl->mpAccessibleInfos.reset( new ImplAccessibleInfos );
610
0
    mpWindowImpl->mpAccessibleInfos->pLabelForWindow = pLabelFor;
611
0
}
612
613
vcl::Window* Window::GetAccessibleRelationMemberOf() const
614
0
{
615
0
    if (!isContainerWindow(this) && !isContainerWindow(GetParent()))
616
0
        return getLegacyNonLayoutAccessibleRelationMemberOf();
617
618
0
    return nullptr;
619
0
}
620
621
vcl::Window* Window::getAccessibleRelationLabelFor() const
622
0
{
623
0
    if (mpWindowImpl->mpAccessibleInfos && mpWindowImpl->mpAccessibleInfos->pLabelForWindow)
624
0
        return mpWindowImpl->mpAccessibleInfos->pLabelForWindow;
625
626
0
    return nullptr;
627
0
}
628
629
vcl::Window* Window::GetAccessibleRelationLabelFor() const
630
0
{
631
0
    vcl::Window* pWindow = getAccessibleRelationLabelFor();
632
633
0
    if (pWindow)
634
0
        return pWindow;
635
636
    // Avoid searching when using LOKit (jsdialog) - it can slow down dumping to json when we have a huge hierarchy
637
0
    if (!comphelper::LibreOfficeKit::isActive() && !isContainerWindow(this) && !isContainerWindow(GetParent()))
638
0
        return getLegacyNonLayoutAccessibleRelationLabelFor();
639
640
0
    return nullptr;
641
0
}
642
643
vcl::Window* Window::GetAccessibleRelationLabeledBy() const
644
0
{
645
0
    if (mpWindowImpl->mpAccessibleInfos && mpWindowImpl->mpAccessibleInfos->pLabeledByWindow)
646
0
        return mpWindowImpl->mpAccessibleInfos->pLabeledByWindow;
647
648
0
    auto const& aMnemonicLabels = list_mnemonic_labels();
649
0
    if (!aMnemonicLabels.empty())
650
0
    {
651
        //if we have multiple labels, then prefer the first that is visible
652
0
        for (auto const & rCandidate : aMnemonicLabels)
653
0
        {
654
0
            if (rCandidate->IsVisible())
655
0
                return rCandidate;
656
0
        }
657
0
        return aMnemonicLabels[0];
658
0
    }
659
660
    // Avoid searching when using LOKit (jsdialog) - it can slow down dumping to json when we have a huge hierarchy
661
0
    if (!comphelper::LibreOfficeKit::isActive() && !isContainerWindow(this) && !isContainerWindow(GetParent()))
662
0
        return getLegacyNonLayoutAccessibleRelationLabeledBy();
663
664
0
    return nullptr;
665
0
}
666
667
bool Window::IsAccessibilityEventsSuppressed()
668
0
{
669
0
    vcl::Window *pParent = this;
670
0
    while (pParent && pParent->mpWindowImpl)
671
0
    {
672
0
        if (pParent->mpWindowImpl->mbSuppressAccessibilityEvents)
673
0
            return true;
674
0
        else
675
0
            pParent = pParent->mpWindowImpl->mpParent; // do not use GetParent() to find borderwindows that are frames
676
0
    }
677
0
    return false;
678
0
}
679
680
} /* namespace vcl */
681
682
uno::Reference<accessibility::XAccessibleEditableText>
683
FindFocusedEditableText(uno::Reference<accessibility::XAccessibleContext> const& xContext)
684
0
{
685
0
    if (!xContext.is())
686
0
        return uno::Reference<accessibility::XAccessibleEditableText>();
687
688
0
    sal_Int64 nState = xContext->getAccessibleStateSet();
689
0
    if (nState & accessibility::AccessibleStateType::FOCUSED)
690
0
    {
691
0
        uno::Reference<accessibility::XAccessibleEditableText> xText(xContext, uno::UNO_QUERY);
692
0
        if (xText.is())
693
0
            return xText;
694
0
        if (nState & accessibility::AccessibleStateType::MANAGES_DESCENDANTS)
695
0
            return uno::Reference<accessibility::XAccessibleEditableText>();
696
0
    }
697
698
0
    bool bSafeToIterate = true;
699
0
    sal_Int64 nCount = xContext->getAccessibleChildCount();
700
0
    if (nCount < 0 || nCount > SAL_MAX_UINT16 /* slow enough for anyone */)
701
0
        bSafeToIterate = false;
702
0
    if (!bSafeToIterate)
703
0
        return uno::Reference<accessibility::XAccessibleEditableText>();
704
705
0
    for (sal_Int64 i = 0; i < xContext->getAccessibleChildCount(); ++i)
706
0
    {
707
0
        uno::Reference<accessibility::XAccessible> xChild = xContext->getAccessibleChild(i);
708
0
        if (!xChild.is())
709
0
            continue;
710
0
        uno::Reference<accessibility::XAccessibleContext> xChildContext
711
0
            = xChild->getAccessibleContext();
712
0
        if (!xChildContext.is())
713
0
            continue;
714
0
        uno::Reference<accessibility::XAccessibleEditableText> xText
715
0
            = FindFocusedEditableText(xChildContext);
716
0
        if (xText.is())
717
0
            return xText;
718
0
    }
719
0
    return uno::Reference<accessibility::XAccessibleEditableText>();
720
0
}
721
722
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */