Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/source/ui/Accessibility/AccessibleCellBase.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 <AccessibleCellBase.hxx>
21
#include <document.hxx>
22
#include <docfunc.hxx>
23
#include <docsh.hxx>
24
#include <strings.hxx>
25
#include <unonames.hxx>
26
#include <detfunc.hxx>
27
28
#include <com/sun/star/accessibility/AccessibleRole.hpp>
29
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
30
#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
31
#include <com/sun/star/sheet/XSpreadsheet.hpp>
32
#include <com/sun/star/sheet/XSheetAnnotationAnchor.hpp>
33
#include <com/sun/star/text/XSimpleText.hpp>
34
#include <com/sun/star/table/BorderLine.hpp>
35
#include <com/sun/star/table/ShadowFormat.hpp>
36
#include <comphelper/sequence.hxx>
37
#include <sfx2/objsh.hxx>
38
#include <vcl/svapp.hxx>
39
40
#include <float.h>
41
42
using namespace ::com::sun::star;
43
using namespace ::com::sun::star::accessibility;
44
45
0
#define DEFAULT_LINE_WIDTH 2
46
47
ScAccessibleCellBase::ScAccessibleCellBase(const uno::Reference<XAccessible>& rxParent,
48
                                           ScDocument* pDoc, const ScAddress& rCellAddress,
49
                                           sal_Int64 nIndex)
50
0
    : ImplInheritanceHelper(rxParent, AccessibleRole::TABLE_CELL)
51
0
    , maCellAddress(rCellAddress)
52
0
    , mpDoc(pDoc)
53
0
    , mnIndex(nIndex)
54
0
{
55
0
}
56
57
ScAccessibleCellBase::~ScAccessibleCellBase()
58
0
{
59
0
}
60
61
    //=====  XAccessibleComponent  ============================================
62
63
bool ScAccessibleCellBase::isVisible()
64
0
{
65
0
    SolarMutexGuard aGuard;
66
0
    ensureAlive();
67
    // test whether the cell is hidden (column/row - hidden/filtered)
68
0
    bool bVisible(true);
69
0
    if (mpDoc)
70
0
    {
71
0
        bool bColHidden = mpDoc->ColHidden(maCellAddress.Col(), maCellAddress.Tab());
72
0
        bool bRowHidden = mpDoc->RowHidden(maCellAddress.Row(), maCellAddress.Tab());
73
0
        bool bColFiltered = mpDoc->ColFiltered(maCellAddress.Col(), maCellAddress.Tab());
74
0
        bool bRowFiltered = mpDoc->RowFiltered(maCellAddress.Row(), maCellAddress.Tab());
75
76
0
        if (bColHidden || bColFiltered || bRowHidden || bRowFiltered)
77
0
            bVisible = false;
78
0
    }
79
0
    return bVisible;
80
0
}
81
82
sal_Int32 SAL_CALL ScAccessibleCellBase::getForeground()
83
0
{
84
0
    SolarMutexGuard aGuard;
85
0
    ensureAlive();
86
0
    sal_Int32 nColor(0);
87
0
    if (mpDoc)
88
0
    {
89
0
        ScDocShell* pObjSh = mpDoc->GetDocumentShell();
90
0
        if ( pObjSh )
91
0
        {
92
0
            ScModelObj* pSpreadDoc = pObjSh->GetModel();
93
0
            if ( pSpreadDoc )
94
0
            {
95
0
                uno::Reference<sheet::XSpreadsheets> xSheets = pSpreadDoc->getSheets();
96
0
                uno::Reference<container::XIndexAccess> xIndex( xSheets, uno::UNO_QUERY );
97
0
                if ( xIndex.is() )
98
0
                {
99
0
                    uno::Any aTable = xIndex->getByIndex(maCellAddress.Tab());
100
0
                    uno::Reference<sheet::XSpreadsheet> xTable;
101
0
                    if (aTable>>=xTable)
102
0
                    {
103
0
                        uno::Reference<table::XCell> xCell = xTable->getCellByPosition(maCellAddress.Col(), maCellAddress.Row());
104
0
                        if (xCell.is())
105
0
                        {
106
0
                            uno::Reference<beans::XPropertySet> xCellProps(xCell, uno::UNO_QUERY);
107
0
                            if (xCellProps.is())
108
0
                            {
109
0
                                uno::Any aAny = xCellProps->getPropertyValue(SC_UNONAME_CCOLOR);
110
0
                                aAny >>= nColor;
111
0
                            }
112
0
                        }
113
0
                    }
114
0
                }
115
0
            }
116
0
        }
117
0
    }
118
0
    return nColor;
119
0
}
120
121
sal_Int32 SAL_CALL ScAccessibleCellBase::getBackground()
122
0
{
123
0
    SolarMutexGuard aGuard;
124
0
    ensureAlive();
125
0
    sal_Int32 nColor(0);
126
127
0
    if (mpDoc)
128
0
    {
129
0
        ScDocShell* pObjSh = mpDoc->GetDocumentShell();
130
0
        if ( pObjSh )
131
0
        {
132
0
            ScModelObj* pSpreadDoc = pObjSh->GetModel();
133
0
            if ( pSpreadDoc )
134
0
            {
135
0
                uno::Reference<sheet::XSpreadsheets> xSheets = pSpreadDoc->getSheets();
136
0
                uno::Reference<container::XIndexAccess> xIndex( xSheets, uno::UNO_QUERY );
137
0
                if ( xIndex.is() )
138
0
                {
139
0
                    uno::Any aTable = xIndex->getByIndex(maCellAddress.Tab());
140
0
                    uno::Reference<sheet::XSpreadsheet> xTable;
141
0
                    if (aTable>>=xTable)
142
0
                    {
143
0
                        uno::Reference<table::XCell> xCell = xTable->getCellByPosition(maCellAddress.Col(), maCellAddress.Row());
144
0
                        if (xCell.is())
145
0
                        {
146
0
                            uno::Reference<beans::XPropertySet> xCellProps(xCell, uno::UNO_QUERY);
147
0
                            if (xCellProps.is())
148
0
                            {
149
0
                                uno::Any aAny = xCellProps->getPropertyValue(SC_UNONAME_CELLBACK);
150
0
                                aAny >>= nColor;
151
0
                            }
152
0
                        }
153
0
                    }
154
0
                }
155
0
            }
156
0
        }
157
0
    }
158
159
0
    return nColor;
160
0
}
161
162
    //=====  XAccessibleContext  ==============================================
163
164
sal_Int64
165
    ScAccessibleCellBase::getAccessibleIndexInParent()
166
0
{
167
0
    SolarMutexGuard aGuard;
168
0
    ensureAlive();
169
0
    return mnIndex;
170
0
}
171
172
OUString
173
    ScAccessibleCellBase::createAccessibleDescription()
174
0
{
175
0
    return STR_ACC_CELL_DESCR;
176
0
}
177
178
OUString
179
    ScAccessibleCellBase::createAccessibleName()
180
0
{
181
    // Document not needed, because only the cell address, but not the tablename is needed
182
    // always us OOO notation
183
0
    return maCellAddress.Format(ScRefFlags::VALID);
184
0
}
185
186
    //=====  XAccessibleValue  ================================================
187
188
uno::Any SAL_CALL
189
    ScAccessibleCellBase::getCurrentValue()
190
0
{
191
0
    SolarMutexGuard aGuard;
192
0
    ensureAlive();
193
0
    uno::Any aAny;
194
0
    if (mpDoc)
195
0
    {
196
0
        aAny <<= mpDoc->GetValue(maCellAddress);
197
0
    }
198
0
    return aAny;
199
0
}
200
201
sal_Bool SAL_CALL
202
    ScAccessibleCellBase::setCurrentValue( const uno::Any& aNumber )
203
0
{
204
0
    SolarMutexGuard aGuard;
205
0
    ensureAlive();
206
0
    double fValue = 0;
207
0
    bool bResult = false;
208
0
    if((aNumber >>= fValue) && mpDoc && mpDoc->GetDocumentShell())
209
0
    {
210
0
        sal_Int64 nParentStates = 0;
211
0
        if (getAccessibleParent().is())
212
0
        {
213
0
            uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
214
0
            nParentStates = xParentContext->getAccessibleStateSet();
215
0
        }
216
0
        if (IsEditable(nParentStates))
217
0
        {
218
0
            ScDocShell* pDocShell = mpDoc->GetDocumentShell();
219
0
            bResult = pDocShell->GetDocFunc().SetValueCell(maCellAddress, fValue, false);
220
0
        }
221
0
    }
222
0
    return bResult;
223
0
}
224
225
uno::Any SAL_CALL
226
    ScAccessibleCellBase::getMaximumValue(  )
227
0
{
228
0
    return uno::Any(DBL_MAX);
229
0
}
230
231
uno::Any SAL_CALL
232
    ScAccessibleCellBase::getMinimumValue(  )
233
0
{
234
0
    return uno::Any(-DBL_MAX);
235
0
}
236
237
uno::Any SAL_CALL
238
    ScAccessibleCellBase::getMinimumIncrement(  )
239
0
{
240
0
    return uno::Any();
241
0
}
242
243
bool ScAccessibleCellBase::IsEditable(sal_Int64 nParentStates)
244
0
{
245
0
    bool bEditable = nParentStates & AccessibleStateType::EDITABLE;
246
0
    return bEditable;
247
0
}
248
249
OUString ScAccessibleCellBase::GetNote() const
250
0
{
251
0
    SolarMutexGuard aGuard;
252
0
    ensureAlive();
253
0
    OUString sNote;
254
0
    if (mpDoc)
255
0
    {
256
0
        ScDocShell* pObjSh = mpDoc->GetDocumentShell();
257
0
        if ( pObjSh )
258
0
        {
259
0
            ScModelObj* pSpreadDoc = pObjSh->GetModel();
260
0
            if ( pSpreadDoc )
261
0
            {
262
0
                uno::Reference<sheet::XSpreadsheets> xSheets = pSpreadDoc->getSheets();
263
0
                uno::Reference<container::XIndexAccess> xIndex( xSheets, uno::UNO_QUERY );
264
0
                if ( xIndex.is() )
265
0
                {
266
0
                    uno::Any aTable = xIndex->getByIndex(maCellAddress.Tab());
267
0
                    uno::Reference<sheet::XSpreadsheet> xTable;
268
0
                    if (aTable>>=xTable)
269
0
                    {
270
0
                        uno::Reference<table::XCell> xCell = xTable->getCellByPosition(maCellAddress.Col(), maCellAddress.Row());
271
0
                        if (xCell.is())
272
0
                        {
273
0
                            uno::Reference <sheet::XSheetAnnotationAnchor> xAnnotationAnchor ( xCell, uno::UNO_QUERY);
274
0
                            if(xAnnotationAnchor.is())
275
0
                            {
276
0
                                uno::Reference <sheet::XSheetAnnotation> xSheetAnnotation = xAnnotationAnchor->getAnnotation();
277
0
                                if (xSheetAnnotation.is())
278
0
                                {
279
0
                                    uno::Reference <text::XSimpleText> xText (xSheetAnnotation, uno::UNO_QUERY);
280
0
                                    if (xText.is())
281
0
                                    {
282
0
                                        sNote = xText->getString();
283
0
                                    }
284
0
                                }
285
0
                            }
286
0
                        }
287
0
                    }
288
0
                }
289
0
            }
290
0
        }
291
0
    }
292
0
    return sNote;
293
0
}
294
295
std::unordered_map<OUString, OUString> ScAccessibleCellBase::getShadowAttrs() const
296
0
{
297
0
    table::ShadowFormat aShadowFmt;
298
0
    if (mpDoc)
299
0
    {
300
0
        ScDocShell* pObjSh = mpDoc->GetDocumentShell();
301
0
        if ( pObjSh )
302
0
        {
303
0
            ScModelObj* pSpreadDoc = pObjSh->GetModel();
304
0
            if ( pSpreadDoc )
305
0
            {
306
0
                uno::Reference<sheet::XSpreadsheets> xSheets = pSpreadDoc->getSheets();
307
0
                uno::Reference<container::XIndexAccess> xIndex( xSheets, uno::UNO_QUERY );
308
0
                if ( xIndex.is() )
309
0
                {
310
0
                    uno::Any aTable = xIndex->getByIndex(maCellAddress.Tab());
311
0
                    uno::Reference<sheet::XSpreadsheet> xTable;
312
0
                    if (aTable>>=xTable)
313
0
                    {
314
0
                        uno::Reference<table::XCell> xCell = xTable->getCellByPosition(maCellAddress.Col(), maCellAddress.Row());
315
0
                        if (xCell.is())
316
0
                        {
317
0
                            uno::Reference<beans::XPropertySet> xCellProps(xCell, uno::UNO_QUERY);
318
0
                            if (xCellProps.is())
319
0
                            {
320
0
                                uno::Any aAny = xCellProps->getPropertyValue(SC_UNONAME_SHADOW);
321
0
                                aAny >>= aShadowFmt;
322
0
                            }
323
0
                        }
324
0
                    }
325
0
                }
326
0
            }
327
0
        }
328
0
    }
329
0
    const OUString sShadowAttrName(u"Shadow"_ustr);
330
0
    OUString sInnerSplit(u","_ustr);
331
0
    sal_Int32 nLocationVal = 0;
332
0
    switch( aShadowFmt.Location )
333
0
    {
334
0
    case table::ShadowLocation_TOP_LEFT:
335
0
        nLocationVal = 1;
336
0
        break;
337
0
    case table::ShadowLocation_TOP_RIGHT:
338
0
        nLocationVal = 2;
339
0
        break;
340
0
    case table::ShadowLocation_BOTTOM_LEFT:
341
0
        nLocationVal = 3;
342
0
        break;
343
0
    case table::ShadowLocation_BOTTOM_RIGHT:
344
0
        nLocationVal = 4;
345
0
        break;
346
0
    default:
347
0
        break;
348
0
    }
349
    //if there is no shadow property for the cell
350
0
    if ( nLocationVal == 0 )
351
0
    {
352
0
        return { { sShadowAttrName, u""_ustr } };
353
0
    }
354
    //else return all the shadow properties
355
0
    const OUString sAttrValue
356
0
        = "Location=" + OUString::number(nLocationVal) + sInnerSplit + "ShadowWidth="
357
0
          + OUString::number(static_cast<sal_Int32>(aShadowFmt.ShadowWidth)) + sInnerSplit
358
0
          + "IsTransparent=" + OUString::number(static_cast<int>(aShadowFmt.IsTransparent))
359
0
          + sInnerSplit + "Color=" + OUString::number(aShadowFmt.Color);
360
0
    return { { sShadowAttrName, sAttrValue } };
361
0
}
362
363
std::unordered_map<OUString, OUString> ScAccessibleCellBase::getBorderAttrs()
364
0
{
365
0
    table::BorderLine aTopBorder;
366
0
    table::BorderLine aBottomBorder;
367
0
    table::BorderLine aLeftBorder;
368
0
    table::BorderLine aRightBorder;
369
0
    if (mpDoc)
370
0
    {
371
0
        ScDocShell* pObjSh = mpDoc->GetDocumentShell();
372
0
        if ( pObjSh )
373
0
        {
374
0
            ScModelObj* pSpreadDoc = pObjSh->GetModel();
375
0
            if ( pSpreadDoc )
376
0
            {
377
0
                uno::Reference<sheet::XSpreadsheets> xSheets = pSpreadDoc->getSheets();
378
0
                uno::Reference<container::XIndexAccess> xIndex( xSheets, uno::UNO_QUERY );
379
0
                if ( xIndex.is() )
380
0
                {
381
0
                    uno::Any aTable = xIndex->getByIndex(maCellAddress.Tab());
382
0
                    uno::Reference<sheet::XSpreadsheet> xTable;
383
0
                    if (aTable>>=xTable)
384
0
                    {
385
0
                        uno::Reference<table::XCell> xCell = xTable->getCellByPosition(maCellAddress.Col(), maCellAddress.Row());
386
0
                        if (xCell.is())
387
0
                        {
388
0
                            uno::Reference<beans::XPropertySet> xCellProps(xCell, uno::UNO_QUERY);
389
0
                            if (xCellProps.is())
390
0
                            {
391
0
                                uno::Any aAny = xCellProps->getPropertyValue(SC_UNONAME_TOPBORDER);
392
0
                                aAny >>= aTopBorder;
393
0
                                aAny = xCellProps->getPropertyValue(SC_UNONAME_BOTTBORDER);
394
0
                                aAny >>= aBottomBorder;
395
0
                                aAny = xCellProps->getPropertyValue(SC_UNONAME_LEFTBORDER);
396
0
                                aAny >>= aLeftBorder;
397
0
                                aAny = xCellProps->getPropertyValue(SC_UNONAME_RIGHTBORDER);
398
0
                                aAny >>= aRightBorder;
399
0
                            }
400
0
                        }
401
0
                    }
402
0
                }
403
0
            }
404
0
        }
405
0
    }
406
407
0
    Color aColor;
408
0
    bool bIn = mpDoc && mpDoc->IsCellInChangeTrack(maCellAddress,&aColor);
409
0
    if (bIn)
410
0
    {
411
0
        aTopBorder.Color = sal_Int32(aColor);
412
0
        aBottomBorder.Color = sal_Int32(aColor);
413
0
        aLeftBorder.Color = sal_Int32(aColor);
414
0
        aRightBorder.Color = sal_Int32(aColor);
415
0
        aTopBorder.OuterLineWidth = DEFAULT_LINE_WIDTH;
416
0
        aBottomBorder.OuterLineWidth = DEFAULT_LINE_WIDTH;
417
0
        aLeftBorder.OuterLineWidth = DEFAULT_LINE_WIDTH;
418
0
        aRightBorder.OuterLineWidth = DEFAULT_LINE_WIDTH;
419
0
    }
420
421
0
    std::unordered_map<OUString, OUString> aBorderAttrs;
422
0
    OUString sInnerSplit(u","_ustr);
423
    //top border
424
    //if top of the cell has no border
425
0
    if ( aTopBorder.InnerLineWidth == 0 && aTopBorder.OuterLineWidth == 0 )
426
0
    {
427
0
        aBorderAttrs.emplace(u"TopBorder"_ustr, u""_ustr);
428
0
    }
429
0
    else//add all the border properties to the return string.
430
0
    {
431
0
        aBorderAttrs.emplace(
432
0
            u"TopBorder"_ustr,
433
0
            u"Color=" + OUString::number(aTopBorder.Color) + sInnerSplit + "InnerLineWidth="
434
0
                + OUString::number(static_cast<sal_Int32>(aTopBorder.InnerLineWidth)) + sInnerSplit
435
0
                + "OuterLineWidth="
436
0
                + OUString::number(static_cast<sal_Int32>(aTopBorder.OuterLineWidth)) + sInnerSplit
437
0
                + "LineDistance="
438
0
                + OUString::number(static_cast<sal_Int32>(aTopBorder.LineDistance)));
439
0
    }
440
    //bottom border
441
0
    if ( aBottomBorder.InnerLineWidth == 0 && aBottomBorder.OuterLineWidth == 0 )
442
0
    {
443
0
        aBorderAttrs.emplace(u"BottomBorder"_ustr, u""_ustr);
444
0
    }
445
0
    else
446
0
    {
447
0
        aBorderAttrs.emplace(
448
0
            u"BottomBorder"_ustr,
449
0
            u"Color" + OUString::number(aBottomBorder.Color) + sInnerSplit + "InnerLineWidth="
450
0
                + OUString::number(static_cast<sal_Int32>(aBottomBorder.InnerLineWidth))
451
0
                + sInnerSplit + "OuterLineWidth="
452
0
                + OUString::number(static_cast<sal_Int32>(aBottomBorder.OuterLineWidth))
453
0
                + sInnerSplit + "LineDistance="
454
0
                + OUString::number(static_cast<sal_Int32>(aBottomBorder.LineDistance)));
455
0
    }
456
    //left border
457
0
    if ( aLeftBorder.InnerLineWidth == 0 && aLeftBorder.OuterLineWidth == 0 )
458
0
    {
459
0
        aBorderAttrs.emplace(u"LeftBorder"_ustr, u""_ustr);
460
0
    }
461
0
    else
462
0
    {
463
0
        aBorderAttrs.emplace(
464
0
            u"LeftBorder"_ustr,
465
0
            u"Color=" + OUString::number(aLeftBorder.Color) + sInnerSplit + "InnerLineWidth="
466
0
                + OUString::number(static_cast<sal_Int32>(aLeftBorder.InnerLineWidth)) + sInnerSplit
467
0
                + "OuterLineWidth="
468
0
                + OUString::number(static_cast<sal_Int32>(aLeftBorder.OuterLineWidth)) + sInnerSplit
469
0
                + "LineDistance="
470
0
                + OUString::number(static_cast<sal_Int32>(aLeftBorder.LineDistance)));
471
0
    }
472
    //right border
473
0
    if ( aRightBorder.InnerLineWidth == 0 && aRightBorder.OuterLineWidth == 0 )
474
0
    {
475
0
        aBorderAttrs.emplace(u"RightBorder"_ustr, u""_ustr);
476
0
    }
477
0
    else
478
0
    {
479
0
        aBorderAttrs.emplace(
480
0
            u"RightBorder"_ustr,
481
0
            u"Color=" + OUString::number(aRightBorder.Color) + sInnerSplit + "InnerLineWidth="
482
0
                + OUString::number(static_cast<sal_Int32>(aRightBorder.InnerLineWidth))
483
0
                + sInnerSplit + "OuterLineWidth="
484
0
                + OUString::number(static_cast<sal_Int32>(aRightBorder.OuterLineWidth))
485
0
                + sInnerSplit + "LineDistance="
486
0
                + OUString::number(static_cast<sal_Int32>(aRightBorder.LineDistance)));
487
0
    }
488
0
    return aBorderAttrs;
489
0
}
490
//end of cell attributes
491
492
OUString ScAccessibleCellBase::GetAllDisplayNote() const
493
0
{
494
0
    OUString strNote;
495
0
    OUString strTrackText;
496
0
    if (mpDoc)
497
0
    {
498
0
        bool bLeftedge = false;
499
0
        mpDoc->GetCellChangeTrackNote(maCellAddress,strTrackText,bLeftedge);
500
0
    }
501
0
    if (!strTrackText.isEmpty())
502
0
    {
503
0
        ScDetectiveFunc::AppendChangTrackNoteSeparator(strTrackText);
504
0
        strNote = strTrackText;
505
0
    }
506
0
    strNote += GetNote();
507
0
    return strNote;
508
0
}
509
510
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */