bump product version to 4.1.6.2
[LibreOffice.git] / sc / source / ui / Accessibility / AccessibleCell.cxx
blob72c61917dc4971f62c80fef624028225d2f989cf
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
29 #include "attrib.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>
44 #include <float.h>
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,
56 sal_Int32 nIndex,
57 ScSplitPos eSplitPos,
58 ScAccessibleDocument* pAccDoc)
60 ScAccessibleCellBase(rxParent, GetDocument(pViewShell), rCellAddress, nIndex),
61 ::accessibility::AccessibleStaticTextBase(CreateEditSource(pViewShell, rCellAddress, eSplitPos)),
62 mpViewShell(pViewShell),
63 mpAccDoc(pAccDoc),
64 meSplitPos(eSplitPos)
66 if (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
77 dispose();
81 void ScAccessibleCell::Init()
83 ScAccessibleCellBase::Init();
85 SetEventSource(this);
88 void SAL_CALL ScAccessibleCell::disposing()
90 SolarMutexGuard aGuard;
91 // dispose in AccessibleStaticTextBase
92 Dispose();
94 if (mpViewShell)
96 mpViewShell->RemoveAccessibilityObject(*this);
97 mpViewShell = NULL;
99 mpAccDoc = NULL;
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;
125 IsObjectValid();
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());
141 if (mpViewShell)
143 Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
144 if (pWindow)
146 Rectangle aRect = pWindow->GetWindowExtentsRelative(NULL);
147 aCellRect.setX(aCellRect.getX() + aRect.getX());
148 aCellRect.setY(aCellRect.getY() + aRect.getY());
151 return aCellRect;
154 Rectangle ScAccessibleCell::GetBoundingBox(void) const
155 throw (uno::RuntimeException)
157 Rectangle aCellRect;
158 if (mpViewShell)
160 long nSizeX, nSizeY;
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);
167 if (pWindow)
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. */
179 if (mpDoc)
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));
193 return aCellRect;
196 //===== XAccessibleContext ==============================================
198 sal_Int32 SAL_CALL
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);
227 else
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);
240 if (IsSelected())
241 pStateSet->AddState(AccessibleStateType::SELECTED);
242 if (isShowing())
243 pStateSet->AddState(AccessibleStateType::SHOWING);
244 pStateSet->AddState(AccessibleStateType::TRANSIENT);
245 if (isVisible())
246 pStateSet->AddState(AccessibleStateType::VISIBLE);
248 return pStateSet;
251 uno::Reference<XAccessibleRelationSet> SAL_CALL
252 ScAccessibleCell::getAccessibleRelationSet(void)
253 throw (uno::RuntimeException)
255 SolarMutexGuard aGuard;
256 IsObjectValid();
257 utl::AccessibleRelationSetHelper* pRelationSet = NULL;
258 if (mpAccDoc)
259 pRelationSet = mpAccDoc->GetRelationSet(&maCellAddress);
260 if (!pRelationSet)
261 pRelationSet = new utl::AccessibleRelationSetHelper();
262 FillDependends(pRelationSet);
263 FillPrecedents(pRelationSet);
264 return 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");
286 return aSequence;
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) &&
303 mpDoc)
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);
309 if (pItem)
310 bEditable = !pItem->GetProtection();
312 return bEditable;
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);
320 if (mpDoc)
322 const SvxBrushItem* pItem = (const SvxBrushItem*)mpDoc->GetAttr(
323 maCellAddress.Col(), maCellAddress.Row(),
324 maCellAddress.Tab(), ATTR_BACKGROUND);
325 if (pItem)
326 bOpaque = pItem->GetColor() != COL_TRANSPARENT;
328 return bOpaque;
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());
339 return bResult;
342 ScDocument* ScAccessibleCell::GetDocument(ScTabViewShell* pViewShell)
344 ScDocument* pDoc = NULL;
345 if (pViewShell && pViewShell->GetViewData())
346 pDoc = pViewShell->GetViewData()->GetDocument();
347 return pDoc;
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));
357 return pEditSource;
359 SAL_WNODEPRECATED_DECLARATIONS_POP
361 void ScAccessibleCell::FillDependends(utl::AccessibleRelationSetHelper* pRelationSet)
363 if (mpDoc)
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)
372 bool bFound = false;
373 ScDetectiveRefIter aIter(aCellIter.getFormulaCell());
374 ScRange aRef;
375 while ( !bFound && aIter.GetNextRef( aRef ) )
377 if (aRef.In(maCellAddress))
378 bFound = true;
380 if (bFound)
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));
392 ScRange aRef;
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 );
412 if (xTable.is())
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();
419 if (pTargetSet)
421 sal_uInt32 nPos(0);
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);
427 ++nPos;
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: */