xref: /AOO41X/main/sc/source/ui/Accessibility/AccessibleCell.cxx (revision 54628ca40d27d15cc98fe861da7fff7e60c2f7d6)
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