Coverage Report

Created: 2026-02-14 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svx/source/accessibility/ChildrenManagerImpl.hxx
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
#ifndef INCLUDED_SVX_SOURCE_ACCESSIBILITY_CHILDRENMANAGERIMPL_HXX
21
#define INCLUDED_SVX_SOURCE_ACCESSIBILITY_CHILDRENMANAGERIMPL_HXX
22
23
#include <svx/AccessibleShape.hxx>
24
#include <svx/IAccessibleViewForwarderListener.hxx>
25
#include <svx/IAccessibleParent.hxx>
26
#include <svx/AccessibleShapeTreeInfo.hxx>
27
#include <editeng/AccessibleContextBase.hxx>
28
#include <comphelper/compbase.hxx>
29
#include <tools/gen.hxx>
30
#include <vector>
31
#include <com/sun/star/drawing/XShape.hpp>
32
#include <com/sun/star/drawing/XShapes.hpp>
33
#include <com/sun/star/document/XEventListener.hpp>
34
#include <com/sun/star/view/XSelectionChangeListener.hpp>
35
#include <com/sun/star/accessibility/XAccessible.hpp>
36
37
namespace accessibility {
38
39
class ChildDescriptor; // See below for declaration.
40
typedef ::std::vector<ChildDescriptor> ChildDescriptorListType;
41
42
// Re-using MutexOwner class defined in AccessibleContextBase.hxx
43
44
/** This class contains the actual implementation of the children manager.
45
46
    <p>It maintains a set of visible accessible shapes in
47
    <member>maVisibleChildren</member>.  The objects in this list stem from
48
    two sources.  The first is a list of UNO shapes like the list of shapes
49
    in a draw page.  A reference to this list is held in
50
    <member>maShapeList</member>.  Accessible objects for these shapes are
51
    created on demand.  The list can be replaced by calls to the
52
    <member>SetShapeList</member> method.  The second source is a list of
53
    already accessible objects.  It can be modified by calls to the
54
    <member>AddAccessibleShape</member> and
55
    <member>ClearAccessibleShapeList</member> methods.</p>
56
57
    <p>Each call of the <member>Update</member> method leads to a
58
    re-calculation of the visible shapes which then can be queried with the
59
    <member>GetChildCount</member> and <member>GetChild</member> methods.
60
    Events are sent informing all listeners about the removed shapes which are
61
    not visible anymore and about the added shapes.</p>
62
63
    <p> The visible area which is used to determine the visibility of the
64
    shapes is taken from the view forwarder.  Thus, to signal a change of
65
    the visible area call <member>ViewForwarderChanged</member>.</p>
66
67
    <p>The children manager adds itself as disposing() listener at every UNO
68
    shape it creates an accessible object for so that when the UNO shape
69
    passes away it can dispose() the associated accessible object.</p>
70
71
    @see ChildrenManager
72
*/
73
class ChildrenManagerImpl final
74
    :   public comphelper::WeakComponentImplHelper<
75
            css::document::XEventListener,
76
            css::view::XSelectionChangeListener>,
77
        public IAccessibleViewForwarderListener,
78
        public IAccessibleParent
79
{
80
public:
81
    /** Create a children manager, which manages the children of the given
82
        parent.  The parent is used for creating accessible objects.  The
83
        list of shapes for which to create those objects is not derived from
84
        the parent and has to be provided separately by calling one of the
85
        update methods.
86
        @param rxParent
87
            The parent of the accessible objects which will be created
88
            on demand at some point of time in the future.
89
        @param rxShapeList
90
            List of UNO shapes to manage.
91
        @param rShapeTreeInfo
92
            Bundle of information passed down the shape tree.
93
        @param rContext
94
            An accessible context object that is called for firing events
95
            for new and deleted children, i.e. that holds a list of
96
            listeners to be informed.
97
    */
98
    ChildrenManagerImpl(rtl::Reference<comphelper::OAccessible> pParent,
99
                        css::uno::Reference<css::drawing::XShapes> xShapeList,
100
                        const AccessibleShapeTreeInfo& rShapeTreeInfo,
101
                        AccessibleContextBase& rContext);
102
103
    /** If there still are managed children these are disposed and
104
        released.
105
    */
106
    virtual ~ChildrenManagerImpl() override;
107
108
    /** Do that part of the initialization that you can not or should not do
109
        in the constructor like registering at broadcasters.
110
    */
111
    void Init();
112
113
    /** Return the number of currently visible accessible children.
114
        @return
115
            If there are no children a 0 is returned.
116
    */
117
    sal_Int64 GetChildCount() const noexcept;
118
119
    /// @throws css::uno::RuntimeException
120
    /// @throws css::lang::IndexOutOfBoundsException
121
    const css::uno::Reference<css::drawing::XShape>& GetChildShape(sal_Int64 nIndex);
122
    /** Return the requested accessible child or throw and
123
        IndexOutOfBoundsException if the given index is invalid.
124
        @param nIndex
125
            Index of the requested child.  Call getChildCount for obtaining
126
            the number of children.
127
        @return
128
            In case of a valid index this method returns a reference to the
129
            requested accessible child.  This reference is empty if it has
130
            not been possible to create the accessible object of the
131
            corresponding shape.
132
        @throws
133
            Throws an IndexOutOfBoundsException if the index is not valid.
134
    */
135
    rtl::Reference<comphelper::OAccessible> GetChild(sal_Int64 nIndex);
136
137
    /** Return the requested accessible child.
138
        @param aChildDescriptor
139
            This object contains references to the original shape and its
140
            associated accessible object.
141
        @param  _nIndex
142
            The index which will be used in getAccessibleIndexInParent of the accessible shape.
143
        @return
144
            Returns a reference to the requested accessible child.  This
145
            reference is empty if it has not been possible to create the
146
            accessible object of the corresponding shape.
147
        @throws css::uno::RuntimeException
148
    */
149
    rtl::Reference<comphelper::OAccessible> GetChild(ChildDescriptor& aChildDescriptor,
150
                                                     sal_Int32 _nIndex);
151
152
    /** Update the child manager.  Take care of a modified set of children
153
        and modified visible area.  This method can optimize the update
154
        process with respect separate updates of a modified children list
155
        and visible area.
156
        @param bCreateNewObjectsOnDemand
157
            If </true> then accessible objects associated with the visible
158
            shapes are created only when asked for.  No event is sent on
159
            creation.  If </false> then the accessible objects are created
160
            before this method returns and events are sent to inform the
161
            listeners of the new object.
162
    */
163
    void Update (bool bCreateNewObjectsOnDemand);
164
165
    /** Set the list of UNO shapes to the given list.  This removes the old
166
        list and does not add to it. The list of accessible shapes that is
167
        build up by calls to <member>AddAccessibleShape</member> is not
168
        modified.  Neither is the list of visible children.  Accessible
169
        objects are created on demand.
170
        @param xShapeList
171
            The list of UNO shapes that replaces the old list.
172
    */
173
    void SetShapeList (const css::uno::Reference<css::drawing::XShapes>& xShapeList);
174
175
    /** Add an accessible shape.  This does not modify the list of UNO shapes
176
        or the list of visible shapes.  Accessible shapes are, at the
177
        moment, not tested against the visible area but are always appended
178
        to the list of visible children.
179
        @param shape
180
            The new shape that is added to the list of accessible shapes; must
181
            be non-null.
182
    */
183
    void AddAccessibleShape (rtl::Reference<AccessibleShape> const & shape);
184
185
    /** Clear the lists of accessible shapes and that of visible accessible
186
        shapes.  The list of UNO shapes is not modified.
187
    */
188
    void ClearAccessibleShapeList();
189
190
    /** Set a new event shape tree info.  Call this method to inform the
191
        children manager of a change of the info bundle.
192
        @param rShapeTreeInfo
193
            The new info that replaces the current one.
194
    */
195
    void SetInfo (const AccessibleShapeTreeInfo& rShapeTreeInfo);
196
197
    /** Update the SELECTED and FOCUSED states of all visible children
198
        according to the given selection.  This includes setting
199
        <em>and</em> resetting the states.
200
    */
201
    void UpdateSelection();
202
203
    /** Return whether one of the shapes managed by this object has
204
        currently the focus.
205
        @return
206
            Returns <true/> when there is a shape that has the focus and
207
            <false/> when there is no such shape.
208
    */
209
    bool HasFocus() const;
210
211
    /** When there is a shape that currently has the focus,
212
        i.e. <member>HasFocus()</member> returns <true/> then remove the
213
        focus from that shape.  Otherwise nothing changes.
214
    */
215
    void RemoveFocus();
216
217
    // lang::XEventListener
218
    virtual void SAL_CALL
219
        disposing (const css::lang::EventObject& rEventObject) override;
220
221
    // document::XEventListener
222
    virtual void SAL_CALL
223
        notifyEvent (const css::document::EventObject& rEventObject) override;
224
225
    // view::XSelectionChangeListener
226
    virtual void  SAL_CALL
227
        selectionChanged (const css::lang::EventObject& rEvent) override;
228
229
    // IAccessibleViewForwarderListener
230
    /** Informs this children manager and its children about a change of one
231
        (or more) aspect of the view forwarder.
232
        @param aChangeType
233
            A change type of <const>VISIBLE_AREA</const> leads to a call to
234
            the <member>Update</member> which creates accessible objects of
235
            new shapes immediately.  Other change types are passed to the
236
            visible accessible children without calling
237
            <member>Update</member>.
238
        @param pViewForwarder
239
            The modified view forwarder.  Use this one from now on.
240
    */
241
    virtual void ViewForwarderChanged() override;
242
243
    // IAccessibleParent
244
    /** Replace the specified child with a replacement.
245
        @param pCurrentChild
246
            This child is to be replaced.
247
        @param pReplacement
248
            The replacement for the current child.
249
        @return
250
            The returned value indicates whether the replacement has been
251
            finished successfully.
252
    */
253
    virtual bool ReplaceChild (
254
        AccessibleShape* pCurrentChild,
255
        const css::uno::Reference< css::drawing::XShape >& _rxShape,
256
        const tools::Long _nIndex,
257
        const AccessibleShapeTreeInfo& _rShapeTreeInfo
258
    ) override;
259
260
    // Add the impl method for IAccessibleParent interface
261
    virtual AccessibleControlShape* GetAccControlShapeFromModel
262
        (css::beans::XPropertySet* pSet) override;
263
    virtual AccessibleShape*
264
        GetAccessibleCaption (const css::uno::Reference<css::drawing::XShape>& xShape) override;
265
266
private:
267
    /** This list holds the descriptors of all currently visible shapes and
268
        associated accessible object.
269
270
        <p>With the descriptors it maintains a mapping of shapes to
271
        accessible objects.  It acts as a cache in that accessible objects
272
        are only created on demand and released with every update (where the
273
        latter may be optimized by the update methods).<p>
274
275
        <p>The list is realized as a vector because it remains unchanged
276
        between updates (i.e. complete rebuilds of the list) and allows a
277
        fast (constant time) access to its elements for given indices.</p>
278
    */
279
    ChildDescriptorListType maVisibleChildren;
280
281
    /** The original list of UNO shapes.  The visible shapes are inserted
282
        into the list of visible children
283
        <member>maVisibleChildren</member>.
284
    */
285
    css::uno::Reference<css::drawing::XShapes> mxShapeList;
286
287
    /** This list of additional accessible shapes that can or shall not be
288
        created by the shape factory.
289
    */
290
    typedef std::vector< rtl::Reference< AccessibleShape> > AccessibleShapeList;
291
    AccessibleShapeList maAccessibleShapes;
292
293
    /** Rectangle that describes the visible area in which a shape has to lie
294
        at least partly, to be accessible through this class.  Used to
295
        detect changes of the visible area after changes of the view forwarder.
296
    */
297
    tools::Rectangle maVisibleArea;
298
299
    /** The parent of the shapes.  It is used for creating accessible
300
        objects for given shapes.
301
    */
302
    rtl::Reference<comphelper::OAccessible> mpParent;
303
304
    /** Bundle of information passed down the shape tree.
305
    */
306
    AccessibleShapeTreeInfo maShapeTreeInfo;
307
308
    /** Reference to an accessible context object that is used to inform its
309
        listeners of new and removed children.
310
    */
311
    AccessibleContextBase& mrContext;
312
313
    /** This method is called from the component helper base class while
314
        disposing.
315
    */
316
    virtual void disposing(std::unique_lock<std::mutex>&) override;
317
318
    void impl_dispose();
319
320
    ChildrenManagerImpl (const ChildrenManagerImpl&) = delete;
321
    ChildrenManagerImpl& operator= (const ChildrenManagerImpl&) = delete;
322
323
    /** This member points to the currently focused shape.  It is NULL when
324
        there is no focused shape.
325
    */
326
    AccessibleShape* mpFocusedShape;
327
328
    /** Three helper functions for the <member>Update</member> method.
329
    */
330
331
    /** Create a list of visible shapes from the list of UNO shapes
332
        <member>maShapeList</member> and the list of accessible objects.
333
        @param raChildList
334
            For every visible shape from the two sources mentioned above one
335
            descriptor is added to this list.
336
    */
337
    void CreateListOfVisibleShapes (ChildDescriptorListType& raChildList);
338
339
    /** From the old list of (former) visible shapes remove those that
340
        are not member of the new list.  Send appropriate events for every
341
        such shape.
342
        @param raNewChildList
343
            The new list of visible children against which the old one
344
            is compared.
345
        @param raOldChildList
346
            The old list of visible children against which the new one
347
            is compared.
348
    */
349
    void RemoveNonVisibleChildren (
350
        const std::vector<ChildDescriptor*>& rNonVisibleChildren);
351
352
    /** Merge the information that is already known about the visible shapes
353
        from the old list into the current list, and return a list of
354
        children that are in the old list, but not the current one.
355
        @param raChildList
356
            Information is merged to the current list of visible children
357
            from this list. The old list can get reordered.
358
        @return
359
            Vector of children that are in the old list, but not the current
360
            one.
361
    */
362
    std::vector<ChildDescriptor*> MergeAccessibilityInformation (ChildDescriptorListType& raChildList);
363
364
    /** If the visible area has changed then send events that signal a
365
        change of their bounding boxes for all shapes that are members of
366
        both the current and the new list of visible shapes.
367
        @param raChildList
368
            Events are sent to all entries of this list that already contain
369
            an accessible object.
370
    */
371
    static void SendVisibleAreaEvents (ChildDescriptorListType& raChildList);
372
373
    /** If children have to be created immediately and not on demand the
374
        create the missing accessible objects now.
375
        @param raDescriptorList
376
            Create an accessible object for every member of this list where
377
            that object does not already exist.
378
    */
379
    void CreateAccessibilityObjects (ChildDescriptorListType& raChildList);
380
381
    /** Add a single shape.  Update all relevant data structures
382
        accordingly.  Use this method instead of <member>Update()</member>
383
        when only a single shape has been added.
384
    */
385
    void AddShape (const css::uno::Reference<css::drawing::XShape>& xShape);
386
387
    /** Remove a single shape.  Update all relevant data structures
388
        accordingly.  Use this method instead of <member>Update()</member>
389
        when only a single shape has been removed.
390
    */
391
    void RemoveShape (const css::uno::Reference<css::drawing::XShape>& xShape);
392
393
    /** Add the children manager as dispose listener at the given shape so
394
        that the associated accessible object can be disposed when the shape
395
        is disposed.
396
        @param xShape
397
            Register at this shape as dispose listener.
398
    */
399
    void RegisterAsDisposeListener (const css::uno::Reference<css::drawing::XShape>& xShape);
400
401
    /** Remove the children manager as dispose listener at the given shape
402
        @param xShape
403
            Unregister at this shape as dispose listener.
404
    */
405
    void UnregisterAsDisposeListener (const css::uno::Reference<css::drawing::XShape>& xShape);
406
};
407
408
409
/** A child descriptor holds a reference to a UNO shape and the
410
    corresponding accessible object.  There are two use cases:
411
    <ol><li>The accessible object is only created on demand and is then
412
    initially empty.</li>
413
    <li>There is no UNO shape.  The accessible object is given as argument
414
    to the constructor.</li>
415
    </ol>
416
    In both cases the child descriptor assumes ownership over the accessible
417
    object.
418
*/
419
class ChildDescriptor
420
{
421
public:
422
    /** Reference to a (partially) visible shape.
423
    */
424
    css::uno::Reference<css::drawing::XShape> mxShape;
425
426
    /** The corresponding accessible object.  This reference is initially
427
        empty and only replaced by a reference to a new object when that is
428
        requested from the outside.
429
    */
430
    rtl::Reference<AccessibleShape> mxAccessibleShape;
431
432
    /** Return a pointer to the implementation object of the accessible
433
        shape of this descriptor.
434
        @return
435
            The result is NULL if either the UNO reference to the accessible
436
            shape is empty or it can not be transformed into a pointer to
437
            the desired class.
438
    */
439
0
    AccessibleShape* GetAccessibleShape() const { return mxAccessibleShape.get(); }
440
441
    /** set the index _nIndex at the accessible shape
442
        @param  _nIndex
443
            The new index in parent.
444
    */
445
    void setIndexAtAccessibleShape(sal_Int32 _nIndex);
446
447
    /** This flag is set during the visibility calculation and indicates
448
        that at one time in this process an event is sent that informs the
449
        listeners of the creation of a new accessible object.  This flags is
450
        not reset afterwards.  Don't use it unless you know exactly what you
451
        are doing.
452
    */
453
    bool mbCreateEventPending;
454
455
    /** Create a new descriptor for the specified shape with empty reference
456
        to accessible object.
457
    */
458
    explicit ChildDescriptor (const css::uno::Reference<css::drawing::XShape>& xShape);
459
460
    /** Create a new descriptor for the specified shape with empty reference
461
        to the original shape.
462
    */
463
    explicit ChildDescriptor (const rtl::Reference<AccessibleShape>& rxAccessibleShape);
464
465
    /** Dispose the accessible object of this descriptor.  If that object
466
        does not exist then do nothing.
467
        @param rParent
468
            The parent of the accessible object to dispose.  A child event
469
            is sent in its name.
470
    */
471
    void disposeAccessibleObject (AccessibleContextBase& rParent);
472
473
    /** Compare two child descriptors.  Take into account that a child
474
        descriptor may be based on a UNO shape or, already, on an accessible
475
        shape.
476
    */
477
    bool operator == (const ChildDescriptor& aDescriptor) const
478
0
    {
479
0
        return (
480
0
                this == &aDescriptor ||
481
0
                (
482
0
                 (mxShape.get() == aDescriptor.mxShape.get() ) &&
483
0
                 (mxShape.is() || mxAccessibleShape.get() == aDescriptor.mxAccessibleShape.get())
484
0
                )
485
0
               );
486
0
    }
487
488
};
489
490
491
} // end of namespace accessibility
492
493
#endif
494
495
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */