1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "AccessibleCell.hxx"
21 #include "scitems.hxx"
22 #include <editeng/eeitem.hxx>
25 #include "AccessibleText.hxx"
26 #include "AccessibleDocument.hxx"
27 #include "tabvwsh.hxx"
28 #include "document.hxx"
30 #include "miscuno.hxx"
31 #include "editsrc.hxx"
32 #include "dociter.hxx"
33 #include "markdata.hxx"
34 #include "cellvalue.hxx"
35 #include "formulaiter.hxx"
36 #include "validat.hxx"
38 #include <unotools/accessiblestatesethelper.hxx>
39 #include <com/sun/star/accessibility/AccessibleRole.hpp>
40 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
41 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
42 #include <com/sun/star/accessibility/XAccessibleTable.hpp>
43 #include <editeng/brushitem.hxx>
44 #include <comphelper/sequence.hxx>
46 #include <vcl/svapp.hxx>
48 #include "AccessibleSpreadsheet.hxx"
50 using namespace ::com::sun::star
;
51 using namespace ::com::sun::star::accessibility
;
53 rtl::Reference
<ScAccessibleCell
> ScAccessibleCell::create(
54 const uno::Reference
<XAccessible
>& rxParent
,
55 ScTabViewShell
* pViewShell
,
56 ScAddress
& rCellAddress
,
59 ScAccessibleDocument
* pAccDoc
)
61 rtl::Reference
<ScAccessibleCell
> x(new ScAccessibleCell(
62 rxParent
, pViewShell
, rCellAddress
, nIndex
, eSplitPos
, pAccDoc
));
67 ScAccessibleCell::ScAccessibleCell(
68 const uno::Reference
<XAccessible
>& rxParent
,
69 ScTabViewShell
* pViewShell
,
70 ScAddress
& rCellAddress
,
73 ScAccessibleDocument
* pAccDoc
)
75 ScAccessibleCellBase(rxParent
, GetDocument(pViewShell
), rCellAddress
, nIndex
),
76 ::accessibility::AccessibleStaticTextBase(CreateEditSource(pViewShell
, rCellAddress
, eSplitPos
)),
77 mpViewShell(pViewShell
),
82 pViewShell
->AddAccessibilityObject(*this);
85 ScAccessibleCell::~ScAccessibleCell()
87 if (!ScAccessibleContextBase::IsDefunc() && !rBHelper
.bInDispose
)
89 // increment refcount to prevent double call off dtor
90 osl_atomic_increment( &m_refCount
);
91 // call dispose to inform object which have a weak reference to this object
96 void ScAccessibleCell::Init()
98 ScAccessibleCellBase::Init();
100 SetEventSource(this);
103 void SAL_CALL
ScAccessibleCell::disposing()
105 SolarMutexGuard aGuard
;
106 // dispose in AccessibleStaticTextBase
111 mpViewShell
->RemoveAccessibilityObject(*this);
116 ScAccessibleCellBase::disposing();
119 //===== XInterface =====================================================
121 IMPLEMENT_FORWARD_XINTERFACE3( ScAccessibleCell
, ScAccessibleCellBase
, AccessibleStaticTextBase
, ScAccessibleCellAttributeImpl
)
123 //===== XTypeProvider ===================================================
125 IMPLEMENT_FORWARD_XTYPEPROVIDER3( ScAccessibleCell
, ScAccessibleCellBase
, AccessibleStaticTextBase
, ScAccessibleCellAttributeImpl
)
127 //===== XAccessibleComponent ============================================
129 uno::Reference
< XAccessible
> SAL_CALL
ScAccessibleCell::getAccessibleAtPoint(
130 const awt::Point
& rPoint
)
131 throw (uno::RuntimeException
, std::exception
)
133 return AccessibleStaticTextBase::getAccessibleAtPoint(rPoint
);
136 void SAL_CALL
ScAccessibleCell::grabFocus( )
137 throw (uno::RuntimeException
, std::exception
)
139 SolarMutexGuard aGuard
;
141 if (getAccessibleParent().is() && mpViewShell
)
143 uno::Reference
<XAccessibleComponent
> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY
);
144 if (xAccessibleComponent
.is())
146 xAccessibleComponent
->grabFocus();
147 mpViewShell
->SetCursor(maCellAddress
.Col(), maCellAddress
.Row());
152 Rectangle
ScAccessibleCell::GetBoundingBoxOnScreen(void) const
153 throw (uno::RuntimeException
, std::exception
)
155 Rectangle
aCellRect(GetBoundingBox());
158 Window
* pWindow
= mpViewShell
->GetWindowByPos(meSplitPos
);
161 Rectangle aRect
= pWindow
->GetWindowExtentsRelative(NULL
);
162 aCellRect
.setX(aCellRect
.getX() + aRect
.getX());
163 aCellRect
.setY(aCellRect
.getY() + aRect
.getY());
169 Rectangle
ScAccessibleCell::GetBoundingBox() const
170 throw (uno::RuntimeException
, std::exception
)
176 mpViewShell
->GetViewData()->GetMergeSizePixel(
177 maCellAddress
.Col(), maCellAddress
.Row(), nSizeX
, nSizeY
);
178 aCellRect
.SetSize(Size(nSizeX
, nSizeY
));
179 aCellRect
.SetPos(mpViewShell
->GetViewData()->GetScrPos(maCellAddress
.Col(), maCellAddress
.Row(), meSplitPos
, true));
181 Window
* pWindow
= mpViewShell
->GetWindowByPos(meSplitPos
);
184 Rectangle
aRect(pWindow
->GetWindowExtentsRelative(pWindow
->GetAccessibleParentWindow()));
185 aRect
.Move(-aRect
.Left(), -aRect
.Top());
186 aCellRect
= aRect
.Intersection(aCellRect
);
189 /* #i19430# Gnopernicus reads text partly if it sticks out of the cell
190 boundaries. This leads to wrong results in cases where the cell
191 text is rotated, because rotation is not taken into account when
192 calculating the visible part of the text. In these cases we will
193 simply expand the cell size to the width of the unrotated text. */
196 const SfxInt32Item
* pItem
= static_cast< const SfxInt32Item
* >(
197 mpDoc
->GetAttr( maCellAddress
.Col(), maCellAddress
.Row(), maCellAddress
.Tab(), ATTR_ROTATE_VALUE
) );
198 if( pItem
&& (pItem
->GetValue() != 0) )
200 Rectangle aParaRect
= GetParagraphBoundingBox();
201 if( !aParaRect
.IsEmpty() && (aCellRect
.GetWidth() < aParaRect
.GetWidth()) )
202 aCellRect
.SetSize( Size( aParaRect
.GetWidth(), aCellRect
.GetHeight() ) );
206 if (aCellRect
.IsEmpty())
207 aCellRect
.SetPos(Point(-1, -1));
211 //===== XAccessibleContext ==============================================
214 ScAccessibleCell::getAccessibleChildCount(void)
215 throw (uno::RuntimeException
, std::exception
)
217 return AccessibleStaticTextBase::getAccessibleChildCount();
220 uno::Reference
< XAccessible
> SAL_CALL
221 ScAccessibleCell::getAccessibleChild(sal_Int32 nIndex
)
222 throw (uno::RuntimeException
,
223 lang::IndexOutOfBoundsException
, std::exception
)
225 return AccessibleStaticTextBase::getAccessibleChild(nIndex
);
228 uno::Reference
<XAccessibleStateSet
> SAL_CALL
229 ScAccessibleCell::getAccessibleStateSet(void)
230 throw (uno::RuntimeException
, std::exception
)
232 SolarMutexGuard aGuard
;
233 uno::Reference
<XAccessibleStateSet
> xParentStates
;
234 if (getAccessibleParent().is())
236 uno::Reference
<XAccessibleContext
> xParentContext
= getAccessibleParent()->getAccessibleContext();
237 xParentStates
= xParentContext
->getAccessibleStateSet();
239 utl::AccessibleStateSetHelper
* pStateSet
= new utl::AccessibleStateSetHelper();
240 if (IsDefunc(xParentStates
))
241 pStateSet
->AddState(AccessibleStateType::DEFUNC
);
246 pStateSet
->AddState(AccessibleStateType::ENABLED
);
247 pStateSet
->AddState(AccessibleStateType::MULTI_LINE
);
248 pStateSet
->AddState(AccessibleStateType::MULTI_SELECTABLE
);
249 if (IsOpaque(xParentStates
))
250 pStateSet
->AddState(AccessibleStateType::OPAQUE
);
251 pStateSet
->AddState(AccessibleStateType::SELECTABLE
);
253 pStateSet
->AddState(AccessibleStateType::SELECTED
);
255 pStateSet
->AddState(AccessibleStateType::SHOWING
);
256 pStateSet
->AddState(AccessibleStateType::TRANSIENT
);
258 pStateSet
->AddState(AccessibleStateType::VISIBLE
);
261 if (IsEditable(xParentStates
))
263 pStateSet
->AddState(AccessibleStateType::EDITABLE
);
264 pStateSet
->AddState(AccessibleStateType::RESIZABLE
);
266 pStateSet
->AddState(AccessibleStateType::ENABLED
);
267 pStateSet
->AddState(AccessibleStateType::MULTI_LINE
);
268 pStateSet
->AddState(AccessibleStateType::MULTI_SELECTABLE
);
269 pStateSet
->AddState(AccessibleStateType::FOCUSABLE
);
270 if (IsOpaque(xParentStates
))
271 pStateSet
->AddState(AccessibleStateType::OPAQUE
);
272 pStateSet
->AddState(AccessibleStateType::SELECTABLE
);
274 pStateSet
->AddState(AccessibleStateType::SELECTED
);
276 pStateSet
->AddState(AccessibleStateType::SHOWING
);
277 pStateSet
->AddState(AccessibleStateType::TRANSIENT
);
279 pStateSet
->AddState(AccessibleStateType::VISIBLE
);
284 uno::Reference
<XAccessibleRelationSet
> SAL_CALL
285 ScAccessibleCell::getAccessibleRelationSet()
286 throw (uno::RuntimeException
, std::exception
)
288 SolarMutexGuard aGuard
;
290 utl::AccessibleRelationSetHelper
* pRelationSet
= NULL
;
292 pRelationSet
= mpAccDoc
->GetRelationSet(&maCellAddress
);
294 pRelationSet
= new utl::AccessibleRelationSetHelper();
295 FillDependends(pRelationSet
);
296 FillPrecedents(pRelationSet
);
300 //===== XServiceInfo ====================================================
302 OUString SAL_CALL
ScAccessibleCell::getImplementationName(void)
303 throw (uno::RuntimeException
, std::exception
)
305 return OUString("ScAccessibleCell");
308 uno::Sequence
< OUString
> SAL_CALL
309 ScAccessibleCell::getSupportedServiceNames(void)
310 throw (uno::RuntimeException
, std::exception
)
312 uno::Sequence
< OUString
> aSequence
= ScAccessibleContextBase::getSupportedServiceNames();
313 sal_Int32
nOldSize(aSequence
.getLength());
314 aSequence
.realloc(nOldSize
+ 1);
316 aSequence
[nOldSize
] = "com.sun.star.sheet.AccessibleCell";
321 //==== internal =========================================================
323 bool ScAccessibleCell::IsDefunc(
324 const uno::Reference
<XAccessibleStateSet
>& rxParentStates
)
326 return ScAccessibleContextBase::IsDefunc() || (mpDoc
== NULL
) || (mpViewShell
== NULL
) || !getAccessibleParent().is() ||
327 (rxParentStates
.is() && rxParentStates
->contains(AccessibleStateType::DEFUNC
));
330 bool ScAccessibleCell::IsEditable(
331 const uno::Reference
<XAccessibleStateSet
>& rxParentStates
)
333 bool bEditable(true);
334 if (rxParentStates
.is() && !rxParentStates
->contains(AccessibleStateType::EDITABLE
) &&
337 // here I have to test whether the protection of the table should influence this cell.
338 const ScProtectionAttr
* pItem
= (const ScProtectionAttr
*)mpDoc
->GetAttr(
339 maCellAddress
.Col(), maCellAddress
.Row(),
340 maCellAddress
.Tab(), ATTR_PROTECTION
);
342 bEditable
= !pItem
->GetProtection();
347 bool ScAccessibleCell::IsOpaque(
348 const uno::Reference
<XAccessibleStateSet
>& /* rxParentStates */)
350 // test whether there is a background color
354 const SvxBrushItem
* pItem
= (const SvxBrushItem
*)mpDoc
->GetAttr(
355 maCellAddress
.Col(), maCellAddress
.Row(),
356 maCellAddress
.Tab(), ATTR_BACKGROUND
);
358 bOpaque
= pItem
->GetColor() != COL_TRANSPARENT
;
363 bool ScAccessibleCell::IsSelected()
367 const ScAccessibleSpreadsheet
*pSheet
=static_cast<const ScAccessibleSpreadsheet
*>(mxParent
.get());
370 return pSheet
->IsScAddrFormulaSel(maCellAddress
);
376 if (mpViewShell
&& mpViewShell
->GetViewData())
378 const ScMarkData
& rMarkdata
= mpViewShell
->GetViewData()->GetMarkData();
379 bResult
= rMarkdata
.IsCellMarked(maCellAddress
.Col(), maCellAddress
.Row());
384 ScDocument
* ScAccessibleCell::GetDocument(ScTabViewShell
* pViewShell
)
386 ScDocument
* pDoc
= NULL
;
387 if (pViewShell
&& pViewShell
->GetViewData())
388 pDoc
= pViewShell
->GetViewData()->GetDocument();
392 SAL_WNODEPRECATED_DECLARATIONS_PUSH
393 ::std::auto_ptr
< SvxEditSource
> ScAccessibleCell::CreateEditSource(ScTabViewShell
* pViewShell
, ScAddress aCell
, ScSplitPos eSplitPos
)
397 return ::std::auto_ptr
< SvxEditSource
>();
399 ::std::auto_ptr
< ScAccessibleTextData
> pAccessibleCellTextData
400 ( new ScAccessibleCellTextData( pViewShell
, aCell
, eSplitPos
, this ) );
401 ::std::auto_ptr
< SvxEditSource
> pEditSource (new ScAccessibilityEditSource(pAccessibleCellTextData
));
405 SAL_WNODEPRECATED_DECLARATIONS_POP
407 void ScAccessibleCell::FillDependends(utl::AccessibleRelationSetHelper
* pRelationSet
)
411 ScRange
aRange(0, 0, maCellAddress
.Tab(), MAXCOL
, MAXROW
, maCellAddress
.Tab());
412 ScCellIterator
aCellIter(mpDoc
, aRange
);
414 for (bool bHasCell
= aCellIter
.first(); bHasCell
; bHasCell
= aCellIter
.next())
416 if (aCellIter
.getType() == CELLTYPE_FORMULA
)
419 ScDetectiveRefIter
aIter(aCellIter
.getFormulaCell());
421 while ( !bFound
&& aIter
.GetNextRef( aRef
) )
423 if (aRef
.In(maCellAddress
))
427 AddRelation(aCellIter
.GetPos(), AccessibleRelationType::CONTROLLER_FOR
, pRelationSet
);
433 void ScAccessibleCell::FillPrecedents(utl::AccessibleRelationSetHelper
* pRelationSet
)
435 if (mpDoc
&& mpDoc
->GetCellType(maCellAddress
) == CELLTYPE_FORMULA
)
437 ScFormulaCell
* pCell
= mpDoc
->GetFormulaCell(maCellAddress
);
440 ScDetectiveRefIter
aIter(pCell
);
442 while ( aIter
.GetNextRef( aRef
) )
444 AddRelation( aRef
, AccessibleRelationType::CONTROLLED_BY
, pRelationSet
);
449 void ScAccessibleCell::AddRelation(const ScAddress
& rCell
,
450 const sal_uInt16 aRelationType
,
451 utl::AccessibleRelationSetHelper
* pRelationSet
)
453 AddRelation(ScRange(rCell
, rCell
), aRelationType
, pRelationSet
);
456 void ScAccessibleCell::AddRelation(const ScRange
& rRange
,
457 const sal_uInt16 aRelationType
,
458 utl::AccessibleRelationSetHelper
* pRelationSet
)
460 uno::Reference
< XAccessibleTable
> xTable ( getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY
);
463 sal_uInt32
nCount(static_cast<sal_uInt32
>(rRange
.aEnd
.Col() -
464 rRange
.aStart
.Col() + 1) * (rRange
.aEnd
.Row() -
465 rRange
.aStart
.Row() + 1));
466 uno::Sequence
< uno::Reference
< uno::XInterface
> > aTargetSet( nCount
);
467 uno::Reference
< uno::XInterface
>* pTargetSet
= aTargetSet
.getArray();
471 for (sal_uInt32 nRow
= rRange
.aStart
.Row(); nRow
<= sal::static_int_cast
<sal_uInt32
>(rRange
.aEnd
.Row()); ++nRow
)
473 for (sal_uInt32 nCol
= rRange
.aStart
.Col(); nCol
<= sal::static_int_cast
<sal_uInt32
>(rRange
.aEnd
.Col()); ++nCol
)
475 pTargetSet
[nPos
] = xTable
->getAccessibleCellAt(nRow
, nCol
);
479 OSL_ENSURE(nCount
== nPos
, "something wents wrong");
481 AccessibleRelation aRelation
;
482 aRelation
.RelationType
= aRelationType
;
483 aRelation
.TargetSet
= aTargetSet
;
484 pRelationSet
->AddRelation(aRelation
);
488 static OUString
ReplaceOneChar(const OUString
& oldOUString
, const OUString
& replacedChar
, const OUString
& replaceStr
)
490 int iReplace
= oldOUString
.lastIndexOf(replacedChar
);
491 OUString aRet
= oldOUString
;
494 aRet
= aRet
.replaceAt(iReplace
, 1, replaceStr
);
495 iReplace
= aRet
.lastIndexOf(replacedChar
, iReplace
);
500 static OUString
ReplaceFourChar(const OUString
& oldOUString
)
502 OUString aRet
= ReplaceOneChar(oldOUString
, "\\", "\\\\");
503 aRet
= ReplaceOneChar(aRet
, ";", "\\;");
504 aRet
= ReplaceOneChar(aRet
, "=", "\\=");
505 aRet
= ReplaceOneChar(aRet
, ",", "\\,");
506 aRet
= ReplaceOneChar(aRet
, ":", "\\:");
510 uno::Any SAL_CALL
ScAccessibleCell::getExtendedAttributes()
511 throw (::com::sun::star::lang::IndexOutOfBoundsException
,
512 ::com::sun::star::uno::RuntimeException
,
515 SolarMutexGuard aGuard
;
520 OUString strFor
= mpViewShell
->GetFormula(maCellAddress
) ;
521 strFor
= strFor
.replaceAt(0,1,"");
522 strFor
= ReplaceFourChar(strFor
);
523 strFor
= "Formula:" + strFor
;
525 strFor
+= ReplaceFourChar(GetAllDisplayNote());
527 strFor
+= getShadowAttrs();//the string returned contains the spliter ";"
528 strFor
+= getBorderAttrs();//the string returned contains the spliter ";"
529 //end of cell attributes
532 strFor
+= "isdropdown:";
544 // 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.
545 uno::Sequence
< beans::PropertyValue
> SAL_CALL
ScAccessibleCell::getCharacterAttributes( sal_Int32 nIndex
, const ::com::sun::star::uno::Sequence
< OUString
>& aRequestedAttributes
) throw (lang::IndexOutOfBoundsException
, uno::RuntimeException
, std::exception
)
547 SolarMutexGuard aGuard
;
549 uno::Sequence
< beans::PropertyValue
> aAttribs
= AccessibleStaticTextBase::getCharacterAttributes( nIndex
, aRequestedAttributes
);
550 beans::PropertyValue
*pAttribs
= aAttribs
.getArray();
552 sal_uInt16 nParaIndent
= static_cast< const SfxUInt16Item
* >( mpDoc
->GetAttr( maCellAddress
.Col(), maCellAddress
.Row(), maCellAddress
.Tab(), ATTR_INDENT
) )->GetValue();
555 OUString
sLeftMarginName ("ParaLeftMargin");
556 for (int i
= 0; i
< aAttribs
.getLength(); ++i
)
558 if (sLeftMarginName
== pAttribs
[i
].Name
)
560 pAttribs
[i
].Value
= uno::makeAny( nParaIndent
);
568 bool ScAccessibleCell::IsFormulaMode()
570 ScAccessibleSpreadsheet
* pSheet
= static_cast<ScAccessibleSpreadsheet
*>(mxParent
.get());
573 return pSheet
->IsFormulaMode();
578 bool ScAccessibleCell::IsDropdown()
580 sal_uInt16 nPosX
= maCellAddress
.Col();
581 sal_uInt16 nPosY
= sal_uInt16(maCellAddress
.Row());
582 sal_uInt16 nTab
= maCellAddress
.Tab();
583 sal_uInt32 nValidation
= static_cast< const SfxUInt32Item
* >( mpDoc
->GetAttr( nPosX
, nPosY
, nTab
, ATTR_VALIDDATA
) )->GetValue();
586 const ScValidationData
* pData
= mpDoc
->GetValidationEntry( nValidation
);
587 if( pData
&& pData
->HasSelectionList() )
590 ScMergeFlagAttr
* pAttr
;
591 pAttr
= (ScMergeFlagAttr
*)mpDoc
->GetAttr( nPosX
, nPosY
, nTab
, ATTR_MERGE_FLAG
);
592 if( pAttr
->HasAutoFilter() )
598 sal_uInt16 nTabCount
= mpDoc
->GetTableCount();
599 if ( nTab
+1<nTabCount
&& mpDoc
->IsScenario(nTab
+1) && !mpDoc
->IsScenario(nTab
) )
603 for (i
=nTab
+1; i
<nTabCount
&& mpDoc
->IsScenario(i
); i
++)
604 mpDoc
->MarkScenario( i
, nTab
, aMarks
, false, SC_SCENARIO_SHOWFRAME
);
606 aMarks
.FillRangeListWithMarks( &aRanges
, false );
608 SCTAB nRangeCount
= aRanges
.size();
609 for (i
=0; i
<nRangeCount
; i
++)
611 ScRange aRange
= *aRanges
[i
];
612 mpDoc
->ExtendTotalMerge( aRange
);
613 bool bTextBelow
= ( aRange
.aStart
.Row() == 0 );
614 // MT IA2: Not used: sal_Bool bIsInScen = sal_False;
617 bHasScenario
= (aRange
.aStart
.Col() == nPosX
&& aRange
.aEnd
.Row() == nPosY
-1);
621 bHasScenario
= (aRange
.aStart
.Col() == nPosX
&& aRange
.aStart
.Row() == nPosY
+1);
623 if( bHasScenario
) return true;
630 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */