xref: /AOO41X/main/sc/source/ui/Accessibility/AccessibleCell.cxx (revision e8c8fa4bdcac50a8fe6c60960dd164b285c48c7e)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26 
27 
28 #include "AccessibleCell.hxx"
29 #include "scitems.hxx"
30 #include <editeng/eeitem.hxx>
31 
32 
33 #include "AccessibleText.hxx"
34 #include "AccessibleDocument.hxx"
35 #include "tabvwsh.hxx"
36 #include "document.hxx"
37 #include "attrib.hxx"
38 #include "miscuno.hxx"
39 #include "unoguard.hxx"
40 #include "editsrc.hxx"
41 #include "dociter.hxx"
42 #include "cell.hxx"
43 
44 #ifndef _UTL_ACCESSIBLESTATESETHELPER_HXX
45 #include <unotools/accessiblestatesethelper.hxx>
46 #endif
47 #ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLEROLE_HPP_
48 #include <com/sun/star/accessibility/AccessibleRole.hpp>
49 #endif
50 #ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLESTATETYPE_HPP_
51 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
52 #endif
53 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
54 #include <com/sun/star/accessibility/XAccessibleTable.hpp>
55 #include <rtl/uuid.h>
56 #include <tools/debug.hxx>
57 #include <editeng/brshitem.hxx>
58 #include <comphelper/sequence.hxx>
59 #include <float.h>
60 
61 using namespace	::com::sun::star;
62 using namespace	::com::sun::star::accessibility;
63 
64 //=====  internal  ============================================================
65 
66 ScAccessibleCell::ScAccessibleCell(
67         const uno::Reference<XAccessible>& rxParent,
68 		ScTabViewShell* pViewShell,
69 		ScAddress& rCellAddress,
70 		sal_Int32 nIndex,
71 		ScSplitPos eSplitPos,
72         ScAccessibleDocument* pAccDoc)
73 	:
74 	ScAccessibleCellBase(rxParent, GetDocument(pViewShell), rCellAddress, nIndex),
75         ::accessibility::AccessibleStaticTextBase(CreateEditSource(pViewShell, rCellAddress, eSplitPos)),
76 	mpViewShell(pViewShell),
77     mpAccDoc(pAccDoc),
78 	meSplitPos(eSplitPos)
79 {
80 	if (pViewShell)
81 		pViewShell->AddAccessibilityObject(*this);
82 }
83 
84 ScAccessibleCell::~ScAccessibleCell()
85 {
86 	if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose)
87 	{
88 		// increment refcount to prevent double call off dtor
89 		osl_incrementInterlockedCount( &m_refCount );
90 		// call dispose to inform object wich have a weak reference to this object
91 		dispose();
92 	}
93 }
94 
95 void ScAccessibleCell::Init()
96 {
97     ScAccessibleCellBase::Init();
98 
99     SetEventSource(this);
100 }
101 
102 void SAL_CALL ScAccessibleCell::disposing()
103 {
104     ScUnoGuard aGuard;
105     // #100593# dispose in AccessibleStaticTextBase
106     Dispose();
107 
108 	if (mpViewShell)
109 	{
110 		mpViewShell->RemoveAccessibilityObject(*this);
111 		mpViewShell = NULL;
112 	}
113     mpAccDoc = NULL;
114 
115     ScAccessibleCellBase::disposing();
116 }
117 
118 	//=====  XInterface  =====================================================
119 
120 IMPLEMENT_FORWARD_XINTERFACE2( ScAccessibleCell, ScAccessibleCellBase, AccessibleStaticTextBase )
121 
122     //=====  XTypeProvider  ===================================================
123 
124 IMPLEMENT_FORWARD_XTYPEPROVIDER2( ScAccessibleCell, ScAccessibleCellBase, AccessibleStaticTextBase )
125 
126 	//=====  XAccessibleComponent  ============================================
127 
128 uno::Reference< XAccessible > SAL_CALL ScAccessibleCell::getAccessibleAtPoint(
129 		const awt::Point& rPoint )
130 		throw (uno::RuntimeException)
131 {
132     return AccessibleStaticTextBase::getAccessibleAtPoint(rPoint);
133 }
134 
135 void SAL_CALL ScAccessibleCell::grabFocus(  )
136 		throw (uno::RuntimeException)
137 {
138  	ScUnoGuard aGuard;
139     IsObjectValid();
140 	if (getAccessibleParent().is() && mpViewShell)
141 	{
142 		uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY);
143 		if (xAccessibleComponent.is())
144 		{
145 			xAccessibleComponent->grabFocus();
146 			mpViewShell->SetCursor(maCellAddress.Col(), maCellAddress.Row());
147 		}
148 	}
149 }
150 
151 Rectangle ScAccessibleCell::GetBoundingBoxOnScreen(void) const
152 		throw (uno::RuntimeException)
153 {
154 	Rectangle aCellRect(GetBoundingBox());
155 	if (mpViewShell)
156 	{
157 		Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
158 		if (pWindow)
159 		{
160 			Rectangle aRect = pWindow->GetWindowExtentsRelative(NULL);
161 			aCellRect.setX(aCellRect.getX() + aRect.getX());
162 			aCellRect.setY(aCellRect.getY() + aRect.getY());
163 		}
164 	}
165 	return aCellRect;
166 }
167 
168 Rectangle ScAccessibleCell::GetBoundingBox(void) const
169 		throw (uno::RuntimeException)
170 {
171 	Rectangle aCellRect;
172 	if (mpViewShell)
173 	{
174 		long nSizeX, nSizeY;
175 		mpViewShell->GetViewData()->GetMergeSizePixel(
176 			maCellAddress.Col(), maCellAddress.Row(), nSizeX, nSizeY);
177 		aCellRect.SetSize(Size(nSizeX, nSizeY));
178 		aCellRect.SetPos(mpViewShell->GetViewData()->GetScrPos(maCellAddress.Col(), maCellAddress.Row(), meSplitPos, sal_True));
179 
180 		Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
181 		if (pWindow)
182 		{
183 			Rectangle aRect(pWindow->GetWindowExtentsRelative(pWindow->GetAccessibleParentWindow()));
184 			aRect.Move(-aRect.Left(), -aRect.Top());
185 			aCellRect = aRect.Intersection(aCellRect);
186 		}
187 
188         /*  #i19430# Gnopernicus reads text partly if it sticks out of the cell
189             boundaries. This leads to wrong results in cases where the cell
190             text is rotated, because rotation is not taken into account when
191             calculating the visible part of the text. In these cases we will
192             simply expand the cell size to the width of the unrotated text. */
193         if (mpDoc)
194         {
195             const SfxInt32Item* pItem = static_cast< const SfxInt32Item* >(
196                 mpDoc->GetAttr( maCellAddress.Col(), maCellAddress.Row(), maCellAddress.Tab(), ATTR_ROTATE_VALUE ) );
197             if( pItem && (pItem->GetValue() != 0) )
198             {
199                 Rectangle aParaRect = GetParagraphBoundingBox();
200                 if( !aParaRect.IsEmpty() && (aCellRect.GetWidth() < aParaRect.GetWidth()) )
201                     aCellRect.SetSize( Size( aParaRect.GetWidth(), aCellRect.GetHeight() ) );
202             }
203         }
204 	}
205     if (aCellRect.IsEmpty())
206         aCellRect.SetPos(Point(-1, -1));
207 	return aCellRect;
208 }
209 
210 	//=====  XAccessibleContext  ==============================================
211 
212 sal_Int32 SAL_CALL
213 	ScAccessibleCell::getAccessibleChildCount(void)
214     				throw (uno::RuntimeException)
215 {
216     return AccessibleStaticTextBase::getAccessibleChildCount();
217 }
218 
219 uno::Reference< XAccessible > SAL_CALL
220 	ScAccessibleCell::getAccessibleChild(sal_Int32 nIndex)
221         throw (uno::RuntimeException,
222 		lang::IndexOutOfBoundsException)
223 {
224     return AccessibleStaticTextBase::getAccessibleChild(nIndex);
225 }
226 
227 uno::Reference<XAccessibleStateSet> SAL_CALL
228 	ScAccessibleCell::getAccessibleStateSet(void)
229     throw (uno::RuntimeException)
230 {
231 	ScUnoGuard aGuard;
232 	uno::Reference<XAccessibleStateSet> xParentStates;
233 	if (getAccessibleParent().is())
234 	{
235 		uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
236 		xParentStates = xParentContext->getAccessibleStateSet();
237 	}
238 	utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper();
239 	if (IsDefunc(xParentStates))
240 		pStateSet->AddState(AccessibleStateType::DEFUNC);
241     else
242     {
243 	    if (IsEditable(xParentStates))
244 	    {
245 		    pStateSet->AddState(AccessibleStateType::EDITABLE);
246 		    pStateSet->AddState(AccessibleStateType::RESIZABLE);
247 	    }
248 	    pStateSet->AddState(AccessibleStateType::ENABLED);
249 	    pStateSet->AddState(AccessibleStateType::MULTI_LINE);
250 	    pStateSet->AddState(AccessibleStateType::MULTI_SELECTABLE);
251 	    if (IsOpaque(xParentStates))
252 		    pStateSet->AddState(AccessibleStateType::OPAQUE);
253 	    pStateSet->AddState(AccessibleStateType::SELECTABLE);
254 	    if (IsSelected())
255 		    pStateSet->AddState(AccessibleStateType::SELECTED);
256 	    if (isShowing())
257 		    pStateSet->AddState(AccessibleStateType::SHOWING);
258 	    pStateSet->AddState(AccessibleStateType::TRANSIENT);
259 	    if (isVisible())
260 		    pStateSet->AddState(AccessibleStateType::VISIBLE);
261     }
262 	return pStateSet;
263 }
264 
265 uno::Reference<XAccessibleRelationSet> SAL_CALL
266    	ScAccessibleCell::getAccessibleRelationSet(void)
267     throw (uno::RuntimeException)
268 {
269 	ScUnoGuard aGuard;
270     IsObjectValid();
271     utl::AccessibleRelationSetHelper* pRelationSet = NULL;
272     if (mpAccDoc)
273         pRelationSet = mpAccDoc->GetRelationSet(&maCellAddress);
274     if (!pRelationSet)
275 	    pRelationSet = new utl::AccessibleRelationSetHelper();
276 	FillDependends(pRelationSet);
277 	FillPrecedents(pRelationSet);
278 	return pRelationSet;
279 }
280 
281 	//=====  XServiceInfo  ====================================================
282 
283 ::rtl::OUString SAL_CALL ScAccessibleCell::getImplementationName(void)
284         throw (uno::RuntimeException)
285 {
286 	return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessibleCell"));
287 }
288 
289 uno::Sequence< ::rtl::OUString> SAL_CALL
290 	ScAccessibleCell::getSupportedServiceNames(void)
291         throw (uno::RuntimeException)
292 {
293 	uno::Sequence< ::rtl::OUString > aSequence = ScAccessibleContextBase::getSupportedServiceNames();
294     sal_Int32 nOldSize(aSequence.getLength());
295     aSequence.realloc(nOldSize + 1);
296     ::rtl::OUString* pNames = aSequence.getArray();
297 
298 	pNames[nOldSize] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sheet.AccessibleCell"));
299 
300 	return aSequence;
301 }
302 
303 	//====  internal  =========================================================
304 
305 sal_Bool ScAccessibleCell::IsDefunc(
306 	const uno::Reference<XAccessibleStateSet>& rxParentStates)
307 {
308 	return ScAccessibleContextBase::IsDefunc() || (mpDoc == NULL) || (mpViewShell == NULL) || !getAccessibleParent().is() ||
309 		 (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC));
310 }
311 
312 sal_Bool ScAccessibleCell::IsEditable(
313 	const uno::Reference<XAccessibleStateSet>& rxParentStates)
314 {
315 	sal_Bool bEditable(sal_True);
316 	if (rxParentStates.is() && !rxParentStates->contains(AccessibleStateType::EDITABLE) &&
317 		mpDoc)
318 	{
319 		// here I have to test whether the protection of the table should influence this cell.
320 		const ScProtectionAttr* pItem = (const ScProtectionAttr*)mpDoc->GetAttr(
321 			maCellAddress.Col(), maCellAddress.Row(),
322 			maCellAddress.Tab(), ATTR_PROTECTION);
323 		if (pItem)
324 			bEditable = !pItem->GetProtection();
325 	}
326 	return bEditable;
327 }
328 
329 sal_Bool ScAccessibleCell::IsOpaque(
330     const uno::Reference<XAccessibleStateSet>& /* rxParentStates */)
331 {
332 	// test whether there is a background color
333 	sal_Bool bOpaque(sal_True);
334 	if (mpDoc)
335 	{
336 		const SvxBrushItem* pItem = (const SvxBrushItem*)mpDoc->GetAttr(
337 			maCellAddress.Col(), maCellAddress.Row(),
338 			maCellAddress.Tab(), ATTR_BACKGROUND);
339 		if (pItem)
340 			bOpaque = pItem->GetColor() != COL_TRANSPARENT;
341 	}
342 	return bOpaque;
343 }
344 
345 sal_Bool ScAccessibleCell::IsSelected()
346 {
347 	sal_Bool bResult(sal_False);
348 	if (mpViewShell && mpViewShell->GetViewData())
349 	{
350 		const ScMarkData& rMarkdata = mpViewShell->GetViewData()->GetMarkData();
351 		bResult = rMarkdata.IsCellMarked(maCellAddress.Col(), maCellAddress.Row());
352 	}
353 	return bResult;
354 }
355 
356 ScDocument* ScAccessibleCell::GetDocument(ScTabViewShell* pViewShell)
357 {
358 	ScDocument* pDoc = NULL;
359 	if (pViewShell && pViewShell->GetViewData())
360 		pDoc = pViewShell->GetViewData()->GetDocument();
361 	return pDoc;
362 }
363 
364 ::std::auto_ptr< SvxEditSource > ScAccessibleCell::CreateEditSource(ScTabViewShell* pViewShell, ScAddress aCell, ScSplitPos eSplitPos)
365 {
366 	::std::auto_ptr < ScAccessibleTextData > pAccessibleCellTextData
367         ( new ScAccessibleCellTextData( pViewShell, aCell, eSplitPos, this ) );
368 	::std::auto_ptr< SvxEditSource > pEditSource (new ScAccessibilityEditSource(pAccessibleCellTextData));
369 
370     return pEditSource;
371 }
372 
373 void ScAccessibleCell::FillDependends(utl::AccessibleRelationSetHelper* pRelationSet)
374 {
375 	if (mpDoc)
376 	{
377 		ScCellIterator aCellIter( mpDoc, 0,0, maCellAddress.Tab(), MAXCOL,MAXROW, maCellAddress.Tab() );
378 		ScBaseCell* pCell = aCellIter.GetFirst();
379 		while (pCell)
380 		{
381 			if (pCell->GetCellType() == CELLTYPE_FORMULA)
382 			{
383 				sal_Bool bFound(sal_False);
384 				ScDetectiveRefIter aIter( (ScFormulaCell*) pCell );
385                 ScRange aRef;
386 				while ( !bFound && aIter.GetNextRef( aRef ) )
387 				{
388 					if (aRef.In(maCellAddress))
389 						bFound = sal_True;
390 				}
391 				if (bFound)
392 					AddRelation(ScAddress(aCellIter.GetCol(), aCellIter.GetRow(), aCellIter.GetTab()), AccessibleRelationType::CONTROLLER_FOR, pRelationSet);
393 			}
394 			pCell = aCellIter.GetNext();
395 		}
396 	}
397 }
398 
399 void ScAccessibleCell::FillPrecedents(utl::AccessibleRelationSetHelper* pRelationSet)
400 {
401 	if (mpDoc)
402 	{
403 		ScBaseCell* pBaseCell = mpDoc->GetCell(maCellAddress);
404 		if (pBaseCell && (pBaseCell->GetCellType() == CELLTYPE_FORMULA))
405 		{
406 			ScFormulaCell* pFCell = (ScFormulaCell*) pBaseCell;
407 
408 			ScDetectiveRefIter aIter( pFCell );
409             ScRange aRef;
410 			while ( aIter.GetNextRef( aRef ) )
411 			{
412 				AddRelation( aRef, AccessibleRelationType::CONTROLLED_BY, pRelationSet);
413 			}
414 		}
415 	}
416 }
417 
418 void ScAccessibleCell::AddRelation(const ScAddress& rCell,
419 	const sal_uInt16 aRelationType,
420 	utl::AccessibleRelationSetHelper* pRelationSet)
421 {
422 	AddRelation(ScRange(rCell, rCell), aRelationType, pRelationSet);
423 }
424 
425 void ScAccessibleCell::AddRelation(const ScRange& rRange,
426 	const sal_uInt16 aRelationType,
427 	utl::AccessibleRelationSetHelper* pRelationSet)
428 {
429 	uno::Reference < XAccessibleTable > xTable ( getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY );
430 	if (xTable.is())
431 	{
432         sal_uInt32 nCount(static_cast<sal_uInt32>(rRange.aEnd.Col() -
433                     rRange.aStart.Col() + 1) * (rRange.aEnd.Row() -
434                     rRange.aStart.Row() + 1));
435 		uno::Sequence < uno::Reference < uno::XInterface > > aTargetSet( nCount );
436 		uno::Reference < uno::XInterface >* pTargetSet = aTargetSet.getArray();
437 		if (pTargetSet)
438 		{
439 			sal_uInt32 nPos(0);
440             for (sal_uInt32 nRow = rRange.aStart.Row(); nRow <= sal::static_int_cast<sal_uInt32>(rRange.aEnd.Row()); ++nRow)
441 			{
442                 for (sal_uInt32 nCol = rRange.aStart.Col(); nCol <= sal::static_int_cast<sal_uInt32>(rRange.aEnd.Col()); ++nCol)
443 				{
444 					pTargetSet[nPos] = xTable->getAccessibleCellAt(nRow, nCol);
445 					++nPos;
446 				}
447 			}
448 			DBG_ASSERT(nCount == nPos, "something wents wrong");
449 		}
450 		AccessibleRelation aRelation;
451 		aRelation.RelationType = aRelationType;
452 		aRelation.TargetSet = aTargetSet;
453 		pRelationSet->AddRelation(aRelation);
454 	}
455 }
456