Coverage Report

Created: 2026-07-10 11:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/source/ui/Accessibility/AccessibleSpreadsheet.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 <AccessibleSpreadsheet.hxx>
21
#include <AccessibleCell.hxx>
22
#include <AccessibleDocument.hxx>
23
#include <tabvwsh.hxx>
24
#include <document.hxx>
25
#include <hints.hxx>
26
#include <scmod.hxx>
27
#include <markdata.hxx>
28
#include <gridwin.hxx>
29
30
#include <o3tl/safeint.hxx>
31
#include <unotools/accessiblerelationsethelper.hxx>
32
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
33
#include <com/sun/star/accessibility/AccessibleEventId.hpp>
34
#include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp>
35
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
36
#include <comphelper/accessibletexthelper.hxx>
37
#include <sal/log.hxx>
38
#include <tools/gen.hxx>
39
#include <svtools/colorcfg.hxx>
40
#include <vcl/svapp.hxx>
41
#include <scresid.hxx>
42
#include <strings.hrc>
43
44
#include <algorithm>
45
#include <cstdlib>
46
47
using namespace ::com::sun::star;
48
using namespace ::com::sun::star::accessibility;
49
50
static bool CompMinCol(const std::pair<sal_uInt16,sal_uInt16> & pc1,const std::pair<sal_uInt16,sal_uInt16>  &pc2)
51
0
{
52
0
    return pc1.first < pc2.first;
53
0
}
54
55
ScMyAddress ScAccessibleSpreadsheet::CalcScAddressFromRangeList(ScRangeList *pMarkedRanges,sal_Int32 nSelectedChildIndex)
56
0
{
57
0
    if (pMarkedRanges->size() <= 1)
58
0
    {
59
0
        ScRange const & rRange = pMarkedRanges->front();
60
        // MT IA2: Not used.
61
        // const int nRowNum = rRange.aEnd.Row() - rRange.aStart.Row() + 1;
62
0
        const int nColNum = rRange.aEnd.Col() - rRange.aStart.Col() + 1;
63
0
        const int nCurCol = nSelectedChildIndex % nColNum;
64
0
        const int nCurRow = (nSelectedChildIndex - nCurCol)/nColNum;
65
0
        return ScMyAddress(static_cast<SCCOL>(rRange.aStart.Col() + nCurCol), rRange.aStart.Row() + nCurRow, maActiveCell.Tab());
66
0
    }
67
0
    else
68
0
    {
69
0
        ScDocument* pDoc= GetDocument(mpViewShell);
70
0
        sal_Int32 nMinRow = pDoc->MaxRow();
71
0
        sal_Int32 nMaxRow = 0;
72
0
        std::vector<ScRange> aRanges;
73
0
        size_t nSize = pMarkedRanges->size();
74
0
        for (size_t i = 0; i < nSize; ++i)
75
0
        {
76
0
            ScRange const & rRange = (*pMarkedRanges)[i];
77
0
            if (rRange.aStart.Tab() != rRange.aEnd.Tab())
78
0
            {
79
0
                if ((maActiveCell.Tab() >= rRange.aStart.Tab()) ||
80
0
                    maActiveCell.Tab() <= rRange.aEnd.Tab())
81
0
                {
82
0
                    aRanges.push_back(rRange);
83
0
                    nMinRow = std::min(rRange.aStart.Row(),nMinRow);
84
0
                    nMaxRow = std::max(rRange.aEnd.Row(),nMaxRow);
85
0
                }
86
0
                else
87
0
                    SAL_WARN("sc", "Range of wrong table");
88
0
            }
89
0
            else if(rRange.aStart.Tab() == maActiveCell.Tab())
90
0
            {
91
0
                aRanges.push_back(rRange);
92
0
                nMinRow = std::min(rRange.aStart.Row(),nMinRow);
93
0
                nMaxRow = std::max(rRange.aEnd.Row(),nMaxRow);
94
0
            }
95
0
            else
96
0
                SAL_WARN("sc", "Range of wrong table");
97
0
        }
98
0
        int nCurrentIndex = 0 ;
99
0
        for(sal_Int32 row = nMinRow ; row <= nMaxRow ; ++row)
100
0
        {
101
0
            std::vector<std::pair<SCCOL, SCCOL>> aVecCol;
102
0
            for (ScRange const & r : aRanges)
103
0
            {
104
0
                if ( row >= r.aStart.Row() && row <= r.aEnd.Row())
105
0
                {
106
0
                    aVecCol.emplace_back(r.aStart.Col(), r.aEnd.Col());
107
0
                }
108
0
            }
109
0
            std::sort(aVecCol.begin(), aVecCol.end(), CompMinCol);
110
0
            for (const std::pair<SCCOL, SCCOL> &pairCol : aVecCol)
111
0
            {
112
0
                SCCOL nCol = pairCol.second - pairCol.first + 1;
113
0
                if (nCol + nCurrentIndex > nSelectedChildIndex)
114
0
                {
115
0
                    return ScMyAddress(static_cast<SCCOL>(pairCol.first + nSelectedChildIndex - nCurrentIndex), row, maActiveCell.Tab());
116
0
                }
117
0
                nCurrentIndex += nCol;
118
0
            }
119
0
        }
120
0
    }
121
0
    return ScMyAddress(0,0,maActiveCell.Tab());
122
0
}
123
124
bool ScAccessibleSpreadsheet::CalcScRangeDifferenceMax(const ScRange & rSrc, const ScRange & rDest, int nMax,
125
                                std::vector<ScMyAddress> &vecRet, int &nSize)
126
0
{
127
    //Src Must be :Src > Dest
128
0
    if (rDest.Contains(rSrc))
129
0
    {//Here is Src In Dest,Src <= Dest
130
0
        return false;
131
0
    }
132
0
    if (!rDest.Intersects(rSrc))
133
0
    {
134
0
        int nCellCount = sal_uInt32(rDest.aEnd.Col() - rDest.aStart.Col() + 1)
135
0
            * sal_uInt32(rDest.aEnd.Row() - rDest.aStart.Row() + 1)
136
0
            * sal_uInt32(rDest.aEnd.Tab() - rDest.aStart.Tab() + 1);
137
0
        if (nCellCount + nSize > nMax)
138
0
        {
139
0
            return true;
140
0
        }
141
0
        else if(nCellCount > 0)
142
0
        {
143
0
            for (sal_Int32 row = rDest.aStart.Row(); row <=  rDest.aEnd.Row();++row)
144
0
            {
145
0
                for (sal_uInt16 col = rDest.aStart.Col(); col <=  rDest.aEnd.Col();++col)
146
0
                {
147
0
                    vecRet.emplace_back(col,row,rDest.aStart.Tab());
148
0
                }
149
0
            }
150
0
        }
151
0
        return false;
152
0
    }
153
0
    sal_Int32 nMinRow = rSrc.aStart.Row();
154
0
    sal_Int32 nMaxRow = rSrc.aEnd.Row();
155
0
    for (; nMinRow <= nMaxRow ; ++nMinRow,--nMaxRow)
156
0
    {
157
0
        for (sal_uInt16 col = rSrc.aStart.Col(); col <=  rSrc.aEnd.Col();++col)
158
0
        {
159
0
            if (nSize > nMax)
160
0
            {
161
0
                return true;
162
0
            }
163
0
            ScMyAddress cell(col,nMinRow,rSrc.aStart.Tab());
164
0
            if(!rDest.Contains(cell))
165
0
            {//In Src ,Not In Dest
166
0
                vecRet.push_back(cell);
167
0
                ++nSize;
168
0
            }
169
0
        }
170
0
        if (nMinRow != nMaxRow)
171
0
        {
172
0
            for (sal_uInt16 col = rSrc.aStart.Col(); col <=  rSrc.aEnd.Col();++col)
173
0
            {
174
0
                if (nSize > nMax)
175
0
                {
176
0
                    return true;
177
0
                }
178
0
                ScMyAddress cell(col,nMaxRow,rSrc.aStart.Tab());
179
0
                if(!rDest.Contains(cell))
180
0
                {//In Src ,Not In Dest
181
0
                    vecRet.push_back(cell);
182
0
                    ++nSize;
183
0
                }
184
0
            }
185
0
        }
186
0
    }
187
0
    return false;
188
0
}
189
190
//In Src , Not in Dest
191
bool ScAccessibleSpreadsheet::CalcScRangeListDifferenceMax(ScRangeList *pSrc, ScRangeList *pDest,
192
                                int nMax, std::vector<ScMyAddress> &vecRet)
193
0
{
194
0
    if (pSrc == nullptr || pDest == nullptr)
195
0
    {
196
0
        return false;
197
0
    }
198
0
    int nSize =0;
199
0
    if (pDest->GetCellCount() == 0)//if the Dest Rang List is empty
200
0
    {
201
0
        if (pSrc->GetCellCount() > o3tl::make_unsigned(nMax))//if the Src Cell count is greater than  nMax
202
0
        {
203
0
            return true;
204
0
        }
205
        //now the cell count is less than nMax
206
0
        vecRet.reserve(10);
207
0
        size_t nSrcSize = pSrc->size();
208
0
        for (size_t i = 0; i < nSrcSize; ++i)
209
0
        {
210
0
            ScRange const & rRange = (*pSrc)[i];
211
0
            for (sal_Int32 row = rRange.aStart.Row(); row <= rRange.aEnd.Row();++row)
212
0
            {
213
0
                for (sal_uInt16 col = rRange.aStart.Col(); col <= rRange.aEnd.Col();++col)
214
0
                {
215
0
                    vecRet.emplace_back(col,row, rRange.aStart.Tab());
216
0
                }
217
0
            }
218
0
        }
219
0
        return false;
220
0
    }
221
    //the Dest Rang List is not empty
222
0
    vecRet.reserve(10);
223
0
    size_t nSizeSrc = pSrc->size();
224
0
    for (size_t i = 0; i < nSizeSrc; ++i)
225
0
    {
226
0
        ScRange const & rRange = (*pSrc)[i];
227
0
        size_t nSizeDest = pDest->size();
228
0
        for (size_t j = 0; j < nSizeDest; ++j)
229
0
        {
230
0
            ScRange const & rRangeDest = (*pDest)[j];
231
0
            if (CalcScRangeDifferenceMax(rRange,rRangeDest,nMax,vecRet,nSize))
232
0
            {
233
0
                return true;
234
0
            }
235
0
        }
236
0
    }
237
0
    return false;
238
0
}
239
240
// FIXME: really unclear why we have an ScAccessibleTableBase with
241
// only this single sub-class
242
ScAccessibleSpreadsheet::ScAccessibleSpreadsheet(
243
        ScAccessibleDocument* pAccDoc,
244
        ScTabViewShell* pViewShell,
245
        SCTAB nTab,
246
        ScSplitPos eSplitPos)
247
    :
248
0
    ScAccessibleTableBase( pAccDoc, GetDocument(pViewShell), ScRange( 0, 0, nTab, GetDocument(pViewShell)->MaxCol(), GetDocument(pViewShell)->MaxRow(), nTab)),
249
0
    mbIsSpreadsheet( true ),
250
0
    m_bFormulaMode( false ),
251
0
    m_bFormulaLastMode( false ),
252
0
    m_nMinX(0),m_nMaxX(0),m_nMinY(0),m_nMaxY(0)
253
0
{
254
0
    ConstructScAccessibleSpreadsheet( pAccDoc, pViewShell, nTab, eSplitPos );
255
0
}
256
257
ScAccessibleSpreadsheet::ScAccessibleSpreadsheet(
258
        ScAccessibleSpreadsheet& rParent, const ScRange& rRange ) :
259
0
    ScAccessibleTableBase( rParent.mpAccDoc, rParent.mpDoc, rRange),
260
0
    mbIsSpreadsheet( false ),
261
0
    m_bFormulaMode( false ),
262
0
    m_bFormulaLastMode( false ),
263
0
    m_nMinX(0),m_nMaxX(0),m_nMinY(0),m_nMaxY(0)
264
0
{
265
0
    ConstructScAccessibleSpreadsheet( rParent.mpAccDoc, rParent.mpViewShell, rParent.mnTab, rParent.meSplitPos );
266
0
}
267
268
ScAccessibleSpreadsheet::~ScAccessibleSpreadsheet()
269
0
{
270
0
    mpMarkedRanges.reset();
271
0
    if (mpViewShell)
272
0
        mpViewShell->RemoveAccessibilityObject(*this);
273
0
}
274
275
void ScAccessibleSpreadsheet::ConstructScAccessibleSpreadsheet(
276
    ScAccessibleDocument* pAccDoc,
277
    ScTabViewShell* pViewShell,
278
    SCTAB nTab,
279
    ScSplitPos eSplitPos)
280
0
{
281
0
    mpViewShell = pViewShell;
282
0
    mpMarkedRanges = nullptr;
283
0
    mpAccDoc = pAccDoc;
284
0
    mpAccCell.clear();
285
0
    meSplitPos = eSplitPos;
286
0
    mnTab = nTab;
287
0
    mbDelIns = false;
288
0
    mbIsFocusSend = false;
289
0
    if (!mpViewShell)
290
0
        return;
291
292
0
    mpViewShell->AddAccessibilityObject(*this);
293
294
0
    const ScViewData& rViewData = mpViewShell->GetViewData();
295
0
    maActiveCell = rViewData.GetCurPos();
296
0
    mpAccCell = GetAccessibleCellAt(maActiveCell.Row(), maActiveCell.Col());
297
0
    ScDocument* pScDoc= GetDocument(mpViewShell);
298
0
    if (pScDoc)
299
0
    {
300
0
        pScDoc->GetName( maActiveCell.Tab(), m_strOldTabName );
301
0
    }
302
0
}
303
304
void SAL_CALL ScAccessibleSpreadsheet::disposing()
305
0
{
306
0
    SolarMutexGuard aGuard;
307
0
    if (mpViewShell)
308
0
    {
309
0
        mpViewShell->RemoveAccessibilityObject(*this);
310
0
        mpViewShell = nullptr;
311
0
    }
312
313
0
    mpAccCell.clear();
314
0
    m_mapSelectionSend.clear();
315
0
    m_mapFormulaSelectionSend.clear();
316
0
    m_pAccFormulaCell.clear();
317
0
    m_mapCells.clear();
318
319
0
    ScAccessibleTableBase::disposing();
320
0
}
321
322
void ScAccessibleSpreadsheet::CompleteSelectionChanged(bool bNewState)
323
0
{
324
0
    if (IsFormulaMode())
325
0
    {
326
0
        return ;
327
0
    }
328
0
    mpMarkedRanges.reset();
329
330
0
    uno::Any aOldValue;
331
0
    uno::Any aNewValue;
332
0
    if (bNewState)
333
0
        aNewValue <<= AccessibleStateType::SELECTED;
334
0
    else
335
0
        aOldValue <<= AccessibleStateType::SELECTED;
336
0
    CommitChange(AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue);
337
0
}
338
339
void ScAccessibleSpreadsheet::LostFocus()
340
0
{
341
0
    CommitChange(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
342
0
                 uno::Any(uno::Reference<XAccessible>(mpAccCell)), uno::Any());
343
0
    CommitFocusLost();
344
0
}
345
346
void ScAccessibleSpreadsheet::GotFocus()
347
0
{
348
0
    CommitFocusGained();
349
350
0
    uno::Reference< XAccessible > xNew;
351
0
    if (IsFormulaMode())
352
0
    {
353
0
        if (!m_pAccFormulaCell.is() || !m_bFormulaLastMode)
354
0
        {
355
0
            ScAddress aFormulaAddr;
356
0
            if(!GetFormulaCurrentFocusCell(aFormulaAddr))
357
0
            {
358
0
                return;
359
0
            }
360
0
            m_pAccFormulaCell = GetAccessibleCellAt(aFormulaAddr.Row(),aFormulaAddr.Col());
361
0
        }
362
0
        xNew = m_pAccFormulaCell.get();
363
0
    }
364
0
    else
365
0
    {
366
0
        if(mpAccCell->GetCellAddress() == maActiveCell)
367
0
        {
368
0
            xNew = mpAccCell.get();
369
0
        }
370
0
        else
371
0
        {
372
0
            CommitFocusCell(maActiveCell);
373
0
            return ;
374
0
        }
375
0
    }
376
377
0
    CommitChange(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, uno::Any(), uno::Any(xNew));
378
0
}
379
380
void ScAccessibleSpreadsheet::BoundingBoxChanged()
381
0
{
382
0
    CommitChange(AccessibleEventId::BOUNDRECT_CHANGED, uno::Any(), uno::Any());
383
0
}
384
385
void ScAccessibleSpreadsheet::VisAreaChanged()
386
0
{
387
0
    CommitChange(AccessibleEventId::VISIBLE_DATA_CHANGED, uno::Any(), uno::Any());
388
0
}
389
390
    //=====  SfxListener  =====================================================
391
392
void ScAccessibleSpreadsheet::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
393
0
{
394
0
    if ( rHint.GetId() == SfxHintId::ScUpdateRef )
395
0
    {
396
0
        auto pRefHint = static_cast<const ScUpdateRefHint*>(&rHint);
397
0
        if (pRefHint->GetMode() == URM_INSDEL && pRefHint->GetDz() == 0) //test whether table is inserted or deleted
398
0
        {
399
0
            if (((pRefHint->GetRange().aStart.Col() == maRange.aStart.Col()) &&
400
0
                (pRefHint->GetRange().aEnd.Col() == maRange.aEnd.Col())) ||
401
0
                ((pRefHint->GetRange().aStart.Row() == maRange.aStart.Row()) &&
402
0
                (pRefHint->GetRange().aEnd.Row() == maRange.aEnd.Row())))
403
0
            {
404
                // ignore next SfxHintId::ScDataChanged notification
405
0
                mbDelIns = true;
406
407
0
                SCROW nFirstRow = -1;
408
0
                SCROW nLastRow = -1;
409
0
                SCCOL nFirstCol = -1;
410
0
                SCCOL nLastCol = -1;
411
412
0
                sal_Int16 nId(0);
413
0
                SCCOL nX(pRefHint->GetDx());
414
0
                SCROW nY(pRefHint->GetDy());
415
0
                ScRange aRange(pRefHint->GetRange());
416
0
                if ((nX < 0) || (nY < 0))
417
0
                {
418
0
                    assert(!((nX < 0) && (nY < 0)) && "should not be possible to remove row and column at the same time");
419
420
                    // Range in the update hint is the range after the removed rows/columns;
421
                    // calculate indices for the removed ones from that
422
0
                    if (nX < 0)
423
0
                    {
424
0
                        nId = AccessibleTableModelChangeType::COLUMNS_REMOVED;
425
0
                        nFirstCol = aRange.aStart.Col() + nX;
426
0
                        nLastCol = aRange.aStart.Col() - 1;
427
0
                    }
428
0
                    else
429
0
                    {
430
0
                        nId = AccessibleTableModelChangeType::ROWS_REMOVED;
431
0
                        nFirstRow = aRange.aStart.Row() + nY;
432
0
                        nLastRow = aRange.aStart.Row() - 1;
433
0
                    }
434
0
                }
435
0
                else if ((nX > 0) || (nY > 0))
436
0
                {
437
0
                    assert(!((nX > 0) && (nY > 0)) && "should not be possible to add row and column at the same time");
438
439
                    // Range in the update hint is from first inserted row/column to last one in spreadsheet;
440
                    // calculate indices for the inserted ones from that
441
0
                    if (nX > 0)
442
0
                    {
443
0
                        nId = AccessibleTableModelChangeType::COLUMNS_INSERTED;
444
0
                        nFirstCol = aRange.aStart.Col();
445
0
                        nLastCol = aRange.aStart.Col() + nX - 1;
446
0
                    }
447
0
                    else
448
0
                    {
449
0
                        nId = AccessibleTableModelChangeType::ROWS_INSERTED;
450
0
                        nFirstRow = aRange.aStart.Row();
451
0
                        nLastRow = aRange.aStart.Row() + nY -1;
452
0
                    }
453
0
                }
454
0
                else
455
0
                {
456
0
                    assert(false && "is it a deletion or an insertion?");
457
0
                }
458
459
0
                CommitTableModelChange(nFirstRow, nFirstCol, nLastRow, nLastCol, nId);
460
0
                CommitChange(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, uno::Any(),
461
0
                             uno::Any(uno::Reference<XAccessible>(mpAccCell)));
462
0
            }
463
0
        }
464
0
    }
465
0
    else
466
0
    {
467
0
        if (rHint.GetId() == SfxHintId::ScAccCursorChanged)
468
0
        {
469
0
            if (mpViewShell)
470
0
            {
471
0
                ScViewData& rViewData = mpViewShell->GetViewData();
472
473
0
                m_bFormulaMode = rViewData.IsRefMode() || ScModule::get()->IsFormulaMode();
474
0
                if ( m_bFormulaMode )
475
0
                {
476
0
                    NotifyRefMode();
477
0
                    m_bFormulaLastMode = true;
478
0
                    return;
479
0
                }
480
0
                if (m_bFormulaLastMode)
481
0
                {//Last Notify Mode  Is Formula Mode.
482
0
                    m_vecFormulaLastMyAddr.clear();
483
0
                    RemoveFormulaSelection(true);
484
0
                    m_pAccFormulaCell.clear();
485
                    //Remove All Selection
486
0
                }
487
0
                m_bFormulaLastMode = m_bFormulaMode;
488
489
0
                ScAddress aNewCell = rViewData.GetCurPos();
490
0
                if(aNewCell.Tab() != maActiveCell.Tab())
491
0
                {
492
0
                    auto pAccParent = getAccessibleParent();
493
0
                    ScAccessibleDocument *pAccDoc =
494
0
                        static_cast<ScAccessibleDocument*>(pAccParent.get());
495
0
                    if(pAccDoc)
496
0
                    {
497
0
                        pAccDoc->CommitChange(AccessibleEventId::PAGE_CHANGED, uno::Any(),
498
0
                                              uno::Any());
499
0
                    }
500
0
                }
501
0
                bool bNewPosCell = (aNewCell != maActiveCell) || mpViewShell->GetForceFocusOnCurCell(); // #i123629#
502
0
                bool bNewPosCellFocus=false;
503
0
                if ( bNewPosCell && IsFocused() && aNewCell.Tab() == maActiveCell.Tab() )
504
0
                {//single Focus
505
0
                    bNewPosCellFocus=true;
506
0
                }
507
0
                ScMarkData &refScMarkData = rViewData.GetMarkData();
508
                // MT IA2: Not used
509
                // int nSelCount = refScMarkData.GetSelectCount();
510
0
                bool bIsMark =refScMarkData.IsMarked();
511
0
                bool bIsMultMark = refScMarkData.IsMultiMarked();
512
0
                bool bNewMarked = refScMarkData.GetTableSelect(aNewCell.Tab()) && ( bIsMark || bIsMultMark );
513
//              sal_Bool bNewCellSelected = isAccessibleSelected(aNewCell.Row(), aNewCell.Col());
514
0
                sal_uInt16 nTab = rViewData.CurrentTabForData();
515
0
                const ScRange& aMarkRange = refScMarkData.GetMarkArea();
516
0
                ScDocument* pDoc= GetDocument(mpViewShell);
517
                //Mark All
518
0
                if ( !bNewPosCellFocus &&
519
0
                    (bNewMarked || bIsMark || bIsMultMark ) &&
520
0
                    aMarkRange == ScRange( 0,0,nTab, pDoc->MaxCol(),pDoc->MaxRow(),nTab ) )
521
0
                {
522
0
                    CommitChange(AccessibleEventId::SELECTION_CHANGED_WITHIN, uno::Any(),
523
0
                                 uno::Any());
524
0
                    return ;
525
0
                }
526
0
                if (!mpMarkedRanges)
527
0
                {
528
0
                    mpMarkedRanges.reset(new ScRangeList());
529
0
                }
530
0
                refScMarkData.FillRangeListWithMarks(mpMarkedRanges.get(), true);
531
532
                //For Whole Col Row
533
0
                bool bWholeRow = std::abs(aMarkRange.aStart.Row() - aMarkRange.aEnd.Row()) == pDoc->MaxRow() ;
534
0
                bool bWholeCol = ::abs(aMarkRange.aStart.Col() - aMarkRange.aEnd.Col()) == pDoc->MaxCol() ;
535
0
                if ((bNewMarked || bIsMark || bIsMultMark ) && (bWholeCol || bWholeRow))
536
0
                {
537
0
                    if ( aMarkRange != m_aLastWithInMarkRange )
538
0
                    {
539
0
                        RemoveSelection(refScMarkData);
540
0
                        if(bNewPosCell)
541
0
                        {
542
0
                            CommitFocusCell(aNewCell);
543
0
                        }
544
0
                        bool bLastIsWholeColRow =
545
0
                            (std::abs(m_aLastWithInMarkRange.aStart.Row() - m_aLastWithInMarkRange.aEnd.Row()) == pDoc->MaxRow() && bWholeRow) ||
546
0
                            (::abs(m_aLastWithInMarkRange.aStart.Col() - m_aLastWithInMarkRange.aEnd.Col()) == pDoc->MaxCol() && bWholeCol);
547
0
                        bool bSelSmaller=
548
0
                            bLastIsWholeColRow &&
549
0
                            !aMarkRange.Contains(m_aLastWithInMarkRange) &&
550
0
                            aMarkRange.Intersects(m_aLastWithInMarkRange);
551
0
                        if( !bSelSmaller )
552
0
                            CommitChange(AccessibleEventId::SELECTION_CHANGED_WITHIN, uno::Any(),
553
0
                                         uno::Any());
554
0
                        m_aLastWithInMarkRange = aMarkRange;
555
0
                    }
556
0
                    return ;
557
0
                }
558
0
                m_aLastWithInMarkRange = aMarkRange;
559
0
                int nNewMarkCount = mpMarkedRanges->GetCellCount();
560
0
                bool bSendSingle= (0 == nNewMarkCount) && bNewPosCell;
561
0
                if (bSendSingle)
562
0
                {
563
0
                    RemoveSelection(refScMarkData);
564
0
                    if(bNewPosCellFocus)
565
0
                    {
566
0
                        CommitFocusCell(aNewCell);
567
0
                    }
568
0
                    rtl::Reference< ScAccessibleCell > xChild ;
569
0
                    if (bNewPosCellFocus)
570
0
                    {
571
0
                        xChild = mpAccCell;
572
0
                    }
573
0
                    else
574
0
                    {
575
0
                        mpAccCell = GetAccessibleCellAt(aNewCell.Row(),aNewCell.Col());
576
0
                        xChild = mpAccCell;
577
578
0
                        maActiveCell = aNewCell;
579
0
                        CommitChange(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS,
580
0
                                     uno::Any(), uno::Any(uno::Reference<XAccessible>(xChild)));
581
0
                    }
582
0
                    CommitChange(AccessibleEventId::SELECTION_CHANGED, uno::Any(),
583
0
                                 uno::Any(uno::Reference<XAccessible>(xChild)));
584
0
                    OSL_ASSERT(m_mapSelectionSend.count(aNewCell) == 0 );
585
0
                    m_mapSelectionSend.emplace(aNewCell,xChild);
586
587
0
                }
588
0
                else
589
0
                {
590
0
                    ScRange aDelRange;
591
0
                    bool bIsDel = rViewData.GetDelMark( aDelRange );
592
0
                    if ( (!bIsDel || aMarkRange != aDelRange) &&
593
0
                        bNewMarked &&
594
0
                        nNewMarkCount > 0 &&
595
0
                        m_LastMarkedRanges != *mpMarkedRanges )
596
0
                    {
597
0
                        RemoveSelection(refScMarkData);
598
0
                        if(bNewPosCellFocus)
599
0
                        {
600
0
                            CommitFocusCell(aNewCell);
601
0
                        }
602
0
                        std::vector<ScMyAddress> vecNew;
603
0
                        if(CalcScRangeListDifferenceMax(mpMarkedRanges.get(), &m_LastMarkedRanges,10,vecNew))
604
0
                        {
605
0
                            CommitChange(AccessibleEventId::SELECTION_CHANGED_WITHIN, uno::Any(),
606
0
                                         uno::Any());
607
0
                        }
608
0
                        else
609
0
                        {
610
0
                            for(const auto& rAddr : vecNew)
611
0
                            {
612
0
                                rtl::Reference< ScAccessibleCell > xChild = GetAccessibleCellAt(rAddr.Row(),rAddr.Col());
613
0
                                if (!(bNewPosCellFocus && rAddr == aNewCell) )
614
0
                                {
615
0
                                    CommitChange(
616
0
                                        AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS,
617
0
                                        uno::Any(), uno::Any(uno::Reference<XAccessible>(xChild)));
618
0
                                }
619
0
                                CommitChange(AccessibleEventId::SELECTION_CHANGED_ADD, uno::Any(),
620
0
                                             uno::Any(uno::Reference<XAccessible>(xChild)));
621
0
                                m_mapSelectionSend.emplace(rAddr,xChild);
622
0
                            }
623
0
                        }
624
0
                    }
625
0
                }
626
0
                if (bNewPosCellFocus && maActiveCell != aNewCell)
627
0
                {
628
0
                    CommitFocusCell(aNewCell);
629
0
                }
630
0
                m_LastMarkedRanges = *mpMarkedRanges;
631
0
            }
632
0
        }
633
0
        else if (rHint.GetId() == SfxHintId::ScDataChanged)
634
0
        {
635
0
            if (!mbDelIns)
636
0
                CommitTableModelChange(maRange.aStart.Row(), maRange.aStart.Col(), maRange.aEnd.Row(), maRange.aEnd.Col(), AccessibleTableModelChangeType::UPDATE);
637
0
            else
638
0
                mbDelIns = false;
639
0
            if (mpViewShell)
640
0
            {
641
0
                ScViewData& rViewData = mpViewShell->GetViewData();
642
0
                ScAddress aNewCell = rViewData.GetCurPos();
643
0
                if( maActiveCell == aNewCell)
644
0
                {
645
0
                    ScDocument* pScDoc= GetDocument(mpViewShell);
646
0
                    if (pScDoc)
647
0
                    {
648
0
                        OUString valStr(pScDoc->GetString(aNewCell.Col(),aNewCell.Row(),aNewCell.Tab()));
649
0
                        if(mpAccCell.is() && m_strCurCellValue != valStr)
650
0
                        {
651
0
                            uno::Any aOldValue;
652
0
                            uno::Any aNewValue;
653
0
                            (void)comphelper::OCommonAccessibleText::implInitTextChangedEvent(
654
0
                                m_strCurCellValue, valStr, aOldValue, aNewValue);
655
0
                            mpAccCell->CommitChange(AccessibleEventId::TEXT_CHANGED, aOldValue,
656
0
                                                    aNewValue);
657
658
0
                            if (pScDoc->HasValueData(maActiveCell))
659
0
                            {
660
0
                                mpAccCell->CommitChange(AccessibleEventId::VALUE_CHANGED,
661
0
                                                        uno::Any(), uno::Any());
662
0
                            }
663
664
0
                            m_strCurCellValue = valStr;
665
0
                        }
666
0
                        OUString tabName;
667
0
                        pScDoc->GetName( maActiveCell.Tab(), tabName );
668
0
                        if( m_strOldTabName != tabName )
669
0
                        {
670
0
                            OUString sOldName(ScResId(STR_ACC_TABLE_NAME));
671
0
                            sOldName = sOldName.replaceFirst("%1", m_strOldTabName);
672
0
                            OUString sNewName(ScResId(STR_ACC_TABLE_NAME));
673
0
                            sNewName = sNewName.replaceFirst("%1", tabName);
674
0
                            CommitChange(AccessibleEventId::NAME_CHANGED, uno::Any(sOldName),
675
0
                                         uno::Any(sNewName));
676
0
                            m_strOldTabName = tabName;
677
0
                        }
678
0
                    }
679
0
                }
680
0
            }
681
0
        }
682
        // commented out, because to use a ModelChangeEvent is not the right way
683
        // at the moment there is no way, but the Java/Gnome Api should be extended sometime
684
/*          if (mpViewShell)
685
            {
686
                Rectangle aNewVisCells(GetVisCells(GetVisArea(mpViewShell, meSplitPos)));
687
688
                Rectangle aNewPos(aNewVisCells);
689
690
                if (aNewVisCells.Overlaps(maVisCells))
691
                    aNewPos.Union(maVisCells);
692
                else
693
                    CommitTableModelChange(maVisCells.Top(), maVisCells.Left(), maVisCells.Bottom(), maVisCells.Right(), AccessibleTableModelChangeType::UPDATE);
694
695
                maVisCells = aNewVisCells;
696
697
                CommitTableModelChange(aNewPos.Top(), aNewPos.Left(), aNewPos.Bottom(), aNewPos.Right(), AccessibleTableModelChangeType::UPDATE);
698
            }
699
        }*/
700
0
    }
701
702
0
    ScAccessibleTableBase::Notify(rBC, rHint);
703
0
}
704
705
void ScAccessibleSpreadsheet::RemoveSelection(const ScMarkData &refScMarkData)
706
0
{
707
0
    MAP_ADDR_XACC::iterator miRemove = m_mapSelectionSend.begin();
708
0
    while (miRemove != m_mapSelectionSend.end())
709
0
    {
710
0
        if (refScMarkData.IsCellMarked(miRemove->first.Col(),miRemove->first.Row(),true) ||
711
0
            refScMarkData.IsCellMarked(miRemove->first.Col(),miRemove->first.Row()) )
712
0
        {
713
0
            ++miRemove;
714
0
            continue;
715
0
        }
716
0
        CommitChange(AccessibleEventId::SELECTION_CHANGED_REMOVE, uno::Any(),
717
0
                     uno::Any(uno::Reference<XAccessible>(miRemove->second)));
718
0
        miRemove = m_mapSelectionSend.erase(miRemove);
719
0
    }
720
0
}
721
void ScAccessibleSpreadsheet::CommitFocusCell(const ScAddress &aNewCell)
722
0
{
723
0
    OSL_ASSERT(!IsFormulaMode());
724
0
    if(IsFormulaMode())
725
0
    {
726
0
        return ;
727
0
    }
728
729
    // Related tdf#158914: check if focused cell has changed
730
    // Some accessibility tools, such as NVDA on Windows, appear to need
731
    // a value changed notification before it will refetch a cell's
732
    // accessible text. While Notify() is able to fire text and value changed
733
    // notifications, it seems to be rarely called and when it is called,
734
    // such as when undoing a cell, it can be called before the cell's
735
    // accessible text has been updated.
736
    // So before a cell loses focus, check if any accessible text changes
737
    // have occurred and fire text and value changed notifications if needed.
738
0
    ScDocument* pScDoc= GetDocument(mpViewShell);
739
0
    if (pScDoc && mpAccCell.is())
740
0
    {
741
0
        const ScAddress aOldActiveCell = mpAccCell->GetCellAddress();
742
0
        OUString valStr(pScDoc->GetString(aOldActiveCell.Col(),aOldActiveCell.Row(),aOldActiveCell.Tab()));
743
0
        if(m_strCurCellValue != valStr)
744
0
        {
745
0
            uno::Any aOldValue;
746
0
            uno::Any aNewValue;
747
0
            (void)comphelper::OCommonAccessibleText::implInitTextChangedEvent(
748
0
                m_strCurCellValue, valStr, aOldValue, aNewValue);
749
0
            mpAccCell->CommitChange(AccessibleEventId::TEXT_CHANGED, aOldValue, aNewValue);
750
751
0
            if (pScDoc->HasValueData(maActiveCell))
752
0
            {
753
0
                mpAccCell->CommitChange(AccessibleEventId::VALUE_CHANGED, uno::Any(), uno::Any());
754
0
            }
755
756
0
            m_strCurCellValue = valStr;
757
0
        }
758
0
    }
759
760
0
    uno::Reference<XAccessible> xOldCell = mpAccCell;
761
0
    mpAccCell.clear();
762
0
    mpAccCell = GetAccessibleCellAt(aNewCell.Row(), aNewCell.Col());
763
0
    maActiveCell = aNewCell;
764
0
    if (pScDoc)
765
0
    {
766
0
        m_strCurCellValue = pScDoc->GetString(maActiveCell.Col(),maActiveCell.Row(),maActiveCell.Tab());
767
0
    }
768
0
    CommitChange(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, uno::Any(xOldCell),
769
0
                 uno::Any(uno::Reference<XAccessible>(mpAccCell)));
770
0
}
771
772
//=====  XAccessibleTable  ================================================
773
774
uno::Reference< XAccessibleTable > SAL_CALL ScAccessibleSpreadsheet::getAccessibleRowHeaders(  )
775
0
{
776
0
    SolarMutexGuard aGuard;
777
0
    ensureAlive();
778
0
    uno::Reference< XAccessibleTable > xAccessibleTable;
779
0
    if( mpDoc && mbIsSpreadsheet )
780
0
    {
781
0
        if( std::optional<ScRange> oRowRange = mpDoc->GetRepeatRowRange( mnTab ) )
782
0
        {
783
0
            SCROW nStart = oRowRange->aStart.Row();
784
0
            SCROW nEnd = oRowRange->aEnd.Row();
785
0
            ScDocument* pDoc = GetDocument(mpViewShell);
786
0
            if( (0 <= nStart) && (nStart <= nEnd) && (nEnd <= pDoc->MaxRow()) )
787
0
                xAccessibleTable.set( new ScAccessibleSpreadsheet( *this, ScRange( 0, nStart, mnTab, pDoc->MaxCol(), nEnd, mnTab ) ) );
788
0
        }
789
0
    }
790
0
    return xAccessibleTable;
791
0
}
792
793
uno::Reference< XAccessibleTable > SAL_CALL ScAccessibleSpreadsheet::getAccessibleColumnHeaders(  )
794
0
{
795
0
    SolarMutexGuard aGuard;
796
0
    ensureAlive();
797
0
    uno::Reference< XAccessibleTable > xAccessibleTable;
798
0
    if( mpDoc && mbIsSpreadsheet )
799
0
    {
800
0
        if( std::optional<ScRange> oColRange = mpDoc->GetRepeatColRange( mnTab ) )
801
0
        {
802
0
            SCCOL nStart = oColRange->aStart.Col();
803
0
            SCCOL nEnd = oColRange->aEnd.Col();
804
0
            ScDocument* pDoc = GetDocument(mpViewShell);
805
0
            if( (0 <= nStart) && (nStart <= nEnd) && (nEnd <= pDoc->MaxCol()) )
806
0
                xAccessibleTable.set( new ScAccessibleSpreadsheet( *this, ScRange( nStart, 0, mnTab, nEnd, pDoc->MaxRow(), mnTab ) ) );
807
0
        }
808
0
    }
809
0
    return xAccessibleTable;
810
0
}
811
812
uno::Sequence< sal_Int32 > SAL_CALL ScAccessibleSpreadsheet::getSelectedAccessibleRows(  )
813
0
{
814
0
    SolarMutexGuard aGuard;
815
0
    ensureAlive();
816
0
    uno::Sequence<sal_Int32> aSequence;
817
0
    if (IsFormulaMode())
818
0
    {
819
0
        return aSequence;
820
0
    }
821
0
    if (mpViewShell)
822
0
    {
823
0
        aSequence.realloc(maRange.aEnd.Row() - maRange.aStart.Row() + 1);
824
0
        const ScMarkData& rMarkdata = mpViewShell->GetViewData().GetMarkData();
825
0
        sal_Int32* pSequence = aSequence.getArray();
826
0
        sal_Int32 nCount(0);
827
0
        for (SCROW i = maRange.aStart.Row(); i <= maRange.aEnd.Row(); ++i)
828
0
        {
829
0
            if (rMarkdata.IsRowMarked(i))
830
0
            {
831
0
                pSequence[nCount] = i;
832
0
                ++nCount;
833
0
            }
834
0
        }
835
0
        aSequence.realloc(nCount);
836
0
    }
837
0
    else
838
0
        aSequence.realloc(0);
839
0
    return aSequence;
840
0
}
841
842
uno::Sequence< sal_Int32 > SAL_CALL ScAccessibleSpreadsheet::getSelectedAccessibleColumns(  )
843
0
{
844
0
    SolarMutexGuard aGuard;
845
0
    ensureAlive();
846
0
    uno::Sequence<sal_Int32> aSequence;
847
0
    if (IsFormulaMode() || !mpViewShell)
848
0
        return aSequence;
849
850
0
    aSequence.realloc(maRange.aEnd.Col() - maRange.aStart.Col() + 1);
851
0
    sal_Int32* pSequence = aSequence.getArray();
852
0
    sal_Int32 nCount(0);
853
0
    const ScMarkData& rMarkdata = mpViewShell->GetViewData().GetMarkData();
854
0
    for (SCCOL i = maRange.aStart.Col(); i <= maRange.aEnd.Col(); ++i)
855
0
    {
856
0
        if (rMarkdata.IsColumnMarked(i))
857
0
        {
858
0
            pSequence[nCount] = i;
859
0
            ++nCount;
860
0
        }
861
0
    }
862
0
    aSequence.realloc(nCount);
863
0
    return aSequence;
864
0
}
865
866
sal_Bool SAL_CALL ScAccessibleSpreadsheet::isAccessibleRowSelected( sal_Int32 nRow )
867
0
{
868
0
    SolarMutexGuard aGuard;
869
0
    ensureAlive();
870
0
    if (IsFormulaMode())
871
0
    {
872
0
        return false;
873
0
    }
874
875
0
    if ((nRow > (maRange.aEnd.Row() - maRange.aStart.Row())) || (nRow < 0))
876
0
        throw lang::IndexOutOfBoundsException();
877
878
0
    bool bResult(false);
879
0
    if (mpViewShell)
880
0
    {
881
0
        const ScMarkData& rMarkdata = mpViewShell->GetViewData().GetMarkData();
882
0
        bResult = rMarkdata.IsRowMarked(static_cast<SCROW>(nRow));
883
0
    }
884
0
    return bResult;
885
0
}
886
887
sal_Bool SAL_CALL ScAccessibleSpreadsheet::isAccessibleColumnSelected( sal_Int32 nColumn )
888
0
{
889
0
    SolarMutexGuard aGuard;
890
0
    ensureAlive();
891
892
0
    if (IsFormulaMode())
893
0
    {
894
0
        return false;
895
0
    }
896
0
    if ((nColumn > (maRange.aEnd.Col() - maRange.aStart.Col())) || (nColumn < 0))
897
0
        throw lang::IndexOutOfBoundsException();
898
899
0
    bool bResult(false);
900
0
    if (mpViewShell)
901
0
    {
902
0
        const ScMarkData& rMarkdata = mpViewShell->GetViewData().GetMarkData();
903
0
        bResult = rMarkdata.IsColumnMarked(static_cast<SCCOL>(nColumn));
904
0
    }
905
0
    return bResult;
906
0
}
907
908
rtl::Reference<ScAccessibleCell> ScAccessibleSpreadsheet::GetAccessibleCellAt(sal_Int32 nRow, sal_Int32 nColumn)
909
0
{
910
0
    if (IsFormulaMode())
911
0
    {
912
0
        ScAddress aCellAddress(static_cast<SCCOL>(nColumn), nRow, mpViewShell->GetViewData().CurrentTabForData());
913
0
        if ((aCellAddress == m_aFormulaActiveCell) && m_pAccFormulaCell.is())
914
0
        {
915
0
            return m_pAccFormulaCell;
916
0
        }
917
0
        else
918
0
        {
919
0
            return ScAccessibleCell::create(this, mpViewShell, aCellAddress, GetAccessibleIndexFormula(nRow, nColumn), meSplitPos, mpAccDoc);
920
0
        }
921
0
    }
922
0
    else
923
0
    {
924
0
        ScAddress aCellAddress(static_cast<SCCOL>(maRange.aStart.Col() + nColumn),
925
0
            static_cast<SCROW>(maRange.aStart.Row() + nRow), maRange.aStart.Tab());
926
0
        if ((aCellAddress == maActiveCell) && mpAccCell.is())
927
0
        {
928
0
            return mpAccCell;
929
0
        }
930
0
        else
931
0
        {
932
            // tdf#158914 add back reusing weakly cached ScAccessibleCells
933
            // While commit 8e886993f32b7db11a99bdecf06451e6de6c3842
934
            // fixed tdf#157568, moving the selected cell rapidly creates
935
            // a large number of stale ScAccessibleCell instances that
936
            // aren't deleted until the Calc document is closed. So reduce
937
            // memory usage by adding back the ScAccessibleCell cache that
938
            // was in commit f22cb3dfab413a2917cd810b8e1b8f644a016327 now
939
            // that a new fix for tdf#157568 has been implemented.
940
0
            rtl::Reference<ScAccessibleCell> xCell;
941
0
            auto it = m_mapCells.find(aCellAddress);
942
0
            if (it != m_mapCells.end())
943
0
                xCell = it->second.get();
944
0
            if (xCell)
945
0
                return xCell;
946
0
            xCell = ScAccessibleCell::create(this, mpViewShell, aCellAddress, getAccessibleIndex(nRow, nColumn), meSplitPos, mpAccDoc);
947
0
            m_mapCells.insert(std::make_pair(aCellAddress, xCell));
948
0
            return xCell;
949
0
        }
950
0
    }
951
0
}
952
953
uno::Reference< XAccessible > SAL_CALL ScAccessibleSpreadsheet::getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn )
954
0
{
955
0
    SolarMutexGuard aGuard;
956
0
    ensureAlive();
957
0
    if (!IsFormulaMode())
958
0
    {
959
0
        if (nRow > (maRange.aEnd.Row() - maRange.aStart.Row()) ||
960
0
            nRow < 0 ||
961
0
            nColumn > (maRange.aEnd.Col() - maRange.aStart.Col()) ||
962
0
            nColumn < 0)
963
0
            throw lang::IndexOutOfBoundsException();
964
0
    }
965
0
    rtl::Reference<ScAccessibleCell> pAccessibleCell = GetAccessibleCellAt(nRow, nColumn);
966
0
    return pAccessibleCell;
967
0
}
968
969
sal_Bool SAL_CALL ScAccessibleSpreadsheet::isAccessibleSelected( sal_Int32 nRow, sal_Int32 nColumn )
970
0
{
971
0
    SolarMutexGuard aGuard;
972
0
    ensureAlive();
973
974
0
    if (IsFormulaMode())
975
0
    {
976
0
        ScAddress addr(static_cast<SCCOL>(nColumn), nRow, 0);
977
0
        return IsScAddrFormulaSel(addr);
978
0
    }
979
0
    if ((nColumn > (maRange.aEnd.Col() - maRange.aStart.Col())) || (nColumn < 0) ||
980
0
        (nRow > (maRange.aEnd.Row() - maRange.aStart.Row())) || (nRow < 0))
981
0
        throw lang::IndexOutOfBoundsException();
982
983
0
    bool bResult(false);
984
0
    if (mpViewShell)
985
0
    {
986
0
        const ScMarkData& rMarkdata = mpViewShell->GetViewData().GetMarkData();
987
0
        bResult = rMarkdata.IsCellMarked(static_cast<SCCOL>(nColumn), static_cast<SCROW>(nRow));
988
0
    }
989
0
    return bResult;
990
0
}
991
992
    //=====  XAccessibleComponent  ============================================
993
994
uno::Reference< XAccessible > SAL_CALL ScAccessibleSpreadsheet::getAccessibleAtPoint(const awt::Point& rPoint)
995
0
{
996
0
    uno::Reference< XAccessible > xAccessible;
997
0
    if (containsPoint(rPoint))
998
0
    {
999
0
        SolarMutexGuard aGuard;
1000
0
        ensureAlive();
1001
0
        if (mpViewShell)
1002
0
        {
1003
0
            SCCOL nX;
1004
0
            SCROW nY;
1005
0
            mpViewShell->GetViewData().GetPosFromPixel( rPoint.X, rPoint.Y, meSplitPos, nX, nY);
1006
0
            try {
1007
0
                xAccessible = getAccessibleCellAt(nY, nX);
1008
0
            }
1009
0
            catch(const css::lang::IndexOutOfBoundsException &)
1010
0
            {
1011
0
                return nullptr;
1012
0
            }
1013
0
        }
1014
0
    }
1015
0
    return xAccessible;
1016
0
}
1017
1018
void SAL_CALL ScAccessibleSpreadsheet::grabFocus(  )
1019
0
{
1020
0
    if (getAccessibleParent().is())
1021
0
    {
1022
0
        uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY);
1023
0
        if (xAccessibleComponent.is())
1024
0
            xAccessibleComponent->grabFocus();
1025
0
    }
1026
0
}
1027
1028
sal_Int32 SAL_CALL ScAccessibleSpreadsheet::getForeground(  )
1029
0
{
1030
0
    return sal_Int32(COL_BLACK);
1031
0
}
1032
1033
sal_Int32 SAL_CALL ScAccessibleSpreadsheet::getBackground(  )
1034
0
{
1035
0
    SolarMutexGuard aGuard;
1036
0
    ensureAlive();
1037
0
    return sal_Int32(ScModule::get()->GetColorConfig().GetColorValue(::svtools::DOCCOLOR).nColor);
1038
0
}
1039
1040
    //=====  XAccessibleContext  ==============================================
1041
1042
uno::Reference<XAccessibleRelationSet> SAL_CALL ScAccessibleSpreadsheet::getAccessibleRelationSet()
1043
0
{
1044
0
    rtl::Reference<utl::AccessibleRelationSetHelper> pRelationSet;
1045
0
    if(mpAccDoc)
1046
0
        pRelationSet = mpAccDoc->GetRelationSet(nullptr);
1047
0
    if (pRelationSet)
1048
0
        return pRelationSet;
1049
0
    return new utl::AccessibleRelationSetHelper();
1050
0
}
1051
1052
sal_Int64 SAL_CALL ScAccessibleSpreadsheet::getAccessibleStateSet()
1053
0
{
1054
0
    SolarMutexGuard aGuard;
1055
0
    sal_Int64 nParentStates = 0;
1056
0
    if (getAccessibleParent().is())
1057
0
    {
1058
0
        uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
1059
0
        nParentStates = xParentContext->getAccessibleStateSet();
1060
0
    }
1061
0
    sal_Int64 nStateSet = 0;
1062
0
    if (IsDefunc(nParentStates))
1063
0
        nStateSet |= AccessibleStateType::DEFUNC;
1064
0
    else
1065
0
    {
1066
0
        nStateSet |= AccessibleStateType::MANAGES_DESCENDANTS;
1067
0
        if (IsEditable())
1068
0
            nStateSet |= AccessibleStateType::EDITABLE;
1069
0
        nStateSet |= AccessibleStateType::ENABLED;
1070
0
        nStateSet |= AccessibleStateType::FOCUSABLE;
1071
0
        if (IsFocused())
1072
0
            nStateSet |= AccessibleStateType::FOCUSED;
1073
0
        nStateSet |= AccessibleStateType::MULTI_SELECTABLE;
1074
0
        nStateSet |= AccessibleStateType::OPAQUE;
1075
0
        nStateSet |= AccessibleStateType::SELECTABLE;
1076
0
        if (IsCompleteSheetSelected())
1077
0
            nStateSet |= AccessibleStateType::SELECTED;
1078
0
        if (isShowing())
1079
0
            nStateSet |= AccessibleStateType::SHOWING;
1080
0
        if (isVisible())
1081
0
            nStateSet |= AccessibleStateType::VISIBLE;
1082
0
    }
1083
0
    return nStateSet;
1084
0
}
1085
1086
    ///=====  XAccessibleSelection  ===========================================
1087
1088
void SAL_CALL ScAccessibleSpreadsheet::selectAccessibleChild( sal_Int64 nChildIndex )
1089
0
{
1090
0
    SolarMutexGuard aGuard;
1091
0
    ensureAlive();
1092
0
    if (nChildIndex < 0 || nChildIndex >= getAccessibleChildCount())
1093
0
        throw lang::IndexOutOfBoundsException();
1094
1095
0
    if (mpViewShell)
1096
0
    {
1097
0
        sal_Int32 nCol(getAccessibleColumn(nChildIndex));
1098
0
        sal_Int32 nRow(getAccessibleRow(nChildIndex));
1099
1100
0
        SelectCell(nRow, nCol, false);
1101
0
    }
1102
0
}
1103
1104
void SAL_CALL
1105
        ScAccessibleSpreadsheet::clearAccessibleSelection(  )
1106
0
{
1107
0
    SolarMutexGuard aGuard;
1108
0
    ensureAlive();
1109
0
    if (mpViewShell && !IsFormulaMode())
1110
0
        mpViewShell->Unmark();
1111
0
}
1112
1113
void SAL_CALL ScAccessibleSpreadsheet::selectAllAccessibleChildren(  )
1114
0
{
1115
0
    SolarMutexGuard aGuard;
1116
0
    ensureAlive();
1117
0
    if (!mpViewShell)
1118
0
        return;
1119
1120
0
    if (IsFormulaMode())
1121
0
    {
1122
0
        ScDocument* pDoc = GetDocument(mpViewShell);
1123
0
        ScViewData& rViewData = mpViewShell->GetViewData();
1124
0
        auto nCurrentTab = rViewData.CurrentTabForData();
1125
0
        mpViewShell->InitRefMode( 0, 0, nCurrentTab, SC_REFTYPE_REF );
1126
0
        rViewData.SetRefStart(0, 0, nCurrentTab);
1127
0
        rViewData.SetRefEnd(pDoc->MaxCol(), pDoc->MaxRow(), nCurrentTab);
1128
0
        mpViewShell->UpdateRef(pDoc->MaxCol(), pDoc->MaxRow(), nCurrentTab);
1129
0
    }
1130
0
    else
1131
0
        mpViewShell->SelectAll();
1132
0
}
1133
1134
sal_Int64 SAL_CALL
1135
        ScAccessibleSpreadsheet::getSelectedAccessibleChildCount(  )
1136
0
{
1137
0
    SolarMutexGuard aGuard;
1138
0
    ensureAlive();
1139
0
    sal_Int64 nResult(0);
1140
0
    if (mpViewShell)
1141
0
    {
1142
0
        if (IsFormulaMode())
1143
0
        {
1144
0
            nResult =  static_cast<sal_Int64>(GetRowAll()) * static_cast<sal_Int64>(GetColAll());
1145
0
        }
1146
0
        else
1147
0
        {
1148
0
            if (!mpMarkedRanges)
1149
0
            {
1150
0
                mpMarkedRanges.reset(new ScRangeList());
1151
0
                ScMarkData aMarkData(mpViewShell->GetViewData().GetMarkData());
1152
0
                aMarkData.FillRangeListWithMarks(mpMarkedRanges.get(), false);
1153
0
            }
1154
            // is possible, because there shouldn't be overlapped ranges in it
1155
0
            nResult = mpMarkedRanges->GetCellCount();
1156
0
        }
1157
0
    }
1158
0
    return nResult;
1159
0
}
1160
1161
uno::Reference<XAccessible > SAL_CALL
1162
        ScAccessibleSpreadsheet::getSelectedAccessibleChild( sal_Int64 nSelectedChildIndex )
1163
0
{
1164
0
    SolarMutexGuard aGuard;
1165
0
    ensureAlive();
1166
0
    uno::Reference < XAccessible > xAccessible;
1167
0
    if (IsFormulaMode())
1168
0
    {
1169
0
        if(CheckChildIndex(nSelectedChildIndex))
1170
0
        {
1171
0
            ScAddress addr = GetChildIndexAddress(nSelectedChildIndex);
1172
0
            xAccessible = getAccessibleCellAt(addr.Row(), addr.Col());
1173
0
        }
1174
0
        return xAccessible;
1175
0
    }
1176
0
    if (mpViewShell)
1177
0
    {
1178
0
        if (!mpMarkedRanges)
1179
0
        {
1180
0
            mpMarkedRanges.reset(new ScRangeList());
1181
0
            mpViewShell->GetViewData().GetMarkData().FillRangeListWithMarks(mpMarkedRanges.get(), false);
1182
0
        }
1183
0
        if ((nSelectedChildIndex < 0) ||
1184
0
                (mpMarkedRanges->GetCellCount() <= o3tl::make_unsigned(nSelectedChildIndex)))
1185
0
        {
1186
0
            throw lang::IndexOutOfBoundsException();
1187
0
        }
1188
0
        ScMyAddress addr = CalcScAddressFromRangeList(mpMarkedRanges.get(),nSelectedChildIndex);
1189
0
        auto it = m_mapSelectionSend.find(addr);
1190
0
        if( it != m_mapSelectionSend.end() )
1191
0
            xAccessible = it->second;
1192
0
        else
1193
0
            xAccessible = getAccessibleCellAt(addr.Row(), addr.Col());
1194
0
    }
1195
0
    return xAccessible;
1196
0
}
1197
1198
void SAL_CALL ScAccessibleSpreadsheet::deselectAccessibleChild( sal_Int64 nChildIndex )
1199
0
{
1200
0
    SolarMutexGuard aGuard;
1201
0
    ensureAlive();
1202
1203
0
    if (nChildIndex < 0 || nChildIndex >= getAccessibleChildCount())
1204
0
        throw lang::IndexOutOfBoundsException();
1205
1206
0
    if (!mpViewShell)
1207
0
        return;
1208
1209
0
    sal_Int32 nCol(getAccessibleColumn(nChildIndex));
1210
0
    sal_Int32 nRow(getAccessibleRow(nChildIndex));
1211
1212
0
    if (IsFormulaMode())
1213
0
    {
1214
0
        if(IsScAddrFormulaSel(
1215
0
            ScAddress(static_cast<SCCOL>(nCol), nRow,mpViewShell->GetViewData().CurrentTabForData()))
1216
0
            )
1217
0
        {
1218
0
            SelectCell(nRow, nCol, true);
1219
0
        }
1220
0
        return ;
1221
0
    }
1222
0
    if (mpViewShell->GetViewData().GetMarkData().IsCellMarked(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow)))
1223
0
        SelectCell(nRow, nCol, true);
1224
0
}
1225
1226
void ScAccessibleSpreadsheet::SelectCell(sal_Int32 nRow, sal_Int32 nCol, bool bDeselect)
1227
0
{
1228
0
    if (IsFormulaMode())
1229
0
    {
1230
0
        if (bDeselect)
1231
0
        {//??
1232
0
                return;
1233
0
        }
1234
0
        else
1235
0
        {
1236
0
            ScViewData& rViewData = mpViewShell->GetViewData();
1237
1238
0
            mpViewShell->InitRefMode( static_cast<SCCOL>(nCol), nRow, rViewData.CurrentTabForData(), SC_REFTYPE_REF );
1239
0
            mpViewShell->UpdateRef(static_cast<SCCOL>(nCol), nRow, rViewData.CurrentTabForData());
1240
0
        }
1241
0
        return ;
1242
0
    }
1243
0
    mpViewShell->SetTabNo( maRange.aStart.Tab() );
1244
1245
0
    mpViewShell->DoneBlockMode( true ); // continue selecting
1246
0
    mpViewShell->InitBlockMode( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), maRange.aStart.Tab(), bDeselect );
1247
1248
0
    mpViewShell->SelectionChanged();
1249
0
}
1250
1251
/*
1252
void ScAccessibleSpreadsheet::CreateSortedMarkedCells()
1253
{
1254
    mpSortedMarkedCells = new std::vector<ScMyAddress>();
1255
    mpSortedMarkedCells->reserve(mpMarkedRanges->GetCellCount());
1256
    for ( size_t i = 0, ListSize = mpMarkedRanges->size(); i < ListSize; ++i )
1257
    {
1258
        ScRange* pRange = (*mpMarkedRanges)[i];
1259
        if (pRange->aStart.Tab() != pRange->aEnd.Tab())
1260
        {
1261
            if ((maActiveCell.Tab() >= pRange->aStart.Tab()) ||
1262
                maActiveCell.Tab() <= pRange->aEnd.Tab())
1263
            {
1264
                ScRange aRange(*pRange);
1265
                aRange.aStart.SetTab(maActiveCell.Tab());
1266
                aRange.aEnd.SetTab(maActiveCell.Tab());
1267
                AddMarkedRange(aRange);
1268
            }
1269
            else
1270
            {
1271
                OSL_FAIL("Range of wrong table");
1272
            }
1273
        }
1274
        else if(pRange->aStart.Tab() == maActiveCell.Tab())
1275
            AddMarkedRange(*pRange);
1276
        else
1277
        {
1278
            OSL_FAIL("Range of wrong table");
1279
        }
1280
    }
1281
    std::sort(mpSortedMarkedCells->begin(), mpSortedMarkedCells->end());
1282
}
1283
1284
void ScAccessibleSpreadsheet::AddMarkedRange(const ScRange& rRange)
1285
{
1286
    for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
1287
    {
1288
        for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
1289
        {
1290
            ScMyAddress aCell(nCol, nRow, maActiveCell.Tab());
1291
            mpSortedMarkedCells->push_back(aCell);
1292
        }
1293
    }
1294
}*/
1295
1296
AbsoluteScreenPixelRectangle ScAccessibleSpreadsheet::GetBoundingBoxOnScreen()
1297
0
{
1298
0
    AbsoluteScreenPixelRectangle aRect;
1299
0
    if (mpViewShell)
1300
0
    {
1301
0
        vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
1302
0
        if (pWindow)
1303
0
            aRect = pWindow->GetWindowExtentsAbsolute();
1304
0
    }
1305
0
    return aRect;
1306
0
}
1307
1308
tools::Rectangle ScAccessibleSpreadsheet::GetBoundingBox()
1309
0
{
1310
0
    tools::Rectangle aRect;
1311
0
    if (mpViewShell)
1312
0
    {
1313
0
        vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
1314
0
        if (pWindow)
1315
            //#101986#; extends to the same window, because the parent is the document and it has the same window
1316
0
            aRect = pWindow->GetWindowExtentsRelative(*pWindow);
1317
0
    }
1318
0
    return aRect;
1319
0
}
1320
1321
bool ScAccessibleSpreadsheet::IsDefunc(sal_Int64 nParentStates)
1322
0
{
1323
0
    return ScAccessibleContextBase::IsDefunc() || (mpViewShell == nullptr) || !getAccessibleParent().is() ||
1324
0
        (nParentStates & AccessibleStateType::DEFUNC);
1325
0
}
1326
1327
bool ScAccessibleSpreadsheet::IsEditable()
1328
0
{
1329
0
    if (IsFormulaMode())
1330
0
    {
1331
0
        return false;
1332
0
    }
1333
0
    bool bProtected(false);
1334
0
    if (mpDoc && mpDoc->IsTabProtected(maRange.aStart.Tab()))
1335
0
        bProtected = true;
1336
0
    return !bProtected;
1337
0
}
1338
1339
bool ScAccessibleSpreadsheet::IsFocused()
1340
0
{
1341
0
    bool bFocused(false);
1342
0
    if (mpViewShell)
1343
0
    {
1344
0
        if (mpViewShell->GetViewData().GetActivePart() == meSplitPos)
1345
0
            bFocused = mpViewShell->GetActiveWin()->HasFocus();
1346
0
    }
1347
0
    return bFocused;
1348
0
}
1349
1350
bool ScAccessibleSpreadsheet::IsCompleteSheetSelected()
1351
0
{
1352
0
    if (IsFormulaMode())
1353
0
    {
1354
0
        return false;
1355
0
    }
1356
1357
0
    bool bResult(false);
1358
0
    if(mpViewShell)
1359
0
    {
1360
        //#103800#; use a copy of MarkData
1361
0
        ScMarkData aMarkData(mpViewShell->GetViewData().GetMarkData());
1362
0
        if (aMarkData.IsAllMarked(maRange))
1363
0
            bResult = true;
1364
0
    }
1365
0
    return bResult;
1366
0
}
1367
1368
ScDocument* ScAccessibleSpreadsheet::GetDocument(ScTabViewShell* pViewShell)
1369
0
{
1370
0
    ScDocument* pDoc = nullptr;
1371
0
    if (pViewShell)
1372
0
        pDoc = &pViewShell->GetViewData().GetDocument();
1373
0
    return pDoc;
1374
0
}
1375
1376
sal_Bool SAL_CALL ScAccessibleSpreadsheet::selectRow( sal_Int32 row )
1377
0
{
1378
0
    SolarMutexGuard g;
1379
1380
0
    if (IsFormulaMode())
1381
0
    {
1382
0
        return false;
1383
0
    }
1384
1385
0
    ScDocument* pDoc = GetDocument(mpViewShell);
1386
0
    mpViewShell->SetTabNo( maRange.aStart.Tab() );
1387
0
    mpViewShell->DoneBlockMode( true ); // continue selecting
1388
0
    mpViewShell->InitBlockMode( 0, row, maRange.aStart.Tab(), false, false, true );
1389
0
    mpViewShell->MarkCursor( pDoc->MaxCol(), row, maRange.aStart.Tab(), false, true );
1390
0
    mpViewShell->SelectionChanged();
1391
0
    return true;
1392
0
}
1393
1394
sal_Bool SAL_CALL ScAccessibleSpreadsheet::selectColumn( sal_Int32 column )
1395
0
{
1396
0
    SolarMutexGuard g;
1397
1398
0
    if (IsFormulaMode())
1399
0
    {
1400
0
        return false;
1401
0
    }
1402
1403
0
    ScDocument* pDoc = GetDocument(mpViewShell);
1404
0
    mpViewShell->SetTabNo( maRange.aStart.Tab() );
1405
0
    mpViewShell->DoneBlockMode( true ); // continue selecting
1406
0
    mpViewShell->InitBlockMode( static_cast<SCCOL>(column), 0, maRange.aStart.Tab(), false, true );
1407
0
    mpViewShell->MarkCursor( static_cast<SCCOL>(column), pDoc->MaxRow(), maRange.aStart.Tab(), true );
1408
0
    mpViewShell->SelectionChanged();
1409
0
    return true;
1410
0
}
1411
1412
sal_Bool SAL_CALL ScAccessibleSpreadsheet::unselectRow( sal_Int32 row )
1413
0
{
1414
0
    SolarMutexGuard g;
1415
1416
0
    if (IsFormulaMode())
1417
0
    {
1418
0
        return false;
1419
0
    }
1420
1421
0
    ScDocument* pDoc = GetDocument(mpViewShell);
1422
0
    mpViewShell->SetTabNo( maRange.aStart.Tab() );
1423
0
    mpViewShell->DoneBlockMode( true ); // continue selecting
1424
0
    mpViewShell->InitBlockMode( 0, row, maRange.aStart.Tab(), false, false, true, true );
1425
0
    mpViewShell->MarkCursor( pDoc->MaxCol(), row, maRange.aStart.Tab(), false, true );
1426
0
    mpViewShell->SelectionChanged();
1427
0
    mpViewShell->DoneBlockMode( true );
1428
0
    return true;
1429
0
}
1430
1431
sal_Bool SAL_CALL ScAccessibleSpreadsheet::unselectColumn( sal_Int32 column )
1432
0
{
1433
0
    SolarMutexGuard g;
1434
1435
0
    if (IsFormulaMode())
1436
0
    {
1437
0
        return false;
1438
0
    }
1439
1440
0
    ScDocument* pDoc = GetDocument(mpViewShell);
1441
0
    mpViewShell->SetTabNo( maRange.aStart.Tab() );
1442
0
    mpViewShell->DoneBlockMode( true ); // continue selecting
1443
0
    mpViewShell->InitBlockMode( static_cast<SCCOL>(column), 0, maRange.aStart.Tab(), false, true, false, true );
1444
0
    mpViewShell->MarkCursor( static_cast<SCCOL>(column), pDoc->MaxRow(), maRange.aStart.Tab(), true );
1445
0
    mpViewShell->SelectionChanged();
1446
0
    mpViewShell->DoneBlockMode( true );
1447
0
    return true;
1448
0
}
1449
1450
void ScAccessibleSpreadsheet::FireFirstCellFocus()
1451
0
{
1452
0
    if (IsFormulaMode())
1453
0
    {
1454
0
        return ;
1455
0
    }
1456
0
    if (mbIsFocusSend)
1457
0
    {
1458
0
        return ;
1459
0
    }
1460
0
    mbIsFocusSend = true;
1461
0
    CommitChange(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, uno::Any(),
1462
0
                 uno::Any(getAccessibleCellAt(maActiveCell.Row(), maActiveCell.Col())));
1463
0
}
1464
1465
void ScAccessibleSpreadsheet::NotifyRefMode()
1466
0
{
1467
0
    ScViewData& rViewData = mpViewShell->GetViewData();
1468
0
    if (!rViewData.IsRefMode())
1469
        // Not in reference mode. Bail out.
1470
0
        return;
1471
1472
0
    sal_uInt16 nRefStartX = rViewData.GetRefStartX();
1473
0
    sal_Int32 nRefStartY = rViewData.GetRefStartY();
1474
0
    sal_uInt16 nRefEndX = rViewData.GetRefEndX();
1475
0
    sal_Int32 nRefEndY = rViewData.GetRefEndY();
1476
0
    ScAddress aFormulaAddr;
1477
0
    if(!GetFormulaCurrentFocusCell(aFormulaAddr))
1478
0
    {
1479
0
        return ;
1480
0
    }
1481
0
    if (m_aFormulaActiveCell != aFormulaAddr)
1482
0
    {//New Focus
1483
0
        m_nMinX =std::min(nRefStartX,nRefEndX);
1484
0
        m_nMaxX =std::max(nRefStartX,nRefEndX);
1485
0
        m_nMinY = std::min(nRefStartY,nRefEndY);
1486
0
        m_nMaxY = std::max(nRefStartY,nRefEndY);
1487
0
        RemoveFormulaSelection();
1488
0
        uno::Reference<XAccessible> xOldFormulaCell = m_pAccFormulaCell;
1489
0
        m_pAccFormulaCell = GetAccessibleCellAt(aFormulaAddr.Row(), aFormulaAddr.Col());
1490
0
        rtl::Reference< ScAccessibleCell > xNew = m_pAccFormulaCell;
1491
0
        CommitChange(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, uno::Any(xOldFormulaCell),
1492
0
                     uno::Any(uno::Reference<XAccessible>(xNew)));
1493
1494
0
        if (nRefStartX == nRefEndX && nRefStartY == nRefEndY)
1495
0
        {//Selection Single
1496
0
            CommitChange(AccessibleEventId::SELECTION_CHANGED, uno::Any(xOldFormulaCell),
1497
0
                         uno::Any(uno::Reference<XAccessible>(xNew)));
1498
0
            m_mapFormulaSelectionSend.emplace(aFormulaAddr,xNew);
1499
0
            m_vecFormulaLastMyAddr.clear();
1500
0
            m_vecFormulaLastMyAddr.emplace_back(aFormulaAddr);
1501
0
        }
1502
0
        else
1503
0
        {
1504
0
            std::vector<ScMyAddress> vecCurSel;
1505
0
            int nCurSize =  (m_nMaxX - m_nMinX +1)*(m_nMaxY - m_nMinY +1) ;
1506
0
            vecCurSel.reserve(nCurSize);
1507
0
            for (sal_uInt16 x = m_nMinX ; x <= m_nMaxX ; ++x)
1508
0
            {
1509
0
                for (sal_Int32 y = m_nMinY ; y <= m_nMaxY ; ++y)
1510
0
                {
1511
0
                    ScMyAddress aAddr(x,y,0);
1512
0
                    vecCurSel.push_back(aAddr);
1513
0
                }
1514
0
            }
1515
0
            std::sort(vecCurSel.begin(), vecCurSel.end());
1516
0
            std::vector<ScMyAddress> vecNew;
1517
0
            std::set_difference(vecCurSel.begin(),vecCurSel.end(),
1518
0
                m_vecFormulaLastMyAddr.begin(),m_vecFormulaLastMyAddr.end(),
1519
0
                std::back_insert_iterator(vecNew));
1520
0
            int nNewSize = vecNew.size();
1521
0
            if ( nNewSize > 10 )
1522
0
            {
1523
0
                CommitChange(AccessibleEventId::SELECTION_CHANGED_WITHIN, uno::Any(), uno::Any());
1524
0
            }
1525
0
            else
1526
0
            {
1527
0
                for(const auto& rAddr : vecNew)
1528
0
                {
1529
0
                    rtl::Reference< ScAccessibleCell > xChild;
1530
0
                    if (rAddr == aFormulaAddr)
1531
0
                    {
1532
0
                        xChild = m_pAccFormulaCell;
1533
0
                    }
1534
0
                    else
1535
0
                    {
1536
0
                        xChild = GetAccessibleCellAt(rAddr.Row(),rAddr.Col());
1537
0
                        CommitChange(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS,
1538
0
                                     uno::Any(xOldFormulaCell),
1539
0
                                     uno::Any(uno::Reference<XAccessible>(xChild)));
1540
0
                    }
1541
0
                    CommitChange(AccessibleEventId::SELECTION_CHANGED_ADD, uno::Any(),
1542
0
                                 uno::Any(uno::Reference<XAccessible>(xChild)));
1543
0
                    m_mapFormulaSelectionSend.emplace(rAddr,xChild);
1544
0
                }
1545
0
            }
1546
0
            m_vecFormulaLastMyAddr.swap(vecCurSel);
1547
0
        }
1548
0
    }
1549
0
    m_aFormulaActiveCell = aFormulaAddr;
1550
0
}
1551
1552
void ScAccessibleSpreadsheet::RemoveFormulaSelection(bool bRemoveAll )
1553
0
{
1554
0
    auto miRemove = m_mapFormulaSelectionSend.begin();
1555
0
    while (miRemove != m_mapFormulaSelectionSend.end())
1556
0
    {
1557
0
        if( !bRemoveAll && IsScAddrFormulaSel(miRemove->first) )
1558
0
        {
1559
0
            ++miRemove;
1560
0
            continue;
1561
0
        }
1562
0
        CommitChange(AccessibleEventId::SELECTION_CHANGED_REMOVE, uno::Any(),
1563
0
                     uno::Any(uno::Reference<XAccessible>(miRemove->second)));
1564
0
        miRemove = m_mapFormulaSelectionSend.erase(miRemove);
1565
0
    }
1566
0
}
1567
1568
bool ScAccessibleSpreadsheet::IsScAddrFormulaSel(const ScAddress &addr) const
1569
0
{
1570
0
    return addr.Col() >= m_nMinX && addr.Col() <= m_nMaxX &&
1571
0
        addr.Row() >= m_nMinY && addr.Row() <= m_nMaxY &&
1572
0
        addr.Tab() == mpViewShell->GetViewData().CurrentTabForData();
1573
0
}
1574
1575
bool ScAccessibleSpreadsheet::CheckChildIndex(sal_Int64 nIndex) const
1576
0
{
1577
0
    sal_Int64 nMaxIndex = static_cast<sal_Int64>(m_nMaxX - m_nMinX +1) * static_cast<sal_Int64>(m_nMaxY - m_nMinY +1) -1 ;
1578
0
    return nIndex <= nMaxIndex && nIndex >= 0 ;
1579
0
}
1580
1581
ScAddress ScAccessibleSpreadsheet::GetChildIndexAddress(sal_Int64 nIndex) const
1582
0
{
1583
0
    sal_Int64 nRowAll = GetRowAll();
1584
0
    sal_Int64 nColAll = GetColAll();
1585
0
    if (nIndex < 0 || nIndex >= nRowAll * nColAll)
1586
0
    {
1587
0
        return ScAddress();
1588
0
    }
1589
0
    return ScAddress(
1590
0
        static_cast<SCCOL>((nIndex - nIndex % nRowAll) / nRowAll +  + m_nMinX),
1591
0
        nIndex % nRowAll + m_nMinY,
1592
0
        mpViewShell->GetViewData().CurrentTabForData()
1593
0
        );
1594
0
}
1595
1596
sal_Int64 ScAccessibleSpreadsheet::GetAccessibleIndexFormula( sal_Int32 nRow, sal_Int32 nColumn )
1597
0
{
1598
0
    sal_uInt16 nColRelative = sal_uInt16(nColumn) - GetColAll();
1599
0
    sal_Int32 nRowRelative = nRow - GetRowAll();
1600
0
    if (nRow < 0 || nColumn < 0  || nRowRelative >= GetRowAll() || nColRelative >= GetColAll() )
1601
0
    {
1602
0
        return -1;
1603
0
    }
1604
0
    return static_cast<sal_Int64>(GetRowAll()) * static_cast<sal_Int64>(nRowRelative) + nColRelative;
1605
0
}
1606
1607
bool ScAccessibleSpreadsheet::IsFormulaMode()
1608
0
{
1609
0
    ScViewData& rViewData = mpViewShell->GetViewData();
1610
0
    m_bFormulaMode = rViewData.IsRefMode() || ScModule::get()->IsFormulaMode();
1611
0
    return m_bFormulaMode ;
1612
0
}
1613
1614
bool ScAccessibleSpreadsheet::GetFormulaCurrentFocusCell(ScAddress &addr)
1615
0
{
1616
0
    ScViewData& rViewData = mpViewShell->GetViewData();
1617
0
    sal_uInt16 nRefX=0;
1618
0
    sal_Int32 nRefY=0;
1619
0
    if(m_bFormulaLastMode)
1620
0
    {
1621
0
        nRefX=rViewData.GetRefEndX();
1622
0
        nRefY=rViewData.GetRefEndY();
1623
0
    }
1624
0
    else
1625
0
    {
1626
0
        nRefX=rViewData.GetRefStartX();
1627
0
        nRefY=rViewData.GetRefStartY();
1628
0
    }
1629
0
    ScDocument* pDoc = GetDocument(mpViewShell);
1630
0
    if( /* Always true: nRefX >= 0 && */ nRefX <= pDoc->MaxCol() && nRefY >= 0 && nRefY <= pDoc->MaxRow())
1631
0
    {
1632
0
        addr = ScAddress(nRefX, nRefY, rViewData.CurrentTabForData());
1633
0
        return true;
1634
0
    }
1635
0
    return false;
1636
0
}
1637
1638
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */