Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/source/ui/Accessibility/AccessibleDocumentPagePreview.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 <AccessibleDocumentPagePreview.hxx>
21
#include <AccessiblePreviewTable.hxx>
22
#include <AccessiblePageHeader.hxx>
23
#include <AccessibilityHints.hxx>
24
#include <AccessibleText.hxx>
25
#include <document.hxx>
26
#include <prevwsh.hxx>
27
#include <prevloc.hxx>
28
#include <drwlayer.hxx>
29
#include <editsrc.hxx>
30
#include <scresid.hxx>
31
#include <strings.hrc>
32
#include <strings.hxx>
33
#include <preview.hxx>
34
#include <postit.hxx>
35
36
#include <com/sun/star/accessibility/AccessibleEventId.hpp>
37
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
38
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
39
#include <comphelper/sequence.hxx>
40
41
#include <tools/gen.hxx>
42
#include <svx/fmview.hxx>
43
#include <svx/svdpage.hxx>
44
#include <svx/svdobj.hxx>
45
#include <svx/AccessibleTextHelper.hxx>
46
#include <svx/AccessibleShape.hxx>
47
#include <svx/AccessibleShapeInfo.hxx>
48
#include <svx/IAccessibleParent.hxx>
49
#include <svx/IAccessibleViewForwarder.hxx>
50
#include <svx/ShapeTypeHandler.hxx>
51
#include <toolkit/helper/vclunohelper.hxx>
52
#include <vcl/svapp.hxx>
53
#include <vcl/unohelp.hxx>
54
#include <sfx2/docfile.hxx>
55
56
#include <vector>
57
#include <algorithm>
58
#include <memory>
59
#include <utility>
60
61
using namespace ::com::sun::star;
62
using namespace ::com::sun::star::accessibility;
63
64
typedef std::vector<rtl::Reference<comphelper::OAccessible>> ScOAccVector;
65
66
namespace {
67
68
struct ScAccNote
69
{
70
    OUString    maNoteText;
71
    tools::Rectangle   maRect;
72
    ScAddress   maNoteCell;
73
    ::accessibility::AccessibleTextHelper* mpTextHelper;
74
    sal_Int32   mnParaCount;
75
    bool    mbMarkNote;
76
77
    ScAccNote()
78
0
        : mpTextHelper(nullptr)
79
0
        , mnParaCount(0)
80
0
        , mbMarkNote(false)
81
0
    {
82
0
    }
83
};
84
85
}
86
87
class ScNotesChildren
88
{
89
public:
90
    ScNotesChildren(ScPreviewShell* pViewShell, ScAccessibleDocumentPagePreview& rAccDoc);
91
    ~ScNotesChildren();
92
    void Init(const tools::Rectangle& rVisRect, sal_Int32 nOffset);
93
94
0
    sal_Int32 GetChildrenCount() const { return mnParagraphs;}
95
    uno::Reference<XAccessible> GetChild(sal_Int32 nIndex) const;
96
    uno::Reference<XAccessible> GetAt(const awt::Point& rPoint) const;
97
98
    void DataChanged(const tools::Rectangle& rVisRect);
99
100
private:
101
    ScPreviewShell*         mpViewShell;
102
    ScAccessibleDocumentPagePreview& mrAccDoc;
103
    typedef std::vector<ScAccNote> ScAccNotes;
104
    mutable ScAccNotes      maNotes;
105
    mutable ScAccNotes      maMarks;
106
    sal_Int32               mnParagraphs;
107
    sal_Int32               mnOffset;
108
109
    ::accessibility::AccessibleTextHelper* CreateTextHelper(const OUString& rString, const tools::Rectangle& rVisRect, const ScAddress& aCellPos, bool bMarkNote, sal_Int32 nChildOffset) const;
110
    sal_Int32 AddNotes(const ScPreviewLocationData& rData, const tools::Rectangle& rVisRect, bool bMark, ScAccNotes& rNotes);
111
112
    static sal_Int8 CompareCell(const ScAddress& aCell1, const ScAddress& aCell2);
113
    static void CollectChildren(const ScAccNote& rNote, ScOAccVector& rVector);
114
    sal_Int32 CheckChanges(const ScPreviewLocationData& rData, const tools::Rectangle& rVisRect,
115
        bool bMark, ScAccNotes& rOldNotes, ScAccNotes& rNewNotes,
116
        ScOAccVector& rOldParas, ScOAccVector& rNewParas);
117
118
    inline ScDocument* GetDocument() const;
119
};
120
121
ScNotesChildren::ScNotesChildren(ScPreviewShell* pViewShell, ScAccessibleDocumentPagePreview& rAccDoc)
122
0
    : mpViewShell(pViewShell),
123
0
    mrAccDoc(rAccDoc),
124
0
    mnParagraphs(0),
125
0
    mnOffset(0)
126
0
{
127
0
}
128
129
ScNotesChildren::~ScNotesChildren()
130
0
{
131
0
    for (auto & i : maNotes)
132
0
        if (i.mpTextHelper)
133
0
        {
134
0
            delete i.mpTextHelper;
135
0
            i.mpTextHelper = nullptr;
136
0
        }
137
0
    for (auto & i : maMarks)
138
0
        if (i.mpTextHelper)
139
0
        {
140
0
            delete i.mpTextHelper;
141
0
            i.mpTextHelper = nullptr;
142
0
        }
143
0
}
144
145
::accessibility::AccessibleTextHelper* ScNotesChildren::CreateTextHelper(const OUString& rString, const tools::Rectangle& rVisRect, const ScAddress& aCellPos, bool bMarkNote, sal_Int32 nChildOffset) const
146
0
{
147
0
    ::accessibility::AccessibleTextHelper* pTextHelper = new ::accessibility::AccessibleTextHelper(std::make_unique<ScAccessibilityEditSource>(std::make_unique<ScAccessibleNoteTextData>(mpViewShell, rString, aCellPos, bMarkNote)));
148
0
    pTextHelper->SetEventSource(&mrAccDoc);
149
0
    pTextHelper->SetStartIndex(nChildOffset);
150
0
    pTextHelper->SetOffset(rVisRect.TopLeft());
151
152
0
    return pTextHelper;
153
0
}
154
155
sal_Int32 ScNotesChildren::AddNotes(const ScPreviewLocationData& rData, const tools::Rectangle& rVisRect, bool bMark, ScAccNotes& rNotes)
156
0
{
157
0
    sal_Int32 nCount = rData.GetNoteCountInRange(rVisRect, bMark);
158
159
0
    rNotes.reserve(nCount);
160
161
0
    sal_Int32 nParagraphs(0);
162
0
    ScDocument* pDoc = GetDocument();
163
0
    if (pDoc)
164
0
    {
165
0
        ScAccNote aNote;
166
0
        aNote.mbMarkNote = bMark;
167
0
        if (bMark)
168
0
            aNote.mnParaCount = 1;
169
0
        for (sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex)
170
0
        {
171
0
            if (rData.GetNoteInRange(rVisRect, nIndex, bMark, aNote.maNoteCell, aNote.maRect))
172
0
            {
173
0
                if (bMark)
174
0
                {
175
                    // Document not needed, because only the cell address, but not the tablename is needed
176
0
                    aNote.maNoteText = aNote.maNoteCell.Format(ScRefFlags::VALID);
177
0
                }
178
0
                else
179
0
                {
180
0
                    if( ScPostIt* pNote = pDoc->GetNote( aNote.maNoteCell ) )
181
0
                        aNote.maNoteText = pNote->GetText();
182
0
                    aNote.mpTextHelper = CreateTextHelper(aNote.maNoteText, aNote.maRect, aNote.maNoteCell, aNote.mbMarkNote, nParagraphs + mnOffset);
183
0
                    if (aNote.mpTextHelper)
184
0
                        aNote.mnParaCount = aNote.mpTextHelper->GetChildCount();
185
0
                }
186
0
                nParagraphs += aNote.mnParaCount;
187
0
                rNotes.push_back(aNote);
188
0
            }
189
0
        }
190
0
    }
191
0
    return nParagraphs;
192
0
}
193
194
void ScNotesChildren::Init(const tools::Rectangle& rVisRect, sal_Int32 nOffset)
195
0
{
196
0
    if (mpViewShell && !mnParagraphs)
197
0
    {
198
0
        mnOffset = nOffset;
199
0
        const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
200
201
0
        mnParagraphs = AddNotes(rData, rVisRect, false, maMarks);
202
0
        mnParagraphs += AddNotes(rData, rVisRect, true, maNotes);
203
0
    }
204
0
}
205
206
namespace {
207
208
struct ScParaFound
209
{
210
    sal_Int32 mnIndex;
211
0
    explicit ScParaFound(sal_Int32 nIndex) : mnIndex(nIndex) {}
212
    bool operator() (const ScAccNote& rNote)
213
0
    {
214
0
        bool bResult(false);
215
0
        if (rNote.mnParaCount > mnIndex)
216
0
            bResult = true;
217
0
        else
218
0
            mnIndex -= rNote.mnParaCount;
219
0
        return bResult;
220
0
    }
221
};
222
223
}
224
225
uno::Reference<XAccessible> ScNotesChildren::GetChild(sal_Int32 nIndex) const
226
0
{
227
0
    rtl::Reference<comphelper::OAccessible> pAccessible;
228
229
0
    if (nIndex < mnParagraphs)
230
0
    {
231
0
        if (nIndex < static_cast<sal_Int32>(maMarks.size()))
232
0
        {
233
0
            ScAccNotes::iterator aEndItr = maMarks.end();
234
0
            ScParaFound aParaFound(nIndex);
235
0
            ScAccNotes::iterator aItr = std::find_if(maMarks.begin(), aEndItr, aParaFound);
236
0
            if (aItr != aEndItr)
237
0
            {
238
0
                OSL_ENSURE((aItr->maNoteCell == maMarks[nIndex].maNoteCell) && (aItr->mbMarkNote == maMarks[nIndex].mbMarkNote), "wrong note found");
239
0
                if (!aItr->mpTextHelper)
240
0
                    aItr->mpTextHelper = CreateTextHelper(maMarks[nIndex].maNoteText, maMarks[nIndex].maRect, maMarks[nIndex].maNoteCell, maMarks[nIndex].mbMarkNote, nIndex + mnOffset); // the marks are the first and every mark has only one paragraph
241
0
                pAccessible = aItr->mpTextHelper->GetChild(aParaFound.mnIndex + aItr->mpTextHelper->GetStartIndex());
242
0
            }
243
0
            else
244
0
            {
245
0
                OSL_FAIL("wrong note found");
246
0
            }
247
0
        }
248
0
        else
249
0
        {
250
0
            nIndex -= maMarks.size();
251
0
            ScAccNotes::iterator aEndItr = maNotes.end();
252
0
            ScParaFound aParaFound(nIndex);
253
0
            ScAccNotes::iterator aItr = std::find_if(maNotes.begin(), aEndItr, aParaFound);
254
0
            if (aEndItr != aItr)
255
0
            {
256
0
                if (!aItr->mpTextHelper)
257
0
                    aItr->mpTextHelper = CreateTextHelper(aItr->maNoteText, aItr->maRect, aItr->maNoteCell, aItr->mbMarkNote, (nIndex - aParaFound.mnIndex) + mnOffset + maMarks.size());
258
0
                pAccessible = aItr->mpTextHelper->GetChild(aParaFound.mnIndex + aItr->mpTextHelper->GetStartIndex());
259
0
            }
260
0
        }
261
0
    }
262
263
0
    return pAccessible;
264
0
}
265
266
namespace {
267
268
struct ScPointFound
269
{
270
    tools::Rectangle maPoint;
271
    sal_Int32 mnParagraphs;
272
0
    explicit ScPointFound(const Point& rPoint) : maPoint(rPoint, Size(0, 0)), mnParagraphs(0) {}
273
    bool operator() (const ScAccNote& rNote)
274
0
    {
275
0
        bool bResult(false);
276
0
        if (maPoint.Contains(rNote.maRect))
277
0
            bResult = true;
278
0
        else
279
0
            mnParagraphs += rNote.mnParaCount;
280
0
        return bResult;
281
0
    }
282
};
283
284
}
285
286
uno::Reference<XAccessible> ScNotesChildren::GetAt(const awt::Point& rPoint) const
287
0
{
288
0
    uno::Reference<XAccessible> xAccessible;
289
290
0
    ScPointFound aPointFound(Point(rPoint.X, rPoint.Y));
291
292
0
    ScAccNotes::iterator aEndItr = maMarks.end();
293
0
    ScAccNotes::iterator aItr = std::find_if(maMarks.begin(), aEndItr, aPointFound);
294
0
    if (aEndItr == aItr)
295
0
    {
296
0
        aEndItr = maNotes.end();
297
0
        aItr = std::find_if(maNotes.begin(), aEndItr, aPointFound);
298
0
    }
299
0
    if (aEndItr != aItr)
300
0
    {
301
0
        if (!aItr->mpTextHelper)
302
0
            aItr->mpTextHelper = CreateTextHelper(aItr->maNoteText, aItr->maRect, aItr->maNoteCell, aItr->mbMarkNote, aPointFound.mnParagraphs + mnOffset);
303
0
        xAccessible = aItr->mpTextHelper->GetAt(rPoint);
304
0
    }
305
306
0
    return xAccessible;
307
0
}
308
309
sal_Int8 ScNotesChildren::CompareCell(const ScAddress& aCell1, const ScAddress& aCell2)
310
0
{
311
0
    OSL_ENSURE(aCell1.Tab() == aCell2.Tab(), "the notes should be on the same table");
312
0
    sal_Int8 nResult(0);
313
0
    if (aCell1 != aCell2)
314
0
    {
315
0
        if (aCell1.Row() == aCell2.Row())
316
0
            nResult = (aCell1.Col() < aCell2.Col()) ? -1 : 1;
317
0
        else
318
0
            nResult = (aCell1.Row() < aCell2.Row()) ? -1 : 1;
319
0
    }
320
0
    return nResult;
321
0
}
322
323
void ScNotesChildren::CollectChildren(const ScAccNote& rNote, ScOAccVector& rVector)
324
0
{
325
0
    if (rNote.mpTextHelper)
326
0
        for (sal_Int32 i = 0; i < rNote.mnParaCount; ++i)
327
0
            rVector.push_back(rNote.mpTextHelper->GetChild(i + rNote.mpTextHelper->GetStartIndex()));
328
0
}
329
330
sal_Int32 ScNotesChildren::CheckChanges(const ScPreviewLocationData& rData,
331
            const tools::Rectangle& rVisRect, bool bMark, ScAccNotes& rOldNotes,
332
            ScAccNotes& rNewNotes, ScOAccVector& rOldParas, ScOAccVector& rNewParas)
333
0
{
334
0
    sal_Int32 nCount = rData.GetNoteCountInRange(rVisRect, bMark);
335
336
0
    rNewNotes.reserve(nCount);
337
338
0
    sal_Int32 nParagraphs(0);
339
0
    ScDocument* pDoc = GetDocument();
340
0
    if (pDoc)
341
0
    {
342
0
        ScAccNote aNote;
343
0
        aNote.mbMarkNote = bMark;
344
0
        if (bMark)
345
0
            aNote.mnParaCount = 1;
346
0
        ScAccNotes::iterator aItr = rOldNotes.begin();
347
0
        ScAccNotes::iterator aEndItr = rOldNotes.end();
348
0
        bool bAddNote(false);
349
0
        for (sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex)
350
0
        {
351
0
            if (rData.GetNoteInRange(rVisRect, nIndex, bMark, aNote.maNoteCell, aNote.maRect))
352
0
            {
353
0
                if (bMark)
354
0
                {
355
                    // Document not needed, because only the cell address, but not the tablename is needed
356
0
                    aNote.maNoteText = aNote.maNoteCell.Format(ScRefFlags::VALID);
357
0
                }
358
0
                else
359
0
                {
360
0
                    if( ScPostIt* pNote = pDoc->GetNote( aNote.maNoteCell ) )
361
0
                        aNote.maNoteText = pNote->GetText();
362
0
                }
363
364
0
                sal_Int8 nCompare(-1); // if there are no more old children it is always a new one
365
0
                if (aItr != aEndItr)
366
0
                    nCompare = CompareCell(aNote.maNoteCell, aItr->maNoteCell);
367
0
                if (nCompare == 0)
368
0
                {
369
0
                    if (aNote.maNoteText == aItr->maNoteText)
370
0
                    {
371
0
                        aNote.mpTextHelper = aItr->mpTextHelper;
372
0
                        if (aNote.maRect != aItr->maRect)  // set new VisArea
373
0
                        {
374
0
                            aNote.mpTextHelper->SetOffset(aNote.maRect.TopLeft());
375
0
                            aNote.mpTextHelper->UpdateChildren();
376
                            //OSL_ENSURE(aItr->maRect.GetSize() == aNote.maRect.GetSize(), "size should be the same, because the text is not changed");
377
                            // could be changed, because only a part of the note is visible
378
0
                        }
379
0
                    }
380
0
                    else
381
0
                    {
382
0
                        aNote.mpTextHelper = CreateTextHelper(aNote.maNoteText, aNote.maRect, aNote.maNoteCell, aNote.mbMarkNote, nParagraphs + mnOffset);
383
0
                        if (aNote.mpTextHelper)
384
0
                            aNote.mnParaCount = aNote.mpTextHelper->GetChildCount();
385
                        // collect removed children
386
0
                        CollectChildren(*aItr, rOldParas);
387
0
                        delete aItr->mpTextHelper;
388
0
                        aItr->mpTextHelper = nullptr;;
389
                        // collect new children
390
0
                        CollectChildren(aNote, rNewParas);
391
0
                    }
392
0
                    bAddNote = true;
393
                    // not necessary, because this branch should not be reached if it is the end
394
                    //if (aItr != aEndItr)
395
0
                    ++aItr;
396
0
                }
397
0
                else if (nCompare < 0)
398
0
                {
399
0
                    aNote.mpTextHelper = CreateTextHelper(aNote.maNoteText, aNote.maRect, aNote.maNoteCell, aNote.mbMarkNote, nParagraphs + mnOffset);
400
0
                    if (aNote.mpTextHelper)
401
0
                        aNote.mnParaCount = aNote.mpTextHelper->GetChildCount();
402
                    // collect new children
403
0
                    CollectChildren(aNote, rNewParas);
404
0
                    bAddNote = true;
405
0
                }
406
0
                else
407
0
                {
408
                    // collect removed children
409
0
                    CollectChildren(*aItr, rOldParas);
410
0
                    delete aItr->mpTextHelper;
411
0
                    aItr->mpTextHelper = nullptr;
412
413
                    // no note to add
414
                    // not necessary, because this branch should not be reached if it is the end
415
                    //if (aItr != aEndItr)
416
0
                    ++aItr;
417
0
                }
418
0
                if (bAddNote)
419
0
                {
420
0
                    nParagraphs += aNote.mnParaCount;
421
0
                    rNewNotes.push_back(aNote);
422
0
                    bAddNote = false;
423
0
                }
424
0
            }
425
0
        }
426
0
    }
427
0
    return nParagraphs;
428
0
}
429
430
namespace {
431
432
struct ScChildGone
433
{
434
    ScAccessibleDocumentPagePreview& mrAccDoc;
435
0
    explicit ScChildGone(ScAccessibleDocumentPagePreview& rAccDoc) : mrAccDoc(rAccDoc) {}
436
    void operator() (const uno::Reference<XAccessible>& xAccessible) const
437
0
    {
438
        // gone child - event
439
0
        mrAccDoc.CommitChange(AccessibleEventId::CHILD, uno::Any(xAccessible), uno::Any());
440
0
    }
441
};
442
443
struct ScChildNew
444
{
445
    ScAccessibleDocumentPagePreview& mrAccDoc;
446
0
    explicit ScChildNew(ScAccessibleDocumentPagePreview& rAccDoc) : mrAccDoc(rAccDoc) {}
447
    void operator() (const uno::Reference<XAccessible>& xAccessible) const
448
0
    {
449
        // new child - event
450
0
        mrAccDoc.CommitChange(AccessibleEventId::CHILD, uno::Any(), uno::Any(xAccessible));
451
0
    }
452
};
453
454
}
455
456
void ScNotesChildren::DataChanged(const tools::Rectangle& rVisRect)
457
0
{
458
0
    if (!mpViewShell)
459
0
        return;
460
461
0
    ScOAccVector aNewParas;
462
0
    ScOAccVector aOldParas;
463
0
    {
464
0
        ScAccNotes aNewMarks;
465
0
        mnParagraphs = CheckChanges(mpViewShell->GetLocationData(), rVisRect, true, maMarks, aNewMarks, aOldParas, aNewParas);
466
0
        maMarks = std::move(aNewMarks);
467
0
    }
468
0
    {
469
0
        ScAccNotes aNewNotes;
470
0
        mnParagraphs += CheckChanges(mpViewShell->GetLocationData(), rVisRect, false, maNotes, aNewNotes, aOldParas, aNewParas);
471
0
        maNotes = std::move(aNewNotes);
472
0
    }
473
474
0
    std::for_each(aOldParas.begin(), aOldParas.end(), ScChildGone(mrAccDoc));
475
0
    std::for_each(aNewParas.begin(), aNewParas.end(), ScChildNew(mrAccDoc));
476
0
}
477
478
inline ScDocument* ScNotesChildren::GetDocument() const
479
0
{
480
0
    ScDocument* pDoc = nullptr;
481
0
    if (mpViewShell)
482
0
        pDoc = &mpViewShell->GetDocument();
483
0
    return pDoc;
484
0
}
485
486
namespace {
487
488
class ScIAccessibleViewForwarder : public ::accessibility::IAccessibleViewForwarder
489
{
490
public:
491
    ScIAccessibleViewForwarder();
492
    ScIAccessibleViewForwarder(ScPreviewShell* pViewShell,
493
                                ScAccessibleDocumentPagePreview* pAccDoc,
494
                                const MapMode& aMapMode);
495
496
    ///=====  IAccessibleViewForwarder  ========================================
497
498
    virtual tools::Rectangle GetVisibleArea() const override;
499
    virtual Point LogicToPixel (const Point& rPoint) const override;
500
    virtual Size LogicToPixel (const Size& rSize) const override;
501
502
private:
503
    ScPreviewShell*                     mpViewShell;
504
    ScAccessibleDocumentPagePreview*    mpAccDoc;
505
    MapMode                             maMapMode;
506
};
507
508
}
509
510
ScIAccessibleViewForwarder::ScIAccessibleViewForwarder()
511
0
    : mpViewShell(nullptr), mpAccDoc(nullptr)
512
0
{
513
0
}
514
515
ScIAccessibleViewForwarder::ScIAccessibleViewForwarder(ScPreviewShell* pViewShell,
516
                                ScAccessibleDocumentPagePreview* pAccDoc,
517
                                const MapMode& aMapMode)
518
0
    : mpViewShell(pViewShell),
519
0
    mpAccDoc(pAccDoc),
520
0
    maMapMode(aMapMode)
521
0
{
522
0
}
523
524
///=====  IAccessibleViewForwarder  ========================================
525
526
tools::Rectangle ScIAccessibleViewForwarder::GetVisibleArea() const
527
0
{
528
0
    SolarMutexGuard aGuard;
529
0
    tools::Rectangle aVisRect;
530
0
    vcl::Window* pWin = mpViewShell->GetWindow();
531
0
    if (pWin)
532
0
    {
533
0
        aVisRect.SetSize(pWin->GetOutputSizePixel());
534
0
        aVisRect.SetPos(Point(0, 0));
535
536
0
        aVisRect = pWin->PixelToLogic(aVisRect, maMapMode);
537
0
    }
538
539
0
    return aVisRect;
540
0
}
541
542
Point ScIAccessibleViewForwarder::LogicToPixel (const Point& rPoint) const
543
0
{
544
0
    SolarMutexGuard aGuard;
545
0
    Point aPoint;
546
0
    vcl::Window* pWin = mpViewShell->GetWindow();
547
0
    if (pWin && mpAccDoc)
548
0
    {
549
0
        tools::Rectangle aRect(mpAccDoc->GetBoundingBoxOnScreen());
550
0
        aPoint = pWin->LogicToPixel(rPoint, maMapMode) + aRect.TopLeft();
551
0
    }
552
553
0
    return aPoint;
554
0
}
555
556
Size ScIAccessibleViewForwarder::LogicToPixel (const Size& rSize) const
557
0
{
558
0
    SolarMutexGuard aGuard;
559
0
    Size aSize;
560
0
    vcl::Window* pWin = mpViewShell->GetWindow();
561
0
    if (pWin)
562
0
        aSize = pWin->LogicToPixel(rSize, maMapMode);
563
0
    return aSize;
564
0
}
565
566
namespace {
567
568
struct ScShapeChild
569
{
570
    ScShapeChild()
571
0
        : mnRangeId(0)
572
0
    {
573
0
    }
574
    ScShapeChild(ScShapeChild const &) = delete;
575
0
    ScShapeChild(ScShapeChild &&) = default;
576
    ~ScShapeChild();
577
    ScShapeChild & operator =(ScShapeChild const &) = delete;
578
0
    ScShapeChild & operator =(ScShapeChild && other) {
579
0
        std::swap(mpAccShape, other.mpAccShape);
580
0
        mxShape = std::move(other.mxShape);
581
0
        mnRangeId = other.mnRangeId;
582
0
        return *this;
583
0
    }
584
585
    mutable rtl::Reference< ::accessibility::AccessibleShape > mpAccShape;
586
    css::uno::Reference< css::drawing::XShape > mxShape;
587
    sal_Int32 mnRangeId;
588
};
589
590
}
591
592
ScShapeChild::~ScShapeChild()
593
0
{
594
0
    if (mpAccShape.is())
595
0
    {
596
0
        mpAccShape->dispose();
597
0
    }
598
0
}
599
600
namespace {
601
602
struct ScShapeChildLess
603
{
604
    bool operator()(const ScShapeChild& rChild1, const ScShapeChild& rChild2) const
605
0
    {
606
0
      bool bResult(false);
607
0
      if (rChild1.mxShape.is() && rChild2.mxShape.is())
608
0
          bResult = (rChild1.mxShape.get() < rChild2.mxShape.get());
609
0
      return bResult;
610
0
    }
611
};
612
613
}
614
615
typedef std::vector<ScShapeChild> ScShapeChildVec;
616
617
namespace {
618
619
struct ScShapeRange
620
{
621
0
    ScShapeRange() = default;
622
    ScShapeRange(ScShapeRange const &) = delete;
623
0
    ScShapeRange(ScShapeRange &&) = default;
624
    ScShapeRange & operator =(ScShapeRange const &) = delete;
625
    ScShapeRange & operator =(ScShapeRange &&) = default;
626
627
    ScShapeChildVec maBackShapes;
628
    ScShapeChildVec maForeShapes; // inclusive internal shapes
629
    ScShapeChildVec maControls;
630
    ScIAccessibleViewForwarder maViewForwarder;
631
};
632
633
}
634
635
typedef std::vector<ScShapeRange> ScShapeRangeVec;
636
637
class ScShapeChildren : public ::accessibility::IAccessibleParent
638
{
639
public:
640
    ScShapeChildren(ScPreviewShell* pViewShell, ScAccessibleDocumentPagePreview* pAccDoc);
641
642
    ///=====  IAccessibleParent  ==============================================
643
644
    virtual bool ReplaceChild (
645
        ::accessibility::AccessibleShape* pCurrentChild,
646
        const css::uno::Reference< css::drawing::XShape >& _rxShape,
647
        const tools::Long _nIndex,
648
        const ::accessibility::AccessibleShapeTreeInfo& _rShapeTreeInfo
649
    ) override;
650
651
    ///=====  Internal  ========================================================
652
653
    void Init();
654
655
    sal_Int32 GetBackShapeCount() const;
656
    uno::Reference<XAccessible> GetBackShape(sal_Int32 nIndex) const;
657
    sal_Int32 GetForeShapeCount() const;
658
    uno::Reference<XAccessible> GetForeShape(sal_Int32 nIndex) const;
659
    sal_Int32 GetControlCount() const;
660
    uno::Reference<XAccessible> GetControl(sal_Int32 nIndex) const;
661
    uno::Reference<XAccessible> GetForegroundShapeAt(const awt::Point& rPoint) const; // inclusive controls
662
    uno::Reference<XAccessible> GetBackgroundShapeAt(const awt::Point& rPoint) const;
663
664
    void DataChanged();
665
    void VisAreaChanged() const;
666
667
private:
668
    ScAccessibleDocumentPagePreview* mpAccDoc;
669
    ScPreviewShell* mpViewShell;
670
    ScShapeRangeVec maShapeRanges;
671
672
    void FindChanged(ScShapeChildVec& aOld, ScShapeChildVec& aNew) const;
673
    void FindChanged(ScShapeRange& aOld, ScShapeRange& aNew) const;
674
    ::accessibility::AccessibleShape* GetAccShape(const ScShapeChild& rShape) const;
675
    ::accessibility::AccessibleShape* GetAccShape(const ScShapeChildVec& rShapes, sal_Int32 nIndex) const;
676
    void FillShapes(const tools::Rectangle& aPixelPaintRect, const MapMode& aMapMode, sal_uInt8 nRangeId);
677
678
//    void AddShape(const uno::Reference<drawing::XShape>& xShape, SdrLayerID aLayerID);
679
//    void RemoveShape(const uno::Reference<drawing::XShape>& xShape, SdrLayerID aLayerID);
680
    SdrPage* GetDrawPage() const;
681
};
682
683
ScShapeChildren::ScShapeChildren(ScPreviewShell* pViewShell, ScAccessibleDocumentPagePreview* pAccDoc)
684
    :
685
0
    mpAccDoc(pAccDoc),
686
0
    mpViewShell(pViewShell),
687
0
    maShapeRanges(SC_PREVIEW_MAXRANGES)
688
0
{
689
0
}
690
691
void ScShapeChildren::FindChanged(ScShapeChildVec& rOld, ScShapeChildVec& rNew) const
692
0
{
693
0
    ScShapeChildVec::iterator aOldItr = rOld.begin();
694
0
    ScShapeChildVec::iterator aOldEnd = rOld.end();
695
0
    ScShapeChildVec::const_iterator aNewItr = rNew.begin();
696
0
    ScShapeChildVec::const_iterator aNewEnd = rNew.end();
697
0
    uno::Reference<XAccessible> xAcc;
698
0
    while ((aNewItr != aNewEnd) && (aOldItr != aOldEnd))
699
0
    {
700
0
        if (aNewItr->mxShape.get() == aOldItr->mxShape.get())
701
0
        {
702
0
            ++aOldItr;
703
0
            ++aNewItr;
704
0
        }
705
0
        else if (aNewItr->mxShape.get() < aOldItr->mxShape.get())
706
0
        {
707
0
            xAcc = GetAccShape(*aNewItr);
708
0
            mpAccDoc->CommitChange(AccessibleEventId::CHILD, uno::Any(), uno::Any(xAcc));
709
0
            ++aNewItr;
710
0
        }
711
0
        else
712
0
        {
713
0
            xAcc = GetAccShape(*aOldItr);
714
0
            mpAccDoc->CommitChange(AccessibleEventId::CHILD, uno::Any(xAcc), uno::Any());
715
0
            ++aOldItr;
716
0
        }
717
0
    }
718
0
    while (aOldItr != aOldEnd)
719
0
    {
720
0
        xAcc = GetAccShape(*aOldItr);
721
0
        mpAccDoc->CommitChange(AccessibleEventId::CHILD, uno::Any(xAcc), uno::Any());
722
0
        ++aOldItr;
723
0
    }
724
0
    while (aNewItr != aNewEnd)
725
0
    {
726
0
        xAcc = GetAccShape(*aNewItr);
727
0
        mpAccDoc->CommitChange(AccessibleEventId::CHILD, uno::Any(), uno::Any(xAcc));
728
0
        ++aNewItr;
729
0
    }
730
0
}
731
732
void ScShapeChildren::FindChanged(ScShapeRange& rOld, ScShapeRange& rNew) const
733
0
{
734
0
    FindChanged(rOld.maBackShapes, rNew.maBackShapes);
735
0
    FindChanged(rOld.maForeShapes, rNew.maForeShapes);
736
0
    FindChanged(rOld.maControls, rNew.maControls);
737
0
}
738
739
void ScShapeChildren::DataChanged()
740
0
{
741
0
    ScShapeRangeVec aOldShapeRanges(std::move(maShapeRanges));
742
0
    maShapeRanges.clear();
743
0
    maShapeRanges.resize(SC_PREVIEW_MAXRANGES);
744
0
    Init();
745
0
    for (sal_Int32 i = 0; i < SC_PREVIEW_MAXRANGES; ++i)
746
0
    {
747
0
        FindChanged(aOldShapeRanges[i], maShapeRanges[i]);
748
0
    }
749
0
}
750
751
namespace
752
{
753
    struct ScVisAreaChanged
754
    {
755
        void operator() (const ScShapeChild& rAccShapeData) const
756
0
        {
757
0
            if (rAccShapeData.mpAccShape.is())
758
0
            {
759
0
                rAccShapeData.mpAccShape->ViewForwarderChanged();
760
0
            }
761
0
        }
762
    };
763
}
764
765
void ScShapeChildren::VisAreaChanged() const
766
0
{
767
0
    for (auto const& shape : maShapeRanges)
768
0
    {
769
0
        ScVisAreaChanged aVisAreaChanged;
770
0
        std::for_each(shape.maBackShapes.begin(), shape.maBackShapes.end(), aVisAreaChanged);
771
0
        std::for_each(shape.maControls.begin(), shape.maControls.end(), aVisAreaChanged);
772
0
        std::for_each(shape.maForeShapes.begin(), shape.maForeShapes.end(), aVisAreaChanged);
773
0
    }
774
0
}
775
776
    ///=====  IAccessibleParent  ==============================================
777
778
bool ScShapeChildren::ReplaceChild (::accessibility::AccessibleShape* /* pCurrentChild */,
779
    const css::uno::Reference< css::drawing::XShape >& /* _rxShape */,
780
        const tools::Long /* _nIndex */, const ::accessibility::AccessibleShapeTreeInfo& /* _rShapeTreeInfo */)
781
0
{
782
0
    OSL_FAIL("should not be called in the page preview");
783
0
    return false;
784
0
}
785
786
    ///=====  Internal  ========================================================
787
788
void ScShapeChildren::Init()
789
0
{
790
0
    if(!mpViewShell)
791
0
        return;
792
793
0
    const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
794
0
    MapMode aMapMode;
795
0
    tools::Rectangle aPixelPaintRect;
796
0
    sal_uInt8 nRangeId;
797
0
    sal_uInt16 nCount(rData.GetDrawRanges());
798
0
    for (sal_uInt16 i = 0; i < nCount; ++i)
799
0
    {
800
0
        rData.GetDrawRange(i, aPixelPaintRect, aMapMode, nRangeId);
801
0
        FillShapes(aPixelPaintRect, aMapMode, nRangeId);
802
0
    }
803
0
}
804
805
sal_Int32 ScShapeChildren::GetBackShapeCount() const
806
0
{
807
0
    sal_Int32 nCount(0);
808
0
    for (auto const& shape : maShapeRanges)
809
0
        nCount += shape.maBackShapes.size();
810
0
    return nCount;
811
0
}
812
813
uno::Reference<XAccessible> ScShapeChildren::GetBackShape(sal_Int32 nIndex) const
814
0
{
815
0
    uno::Reference<XAccessible> xAccessible;
816
0
    for (const auto& rShapeRange : maShapeRanges)
817
0
    {
818
0
        sal_Int32 nCount(rShapeRange.maBackShapes.size());
819
0
        if(nIndex < nCount)
820
0
            xAccessible = GetAccShape(rShapeRange.maBackShapes, nIndex);
821
0
        nIndex -= nCount;
822
0
        if (xAccessible.is())
823
0
            break;
824
0
    }
825
826
0
    if (nIndex >= 0)
827
0
        throw lang::IndexOutOfBoundsException();
828
829
0
    return xAccessible;
830
0
}
831
832
sal_Int32 ScShapeChildren::GetForeShapeCount() const
833
0
{
834
0
    sal_Int32 nCount(0);
835
0
    for (auto const& shape : maShapeRanges)
836
0
        nCount += shape.maForeShapes.size();
837
0
    return nCount;
838
0
}
839
840
uno::Reference<XAccessible> ScShapeChildren::GetForeShape(sal_Int32 nIndex) const
841
0
{
842
0
    uno::Reference<XAccessible> xAccessible;
843
0
    for (const auto& rShapeRange : maShapeRanges)
844
0
    {
845
0
        sal_Int32 nCount(rShapeRange.maForeShapes.size());
846
0
        if(nIndex < nCount)
847
0
            xAccessible = GetAccShape(rShapeRange.maForeShapes, nIndex);
848
0
        nIndex -= nCount;
849
0
        if (xAccessible.is())
850
0
            break;
851
0
    }
852
853
0
    if (nIndex >= 0)
854
0
        throw lang::IndexOutOfBoundsException();
855
856
0
    return xAccessible;
857
0
}
858
859
sal_Int32 ScShapeChildren::GetControlCount() const
860
0
{
861
0
    sal_Int32 nCount(0);
862
0
    for (auto const& shape : maShapeRanges)
863
0
        nCount += shape.maControls.size();
864
0
    return nCount;
865
0
}
866
867
uno::Reference<XAccessible> ScShapeChildren::GetControl(sal_Int32 nIndex) const
868
0
{
869
0
    uno::Reference<XAccessible> xAccessible;
870
0
    for (const auto& rShapeRange : maShapeRanges)
871
0
    {
872
0
        sal_Int32 nCount(rShapeRange.maControls.size());
873
0
        if(nIndex < nCount)
874
0
            xAccessible = GetAccShape(rShapeRange.maControls, nIndex);
875
0
        nIndex -= nCount;
876
0
        if (xAccessible.is())
877
0
            break;
878
0
    }
879
880
0
    if (nIndex >= 0)
881
0
        throw lang::IndexOutOfBoundsException();
882
883
0
    return xAccessible;
884
0
}
885
886
namespace {
887
888
struct ScShapePointFound
889
{
890
    Point maPoint;
891
    explicit ScShapePointFound(const awt::Point& rPoint)
892
0
        : maPoint(vcl::unohelper::ConvertToVCLPoint(rPoint))
893
0
    {
894
0
    }
895
    bool operator() (const ScShapeChild& rShape)
896
0
    {
897
0
        bool bResult(false);
898
0
        if (vcl::unohelper::ConvertToVCLRect(rShape.mpAccShape->getBounds()).Contains(maPoint))
899
0
            bResult = true;
900
0
        return bResult;
901
0
    }
902
};
903
904
}
905
906
uno::Reference<XAccessible> ScShapeChildren::GetForegroundShapeAt(const awt::Point& rPoint) const //inclusive Controls
907
0
{
908
0
    uno::Reference<XAccessible> xAcc;
909
910
0
    for(const auto& rShapeRange : maShapeRanges)
911
0
    {
912
0
        ScShapeChildVec::const_iterator aFindItr = std::find_if(rShapeRange.maForeShapes.begin(), rShapeRange.maForeShapes.end(), ScShapePointFound(rPoint));
913
0
        if (aFindItr != rShapeRange.maForeShapes.end())
914
0
            xAcc = GetAccShape(*aFindItr);
915
0
        else
916
0
        {
917
0
            ScShapeChildVec::const_iterator aCtrlItr = std::find_if(rShapeRange.maControls.begin(), rShapeRange.maControls.end(), ScShapePointFound(rPoint));
918
0
            if (aCtrlItr != rShapeRange.maControls.end())
919
0
                xAcc = GetAccShape(*aCtrlItr);
920
0
        }
921
922
0
        if (xAcc.is())
923
0
            break;
924
0
    }
925
926
0
    return xAcc;
927
0
}
928
929
uno::Reference<XAccessible> ScShapeChildren::GetBackgroundShapeAt(const awt::Point& rPoint) const
930
0
{
931
0
    uno::Reference<XAccessible> xAcc;
932
933
0
    for(const auto& rShapeRange : maShapeRanges)
934
0
    {
935
0
        ScShapeChildVec::const_iterator aFindItr = std::find_if(rShapeRange.maBackShapes.begin(), rShapeRange.maBackShapes.end(), ScShapePointFound(rPoint));
936
0
        if (aFindItr != rShapeRange.maBackShapes.end())
937
0
            xAcc = GetAccShape(*aFindItr);
938
0
        if (xAcc.is())
939
0
            break;
940
0
    }
941
942
0
    return xAcc;
943
0
}
944
945
::accessibility::AccessibleShape* ScShapeChildren::GetAccShape(const ScShapeChild& rShape) const
946
0
{
947
0
    if (!rShape.mpAccShape.is())
948
0
    {
949
0
        ::accessibility::ShapeTypeHandler& rShapeHandler = ::accessibility::ShapeTypeHandler::Instance();
950
0
        ::accessibility::AccessibleShapeInfo aShapeInfo(rShape.mxShape, mpAccDoc);
951
952
0
        if (mpViewShell)
953
0
        {
954
0
            ::accessibility::AccessibleShapeTreeInfo aShapeTreeInfo;
955
0
            aShapeTreeInfo.SetSdrView(mpViewShell->GetPreview()->GetDrawView());
956
0
            aShapeTreeInfo.SetController(nullptr);
957
0
            aShapeTreeInfo.SetWindow(mpViewShell->GetWindow());
958
0
            aShapeTreeInfo.SetViewForwarder(&(maShapeRanges[rShape.mnRangeId].maViewForwarder));
959
0
            rShape.mpAccShape = rShapeHandler.CreateAccessibleObject(aShapeInfo, aShapeTreeInfo);
960
0
            if (rShape.mpAccShape.is())
961
0
            {
962
0
                rShape.mpAccShape->Init();
963
0
            }
964
0
        }
965
0
    }
966
0
    return rShape.mpAccShape.get();
967
0
}
968
969
::accessibility::AccessibleShape* ScShapeChildren::GetAccShape(const ScShapeChildVec& rShapes, sal_Int32 nIndex) const
970
0
{
971
0
    return GetAccShape(rShapes[nIndex]);
972
0
}
973
974
void ScShapeChildren::FillShapes(const tools::Rectangle& aPixelPaintRect, const MapMode& aMapMode, sal_uInt8 nRangeId)
975
0
{
976
0
    OSL_ENSURE(nRangeId < maShapeRanges.size(), "this is not a valid range for draw objects");
977
0
    SdrPage* pPage = GetDrawPage();
978
0
    vcl::Window* pWin = mpViewShell->GetWindow();
979
0
    if (!(pPage && pWin))
980
0
        return;
981
982
0
    bool bForeAdded(false);
983
0
    bool bBackAdded(false);
984
0
    bool bControlAdded(false);
985
0
    tools::Rectangle aClippedPixelPaintRect(aPixelPaintRect);
986
0
    if (mpAccDoc)
987
0
    {
988
0
        tools::Rectangle aRect2(Point(0,0), mpAccDoc->GetBoundingBoxOnScreen().GetSize());
989
0
        aClippedPixelPaintRect = aPixelPaintRect.GetIntersection(aRect2);
990
0
    }
991
0
    maShapeRanges[nRangeId].maViewForwarder = ScIAccessibleViewForwarder(mpViewShell, mpAccDoc, aMapMode);
992
0
    for (const rtl::Reference<SdrObject>& pObj : *pPage)
993
0
    {
994
0
        uno::Reference< drawing::XShape > xShape(pObj->getUnoShape(), uno::UNO_QUERY);
995
0
        if (xShape.is())
996
0
        {
997
0
            tools::Rectangle aRect(pWin->LogicToPixel(
998
0
                tools::Rectangle(vcl::unohelper::ConvertToVCLPoint(xShape->getPosition()),
999
0
                                 vcl::unohelper::ConvertToVCLSize(xShape->getSize())), aMapMode));
1000
0
            if(!aClippedPixelPaintRect.GetIntersection(aRect).IsEmpty())
1001
0
            {
1002
0
                ScShapeChild aShape;
1003
0
                aShape.mxShape = std::move(xShape);
1004
0
                aShape.mnRangeId = nRangeId;
1005
0
                if (pObj->GetLayer().anyOf(SC_LAYER_INTERN, SC_LAYER_FRONT))
1006
0
                {
1007
0
                    maShapeRanges[nRangeId].maForeShapes.push_back(std::move(aShape));
1008
0
                    bForeAdded = true;
1009
0
                }
1010
0
                else if (pObj->GetLayer() == SC_LAYER_BACK)
1011
0
                {
1012
0
                    maShapeRanges[nRangeId].maBackShapes.push_back(std::move(aShape));
1013
0
                    bBackAdded = true;
1014
0
                }
1015
0
                else if (pObj->GetLayer() == SC_LAYER_CONTROLS)
1016
0
                {
1017
0
                    maShapeRanges[nRangeId].maControls.push_back(std::move(aShape));
1018
0
                    bControlAdded = true;
1019
0
                }
1020
0
                else
1021
0
                {
1022
0
                    OSL_FAIL("I don't know this layer.");
1023
0
                }
1024
0
            }
1025
0
        }
1026
0
    }
1027
0
    if (bForeAdded)
1028
0
        std::sort(maShapeRanges[nRangeId].maForeShapes.begin(), maShapeRanges[nRangeId].maForeShapes.end(),ScShapeChildLess());
1029
0
    if (bBackAdded)
1030
0
        std::sort(maShapeRanges[nRangeId].maBackShapes.begin(), maShapeRanges[nRangeId].maBackShapes.end(),ScShapeChildLess());
1031
0
    if (bControlAdded)
1032
0
        std::sort(maShapeRanges[nRangeId].maControls.begin(), maShapeRanges[nRangeId].maControls.end(),ScShapeChildLess());
1033
0
}
1034
1035
SdrPage* ScShapeChildren::GetDrawPage() const
1036
0
{
1037
0
    SCTAB nTab( mpViewShell->GetLocationData().GetPrintTab() );
1038
0
    SdrPage* pDrawPage = nullptr;
1039
0
    ScDocument& rDoc = mpViewShell->GetDocument();
1040
0
    if (rDoc.GetDrawLayer())
1041
0
    {
1042
0
        ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
1043
0
        if (pDrawLayer->HasObjects() && (pDrawLayer->GetPageCount() > nTab))
1044
0
            pDrawPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(static_cast<sal_Int16>(nTab)));
1045
0
    }
1046
0
    return pDrawPage;
1047
0
}
1048
1049
namespace {
1050
1051
struct ScPagePreviewCountData
1052
{
1053
    //  order is background shapes, header, table or notes, footer, foreground shapes, controls
1054
1055
    tools::Rectangle aVisRect;
1056
    tools::Long nBackShapes;
1057
    tools::Long nHeaders;
1058
    tools::Long nTables;
1059
    tools::Long nNoteParagraphs;
1060
    tools::Long nFooters;
1061
    tools::Long nForeShapes;
1062
    tools::Long nControls;
1063
1064
    ScPagePreviewCountData( const ScPreviewLocationData& rData, const vcl::Window* pSizeWindow,
1065
        const ScNotesChildren* pNotesChildren, const ScShapeChildren* pShapeChildren );
1066
1067
    tools::Long GetTotal() const
1068
0
    {
1069
0
        return nBackShapes + nHeaders + nTables + nNoteParagraphs + nFooters + nForeShapes + nControls;
1070
0
    }
1071
};
1072
1073
}
1074
1075
ScPagePreviewCountData::ScPagePreviewCountData( const ScPreviewLocationData& rData,
1076
                                const vcl::Window* pSizeWindow, const ScNotesChildren* pNotesChildren,
1077
                                const ScShapeChildren* pShapeChildren) :
1078
0
    nBackShapes( 0 ),
1079
0
    nHeaders( 0 ),
1080
0
    nTables( 0 ),
1081
0
    nNoteParagraphs( 0 ),
1082
0
    nFooters( 0 ),
1083
0
    nForeShapes( 0 ),
1084
0
    nControls( 0 )
1085
0
{
1086
0
    Size aOutputSize;
1087
0
    if ( pSizeWindow )
1088
0
        aOutputSize = pSizeWindow->GetOutputSizePixel();
1089
0
    aVisRect = tools::Rectangle( Point(), aOutputSize );
1090
1091
0
    tools::Rectangle aObjRect;
1092
1093
0
    if ( rData.GetHeaderPosition( aObjRect ) && aObjRect.Overlaps( aVisRect ) )
1094
0
        nHeaders = 1;
1095
1096
0
    if ( rData.GetFooterPosition( aObjRect ) && aObjRect.Overlaps( aVisRect ) )
1097
0
        nFooters = 1;
1098
1099
0
    if ( rData.HasCellsInRange( aVisRect ) )
1100
0
        nTables = 1;
1101
1102
    //! shapes...
1103
0
    nBackShapes = pShapeChildren->GetBackShapeCount();
1104
0
    nForeShapes = pShapeChildren->GetForeShapeCount();
1105
0
    nControls = pShapeChildren->GetControlCount();
1106
1107
    // there are only notes if there is no table
1108
0
    if (nTables == 0)
1109
0
        nNoteParagraphs = pNotesChildren->GetChildrenCount();
1110
0
}
1111
1112
ScAccessibleDocumentPagePreview::ScAccessibleDocumentPagePreview(
1113
        const uno::Reference<XAccessible>& rxParent, ScPreviewShell* pViewShell ) :
1114
0
    ScAccessibleDocumentBase(rxParent),
1115
0
    mpViewShell(pViewShell)
1116
0
{
1117
0
    if (pViewShell)
1118
0
        pViewShell->AddAccessibilityObject(*this);
1119
1120
0
}
1121
1122
ScAccessibleDocumentPagePreview::~ScAccessibleDocumentPagePreview()
1123
0
{
1124
0
    if (!ScAccessibleDocumentBase::IsDefunc() && !rBHelper.bInDispose)
1125
0
    {
1126
        // increment refcount to prevent double call of dtor
1127
0
        osl_atomic_increment( &m_refCount );
1128
        // call dispose to inform object which have a weak reference to this object
1129
0
        dispose();
1130
0
    }
1131
0
}
1132
1133
void SAL_CALL ScAccessibleDocumentPagePreview::disposing()
1134
0
{
1135
0
    SolarMutexGuard aGuard;
1136
0
    if (mpTable.is())
1137
0
    {
1138
0
        mpTable->dispose();
1139
0
        mpTable.clear();
1140
0
    }
1141
0
    if (mpHeader)
1142
0
    {
1143
0
        mpHeader->dispose();
1144
0
        mpHeader.clear();
1145
0
    }
1146
0
    if (mpFooter)
1147
0
    {
1148
0
        mpFooter->dispose();
1149
0
        mpFooter.clear();
1150
0
    }
1151
1152
0
    if (mpViewShell)
1153
0
    {
1154
0
        mpViewShell->RemoveAccessibilityObject(*this);
1155
0
        mpViewShell = nullptr;
1156
0
    }
1157
1158
    // no need to Dispose the AccessibleTextHelper,
1159
    // as long as mpNotesChildren are destructed here
1160
0
    mpNotesChildren.reset();
1161
1162
0
    mpShapeChildren.reset();
1163
1164
0
    ScAccessibleDocumentBase::disposing();
1165
0
}
1166
1167
//=====  SfxListener  =====================================================
1168
1169
void ScAccessibleDocumentPagePreview::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
1170
0
{
1171
0
    if ( rHint.GetId() == SfxHintId::ScAccWinFocusLost )
1172
0
    {
1173
0
        CommitFocusLost();
1174
0
    }
1175
0
    else if ( rHint.GetId() == SfxHintId::ScAccGridWinFocusLost )
1176
0
    {
1177
0
        CommitFocusLost();
1178
0
    }
1179
0
    else if ( rHint.GetId() == SfxHintId::ScAccWinFocusGot )
1180
0
    {
1181
0
        CommitFocusGained();
1182
0
    }
1183
0
    else if ( rHint.GetId() == SfxHintId::ScAccGridWinFocusGot )
1184
0
    {
1185
0
        CommitFocusGained();
1186
0
    }
1187
0
    else if (rHint.GetId() == SfxHintId::ScDataChanged)
1188
0
    {
1189
        // only notify if child exist, otherwise it is not necessary
1190
0
        if (mpTable.is()) // if there is no table there is nothing to notify, because no one recognizes the change
1191
0
        {
1192
0
            CommitChange(AccessibleEventId::CHILD, uno::Any(uno::Reference<XAccessible>(mpTable)),
1193
0
                         uno::Any());
1194
1195
0
            mpTable->dispose();
1196
0
            mpTable.clear();
1197
0
        }
1198
1199
0
        Size aOutputSize;
1200
0
        vcl::Window* pSizeWindow = mpViewShell->GetWindow();
1201
0
        if ( pSizeWindow )
1202
0
            aOutputSize = pSizeWindow->GetOutputSizePixel();
1203
0
        tools::Rectangle aVisRect( Point(), aOutputSize );
1204
0
        GetNotesChildren()->DataChanged(aVisRect);
1205
1206
0
        GetShapeChildren()->DataChanged();
1207
1208
0
        const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
1209
0
        ScPagePreviewCountData aCount( rData, mpViewShell->GetWindow(), GetNotesChildren(), GetShapeChildren() );
1210
1211
0
        if (aCount.nTables > 0)
1212
0
        {
1213
            //! order is background shapes, header, table or notes, footer, foreground shapes, controls
1214
0
            sal_Int32 nIndex (aCount.nBackShapes + aCount.nHeaders);
1215
1216
0
            mpTable = new ScAccessiblePreviewTable( this, mpViewShell, nIndex );
1217
0
            mpTable->Init();
1218
1219
0
            CommitChange(AccessibleEventId::CHILD, uno::Any(),
1220
0
                         uno::Any(uno::Reference<XAccessible>(mpTable)));
1221
0
        }
1222
0
    }
1223
0
    else if (rHint.GetId() == SfxHintId::ScAccVisAreaChanged)
1224
0
    {
1225
0
        Size aOutputSize;
1226
0
        vcl::Window* pSizeWindow = mpViewShell->GetWindow();
1227
0
        if ( pSizeWindow )
1228
0
            aOutputSize = pSizeWindow->GetOutputSizePixel();
1229
0
        tools::Rectangle aVisRect( Point(), aOutputSize );
1230
0
        GetNotesChildren()->DataChanged(aVisRect);
1231
1232
0
        GetShapeChildren()->VisAreaChanged();
1233
1234
0
        CommitChange(AccessibleEventId::VISIBLE_DATA_CHANGED, uno::Any(), uno::Any());
1235
0
    }
1236
0
    ScAccessibleDocumentBase::Notify(rBC, rHint);
1237
0
}
1238
1239
//=====  XAccessibleComponent  ============================================
1240
1241
uno::Reference< XAccessible > SAL_CALL ScAccessibleDocumentPagePreview::getAccessibleAtPoint( const awt::Point& rPoint )
1242
0
{
1243
0
    uno::Reference<XAccessible> xAccessible;
1244
0
    if (containsPoint(rPoint))
1245
0
    {
1246
0
        SolarMutexGuard aGuard;
1247
0
        ensureAlive();
1248
1249
0
        if ( mpViewShell )
1250
0
        {
1251
0
            xAccessible = GetShapeChildren()->GetForegroundShapeAt(rPoint);
1252
0
            if (!xAccessible.is())
1253
0
            {
1254
0
                const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
1255
0
                ScPagePreviewCountData aCount( rData, mpViewShell->GetWindow(), GetNotesChildren(), GetShapeChildren() );
1256
1257
0
                if ( !mpTable.is() && (aCount.nTables > 0) )
1258
0
                {
1259
                    //! order is background shapes, header, table or notes, footer, foreground shapes, controls
1260
0
                    sal_Int32 nIndex (aCount.nBackShapes + aCount.nHeaders);
1261
1262
0
                    mpTable = new ScAccessiblePreviewTable( this, mpViewShell, nIndex );
1263
0
                    mpTable->Init();
1264
0
                }
1265
0
                if (mpTable.is()
1266
0
                    && vcl::unohelper::ConvertToVCLRect(mpTable->getBounds())
1267
0
                           .Contains(vcl::unohelper::ConvertToVCLPoint(rPoint)))
1268
0
                    xAccessible = mpTable.get();
1269
0
            }
1270
0
            if (!xAccessible.is())
1271
0
                xAccessible = GetNotesChildren()->GetAt(rPoint);
1272
0
            if (!xAccessible.is())
1273
0
            {
1274
0
                if (!mpHeader.is() || !mpFooter.is())
1275
0
                {
1276
0
                    const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
1277
0
                    ScPagePreviewCountData aCount( rData, mpViewShell->GetWindow(), GetNotesChildren(), GetShapeChildren() );
1278
1279
0
                    if (!mpHeader.is())
1280
0
                    {
1281
0
                        mpHeader = new ScAccessiblePageHeader( this, mpViewShell, true, aCount.nBackShapes + aCount.nHeaders - 1);
1282
0
                    }
1283
0
                    if (!mpFooter.is())
1284
0
                    {
1285
0
                        mpFooter = new ScAccessiblePageHeader( this, mpViewShell, false, aCount.nBackShapes + aCount.nHeaders + aCount.nTables + aCount.nNoteParagraphs + aCount.nFooters - 1 );
1286
0
                    }
1287
0
                }
1288
1289
0
                Point aPoint(vcl::unohelper::ConvertToVCLPoint(rPoint));
1290
1291
0
                if (vcl::unohelper::ConvertToVCLRect(mpHeader->getBounds()).Contains(aPoint))
1292
0
                    xAccessible = mpHeader.get();
1293
0
                else if (vcl::unohelper::ConvertToVCLRect(mpFooter->getBounds()).Contains(aPoint))
1294
0
                    xAccessible = mpFooter.get();
1295
0
            }
1296
0
            if (!xAccessible.is())
1297
0
                xAccessible = GetShapeChildren()->GetBackgroundShapeAt(rPoint);
1298
0
        }
1299
0
    }
1300
1301
0
    return xAccessible;
1302
0
}
1303
1304
void SAL_CALL ScAccessibleDocumentPagePreview::grabFocus()
1305
0
{
1306
0
    SolarMutexGuard aGuard;
1307
0
    ensureAlive();
1308
0
    if (getAccessibleParent().is())
1309
0
    {
1310
0
        uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY);
1311
0
        if (xAccessibleComponent.is())
1312
0
        {
1313
            // just grab the focus for the window
1314
0
            xAccessibleComponent->grabFocus();
1315
0
        }
1316
0
    }
1317
0
}
1318
1319
//=====  XAccessibleContext  ==============================================
1320
1321
sal_Int64 SAL_CALL ScAccessibleDocumentPagePreview::getAccessibleChildCount()
1322
0
{
1323
0
    SolarMutexGuard aGuard;
1324
0
    ensureAlive();
1325
1326
0
    sal_Int64 nRet = 0;
1327
0
    if ( mpViewShell )
1328
0
    {
1329
0
        ScPagePreviewCountData aCount( mpViewShell->GetLocationData(), mpViewShell->GetWindow(), GetNotesChildren(), GetShapeChildren() );
1330
0
        nRet = aCount.GetTotal();
1331
0
    }
1332
1333
0
    return nRet;
1334
0
}
1335
1336
uno::Reference<XAccessible> SAL_CALL ScAccessibleDocumentPagePreview::getAccessibleChild(sal_Int64 nIndex)
1337
0
{
1338
0
    SolarMutexGuard aGuard;
1339
0
    ensureAlive();
1340
0
    uno::Reference<XAccessible> xAccessible;
1341
1342
0
    if ( mpViewShell )
1343
0
    {
1344
0
        const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
1345
0
        ScPagePreviewCountData aCount( rData, mpViewShell->GetWindow(), GetNotesChildren(), GetShapeChildren() );
1346
1347
0
        if ( nIndex < aCount.nBackShapes )
1348
0
        {
1349
0
            xAccessible = GetShapeChildren()->GetBackShape(nIndex);
1350
0
        }
1351
0
        else if ( nIndex < aCount.nBackShapes + aCount.nHeaders )
1352
0
        {
1353
0
            if ( !mpHeader.is() )
1354
0
            {
1355
0
                mpHeader = new ScAccessiblePageHeader( this, mpViewShell, true, nIndex );
1356
0
            }
1357
1358
0
            xAccessible = mpHeader.get();
1359
0
        }
1360
0
        else if ( nIndex < aCount.nBackShapes + aCount.nHeaders + aCount.nTables )
1361
0
        {
1362
0
            if ( !mpTable.is() )
1363
0
            {
1364
0
                mpTable = new ScAccessiblePreviewTable( this, mpViewShell, nIndex );
1365
0
                mpTable->Init();
1366
0
            }
1367
0
            xAccessible = mpTable.get();
1368
0
        }
1369
0
        else if ( nIndex < aCount.nBackShapes + aCount.nHeaders + aCount.nNoteParagraphs )
1370
0
        {
1371
0
            xAccessible = GetNotesChildren()->GetChild(nIndex - aCount.nBackShapes - aCount.nHeaders);
1372
0
        }
1373
0
        else if ( nIndex < aCount.nBackShapes + aCount.nHeaders + aCount.nTables + aCount.nNoteParagraphs + aCount.nFooters )
1374
0
        {
1375
0
            if ( !mpFooter.is() )
1376
0
            {
1377
0
                mpFooter = new ScAccessiblePageHeader( this, mpViewShell, false, nIndex );
1378
0
            }
1379
0
            xAccessible = mpFooter.get();
1380
0
        }
1381
0
        else
1382
0
        {
1383
0
            sal_Int64 nIdx(nIndex - (aCount.nBackShapes + aCount.nHeaders + aCount.nTables + aCount.nNoteParagraphs + aCount.nFooters));
1384
0
            if (nIdx < aCount.nForeShapes)
1385
0
                xAccessible = GetShapeChildren()->GetForeShape(nIdx);
1386
0
            else
1387
0
                xAccessible = GetShapeChildren()->GetControl(nIdx - aCount.nForeShapes);
1388
0
        }
1389
0
    }
1390
1391
0
    if ( !xAccessible.is() )
1392
0
        throw lang::IndexOutOfBoundsException();
1393
1394
0
    return xAccessible;
1395
0
}
1396
1397
    /// Return the set of current states.
1398
sal_Int64 SAL_CALL ScAccessibleDocumentPagePreview::getAccessibleStateSet()
1399
0
{
1400
0
    SolarMutexGuard aGuard;
1401
0
    sal_Int64 nParentStates = 0;
1402
0
    if (getAccessibleParent().is())
1403
0
    {
1404
0
        uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
1405
0
        nParentStates = xParentContext->getAccessibleStateSet();
1406
0
    }
1407
0
    sal_Int64 nStateSet = 0;
1408
0
    if (IsDefunc(nParentStates))
1409
0
        nStateSet |= AccessibleStateType::DEFUNC;
1410
0
    else
1411
0
    {
1412
        // never editable
1413
0
        nStateSet |= AccessibleStateType::ENABLED;
1414
0
        nStateSet |= AccessibleStateType::OPAQUE;
1415
0
        if (isShowing())
1416
0
            nStateSet |= AccessibleStateType::SHOWING;
1417
0
        if (isVisible())
1418
0
            nStateSet |= AccessibleStateType::VISIBLE;
1419
0
    }
1420
0
    return nStateSet;
1421
0
}
1422
1423
OUString ScAccessibleDocumentPagePreview::createAccessibleDescription()
1424
0
{
1425
0
    return STR_ACC_PREVIEWDOC_DESCR;
1426
0
}
1427
1428
OUString ScAccessibleDocumentPagePreview::createAccessibleName()
1429
0
{
1430
0
    OUString sName = ScResId(STR_ACC_PREVIEWDOC_NAME);
1431
0
    return sName;
1432
0
}
1433
1434
AbsoluteScreenPixelRectangle ScAccessibleDocumentPagePreview::GetBoundingBoxOnScreen()
1435
0
{
1436
0
    AbsoluteScreenPixelRectangle aRect;
1437
0
    if (mpViewShell)
1438
0
    {
1439
0
        vcl::Window* pWindow = mpViewShell->GetWindow();
1440
0
        if (pWindow)
1441
0
            aRect = pWindow->GetWindowExtentsAbsolute();
1442
0
    }
1443
0
    return aRect;
1444
0
}
1445
1446
tools::Rectangle ScAccessibleDocumentPagePreview::GetBoundingBox()
1447
0
{
1448
0
    tools::Rectangle aRect;
1449
0
    if (mpViewShell)
1450
0
    {
1451
0
        vcl::Window* pWindow = mpViewShell->GetWindow();
1452
0
        if (pWindow)
1453
0
            aRect = pWindow->GetWindowExtentsRelative(*pWindow->GetAccessibleParentWindow());
1454
0
    }
1455
0
    return aRect;
1456
0
}
1457
1458
bool ScAccessibleDocumentPagePreview::IsDefunc(sal_Int64 nParentStates)
1459
0
{
1460
0
    return ScAccessibleContextBase::IsDefunc() || !getAccessibleParent().is() ||
1461
0
        (nParentStates & AccessibleStateType::DEFUNC);
1462
0
}
1463
1464
ScNotesChildren* ScAccessibleDocumentPagePreview::GetNotesChildren()
1465
0
{
1466
0
    if (!mpNotesChildren && mpViewShell)
1467
0
    {
1468
0
        mpNotesChildren.reset(new ScNotesChildren(mpViewShell, *this));
1469
1470
0
        const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
1471
0
        ScPagePreviewCountData aCount( rData, mpViewShell->GetWindow(), GetNotesChildren(), GetShapeChildren() );
1472
1473
        //! order is background shapes, header, table or notes, footer, foreground shapes, controls
1474
0
        mpNotesChildren->Init(aCount.aVisRect, aCount.nBackShapes + aCount.nHeaders);
1475
0
    }
1476
0
    return mpNotesChildren.get();
1477
0
}
1478
1479
ScShapeChildren* ScAccessibleDocumentPagePreview::GetShapeChildren()
1480
0
{
1481
0
    if (!mpShapeChildren && mpViewShell)
1482
0
    {
1483
0
        mpShapeChildren.reset( new ScShapeChildren(mpViewShell, this) );
1484
0
        mpShapeChildren->Init();
1485
0
    }
1486
1487
0
    return mpShapeChildren.get();
1488
0
}
1489
1490
OUString ScAccessibleDocumentPagePreview::getAccessibleName()
1491
0
{
1492
0
    SolarMutexGuard g;
1493
1494
0
    OUString aName = ScResId(STR_ACC_DOC_SPREADSHEET);
1495
0
    ScDocument& rScDoc = mpViewShell->GetDocument();
1496
1497
0
    ScDocShell* pObjSh = rScDoc.GetDocumentShell();
1498
0
    if (!pObjSh)
1499
0
        return aName;
1500
1501
0
    OUString aFileName;
1502
0
    SfxMedium* pMed = pObjSh->GetMedium();
1503
0
    if (pMed)
1504
0
        aFileName = pMed->GetName();
1505
1506
0
    if (aFileName.isEmpty())
1507
0
        aFileName = pObjSh->GetTitle(SFX_TITLE_APINAME);
1508
1509
0
    if (!aFileName.isEmpty())
1510
0
    {
1511
0
        aName = aFileName + " - " + aName + ScResId(STR_ACC_DOC_PREVIEW_SUFFIX);
1512
1513
0
    }
1514
1515
0
    return aName;
1516
0
}
1517
1518
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */