Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/toolkit/source/controls/accessiblecontrolcontext.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 <controls/accessiblecontrolcontext.hxx>
21
#include <com/sun/star/awt/XControl.hpp>
22
#include <com/sun/star/awt/XWindow.hpp>
23
#include <com/sun/star/beans/XPropertySet.hpp>
24
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
25
#include <vcl/svapp.hxx>
26
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
27
#include <com/sun/star/accessibility/AccessibleRole.hpp>
28
#include <toolkit/helper/vclunohelper.hxx>
29
#include <comphelper/accessiblecontexthelper.hxx>
30
#include <comphelper/diagnose_ex.hxx>
31
#include <vcl/window.hxx>
32
33
namespace toolkit
34
{
35
using ::comphelper::OContextEntryGuard;
36
using namespace ::com::sun::star;
37
using namespace ::com::sun::star::uno;
38
using namespace ::com::sun::star::lang;
39
using namespace ::com::sun::star::beans;
40
using namespace ::com::sun::star::accessibility;
41
42
//= OAccessibleControlContext
43
44
OAccessibleControlContext::OAccessibleControlContext(
45
    const css::uno::Reference<css::awt::XControl>& rxControl)
46
0
{
47
0
    if (rxControl.is())
48
0
        m_xControlModel.set(rxControl->getModel(), css::uno::UNO_QUERY);
49
0
    OSL_ENSURE(
50
0
        m_xControlModel.is(),
51
0
        "OAccessibleControlContext::Init: invalid creator (no control, or control without model!");
52
0
    if (!m_xControlModel.is())
53
0
        throw DisposedException(); // caught by the caller (the create method)
54
55
    // start listening at the model
56
0
    startModelListening();
57
58
0
    m_aControl = rxControl;
59
0
}
60
61
0
OAccessibleControlContext::~OAccessibleControlContext() { ensureDisposed(); }
62
63
rtl::Reference<OAccessibleControlContext>
64
OAccessibleControlContext::create(const Reference<awt::XControl>& rXControl)
65
0
{
66
0
    rtl::Reference<OAccessibleControlContext> pNew;
67
0
    try
68
0
    {
69
0
        pNew = new OAccessibleControlContext(rXControl);
70
0
    }
71
0
    catch (const Exception&)
72
0
    {
73
0
        TOOLS_WARN_EXCEPTION("toolkit",
74
0
                             "OAccessibleControlContext::create: caught an exception in ctor!");
75
0
    }
76
0
    return pNew;
77
0
}
78
79
void OAccessibleControlContext::startModelListening()
80
0
{
81
0
    Reference<XComponent> xModelComp(m_xControlModel, UNO_QUERY);
82
0
    OSL_ENSURE(xModelComp.is(), "OAccessibleControlContext::startModelListening: invalid model!");
83
0
    if (xModelComp.is())
84
0
        xModelComp->addEventListener(this);
85
0
}
86
87
void OAccessibleControlContext::stopModelListening()
88
0
{
89
0
    Reference<XComponent> xModelComp(m_xControlModel, UNO_QUERY);
90
0
    OSL_ENSURE(xModelComp.is(), "OAccessibleControlContext::stopModelListening: invalid model!");
91
0
    if (xModelComp.is())
92
0
        xModelComp->removeEventListener(this);
93
0
}
94
95
sal_Int64 SAL_CALL OAccessibleControlContext::getAccessibleChildCount()
96
0
{
97
    // we do not have children
98
0
    return 0;
99
0
}
100
101
Reference<XAccessible> SAL_CALL OAccessibleControlContext::getAccessibleChild(sal_Int64)
102
0
{
103
    // we do not have children
104
0
    throw IndexOutOfBoundsException();
105
0
}
106
107
Reference<XAccessible> SAL_CALL OAccessibleControlContext::getAccessibleParent()
108
0
{
109
0
    return Reference<XAccessible>();
110
0
}
111
112
0
sal_Int16 SAL_CALL OAccessibleControlContext::getAccessibleRole() { return AccessibleRole::SHAPE; }
113
114
OUString SAL_CALL OAccessibleControlContext::getAccessibleDescription()
115
0
{
116
0
    OContextEntryGuard aGuard(this);
117
0
    return getModelStringProperty(u"HelpText"_ustr);
118
0
}
119
120
OUString SAL_CALL OAccessibleControlContext::getAccessibleName()
121
0
{
122
0
    OContextEntryGuard aGuard(this);
123
0
    return getModelStringProperty(u"Name"_ustr);
124
0
}
125
126
Reference<XAccessibleRelationSet> SAL_CALL OAccessibleControlContext::getAccessibleRelationSet()
127
0
{
128
0
    return nullptr;
129
0
}
130
131
sal_Int64 SAL_CALL OAccessibleControlContext::getAccessibleStateSet()
132
0
{
133
0
    ::osl::MutexGuard aGuard(GetMutex());
134
    // no OContextEntryGuard here, as we do not want to throw an exception in case we're not alive anymore
135
136
0
    sal_Int64 nStateSet = 0;
137
0
    if (isAlive())
138
0
    {
139
        // no own states, only the ones which are foreign controlled
140
0
    }
141
0
    else
142
0
    { // only the DEFUNC state if we're already disposed
143
0
        nStateSet |= AccessibleStateType::DEFUNC;
144
0
    }
145
0
    return nStateSet;
146
0
}
147
148
void SAL_CALL OAccessibleControlContext::disposing(const EventObject& _rSource)
149
0
{
150
0
    OSL_ENSURE(Reference<XPropertySet>(_rSource.Source, UNO_QUERY).get() == m_xControlModel.get(),
151
0
               "OAccessibleControlContext::disposing: where did this come from?");
152
153
0
    stopModelListening();
154
0
    m_xControlModel.clear();
155
0
    m_xModelPropsInfo.clear();
156
157
0
    comphelper::OAccessible::disposing();
158
0
}
159
160
OUString OAccessibleControlContext::getModelStringProperty(const OUString& _pPropertyName)
161
0
{
162
0
    OUString sReturn;
163
0
    try
164
0
    {
165
0
        if (!m_xModelPropsInfo.is() && m_xControlModel.is())
166
0
            m_xModelPropsInfo = m_xControlModel->getPropertySetInfo();
167
168
0
        if (m_xModelPropsInfo.is() && m_xModelPropsInfo->hasPropertyByName(_pPropertyName))
169
0
            m_xControlModel->getPropertyValue(_pPropertyName) >>= sReturn;
170
0
    }
171
0
    catch (const Exception&)
172
0
    {
173
0
        TOOLS_WARN_EXCEPTION("toolkit", "OAccessibleControlContext::getModelStringProperty");
174
0
    }
175
0
    return sReturn;
176
0
}
177
178
vcl::Window* OAccessibleControlContext::implGetWindow(Reference<awt::XWindow>* _pxUNOWindow) const
179
0
{
180
0
    Reference<awt::XControl> xControl(m_aControl);
181
0
    Reference<awt::XWindow> xWindow;
182
0
    if (xControl.is())
183
0
        xWindow.set(xControl->getPeer(), css::uno::UNO_QUERY);
184
185
0
    vcl::Window* pWindow = xWindow.is() ? VCLUnoHelper::GetWindow(xWindow) : nullptr;
186
187
0
    if (_pxUNOWindow)
188
0
        *_pxUNOWindow = std::move(xWindow);
189
190
0
    return pWindow;
191
0
}
192
193
awt::Rectangle OAccessibleControlContext::implGetBounds()
194
0
{
195
0
    SolarMutexGuard aSolarGuard;
196
    // want to do some VCL stuff here ...
197
0
    OContextEntryGuard aGuard(this);
198
199
0
    OSL_FAIL("OAccessibleControlContext::implGetBounds: performance issue: forced to calc the size "
200
0
             "myself!");
201
    // In design mode (and this is what this class is for), the surrounding shape (if any) should handle this call
202
    // The problem is that in design mode, our size may not be correct (in the drawing layer, controls are
203
    // positioned/sized for painting only), and that calculation of our position is expensive
204
205
    // what we know (or can obtain from somewhere):
206
    // * the PosSize of our peer, relative to its parent window
207
    // * the parent window which the PosSize is relative to
208
    // * our foreign controlled accessible parent
209
    // from this info, we can determine the position of our peer relative to the foreign parent
210
211
    // our control
212
0
    Reference<awt::XWindow> xWindow;
213
0
    VclPtr<vcl::Window> pVCLWindow = implGetWindow(&xWindow);
214
215
0
    awt::Rectangle aBounds(0, 0, 0, 0);
216
0
    if (xWindow.is())
217
0
    {
218
        // ugly, but... though the XWindow has a getPosSize, it is impossible to determine the
219
        // parent which this position/size is relative to. This means we must tunnel UNO and ask the
220
        // implementation
221
0
        vcl::Window* pVCLParent = pVCLWindow ? pVCLWindow->GetParent() : nullptr;
222
223
        // the relative location of the window
224
0
        ::Point aWindowRelativePos(0, 0);
225
0
        if (pVCLWindow)
226
0
            aWindowRelativePos = pVCLWindow->GetPosPixel();
227
228
        // the screen position of the "window parent" of the control
229
0
        ::Point aVCLParentScreenPos(0, 0);
230
0
        if (pVCLParent)
231
0
            aVCLParentScreenPos = pVCLParent->GetPosPixel();
232
233
        // now the size of the control
234
0
        aBounds = xWindow->getPosSize();
235
236
        // correct the pos
237
0
        aBounds.X = aWindowRelativePos.X() + aVCLParentScreenPos.X();
238
0
        aBounds.Y = aWindowRelativePos.Y() + aVCLParentScreenPos.Y();
239
0
    }
240
241
0
    return aBounds;
242
0
}
243
244
Reference<XAccessible>
245
    SAL_CALL OAccessibleControlContext::getAccessibleAtPoint(const awt::Point& /* _rPoint */)
246
0
{
247
    // no children at all
248
0
    return nullptr;
249
0
}
250
251
void SAL_CALL OAccessibleControlContext::grabFocus()
252
0
{
253
0
    OSL_FAIL("OAccessibleControlContext::grabFocus: !isFocusTraversable, but grabFocus!");
254
0
}
255
256
sal_Int32 SAL_CALL OAccessibleControlContext::getForeground()
257
0
{
258
0
    SolarMutexGuard aSolarGuard;
259
    // want to do some VCL stuff here ...
260
0
    OContextEntryGuard aGuard(this);
261
262
0
    VclPtr<vcl::Window> pWindow = implGetWindow();
263
0
    Color nColor;
264
0
    if (pWindow)
265
0
    {
266
0
        if (pWindow->IsControlForeground())
267
0
            nColor = pWindow->GetControlForeground();
268
0
        else
269
0
        {
270
0
            vcl::Font aFont;
271
0
            if (pWindow->IsControlFont())
272
0
                aFont = pWindow->GetControlFont();
273
0
            else
274
0
                aFont = pWindow->GetFont();
275
0
            nColor = aFont.GetColor();
276
0
        }
277
0
    }
278
0
    return sal_Int32(nColor);
279
0
}
280
281
sal_Int32 SAL_CALL OAccessibleControlContext::getBackground()
282
0
{
283
0
    SolarMutexGuard aSolarGuard;
284
    // want to do some VCL stuff here ...
285
0
    OContextEntryGuard aGuard(this);
286
287
0
    VclPtr<vcl::Window> pWindow = implGetWindow();
288
0
    Color nColor;
289
0
    if (pWindow)
290
0
    {
291
0
        if (pWindow->IsControlBackground())
292
0
            nColor = pWindow->GetControlBackground();
293
0
        else
294
0
            nColor = pWindow->GetBackground().GetColor();
295
0
    }
296
297
0
    return sal_Int32(nColor);
298
0
}
299
300
} //namespace toolkit
301
302
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */