Coverage Report

Created: 2026-11-06 11:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/source/ui/Accessibility/AccessibleCell.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 <memory>
21
#include <string_view>
22
23
#include <sal/config.h>
24
25
#include <AccessibleCell.hxx>
26
#include <scitems.hxx>
27
#include <AccessibleText.hxx>
28
#include <AccessibleDocument.hxx>
29
#include <tabvwsh.hxx>
30
#include <comphelper/sequence.hxx>
31
#include <document.hxx>
32
#include <attrib.hxx>
33
#include <editsrc.hxx>
34
#include <dociter.hxx>
35
#include <markdata.hxx>
36
#include <cellvalue.hxx>
37
#include <formulaiter.hxx>
38
#include <validat.hxx>
39
40
#include <unotools/accessiblerelationsethelper.hxx>
41
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
42
#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
43
#include <com/sun/star/accessibility/XAccessibleTable.hpp>
44
#include <editeng/brushitem.hxx>
45
#include <vcl/accessibility/AccessibleAttribute.hxx>
46
#include <vcl/svapp.hxx>
47
48
#include <AccessibleSpreadsheet.hxx>
49
50
using namespace ::com::sun::star;
51
using namespace ::com::sun::star::accessibility;
52
53
rtl::Reference<ScAccessibleCell>
54
ScAccessibleCell::create(const rtl::Reference<comphelper::OAccessible>& rpParent,
55
                         ScTabViewShell* pViewShell, const ScAddress& rCellAddress,
56
                         sal_Int64 nIndex, ScSplitPos eSplitPos, ScAccessibleDocument* pAccDoc)
57
0
{
58
0
    rtl::Reference<ScAccessibleCell> x(
59
0
        new ScAccessibleCell(rpParent, pViewShell, rCellAddress, nIndex, eSplitPos, pAccDoc));
60
0
    x->Init();
61
0
    return x;
62
0
}
63
64
ScAccessibleCell::ScAccessibleCell(const rtl::Reference<comphelper::OAccessible>& rpParent,
65
                                   ScTabViewShell* pViewShell, const ScAddress& rCellAddress,
66
                                   sal_Int64 nIndex, ScSplitPos eSplitPos,
67
                                   ScAccessibleDocument* pAccDoc)
68
    :
69
0
    ScAccessibleCellBase(rpParent, GetDocument(pViewShell), rCellAddress, nIndex),
70
0
        ::accessibility::AccessibleStaticTextBase(CreateEditSource(pViewShell, rCellAddress, eSplitPos)),
71
0
    mpViewShell(pViewShell),
72
0
    mpAccDoc(pAccDoc),
73
0
    meSplitPos(eSplitPos)
74
0
{
75
0
    if (pViewShell)
76
0
        pViewShell->AddAccessibilityObject(*this);
77
0
}
78
79
ScAccessibleCell::~ScAccessibleCell()
80
0
{
81
0
    if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose)
82
0
    {
83
        // increment refcount to prevent double call of dtor
84
0
        osl_atomic_increment( &m_refCount );
85
        // call dispose to inform object which have a weak reference to this object
86
0
        dispose();
87
0
    }
88
0
}
89
90
void SAL_CALL ScAccessibleCell::disposing()
91
0
{
92
0
    SolarMutexGuard aGuard;
93
    // dispose in AccessibleStaticTextBase
94
0
    Dispose();
95
96
0
    if (mpViewShell)
97
0
    {
98
0
        mpViewShell->RemoveAccessibilityObject(*this);
99
0
        mpViewShell = nullptr;
100
0
    }
101
0
    mpAccDoc = nullptr;
102
103
0
    ScAccessibleCellBase::disposing();
104
0
}
105
106
    //=====  XInterface  =====================================================
107
108
IMPLEMENT_FORWARD_XINTERFACE2(ScAccessibleCell, ScAccessibleCellBase, AccessibleStaticTextBase)
109
110
    //=====  XTypeProvider  ===================================================
111
112
css::uno::Sequence< css::uno::Type > SAL_CALL ScAccessibleCell::getTypes()
113
0
{
114
0
    return ::comphelper::concatSequences(ScAccessibleCellBase::getTypes(),
115
0
                                         AccessibleStaticTextBase::getTypes());
116
0
}
117
IMPLEMENT_GET_IMPLEMENTATION_ID( ScAccessibleCell )
118
119
    //=====  XAccessibleComponent  ============================================
120
121
uno::Reference< XAccessible > SAL_CALL ScAccessibleCell::getAccessibleAtPoint(
122
        const awt::Point& rPoint )
123
0
{
124
0
    return AccessibleStaticTextBase::getAccessibleAtPoint(rPoint);
125
0
}
126
127
void SAL_CALL ScAccessibleCell::grabFocus(  )
128
0
{
129
0
    SolarMutexGuard aGuard;
130
0
    ensureAlive();
131
0
    if (getAccessibleParent().is() && mpViewShell)
132
0
    {
133
0
        uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY);
134
0
        if (xAccessibleComponent.is())
135
0
        {
136
0
            xAccessibleComponent->grabFocus();
137
0
            mpViewShell->SetCursor(maCellAddress.Col(), maCellAddress.Row());
138
0
        }
139
0
    }
140
0
}
141
142
AbsoluteScreenPixelRectangle ScAccessibleCell::GetBoundingBoxOnScreen()
143
0
{
144
0
    AbsoluteScreenPixelRectangle aCellRect(GetBoundingBox());
145
0
    if (mpViewShell)
146
0
    {
147
0
        vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
148
0
        if (pWindow)
149
0
        {
150
0
            AbsoluteScreenPixelRectangle aRect = pWindow->GetWindowExtentsAbsolute();
151
0
            aCellRect.Move(aRect.Left(), aRect.Top());
152
0
        }
153
0
    }
154
0
    return aCellRect;
155
0
}
156
157
tools::Rectangle ScAccessibleCell::GetBoundingBox()
158
0
{
159
0
    tools::Rectangle aCellRect;
160
0
    if (mpViewShell)
161
0
    {
162
0
        tools::Long nSizeX, nSizeY;
163
0
        mpViewShell->GetViewData().GetMergeSizePixel(
164
0
            maCellAddress.Col(), maCellAddress.Row(), nSizeX, nSizeY);
165
0
        aCellRect.SetSize(Size(nSizeX, nSizeY));
166
0
        aCellRect.SetPos(mpViewShell->GetViewData().GetScrPos(maCellAddress.Col(), maCellAddress.Row(), meSplitPos, true));
167
168
0
        vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
169
0
        if (pWindow)
170
0
        {
171
0
            tools::Rectangle aRect(pWindow->GetWindowExtentsRelative(*pWindow->GetAccessibleParentWindow()));
172
0
            aRect.Move(-aRect.Left(), -aRect.Top());
173
0
            aCellRect = aRect.Intersection(aCellRect);
174
0
        }
175
176
        /*  #i19430# Gnopernicus reads text partly if it sticks out of the cell
177
            boundaries. This leads to wrong results in cases where the cell
178
            text is rotated, because rotation is not taken into account when
179
            calculating the visible part of the text. In these cases we will
180
            simply expand the cell size to the width of the unrotated text. */
181
0
        if (mpDoc)
182
0
        {
183
0
            const ScRotateValueItem& rItem = mpDoc->GetAttr( maCellAddress, ATTR_ROTATE_VALUE );
184
0
            if (rItem.GetValue() != 0_deg100)
185
0
            {
186
0
                tools::Rectangle aParaRect = GetParagraphBoundingBox();
187
0
                if( !aParaRect.IsEmpty() && (aCellRect.GetWidth() < aParaRect.GetWidth()) )
188
0
                    aCellRect.SetSize( Size( aParaRect.GetWidth(), aCellRect.GetHeight() ) );
189
0
            }
190
0
        }
191
0
    }
192
0
    if (aCellRect.IsEmpty())
193
0
        aCellRect.SetPos(Point(-1, -1));
194
0
    return aCellRect;
195
0
}
196
197
    //=====  XAccessibleContext  ==============================================
198
199
sal_Int64 SAL_CALL
200
    ScAccessibleCell::getAccessibleChildCount()
201
0
{
202
0
    return AccessibleStaticTextBase::getAccessibleChildCount();
203
0
}
204
205
uno::Reference< XAccessible > SAL_CALL
206
    ScAccessibleCell::getAccessibleChild(sal_Int64 nIndex)
207
0
{
208
0
    return AccessibleStaticTextBase::getAccessibleChild(nIndex);
209
0
}
210
211
sal_Int64 SAL_CALL
212
    ScAccessibleCell::getAccessibleStateSet()
213
0
{
214
0
    SolarMutexGuard aGuard;
215
0
    sal_Int64 nParentStates = 0;
216
0
    if (getAccessibleParent().is())
217
0
    {
218
0
        uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
219
0
        nParentStates = xParentContext->getAccessibleStateSet();
220
0
    }
221
0
    sal_Int64 nStateSet = 0;
222
0
    if (IsDefunc(nParentStates))
223
0
        nStateSet |= AccessibleStateType::DEFUNC;
224
0
    else
225
0
    {
226
0
        if (IsFocused())
227
0
            nStateSet |= AccessibleStateType::FOCUSED;
228
229
0
        if (IsFormulaMode())
230
0
        {
231
0
            nStateSet |= AccessibleStateType::ENABLED;
232
0
            nStateSet |= AccessibleStateType::MULTI_LINE;
233
0
            nStateSet |= AccessibleStateType::MULTI_SELECTABLE;
234
0
            if (IsOpaque())
235
0
                nStateSet |= AccessibleStateType::OPAQUE;
236
0
            nStateSet |= AccessibleStateType::SELECTABLE;
237
0
            if (IsSelected())
238
0
                nStateSet |= AccessibleStateType::SELECTED;
239
0
            if (isShowing())
240
0
                nStateSet |= AccessibleStateType::SHOWING;
241
0
            nStateSet |= AccessibleStateType::TRANSIENT;
242
0
            if (isVisible())
243
0
                nStateSet |= AccessibleStateType::VISIBLE;
244
0
            return nStateSet;
245
0
        }
246
0
        if (IsEditable(nParentStates))
247
0
        {
248
0
            nStateSet |= AccessibleStateType::EDITABLE;
249
0
            nStateSet |= AccessibleStateType::RESIZABLE;
250
0
        }
251
0
        nStateSet |= AccessibleStateType::ENABLED;
252
0
        nStateSet |= AccessibleStateType::MULTI_LINE;
253
0
        nStateSet |= AccessibleStateType::MULTI_SELECTABLE;
254
0
        nStateSet |= AccessibleStateType::FOCUSABLE;
255
0
        if (IsOpaque())
256
0
            nStateSet |= AccessibleStateType::OPAQUE;
257
0
        nStateSet |= AccessibleStateType::SELECTABLE;
258
0
        if (IsSelected())
259
0
            nStateSet |= AccessibleStateType::SELECTED;
260
0
        if (isShowing())
261
0
            nStateSet |= AccessibleStateType::SHOWING;
262
0
        nStateSet |= AccessibleStateType::TRANSIENT;
263
0
        if (isVisible())
264
0
            nStateSet |= AccessibleStateType::VISIBLE;
265
0
    }
266
0
    return nStateSet;
267
0
}
268
269
uno::Reference<XAccessibleRelationSet> SAL_CALL
270
       ScAccessibleCell::getAccessibleRelationSet()
271
0
{
272
0
    SolarMutexGuard aGuard;
273
0
    ensureAlive();
274
0
    rtl::Reference<utl::AccessibleRelationSetHelper> pRelationSet;
275
0
    if (mpAccDoc)
276
0
        pRelationSet = mpAccDoc->GetRelationSet(&maCellAddress);
277
0
    if (!pRelationSet)
278
0
        pRelationSet = new utl::AccessibleRelationSetHelper();
279
0
    FillDependents(pRelationSet.get());
280
0
    FillPrecedents(pRelationSet.get());
281
0
    return pRelationSet;
282
0
}
283
284
bool ScAccessibleCell::IsDefunc(sal_Int64 nParentStates)
285
0
{
286
0
    return ScAccessibleContextBase::IsDefunc() || (mpDoc == nullptr) || (mpViewShell == nullptr) || !getAccessibleParent().is() ||
287
0
         (nParentStates & AccessibleStateType::DEFUNC);
288
0
}
289
290
bool ScAccessibleCell::IsEditable(sal_Int64 nParentStates)
291
0
{
292
0
    bool bEditable(true);
293
0
    if ( !(nParentStates & AccessibleStateType::EDITABLE) &&
294
0
        mpDoc)
295
0
    {
296
        // here I have to test whether the protection of the table should influence this cell.
297
0
        const ScProtectionAttr& rItem = mpDoc->GetAttr(maCellAddress, ATTR_PROTECTION);
298
0
        bEditable = !rItem.GetProtection();
299
0
    }
300
0
    return bEditable;
301
0
}
302
303
bool ScAccessibleCell::IsOpaque() const
304
0
{
305
    // test whether there is a background color
306
0
    bool bOpaque(true);
307
0
    if (mpDoc)
308
0
    {
309
0
        const SvxBrushItem& rItem = mpDoc->GetAttr(maCellAddress, ATTR_BACKGROUND);
310
0
        bOpaque = rItem.GetColor() != COL_TRANSPARENT;
311
0
    }
312
0
    return bOpaque;
313
0
}
314
315
bool ScAccessibleCell::IsFocused() const
316
0
{
317
0
    if (mpViewShell && mpViewShell->GetViewData().GetCurPos() == maCellAddress)
318
0
        return mpViewShell->GetActiveWin()->HasFocus();
319
320
0
    return false;
321
0
}
322
323
bool ScAccessibleCell::IsSelected()
324
0
{
325
0
    if (IsFormulaMode())
326
0
    {
327
0
        const ScAccessibleSpreadsheet* pSheet
328
0
            = static_cast<const ScAccessibleSpreadsheet*>(mpParent.get());
329
0
        if (pSheet)
330
0
        {
331
0
            return pSheet->IsScAddrFormulaSel(maCellAddress);
332
0
        }
333
0
        return false;
334
0
    }
335
336
0
    bool bResult(false);
337
0
    if (mpViewShell)
338
0
    {
339
0
        const ScMarkData& rMarkdata = mpViewShell->GetViewData().GetMarkData();
340
0
        bResult = rMarkdata.IsCellMarked(maCellAddress.Col(), maCellAddress.Row());
341
0
    }
342
0
    return bResult;
343
0
}
344
345
ScDocument* ScAccessibleCell::GetDocument(ScTabViewShell* pViewShell)
346
0
{
347
0
    ScDocument* pDoc = nullptr;
348
0
    if (pViewShell)
349
0
        pDoc = &pViewShell->GetViewData().GetDocument();
350
0
    return pDoc;
351
0
}
352
353
::std::unique_ptr< SvxEditSource > ScAccessibleCell::CreateEditSource(ScTabViewShell* pViewShell, ScAddress aCell, ScSplitPos eSplitPos)
354
0
{
355
0
    if (IsFormulaMode())
356
0
    {
357
0
        return ::std::unique_ptr< SvxEditSource >();
358
0
    }
359
0
    ::std::unique_ptr< SvxEditSource > pEditSource (new ScAccessibilityEditSource(std::make_unique<ScAccessibleCellTextData>(pViewShell, aCell, eSplitPos, this)));
360
361
0
    return pEditSource;
362
0
}
363
364
void ScAccessibleCell::FillDependents(utl::AccessibleRelationSetHelper* pRelationSet)
365
0
{
366
0
    if (!mpDoc)
367
0
        return;
368
369
0
    ScRange aRange(0, 0, maCellAddress.Tab(), mpDoc->MaxCol(), mpDoc->MaxRow(), maCellAddress.Tab());
370
0
    ScCellIterator aCellIter(*mpDoc, aRange);
371
372
0
    for (bool bHasCell = aCellIter.first(); bHasCell; bHasCell = aCellIter.next())
373
0
    {
374
0
        if (aCellIter.getType() == CELLTYPE_FORMULA)
375
0
        {
376
0
            bool bFound = false;
377
0
            ScDetectiveRefIter aIter(*mpDoc, aCellIter.getFormulaCell());
378
0
            ScRange aRef;
379
0
            while ( !bFound && aIter.GetNextRef( aRef ) )
380
0
            {
381
0
                if (aRef.Contains(maCellAddress))
382
0
                    bFound = true;
383
0
            }
384
0
            if (bFound)
385
0
                AddRelation(aCellIter.GetPos(), AccessibleRelationType_CONTROLLER_FOR, pRelationSet);
386
0
        }
387
0
    }
388
0
}
389
390
void ScAccessibleCell::FillPrecedents(utl::AccessibleRelationSetHelper* pRelationSet)
391
0
{
392
0
    if (!mpDoc)
393
0
        return;
394
395
0
    ScRefCellValue aCell(*mpDoc, maCellAddress);
396
0
    if (aCell.getType() == CELLTYPE_FORMULA)
397
0
    {
398
0
        ScFormulaCell* pCell = aCell.getFormula();
399
0
        ScDetectiveRefIter aIter(*mpDoc, pCell);
400
0
        ScRange aRef;
401
0
        while ( aIter.GetNextRef( aRef ) )
402
0
        {
403
0
            AddRelation( aRef, AccessibleRelationType_CONTROLLED_BY, pRelationSet);
404
0
        }
405
0
    }
406
0
}
407
408
void ScAccessibleCell::AddRelation(const ScAddress& rCell,
409
    const AccessibleRelationType eRelationType,
410
    utl::AccessibleRelationSetHelper* pRelationSet)
411
0
{
412
0
    AddRelation(ScRange(rCell, rCell), eRelationType, pRelationSet);
413
0
}
414
415
void ScAccessibleCell::AddRelation(const ScRange& rRange,
416
    const AccessibleRelationType eRelationType,
417
    utl::AccessibleRelationSetHelper* pRelationSet)
418
0
{
419
0
    uno::Reference < XAccessibleTable > xTable ( getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY );
420
0
    if (!xTable.is())
421
0
        return;
422
423
0
    const sal_uInt32 nCount(static_cast<sal_uInt32>(rRange.aEnd.Col() -
424
0
                rRange.aStart.Col() + 1) * (rRange.aEnd.Row() -
425
0
                rRange.aStart.Row() + 1));
426
427
    // tdf#157299 avoid handling a large amount of cells for performance reasons
428
0
    if (nCount > 1000)
429
0
    {
430
0
        SAL_WARN("sc", "ScAccessibleCell::AddRelation: Not setting relations "
431
0
                       "for cell range with more than 1000 cells for performance reasons.");
432
0
        return;
433
0
    }
434
435
0
    uno::Sequence<uno::Reference<css::accessibility::XAccessible>> aTargetSet(nCount);
436
0
    uno::Reference <css::accessibility::XAccessible>* pTargetSet = aTargetSet.getArray();
437
0
    sal_uInt32 nPos(0);
438
0
    for (sal_uInt32 nRow = rRange.aStart.Row(); nRow <= sal::static_int_cast<sal_uInt32>(rRange.aEnd.Row()); ++nRow)
439
0
    {
440
0
        for (sal_uInt32 nCol = rRange.aStart.Col(); nCol <= sal::static_int_cast<sal_uInt32>(rRange.aEnd.Col()); ++nCol)
441
0
        {
442
0
            pTargetSet[nPos] = xTable->getAccessibleCellAt(nRow, nCol);
443
0
            ++nPos;
444
0
        }
445
0
    }
446
0
    OSL_ENSURE(nCount == nPos, "something went wrong");
447
0
    AccessibleRelation aRelation;
448
0
    aRelation.RelationType = eRelationType;
449
0
    aRelation.TargetSet = std::move(aTargetSet);
450
0
    pRelationSet->AddRelation(aRelation);
451
0
}
452
453
static OUString ReplaceFourChar(const OUString& oldOUString)
454
0
{
455
0
    return oldOUString.replaceAll(u"\\", u"\\\\")
456
0
        .replaceAll(u";", u"\\;")
457
0
        .replaceAll(u"=", u"\\=")
458
0
        .replaceAll(u",", u"\\,")
459
0
        .replaceAll(u":", u"\\:");
460
0
}
461
462
std::unordered_map<OUString, OUString> ScAccessibleCell::implGetExtendedAttributes()
463
0
{
464
0
    const OUString sRowIndexText = maCellAddress.Format(ScRefFlags::ROW_VALID);
465
0
    const OUString sColIndexText = maCellAddress.Format(ScRefFlags::COL_VALID);
466
0
    std::unordered_map<OUString, OUString> aAttributes
467
0
        = { { AccessibleAttribute::RowIndexText, sRowIndexText },
468
0
            { AccessibleAttribute::ColIndexText, sColIndexText } };
469
470
0
    if (mpViewShell)
471
0
    {
472
0
        const OUString sFormula = mpViewShell->GetFormula(maCellAddress) ;
473
0
        if (!sFormula.isEmpty())
474
0
            aAttributes.emplace(u"Formula"_ustr, ReplaceFourChar(sFormula.copy(1)));
475
476
0
        aAttributes.emplace(u"Note"_ustr, ReplaceFourChar(GetAllDisplayNote()));
477
0
        for (const auto& rAttr : getShadowAttrs())
478
0
            aAttributes.insert(rAttr);
479
0
        for (const auto& rAttr : getBorderAttrs())
480
0
            aAttributes.insert(rAttr);
481
        //end of cell attributes
482
0
        if( mpDoc )
483
0
        {
484
0
            const OUString sDropDownValue = IsDropdown() ? u"true"_ustr : u"false"_ustr;
485
0
            aAttributes.emplace(u"isdropdown"_ustr, sDropDownValue);
486
0
        }
487
0
    }
488
489
0
    return aAttributes;
490
0
}
491
492
// cell has its own ParaIndent property, so when calling character attributes on cell, the ParaIndent should replace the ParaLeftMargin if its value is not zero.
493
uno::Sequence< beans::PropertyValue > SAL_CALL ScAccessibleCell::getCharacterAttributes( sal_Int32 nIndex, const css::uno::Sequence< OUString >& aRequestedAttributes )
494
0
{
495
0
    SolarMutexGuard aGuard;
496
497
0
    uno::Sequence< beans::PropertyValue > aAttribs = AccessibleStaticTextBase::getCharacterAttributes( nIndex, aRequestedAttributes );
498
499
0
    sal_uInt16 nParaIndent = mpDoc->GetAttr( maCellAddress, ATTR_INDENT ).GetValue();
500
0
    if (nParaIndent > 0)
501
0
    {
502
0
        auto [begin, end] = asNonConstRange(aAttribs);
503
0
        auto pAttrib = std::find_if(begin, end,
504
0
            [](const beans::PropertyValue& rAttrib) { return "ParaLeftMargin" == rAttrib.Name; });
505
0
        if (pAttrib != end)
506
0
            pAttrib->Value <<= nParaIndent;
507
0
    }
508
0
    return aAttribs;
509
0
}
510
511
bool ScAccessibleCell::IsFormulaMode()
512
0
{
513
0
    ScAccessibleSpreadsheet* pSheet = static_cast<ScAccessibleSpreadsheet*>(mpParent.get());
514
0
    if (pSheet)
515
0
    {
516
0
        return pSheet->IsFormulaMode();
517
0
    }
518
0
    return false;
519
0
}
520
521
bool ScAccessibleCell::IsDropdown() const
522
0
{
523
0
    sal_uInt16 nPosX = maCellAddress.Col();
524
0
    sal_uInt16 nPosY = sal_uInt16(maCellAddress.Row());
525
0
    sal_uInt16 nTab = maCellAddress.Tab();
526
0
    sal_uInt32 nValidation = mpDoc->GetAttr( nPosX, nPosY, nTab, ATTR_VALIDDATA ).GetValue();
527
0
    if( nValidation )
528
0
    {
529
0
        const ScValidationData* pData = mpDoc->GetValidationEntry( nValidation );
530
0
        if( pData && pData->HasSelectionList() )
531
0
            return true;
532
0
    }
533
0
    const ScMergeFlagAttr& rAttr = mpDoc->GetAttr( nPosX, nPosY, nTab, ATTR_MERGE_FLAG );
534
0
    if (rAttr.HasAutoFilter())
535
0
    {
536
0
        return true;
537
0
    }
538
0
    else
539
0
    {
540
0
        sal_uInt16 nTabCount = mpDoc->GetTableCount();
541
0
        if ( nTab+1<nTabCount && mpDoc->IsScenario(nTab+1) && !mpDoc->IsScenario(nTab) )
542
0
        {
543
0
            SCTAB i;
544
0
            ScMarkData aMarks(mpDoc->GetSheetLimits());
545
0
            for (i=nTab+1; i<nTabCount && mpDoc->IsScenario(i); i++)
546
0
                mpDoc->MarkScenario( i, nTab, aMarks, false, ScScenarioFlags::ShowFrame );
547
0
            ScRangeList aRanges;
548
0
            aMarks.FillRangeListWithMarks( &aRanges, false );
549
0
            bool bHasScenario;
550
0
            SCTAB nRangeCount = aRanges.size();
551
0
            for (i=0; i<nRangeCount; i++)
552
0
            {
553
0
                ScRange aRange = aRanges[i];
554
0
                mpDoc->ExtendTotalMerge( aRange );
555
0
                bool bTextBelow = ( aRange.aStart.Row() == 0 );
556
                // MT IA2: Not used: sal_Bool bIsInScen = sal_False;
557
0
                if ( bTextBelow )
558
0
                {
559
0
                    bHasScenario = (aRange.aStart.Col() == nPosX && aRange.aEnd.Row() == nPosY-1);
560
0
                }
561
0
                else
562
0
                {
563
0
                    bHasScenario = (aRange.aStart.Col() == nPosX && aRange.aStart.Row() == nPosY+1);
564
0
                }
565
0
                if( bHasScenario ) return true;
566
0
            }
567
0
        }
568
0
    }
569
0
    return false;
570
0
}
571
572
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */