Coverage Report

Created: 2026-02-14 09:37

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