Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/chart2/source/controller/accessibility/AccessibleChartView.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 <AccessibleChartView.hxx>
21
#include <ObjectHierarchy.hxx>
22
#include <ObjectIdentifier.hxx>
23
#include <ResId.hxx>
24
#include <strings.hrc>
25
#include "AccessibleViewForwarder.hxx"
26
#include <ChartModel.hxx>
27
#include <ChartView.hxx>
28
#include <ChartController.hxx>
29
30
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
31
#include <com/sun/star/accessibility/AccessibleRole.hpp>
32
#include <com/sun/star/view/XSelectionSupplier.hpp>
33
34
#include <rtl/ustring.hxx>
35
#include <vcl/window.hxx>
36
#include <vcl/svapp.hxx>
37
#include <osl/mutex.hxx>
38
39
using namespace ::com::sun::star;
40
using namespace ::com::sun::star::accessibility;
41
42
using ::com::sun::star::uno::Reference;
43
using ::com::sun::star::uno::WeakReference;
44
using osl::MutexGuard;
45
46
namespace chart
47
{
48
49
AccessibleChartView::AccessibleChartView(SdrView* pView)
50
0
    : ImplInheritanceHelper(AccessibleElementInfo(), // empty for now
51
0
                            true, // has children
52
0
                            true // always transparent
53
0
                            )
54
0
    , m_pSdrView(pView)
55
0
{
56
0
    AddState( AccessibleStateType::OPAQUE );
57
0
}
58
59
AccessibleChartView::~AccessibleChartView()
60
0
{
61
0
}
62
63
awt::Rectangle AccessibleChartView::GetWindowPosSize() const
64
0
{
65
0
    SolarMutexGuard aSolarGuard;
66
67
0
    VclPtr<vcl::Window> pWindow = GetInfo().m_pWindow;
68
0
    if (!pWindow)
69
0
        return awt::Rectangle();
70
71
0
    awt::Rectangle aBBox;
72
0
    Point aVCLPoint( pWindow->OutputToAbsoluteScreenPixel( Point( 0, 0 ) ));
73
0
    const Size aSize = pWindow->GetSizePixel();
74
0
    aBBox.X = aVCLPoint.getX();
75
0
    aBBox.Y = aVCLPoint.getY();
76
0
    aBBox.Width = aSize.Width();
77
0
    aBBox.Height = aSize.Height();
78
79
0
    return aBBox;
80
0
}
81
82
awt::Point AccessibleChartView::GetUpperLeftOnScreen() const
83
0
{
84
0
    awt::Point aParentPosition;
85
86
0
    awt::Rectangle aBBox( GetWindowPosSize() );
87
0
    aParentPosition.X = aBBox.X;
88
0
    aParentPosition.Y = aBBox.Y;
89
90
0
    return aParentPosition;
91
0
}
92
93
// ________ XAccessibleContext ________
94
OUString SAL_CALL AccessibleChartView::getAccessibleName()
95
0
{
96
0
    return SchResId(STR_OBJECT_DIAGRAM);
97
0
}
98
99
OUString SAL_CALL AccessibleChartView::getAccessibleDescription()
100
0
{
101
0
    return getAccessibleName();
102
0
}
103
104
Reference< XAccessible > SAL_CALL AccessibleChartView::getAccessibleParent()
105
0
{
106
0
    return Reference< XAccessible >( m_xParent );
107
0
}
108
109
sal_Int64 SAL_CALL AccessibleChartView::getAccessibleIndexInParent()
110
0
{
111
    // the document is always the only child of the window
112
0
    return 0;
113
0
}
114
115
sal_Int16 SAL_CALL AccessibleChartView::getAccessibleRole()
116
0
{
117
0
    return AccessibleRole::DOCUMENT;
118
0
}
119
120
awt::Rectangle AccessibleChartView::implGetBounds()
121
0
{
122
0
    awt::Rectangle aResult( GetWindowPosSize());
123
0
    Reference< XAccessible > xParent( m_xParent );
124
0
    if( xParent.is())
125
0
    {
126
0
        Reference< XAccessibleComponent > xContext( xParent->getAccessibleContext(), uno::UNO_QUERY );
127
0
        if( xContext.is())
128
0
        {
129
0
            awt::Point aParentPosition = xContext->getLocationOnScreen();
130
0
            aResult.X -= aParentPosition.X;
131
0
            aResult.Y -= aParentPosition.Y;
132
0
        }
133
0
    }
134
0
    return aResult;
135
0
}
136
137
138
void SAL_CALL AccessibleChartView::disposing()
139
0
{
140
0
    m_pChartWindow.reset();
141
142
0
    AccessibleBase::disposing();
143
0
}
144
145
void AccessibleChartView::initialize( ChartController& rNewChartController,
146
                     const rtl::Reference<::chart::ChartModel>& xNewChartModel,
147
                     const rtl::Reference<::chart::ChartView>& xNewChartView,
148
                     const uno::Reference< XAccessible >& xNewParent,
149
                     ChartWindow* pNewChartWindow)
150
0
{
151
    //0: view::XSelectionSupplier offers notifications for selection changes and access to the selection itself
152
    //1: frame::XModel representing the chart model - offers access to object data
153
    //2: lang::XInterface representing the normal chart view - offers access to some extra object data
154
155
    //all arguments are only valid until next initialization
156
0
    bool bChanged = false;
157
0
    bool bOldInvalid = false;
158
0
    bool bNewInvalid = false;
159
160
0
    rtl::Reference< ::chart::ChartController > xChartController;
161
0
    rtl::Reference<::chart::ChartModel> xChartModel;
162
0
    rtl::Reference<::chart::ChartView> xChartView;
163
0
    Reference< XAccessible > xParent;
164
0
    VclPtr<ChartWindow> pChartWindow;
165
0
    {
166
0
        MutexGuard aGuard( m_aMutex);
167
0
        xChartController = m_xChartController;
168
0
        xChartModel = m_xChartModel;
169
0
        xChartView = m_xChartView;
170
0
        xParent.set( m_xParent );
171
0
        pChartWindow = m_pChartWindow;
172
0
    }
173
174
0
    if( !xChartController.is() || !xChartModel.is() || !xChartView.is() )
175
0
    {
176
0
        bOldInvalid = true;
177
0
    }
178
179
0
    if( xNewChartModel.get() != xChartModel.get() )
180
0
    {
181
0
        xChartModel = xNewChartModel;
182
0
        bChanged = true;
183
0
    }
184
185
0
    if( xNewChartView != xChartView )
186
0
    {
187
0
        xChartView = xNewChartView;
188
0
        bChanged = true;
189
0
    }
190
191
0
    if( xNewParent != xParent )
192
0
    {
193
0
        xParent = xNewParent;
194
0
        bChanged = true;
195
0
    }
196
197
0
    if (pNewChartWindow != pChartWindow)
198
0
    {
199
0
        pChartWindow = pNewChartWindow;
200
0
        bChanged = true;
201
0
    }
202
203
0
    if(xChartController != &rNewChartController)
204
0
    {
205
0
        if (xChartController)
206
0
            xChartController->removeSelectionChangeListener(this);
207
0
        rNewChartController.addSelectionChangeListener(this);
208
0
        xChartController = &rNewChartController;
209
0
        bChanged = true;
210
0
    }
211
212
0
    if( !xChartController.is() || !xChartModel.is() || !xChartView.is() )
213
0
    {
214
0
        if(xChartController.is())
215
0
        {
216
0
            xChartController->removeSelectionChangeListener(this);
217
0
            xChartController.clear();
218
0
        }
219
0
        xChartModel.clear();
220
0
        xChartView.clear();
221
0
        xParent.clear();
222
0
        pChartWindow.reset();
223
224
0
        bNewInvalid = true;
225
0
    }
226
227
0
    {
228
0
        MutexGuard aGuard( m_aMutex);
229
0
        m_xChartController = xChartController.get();
230
0
        m_xChartModel = xChartModel.get();
231
0
        m_xChartView = xChartView.get();
232
0
        m_xParent = xParent;
233
0
        m_pChartWindow = std::move(pChartWindow);
234
0
    }
235
236
0
    if( bOldInvalid && bNewInvalid )
237
0
        bChanged = false;
238
239
0
    if( !bChanged )
240
0
        return;
241
242
0
    {
243
        //before notification we prepare for creation of new context
244
        //the old context will be deleted after notification than
245
0
        MutexGuard aGuard( m_aMutex);
246
0
        if( xChartModel.is())
247
0
            m_spObjectHierarchy =
248
0
                std::make_shared<ObjectHierarchy>( xChartModel, m_xChartView.get().get() );
249
0
        else
250
0
            m_spObjectHierarchy.reset();
251
0
    }
252
253
0
    {
254
0
        AccessibleElementInfo aAccInfo;
255
0
        aAccInfo.m_aOID = ObjectIdentifier(u"ROOT"_ustr);
256
0
        aAccInfo.m_xChartDocument = m_xChartModel;
257
0
        aAccInfo.m_xChartController = m_xChartController;
258
0
        aAccInfo.m_xView = m_xChartView;
259
0
        aAccInfo.m_pWindow = m_pChartWindow;
260
0
        aAccInfo.m_pParent = nullptr;
261
0
        aAccInfo.m_spObjectHierarchy = m_spObjectHierarchy;
262
0
        aAccInfo.m_pSdrView = m_pSdrView;
263
0
        m_pViewForwarder.reset(new AccessibleViewForwarder(this, m_pChartWindow));
264
0
        aAccInfo.m_pViewForwarder = m_pViewForwarder.get();
265
        // broadcasts an INVALIDATE_ALL_CHILDREN event globally
266
0
        SetInfo( aAccInfo );
267
0
    }
268
0
}
269
270
void AccessibleChartView::initialize()
271
0
{
272
    //0: view::XSelectionSupplier offers notifications for selection changes and access to the selection itself
273
    //1: frame::XModel representing the chart model - offers access to object data
274
    //2: lang::XInterface representing the normal chart view - offers access to some extra object data
275
276
    //all arguments are only valid until next initialization
277
0
    bool bChanged = false;
278
0
    bool bOldInvalid = false;
279
280
0
    rtl::Reference< ::chart::ChartController > xChartController;
281
0
    rtl::Reference<::chart::ChartModel> xChartModel;
282
0
    rtl::Reference<::chart::ChartView> xChartView;
283
0
    {
284
0
        MutexGuard aGuard( m_aMutex);
285
0
        xChartController = m_xChartController;
286
0
        xChartModel = m_xChartModel;
287
0
        xChartView = m_xChartView;
288
0
    }
289
290
0
    if( !xChartController.is() || !xChartModel.is() || !xChartView.is() )
291
0
    {
292
0
        bOldInvalid = true;
293
0
    }
294
295
0
    if( xChartModel.is() )
296
0
    {
297
0
        bChanged = true;
298
0
        xChartModel = nullptr;
299
0
    }
300
301
0
    if( xChartView.is() )
302
0
    {
303
0
        bChanged = true;
304
0
        xChartView = nullptr;
305
0
    }
306
307
0
    if( xChartController.is() )
308
0
    {
309
0
        bChanged = true;
310
0
        xChartController->removeSelectionChangeListener(this);
311
0
        xChartController = nullptr;
312
0
    }
313
314
0
    {
315
0
        MutexGuard aGuard( m_aMutex);
316
0
        m_xChartController = xChartController.get();
317
0
        m_xChartModel = xChartModel.get();
318
0
        m_xChartView = xChartView.get();
319
0
        m_xParent.clear();
320
0
        m_pChartWindow.reset();
321
0
    }
322
323
0
    if( bOldInvalid )
324
0
        bChanged = false;
325
326
0
    if( !bChanged )
327
0
        return;
328
329
0
    {
330
        //before notification we prepare for creation of new context
331
        //the old context will be deleted after notification than
332
0
        MutexGuard aGuard( m_aMutex);
333
0
        if( xChartModel.is())
334
0
            m_spObjectHierarchy =
335
0
                std::make_shared<ObjectHierarchy>( xChartModel, m_xChartView.get().get() );
336
0
        else
337
0
            m_spObjectHierarchy.reset();
338
0
    }
339
340
0
    {
341
0
        AccessibleElementInfo aAccInfo;
342
0
        aAccInfo.m_aOID = ObjectIdentifier(u"ROOT"_ustr);
343
0
        aAccInfo.m_xChartDocument = m_xChartModel;
344
0
        aAccInfo.m_xChartController = m_xChartController;
345
0
        aAccInfo.m_xView = m_xChartView;
346
0
        aAccInfo.m_pWindow.reset();
347
0
        aAccInfo.m_pParent = nullptr;
348
0
        aAccInfo.m_spObjectHierarchy = m_spObjectHierarchy;
349
0
        aAccInfo.m_pSdrView = m_pSdrView;
350
0
        m_pViewForwarder.reset(new AccessibleViewForwarder(this, nullptr));
351
0
        aAccInfo.m_pViewForwarder = m_pViewForwarder.get();
352
        // broadcasts an INVALIDATE_ALL_CHILDREN event globally
353
0
        SetInfo( aAccInfo );
354
0
    }
355
0
}
356
357
// view::XSelectionChangeListener
358
359
void SAL_CALL AccessibleChartView::selectionChanged( const lang::EventObject& /*rEvent*/ )
360
0
{
361
0
    rtl::Reference< ::chart::ChartController > xChartController;
362
0
    {
363
0
        MutexGuard aGuard( m_aMutex);
364
0
        xChartController = m_xChartController.get();
365
0
    }
366
367
0
    if( !xChartController.is() )
368
0
        return;
369
370
0
    ObjectIdentifier aSelectedOID( xChartController->getSelection() );
371
0
    if ( m_aCurrentSelectionOID.isValid() )
372
0
    {
373
0
        NotifyEvent( EventType::LOST_SELECTION, m_aCurrentSelectionOID );
374
0
    }
375
0
    if( aSelectedOID.isValid() )
376
0
    {
377
0
        NotifyEvent( EventType::GOT_SELECTION, aSelectedOID );
378
0
    }
379
0
    m_aCurrentSelectionOID = std::move(aSelectedOID);
380
0
}
381
382
// XEventListener
383
void SAL_CALL AccessibleChartView::disposing( const lang::EventObject& /*Source*/ )
384
0
{
385
0
}
386
387
} //namespace chart
388
389
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */