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"
37 #include <unotools/accessiblestatesethelper.hxx>
38 #include <com/sun/star/accessibility/AccessibleRole.hpp>
39 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
40 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
41 #include <com/sun/star/accessibility/XAccessibleTable.hpp>
42 #include <editeng/brushitem.hxx>
43 #include <comphelper/sequence.hxx>
45 #include <vcl/svapp.hxx>
47 using namespace ::com::sun::star
;
48 using namespace ::com::sun::star::accessibility
;
50 //===== internal ============================================================
52 ScAccessibleCell::ScAccessibleCell(
53 const uno::Reference
<XAccessible
>& rxParent
,
54 ScTabViewShell
* pViewShell
,
55 ScAddress
& rCellAddress
,
58 ScAccessibleDocument
* pAccDoc
)
60 ScAccessibleCellBase(rxParent
, GetDocument(pViewShell
), rCellAddress
, nIndex
),
61 ::accessibility::AccessibleStaticTextBase(CreateEditSource(pViewShell
, rCellAddress
, eSplitPos
)),
62 mpViewShell(pViewShell
),
67 pViewShell
->AddAccessibilityObject(*this);
70 ScAccessibleCell::~ScAccessibleCell()
72 if (!ScAccessibleContextBase::IsDefunc() && !rBHelper
.bInDispose
)
74 // increment refcount to prevent double call off dtor
75 osl_atomic_increment( &m_refCount
);
76 // call dispose to inform object which have a weak reference to this object
81 void ScAccessibleCell::Init()
83 ScAccessibleCellBase::Init();
88 void SAL_CALL
ScAccessibleCell::disposing()
90 SolarMutexGuard aGuard
;
91 // dispose in AccessibleStaticTextBase
96 mpViewShell
->RemoveAccessibilityObject(*this);
101 ScAccessibleCellBase::disposing();
104 //===== XInterface =====================================================
106 IMPLEMENT_FORWARD_XINTERFACE2( ScAccessibleCell
, ScAccessibleCellBase
, AccessibleStaticTextBase
)
108 //===== XTypeProvider ===================================================
110 IMPLEMENT_FORWARD_XTYPEPROVIDER2( ScAccessibleCell
, ScAccessibleCellBase
, AccessibleStaticTextBase
)
112 //===== XAccessibleComponent ============================================
114 uno::Reference
< XAccessible
> SAL_CALL
ScAccessibleCell::getAccessibleAtPoint(
115 const awt::Point
& rPoint
)
116 throw (uno::RuntimeException
)
118 return AccessibleStaticTextBase::getAccessibleAtPoint(rPoint
);
121 void SAL_CALL
ScAccessibleCell::grabFocus( )
122 throw (uno::RuntimeException
)
124 SolarMutexGuard aGuard
;
126 if (getAccessibleParent().is() && mpViewShell
)
128 uno::Reference
<XAccessibleComponent
> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY
);
129 if (xAccessibleComponent
.is())
131 xAccessibleComponent
->grabFocus();
132 mpViewShell
->SetCursor(maCellAddress
.Col(), maCellAddress
.Row());
137 Rectangle
ScAccessibleCell::GetBoundingBoxOnScreen(void) const
138 throw (uno::RuntimeException
)
140 Rectangle
aCellRect(GetBoundingBox());
143 Window
* pWindow
= mpViewShell
->GetWindowByPos(meSplitPos
);
146 Rectangle aRect
= pWindow
->GetWindowExtentsRelative(NULL
);
147 aCellRect
.setX(aCellRect
.getX() + aRect
.getX());
148 aCellRect
.setY(aCellRect
.getY() + aRect
.getY());
154 Rectangle
ScAccessibleCell::GetBoundingBox(void) const
155 throw (uno::RuntimeException
)
161 mpViewShell
->GetViewData()->GetMergeSizePixel(
162 maCellAddress
.Col(), maCellAddress
.Row(), nSizeX
, nSizeY
);
163 aCellRect
.SetSize(Size(nSizeX
, nSizeY
));
164 aCellRect
.SetPos(mpViewShell
->GetViewData()->GetScrPos(maCellAddress
.Col(), maCellAddress
.Row(), meSplitPos
, sal_True
));
166 Window
* pWindow
= mpViewShell
->GetWindowByPos(meSplitPos
);
169 Rectangle
aRect(pWindow
->GetWindowExtentsRelative(pWindow
->GetAccessibleParentWindow()));
170 aRect
.Move(-aRect
.Left(), -aRect
.Top());
171 aCellRect
= aRect
.Intersection(aCellRect
);
174 /* #i19430# Gnopernicus reads text partly if it sticks out of the cell
175 boundaries. This leads to wrong results in cases where the cell
176 text is rotated, because rotation is not taken into account when
177 calculating the visible part of the text. In these cases we will
178 simply expand the cell size to the width of the unrotated text. */
181 const SfxInt32Item
* pItem
= static_cast< const SfxInt32Item
* >(
182 mpDoc
->GetAttr( maCellAddress
.Col(), maCellAddress
.Row(), maCellAddress
.Tab(), ATTR_ROTATE_VALUE
) );
183 if( pItem
&& (pItem
->GetValue() != 0) )
185 Rectangle aParaRect
= GetParagraphBoundingBox();
186 if( !aParaRect
.IsEmpty() && (aCellRect
.GetWidth() < aParaRect
.GetWidth()) )
187 aCellRect
.SetSize( Size( aParaRect
.GetWidth(), aCellRect
.GetHeight() ) );
191 if (aCellRect
.IsEmpty())
192 aCellRect
.SetPos(Point(-1, -1));
196 //===== XAccessibleContext ==============================================
199 ScAccessibleCell::getAccessibleChildCount(void)
200 throw (uno::RuntimeException
)
202 return AccessibleStaticTextBase::getAccessibleChildCount();
205 uno::Reference
< XAccessible
> SAL_CALL
206 ScAccessibleCell::getAccessibleChild(sal_Int32 nIndex
)
207 throw (uno::RuntimeException
,
208 lang::IndexOutOfBoundsException
)
210 return AccessibleStaticTextBase::getAccessibleChild(nIndex
);
213 uno::Reference
<XAccessibleStateSet
> SAL_CALL
214 ScAccessibleCell::getAccessibleStateSet(void)
215 throw (uno::RuntimeException
)
217 SolarMutexGuard aGuard
;
218 uno::Reference
<XAccessibleStateSet
> xParentStates
;
219 if (getAccessibleParent().is())
221 uno::Reference
<XAccessibleContext
> xParentContext
= getAccessibleParent()->getAccessibleContext();
222 xParentStates
= xParentContext
->getAccessibleStateSet();
224 utl::AccessibleStateSetHelper
* pStateSet
= new utl::AccessibleStateSetHelper();
225 if (IsDefunc(xParentStates
))
226 pStateSet
->AddState(AccessibleStateType::DEFUNC
);
229 if (IsEditable(xParentStates
))
231 pStateSet
->AddState(AccessibleStateType::EDITABLE
);
232 pStateSet
->AddState(AccessibleStateType::RESIZABLE
);
234 pStateSet
->AddState(AccessibleStateType::ENABLED
);
235 pStateSet
->AddState(AccessibleStateType::MULTI_LINE
);
236 pStateSet
->AddState(AccessibleStateType::MULTI_SELECTABLE
);
237 if (IsOpaque(xParentStates
))
238 pStateSet
->AddState(AccessibleStateType::OPAQUE
);
239 pStateSet
->AddState(AccessibleStateType::SELECTABLE
);
241 pStateSet
->AddState(AccessibleStateType::SELECTED
);
243 pStateSet
->AddState(AccessibleStateType::SHOWING
);
244 pStateSet
->AddState(AccessibleStateType::TRANSIENT
);
246 pStateSet
->AddState(AccessibleStateType::VISIBLE
);
251 uno::Reference
<XAccessibleRelationSet
> SAL_CALL
252 ScAccessibleCell::getAccessibleRelationSet(void)
253 throw (uno::RuntimeException
)
255 SolarMutexGuard aGuard
;
257 utl::AccessibleRelationSetHelper
* pRelationSet
= NULL
;
259 pRelationSet
= mpAccDoc
->GetRelationSet(&maCellAddress
);
261 pRelationSet
= new utl::AccessibleRelationSetHelper();
262 FillDependends(pRelationSet
);
263 FillPrecedents(pRelationSet
);
267 //===== XServiceInfo ====================================================
269 OUString SAL_CALL
ScAccessibleCell::getImplementationName(void)
270 throw (uno::RuntimeException
)
272 return OUString("ScAccessibleCell");
275 uno::Sequence
< OUString
> SAL_CALL
276 ScAccessibleCell::getSupportedServiceNames(void)
277 throw (uno::RuntimeException
)
279 uno::Sequence
< OUString
> aSequence
= ScAccessibleContextBase::getSupportedServiceNames();
280 sal_Int32
nOldSize(aSequence
.getLength());
281 aSequence
.realloc(nOldSize
+ 1);
282 OUString
* pNames
= aSequence
.getArray();
284 pNames
[nOldSize
] = OUString("com.sun.star.sheet.AccessibleCell");
289 //==== internal =========================================================
291 sal_Bool
ScAccessibleCell::IsDefunc(
292 const uno::Reference
<XAccessibleStateSet
>& rxParentStates
)
294 return ScAccessibleContextBase::IsDefunc() || (mpDoc
== NULL
) || (mpViewShell
== NULL
) || !getAccessibleParent().is() ||
295 (rxParentStates
.is() && rxParentStates
->contains(AccessibleStateType::DEFUNC
));
298 sal_Bool
ScAccessibleCell::IsEditable(
299 const uno::Reference
<XAccessibleStateSet
>& rxParentStates
)
301 sal_Bool
bEditable(sal_True
);
302 if (rxParentStates
.is() && !rxParentStates
->contains(AccessibleStateType::EDITABLE
) &&
305 // here I have to test whether the protection of the table should influence this cell.
306 const ScProtectionAttr
* pItem
= (const ScProtectionAttr
*)mpDoc
->GetAttr(
307 maCellAddress
.Col(), maCellAddress
.Row(),
308 maCellAddress
.Tab(), ATTR_PROTECTION
);
310 bEditable
= !pItem
->GetProtection();
315 sal_Bool
ScAccessibleCell::IsOpaque(
316 const uno::Reference
<XAccessibleStateSet
>& /* rxParentStates */)
318 // test whether there is a background color
319 sal_Bool
bOpaque(sal_True
);
322 const SvxBrushItem
* pItem
= (const SvxBrushItem
*)mpDoc
->GetAttr(
323 maCellAddress
.Col(), maCellAddress
.Row(),
324 maCellAddress
.Tab(), ATTR_BACKGROUND
);
326 bOpaque
= pItem
->GetColor() != COL_TRANSPARENT
;
331 sal_Bool
ScAccessibleCell::IsSelected()
333 sal_Bool
bResult(false);
334 if (mpViewShell
&& mpViewShell
->GetViewData())
336 const ScMarkData
& rMarkdata
= mpViewShell
->GetViewData()->GetMarkData();
337 bResult
= rMarkdata
.IsCellMarked(maCellAddress
.Col(), maCellAddress
.Row());
342 ScDocument
* ScAccessibleCell::GetDocument(ScTabViewShell
* pViewShell
)
344 ScDocument
* pDoc
= NULL
;
345 if (pViewShell
&& pViewShell
->GetViewData())
346 pDoc
= pViewShell
->GetViewData()->GetDocument();
350 SAL_WNODEPRECATED_DECLARATIONS_PUSH
351 ::std::auto_ptr
< SvxEditSource
> ScAccessibleCell::CreateEditSource(ScTabViewShell
* pViewShell
, ScAddress aCell
, ScSplitPos eSplitPos
)
353 ::std::auto_ptr
< ScAccessibleTextData
> pAccessibleCellTextData
354 ( new ScAccessibleCellTextData( pViewShell
, aCell
, eSplitPos
, this ) );
355 ::std::auto_ptr
< SvxEditSource
> pEditSource (new ScAccessibilityEditSource(pAccessibleCellTextData
));
359 SAL_WNODEPRECATED_DECLARATIONS_POP
361 void ScAccessibleCell::FillDependends(utl::AccessibleRelationSetHelper
* pRelationSet
)
365 ScRange
aRange(0, 0, maCellAddress
.Tab(), MAXCOL
, MAXROW
, maCellAddress
.Tab());
366 ScCellIterator
aCellIter(mpDoc
, aRange
);
368 for (bool bHasCell
= aCellIter
.first(); bHasCell
; bHasCell
= aCellIter
.next())
370 if (aCellIter
.getType() == CELLTYPE_FORMULA
)
373 ScDetectiveRefIter
aIter(aCellIter
.getFormulaCell());
375 while ( !bFound
&& aIter
.GetNextRef( aRef
) )
377 if (aRef
.In(maCellAddress
))
381 AddRelation(aCellIter
.GetPos(), AccessibleRelationType::CONTROLLER_FOR
, pRelationSet
);
387 void ScAccessibleCell::FillPrecedents(utl::AccessibleRelationSetHelper
* pRelationSet
)
389 if (mpDoc
&& mpDoc
->GetCellType(maCellAddress
) == CELLTYPE_FORMULA
)
391 ScDetectiveRefIter
aIter(mpDoc
->GetFormulaCell(maCellAddress
));
393 while ( aIter
.GetNextRef( aRef
) )
395 AddRelation( aRef
, AccessibleRelationType::CONTROLLED_BY
, pRelationSet
);
400 void ScAccessibleCell::AddRelation(const ScAddress
& rCell
,
401 const sal_uInt16 aRelationType
,
402 utl::AccessibleRelationSetHelper
* pRelationSet
)
404 AddRelation(ScRange(rCell
, rCell
), aRelationType
, pRelationSet
);
407 void ScAccessibleCell::AddRelation(const ScRange
& rRange
,
408 const sal_uInt16 aRelationType
,
409 utl::AccessibleRelationSetHelper
* pRelationSet
)
411 uno::Reference
< XAccessibleTable
> xTable ( getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY
);
414 sal_uInt32
nCount(static_cast<sal_uInt32
>(rRange
.aEnd
.Col() -
415 rRange
.aStart
.Col() + 1) * (rRange
.aEnd
.Row() -
416 rRange
.aStart
.Row() + 1));
417 uno::Sequence
< uno::Reference
< uno::XInterface
> > aTargetSet( nCount
);
418 uno::Reference
< uno::XInterface
>* pTargetSet
= aTargetSet
.getArray();
422 for (sal_uInt32 nRow
= rRange
.aStart
.Row(); nRow
<= sal::static_int_cast
<sal_uInt32
>(rRange
.aEnd
.Row()); ++nRow
)
424 for (sal_uInt32 nCol
= rRange
.aStart
.Col(); nCol
<= sal::static_int_cast
<sal_uInt32
>(rRange
.aEnd
.Col()); ++nCol
)
426 pTargetSet
[nPos
] = xTable
->getAccessibleCellAt(nRow
, nCol
);
430 OSL_ENSURE(nCount
== nPos
, "something wents wrong");
432 AccessibleRelation aRelation
;
433 aRelation
.RelationType
= aRelationType
;
434 aRelation
.TargetSet
= aTargetSet
;
435 pRelationSet
->AddRelation(aRelation
);
439 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */