xref: /trunk/main/sc/source/ui/Accessibility/AccessibleSpreadsheet.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 
32 #include "AccessibleSpreadsheet.hxx"
33 #include "AccessibilityHints.hxx"
34 #include "AccessibleCell.hxx"
35 #include "AccessibleDocument.hxx"
36 #include "tabvwsh.hxx"
37 #include "document.hxx"
38 #include "unoguard.hxx"
39 #include "hints.hxx"
40 #include "scmod.hxx"
41 
42 #ifndef _UTL_ACCESSIBLESTATESETHELPER_HXX
43 #include <unotools/accessiblestatesethelper.hxx>
44 #endif
45 #ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLEROLE_HPP_
46 #include <com/sun/star/accessibility/AccessibleRole.hpp>
47 #endif
48 #ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLESTATETYPE_HPP_
49 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
50 #endif
51 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
52 #include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp>
53 #include <rtl/uuid.h>
54 #include <tools/debug.hxx>
55 #include <tools/gen.hxx>
56 #include <svtools/colorcfg.hxx>
57 
58 #include <algorithm>
59 
60 using namespace ::com::sun::star;
61 using namespace ::com::sun::star::accessibility;
62 
63 //=====  internal  ============================================================
64 
65 ScAccessibleSpreadsheet::ScAccessibleSpreadsheet(
66         ScAccessibleDocument* pAccDoc,
67         ScTabViewShell* pViewShell,
68         SCTAB nTab,
69         ScSplitPos eSplitPos)
70     :
71     ScAccessibleTableBase (pAccDoc, GetDocument(pViewShell),
72         ScRange(ScAddress(0, 0, nTab),ScAddress(MAXCOL, MAXROW, nTab))),
73     mbIsSpreadsheet( sal_True )
74 {
75     ConstructScAccessibleSpreadsheet( pAccDoc, pViewShell, nTab, eSplitPos );
76 }
77 
78 ScAccessibleSpreadsheet::ScAccessibleSpreadsheet(
79         ScAccessibleSpreadsheet& rParent, const ScRange& rRange ) :
80     ScAccessibleTableBase( rParent.mpAccDoc, rParent.mpDoc, rRange),
81     mbIsSpreadsheet( sal_False )
82 {
83     ConstructScAccessibleSpreadsheet( rParent.mpAccDoc, rParent.mpViewShell, rParent.mnTab, rParent.meSplitPos );
84 }
85 
86 ScAccessibleSpreadsheet::~ScAccessibleSpreadsheet()
87 {
88     if (mpMarkedRanges)
89         delete mpMarkedRanges;
90     if (mpSortedMarkedCells)
91         delete mpSortedMarkedCells;
92     if (mpViewShell)
93         mpViewShell->RemoveAccessibilityObject(*this);
94 }
95 
96 void ScAccessibleSpreadsheet::ConstructScAccessibleSpreadsheet(
97     ScAccessibleDocument* pAccDoc,
98     ScTabViewShell* pViewShell,
99     SCTAB nTab,
100     ScSplitPos eSplitPos)
101 {
102     mpViewShell = pViewShell;
103     mpMarkedRanges = 0;
104     mpSortedMarkedCells = 0;
105     mpAccDoc = pAccDoc;
106     mpAccCell = 0;
107     meSplitPos = eSplitPos;
108     mnTab = nTab;
109     mbHasSelection = sal_False;
110     mbDelIns = sal_False;
111     mbIsFocusSend = sal_False;
112     maVisCells = GetVisCells(GetVisArea(mpViewShell, meSplitPos));
113     if (mpViewShell)
114     {
115         mpViewShell->AddAccessibilityObject(*this);
116 
117         const ScViewData& rViewData = *mpViewShell->GetViewData();
118         const ScMarkData& rMarkData = rViewData.GetMarkData();
119         maActiveCell = rViewData.GetCurPos();
120         mbHasSelection = rMarkData.GetTableSelect(maActiveCell.Tab()) &&
121                     (rMarkData.IsMarked() || rMarkData.IsMultiMarked());
122         mpAccCell = GetAccessibleCellAt(maActiveCell.Row(), maActiveCell.Col());
123         mpAccCell->acquire();
124         mpAccCell->Init();
125     }
126 }
127 
128 void SAL_CALL ScAccessibleSpreadsheet::disposing()
129 {
130     ScUnoGuard aGuard;
131     if (mpViewShell)
132     {
133         mpViewShell->RemoveAccessibilityObject(*this);
134         mpViewShell = NULL;
135     }
136     if (mpAccCell)
137     {
138         mpAccCell->release();
139         mpAccCell = NULL;
140     }
141 
142     ScAccessibleTableBase::disposing();
143 }
144 
145 void ScAccessibleSpreadsheet::CompleteSelectionChanged(sal_Bool bNewState)
146 {
147     if (mpMarkedRanges)
148         DELETEZ(mpMarkedRanges);
149     if (mpSortedMarkedCells)
150         DELETEZ(mpSortedMarkedCells);
151 
152     mbHasSelection = bNewState;
153 
154     AccessibleEventObject aEvent;
155     aEvent.EventId = AccessibleEventId::STATE_CHANGED;
156     if (bNewState)
157         aEvent.NewValue = uno::makeAny(AccessibleStateType::SELECTED);
158     else
159         aEvent.OldValue = uno::makeAny(AccessibleStateType::SELECTED);
160     aEvent.Source = uno::Reference< XAccessibleContext >(this);
161 
162     CommitChange(aEvent);
163 }
164 
165 void ScAccessibleSpreadsheet::LostFocus()
166 {
167     AccessibleEventObject aEvent;
168     aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED;
169     aEvent.Source = uno::Reference< XAccessibleContext >(this);
170     uno::Reference< XAccessible > xOld = mpAccCell;
171     aEvent.OldValue <<= xOld;
172 
173     CommitChange(aEvent);
174 
175     CommitFocusLost();
176 }
177 
178 void ScAccessibleSpreadsheet::GotFocus()
179 {
180     CommitFocusGained();
181 
182     AccessibleEventObject aEvent;
183     aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED;
184     aEvent.Source = uno::Reference< XAccessibleContext >(this);
185     uno::Reference< XAccessible > xNew = mpAccCell;
186     aEvent.NewValue <<= xNew;
187 
188     CommitChange(aEvent);
189 }
190 
191 void ScAccessibleSpreadsheet::BoundingBoxChanged()
192 {
193     AccessibleEventObject aEvent;
194     aEvent.EventId = AccessibleEventId::BOUNDRECT_CHANGED;
195     aEvent.Source = uno::Reference< XAccessibleContext >(this);
196 
197     CommitChange(aEvent);
198 }
199 
200 void ScAccessibleSpreadsheet::VisAreaChanged()
201 {
202     AccessibleEventObject aEvent;
203     aEvent.EventId = AccessibleEventId::VISIBLE_DATA_CHANGED;
204     aEvent.Source = uno::Reference< XAccessibleContext >(this);
205 
206     CommitChange(aEvent);
207 }
208 
209     //=====  SfxListener  =====================================================
210 
211 void ScAccessibleSpreadsheet::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
212 {
213     if (rHint.ISA( SfxSimpleHint ) )
214     {
215         const SfxSimpleHint& rRef = (const SfxSimpleHint&)rHint;
216         // only notify if child exist, otherwise it is not necessary
217         if ((rRef.GetId() == SC_HINT_ACC_CURSORCHANGED))
218         {
219             if (mpViewShell)
220             {
221                 ScAddress aNewCell = mpViewShell->GetViewData()->GetCurPos();
222                 sal_Bool bNewMarked(mpViewShell->GetViewData()->GetMarkData().GetTableSelect(aNewCell.Tab()) &&
223                     (mpViewShell->GetViewData()->GetMarkData().IsMarked() ||
224                     mpViewShell->GetViewData()->GetMarkData().IsMultiMarked()));
225                 sal_Bool bNewCellSelected(isAccessibleSelected(aNewCell.Row(), aNewCell.Col()));
226                 if ((bNewMarked != mbHasSelection) ||
227                     (!bNewCellSelected && bNewMarked) ||
228                     (bNewCellSelected && mbHasSelection))
229                 {
230                     if (mpMarkedRanges)
231                         DELETEZ(mpMarkedRanges);
232                     if (mpSortedMarkedCells)
233                         DELETEZ(mpSortedMarkedCells);
234                     AccessibleEventObject aEvent;
235                     aEvent.EventId = AccessibleEventId::SELECTION_CHANGED;
236                     aEvent.Source = uno::Reference< XAccessibleContext >(this);
237 
238                     mbHasSelection = bNewMarked;
239 
240                     CommitChange(aEvent);
241                 }
242 
243                 // active descendant changed event (new cell selected)
244                 bool bFireActiveDescChanged = (aNewCell != maActiveCell) &&
245                     (aNewCell.Tab() == maActiveCell.Tab()) && IsFocused();
246 
247                 /*  Remember old active cell and set new active cell.
248                     #i82409# always update the class members mpAccCell and
249                     maActiveCell, even if the sheet is not focused, e.g. when
250                     using the name box in the toolbar. */
251                 uno::Reference< XAccessible > xOld = mpAccCell;
252                 mpAccCell->release();
253                 mpAccCell = GetAccessibleCellAt(aNewCell.Row(), aNewCell.Col());
254                 mpAccCell->acquire();
255                 mpAccCell->Init();
256                 uno::Reference< XAccessible > xNew = mpAccCell;
257                 maActiveCell = aNewCell;
258 
259                 // #i14108# fire event only if sheet is focused
260                 if( bFireActiveDescChanged )
261                 {
262                     AccessibleEventObject aEvent;
263                     aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED;
264                     aEvent.Source = uno::Reference< XAccessibleContext >(this);
265                     aEvent.OldValue <<= xOld;
266                     aEvent.NewValue <<= xNew;
267                     CommitChange(aEvent);
268                 }
269             }
270         }
271         else if ((rRef.GetId() == SC_HINT_DATACHANGED))
272         {
273             if (!mbDelIns)
274                 CommitTableModelChange(maRange.aStart.Row(), maRange.aStart.Col(), maRange.aEnd.Row(), maRange.aEnd.Col(), AccessibleTableModelChangeType::UPDATE);
275             else
276                 mbDelIns = sal_False;
277         }
278         // no longer needed, because the document calls the VisAreaChanged method
279 /*      else if (rRef.GetId() == SC_HINT_ACC_VISAREACHANGED)
280         {
281             AccessibleEventObject aEvent;
282             aEvent.EventId = AccessibleEventId::VISIBLE_DATA_CHANGED;
283             aEvent.Source = uno::Reference< XAccessibleContext >(this);
284 
285             CommitChange(aEvent);*/
286         // commented out, because to use a ModelChangeEvent is not the right way
287         // at the moment there is no way, but the Java/Gnome Api should be extended sometime
288 /*          if (mpViewShell)
289             {
290                 Rectangle aNewVisCells(GetVisCells(GetVisArea(mpViewShell, meSplitPos)));
291 
292                 Rectangle aNewPos(aNewVisCells);
293 
294                 if (aNewVisCells.IsOver(maVisCells))
295                     aNewPos.Union(maVisCells);
296                 else
297                     CommitTableModelChange(maVisCells.Top(), maVisCells.Left(), maVisCells.Bottom(), maVisCells.Right(), AccessibleTableModelChangeType::UPDATE);
298 
299                 maVisCells = aNewVisCells;
300 
301                 CommitTableModelChange(aNewPos.Top(), aNewPos.Left(), aNewPos.Bottom(), aNewPos.Right(), AccessibleTableModelChangeType::UPDATE);
302             }
303         }*/
304         // no longer needed, because the document calls the BoundingBoxChanged method
305 /*        else if (rRef.GetId() == SC_HINT_ACC_WINDOWRESIZED)
306         {
307             AccessibleEventObject aEvent;
308             aEvent.EventId = AccessibleEventId::BOUNDRECT_CHANGED;
309             aEvent.Source = uno::Reference< XAccessibleContext >(this);
310 
311             CommitChange(aEvent);
312         }*/
313     }
314     else if (rHint.ISA( ScUpdateRefHint ))
315     {
316         const ScUpdateRefHint& rRef = (const ScUpdateRefHint&)rHint;
317         if (rRef.GetMode() == URM_INSDEL && rRef.GetDz() == 0) //#107250# test whether table is inserted or deleted
318         {
319             if (((rRef.GetRange().aStart.Col() == maRange.aStart.Col()) &&
320                 (rRef.GetRange().aEnd.Col() == maRange.aEnd.Col())) ||
321                 ((rRef.GetRange().aStart.Row() == maRange.aStart.Row()) &&
322                 (rRef.GetRange().aEnd.Row() == maRange.aEnd.Row())))
323             {
324                 // ignore next SC_HINT_DATACHANGED notification
325                 mbDelIns = sal_True;
326 
327                 sal_Int16 nId(0);
328                 SCsCOL nX(rRef.GetDx());
329                 SCsROW nY(rRef.GetDy());
330                 ScRange aRange(rRef.GetRange());
331                 if ((nX < 0) || (nY < 0))
332                 {
333                     DBG_ASSERT(!((nX < 0) && (nY < 0)), "should not be possible to remove row and column at the same time");
334                     nId = AccessibleTableModelChangeType::DELETE;
335                     if (nX < 0)
336                     {
337                         nX = -nX;
338                         nY = aRange.aEnd.Row() - aRange.aStart.Row();
339                     }
340                     else
341                     {
342                         nY = -nY;
343                         nX = aRange.aEnd.Col() - aRange.aStart.Col();
344                     }
345                 }
346                 else if ((nX > 0) || (nY > 0))
347                 {
348                     DBG_ASSERT(!((nX > 0) && (nY > 0)), "should not be possible to add row and column at the same time");
349                     nId = AccessibleTableModelChangeType::INSERT;
350                     if (nX < 0)
351                         nY = aRange.aEnd.Row() - aRange.aStart.Row();
352                     else
353                         nX = aRange.aEnd.Col() - aRange.aStart.Col();
354                 }
355                 else
356                 {
357                     DBG_ERROR("is it a deletion or a insertion?");
358                 }
359 
360                 CommitTableModelChange(rRef.GetRange().aStart.Row(),
361                     rRef.GetRange().aStart.Col(),
362                     rRef.GetRange().aStart.Row() + nY,
363                     rRef.GetRange().aStart.Col() + nX, nId);
364 
365                 AccessibleEventObject aEvent;
366                 aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED;
367                 aEvent.Source = uno::Reference< XAccessibleContext >(this);
368                 uno::Reference< XAccessible > xNew = mpAccCell;
369                 aEvent.NewValue <<= xNew;
370 
371                 CommitChange(aEvent);
372             }
373         }
374     }
375 
376     ScAccessibleTableBase::Notify(rBC, rHint);
377 }
378 
379     //=====  XAccessibleTable  ================================================
380 
381 uno::Reference< XAccessibleTable > SAL_CALL ScAccessibleSpreadsheet::getAccessibleRowHeaders(  )
382                     throw (uno::RuntimeException)
383 {
384     ScUnoGuard aGuard;
385     IsObjectValid();
386     uno::Reference< XAccessibleTable > xAccessibleTable;
387     if( mpDoc && mbIsSpreadsheet )
388     {
389         if( const ScRange* pRowRange = mpDoc->GetRepeatRowRange( mnTab ) )
390         {
391             SCROW nStart = pRowRange->aStart.Row();
392             SCROW nEnd = pRowRange->aEnd.Row();
393             if( (0 <= nStart) && (nStart <= nEnd) && (nEnd <= MAXROW) )
394                 xAccessibleTable.set( new ScAccessibleSpreadsheet( *this, ScRange( 0, nStart, mnTab, MAXCOL, nEnd, mnTab ) ) );
395         }
396     }
397     return xAccessibleTable;
398 }
399 
400 uno::Reference< XAccessibleTable > SAL_CALL ScAccessibleSpreadsheet::getAccessibleColumnHeaders(  )
401                     throw (uno::RuntimeException)
402 {
403     ScUnoGuard aGuard;
404     IsObjectValid();
405     uno::Reference< XAccessibleTable > xAccessibleTable;
406     if( mpDoc && mbIsSpreadsheet )
407     {
408         if( const ScRange* pColRange = mpDoc->GetRepeatColRange( mnTab ) )
409         {
410             SCCOL nStart = pColRange->aStart.Col();
411             SCCOL nEnd = pColRange->aEnd.Col();
412             if( (0 <= nStart) && (nStart <= nEnd) && (nEnd <= MAXCOL) )
413                 xAccessibleTable.set( new ScAccessibleSpreadsheet( *this, ScRange( nStart, 0, mnTab, nEnd, MAXROW, mnTab ) ) );
414         }
415     }
416     return xAccessibleTable;
417 }
418 
419 uno::Sequence< sal_Int32 > SAL_CALL ScAccessibleSpreadsheet::getSelectedAccessibleRows(  )
420                     throw (uno::RuntimeException)
421 {
422     ScUnoGuard aGuard;
423     IsObjectValid();
424     uno::Sequence<sal_Int32> aSequence;
425     if (mpViewShell && mpViewShell->GetViewData())
426     {
427         aSequence.realloc(maRange.aEnd.Row() - maRange.aStart.Row() + 1);
428         const ScMarkData& rMarkdata = mpViewShell->GetViewData()->GetMarkData();
429         sal_Int32* pSequence = aSequence.getArray();
430         sal_Int32 nCount(0);
431         for (SCROW i = maRange.aStart.Row(); i <= maRange.aEnd.Row(); ++i)
432         {
433             if (rMarkdata.IsRowMarked(i))
434             {
435                 pSequence[nCount] = i;
436                 ++nCount;
437             }
438         }
439         aSequence.realloc(nCount);
440     }
441     else
442         aSequence.realloc(0);
443     return aSequence;
444 }
445 
446 uno::Sequence< sal_Int32 > SAL_CALL ScAccessibleSpreadsheet::getSelectedAccessibleColumns(  )
447                     throw (uno::RuntimeException)
448 {
449     ScUnoGuard aGuard;
450     IsObjectValid();
451     uno::Sequence<sal_Int32> aSequence;
452     if (mpViewShell && mpViewShell->GetViewData())
453     {
454         aSequence.realloc(maRange.aEnd.Col() - maRange.aStart.Col() + 1);
455         const ScMarkData& rMarkdata = mpViewShell->GetViewData()->GetMarkData();
456         sal_Int32* pSequence = aSequence.getArray();
457         sal_Int32 nCount(0);
458         for (SCCOL i = maRange.aStart.Col(); i <= maRange.aEnd.Col(); ++i)
459         {
460             if (rMarkdata.IsColumnMarked(i))
461             {
462                 pSequence[nCount] = i;
463                 ++nCount;
464             }
465         }
466         aSequence.realloc(nCount);
467     }
468     else
469         aSequence.realloc(0);
470     return aSequence;
471 }
472 
473 sal_Bool SAL_CALL ScAccessibleSpreadsheet::isAccessibleRowSelected( sal_Int32 nRow )
474     throw (uno::RuntimeException, lang::IndexOutOfBoundsException)
475 {
476     ScUnoGuard aGuard;
477     IsObjectValid();
478 
479     if ((nRow > (maRange.aEnd.Row() - maRange.aStart.Row())) || (nRow < 0))
480         throw lang::IndexOutOfBoundsException();
481 
482     sal_Bool bResult(sal_False);
483     if (mpViewShell && mpViewShell->GetViewData())
484     {
485         const ScMarkData& rMarkdata = mpViewShell->GetViewData()->GetMarkData();
486         bResult = rMarkdata.IsRowMarked((SCROW)nRow);
487     }
488     return bResult;
489 }
490 
491 sal_Bool SAL_CALL ScAccessibleSpreadsheet::isAccessibleColumnSelected( sal_Int32 nColumn )
492     throw (uno::RuntimeException, lang::IndexOutOfBoundsException)
493 {
494     ScUnoGuard aGuard;
495     IsObjectValid();
496 
497     if ((nColumn > (maRange.aEnd.Col() - maRange.aStart.Col())) || (nColumn < 0))
498         throw lang::IndexOutOfBoundsException();
499 
500     sal_Bool bResult(sal_False);
501     if (mpViewShell && mpViewShell->GetViewData())
502     {
503         const ScMarkData& rMarkdata = mpViewShell->GetViewData()->GetMarkData();
504         bResult = rMarkdata.IsColumnMarked((SCCOL)nColumn);
505     }
506     return bResult;
507 }
508 
509 ScAccessibleCell* ScAccessibleSpreadsheet::GetAccessibleCellAt(sal_Int32 nRow, sal_Int32 nColumn)
510 {
511     ScAccessibleCell* pAccessibleCell = NULL;
512     ScAddress aCellAddress(static_cast<SCCOL>(maRange.aStart.Col() + nColumn),
513         static_cast<SCROW>(maRange.aStart.Row() + nRow), maRange.aStart.Tab());
514     if ((aCellAddress == maActiveCell) && mpAccCell)
515     {
516         pAccessibleCell = mpAccCell;
517     }
518     else
519         pAccessibleCell = new ScAccessibleCell(this, mpViewShell, aCellAddress, getAccessibleIndex(nRow, nColumn), meSplitPos, mpAccDoc);
520 
521     return pAccessibleCell;
522 }
523 
524 uno::Reference< XAccessible > SAL_CALL ScAccessibleSpreadsheet::getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn )
525                     throw (uno::RuntimeException, lang::IndexOutOfBoundsException)
526 {
527     ScUnoGuard aGuard;
528     IsObjectValid();
529     if (nRow > (maRange.aEnd.Row() - maRange.aStart.Row()) ||
530         nRow < 0 ||
531         nColumn > (maRange.aEnd.Col() - maRange.aStart.Col()) ||
532         nColumn < 0)
533         throw lang::IndexOutOfBoundsException();
534 
535     uno::Reference<XAccessible> xAccessible;
536     ScAccessibleCell* pAccessibleCell = GetAccessibleCellAt(nRow, nColumn);
537     xAccessible = pAccessibleCell;
538     pAccessibleCell->Init();
539     return xAccessible;
540 }
541 
542 sal_Bool SAL_CALL ScAccessibleSpreadsheet::isAccessibleSelected( sal_Int32 nRow, sal_Int32 nColumn )
543     throw (uno::RuntimeException, lang::IndexOutOfBoundsException)
544 {
545     ScUnoGuard aGuard;
546     IsObjectValid();
547 
548     if ((nColumn > (maRange.aEnd.Col() - maRange.aStart.Col())) || (nColumn < 0) ||
549         (nRow > (maRange.aEnd.Row() - maRange.aStart.Row())) || (nRow < 0))
550         throw lang::IndexOutOfBoundsException();
551 
552     sal_Bool bResult(sal_False);
553     if (mpViewShell)
554     {
555         const ScMarkData& rMarkdata = mpViewShell->GetViewData()->GetMarkData();
556         bResult = rMarkdata.IsCellMarked(static_cast<SCCOL>(nColumn), static_cast<SCROW>(nRow));
557     }
558     return bResult;
559 }
560 
561     //=====  XAccessibleComponent  ============================================
562 
563 uno::Reference< XAccessible > SAL_CALL ScAccessibleSpreadsheet::getAccessibleAtPoint(
564     const awt::Point& rPoint )
565         throw (uno::RuntimeException)
566 {
567     uno::Reference< XAccessible > xAccessible;
568     if (containsPoint(rPoint))
569     {
570         ScUnoGuard aGuard;
571         IsObjectValid();
572         if (mpViewShell)
573         {
574             SCsCOL nX;
575             SCsROW nY;
576             mpViewShell->GetViewData()->GetPosFromPixel( rPoint.X, rPoint.Y, meSplitPos, nX, nY);
577             xAccessible = getAccessibleCellAt(nY, nX);
578         }
579     }
580     return xAccessible;
581 }
582 
583 void SAL_CALL ScAccessibleSpreadsheet::grabFocus(  )
584         throw (uno::RuntimeException)
585 {
586     if (getAccessibleParent().is())
587     {
588         uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY);
589         if (xAccessibleComponent.is())
590             xAccessibleComponent->grabFocus();
591     }
592 }
593 
594 sal_Int32 SAL_CALL ScAccessibleSpreadsheet::getForeground(  )
595         throw (uno::RuntimeException)
596 {
597     return COL_BLACK;
598 }
599 
600 sal_Int32 SAL_CALL ScAccessibleSpreadsheet::getBackground(  )
601         throw (uno::RuntimeException)
602 {
603     ScUnoGuard aGuard;
604     IsObjectValid();
605     return SC_MOD()->GetColorConfig().GetColorValue( ::svtools::DOCCOLOR ).nColor;
606 }
607 
608     //=====  XAccessibleContext  ==============================================
609 
610 uno::Reference<XAccessibleRelationSet> SAL_CALL ScAccessibleSpreadsheet::getAccessibleRelationSet(void)
611         throw (::com::sun::star::uno::RuntimeException)
612 {
613     utl::AccessibleRelationSetHelper* pRelationSet = NULL;
614     if(mpAccDoc)
615         pRelationSet = mpAccDoc->GetRelationSet(NULL);
616     if (!pRelationSet)
617         pRelationSet = new utl::AccessibleRelationSetHelper();
618     return pRelationSet;
619 }
620 
621 uno::Reference<XAccessibleStateSet> SAL_CALL
622     ScAccessibleSpreadsheet::getAccessibleStateSet(void)
623     throw (uno::RuntimeException)
624 {
625     ScUnoGuard aGuard;
626     uno::Reference<XAccessibleStateSet> xParentStates;
627     if (getAccessibleParent().is())
628     {
629         uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
630         xParentStates = xParentContext->getAccessibleStateSet();
631     }
632     utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper();
633     if (IsDefunc(xParentStates))
634         pStateSet->AddState(AccessibleStateType::DEFUNC);
635     else
636     {
637         pStateSet->AddState(AccessibleStateType::MANAGES_DESCENDANTS);
638         if (IsEditable(xParentStates))
639             pStateSet->AddState(AccessibleStateType::EDITABLE);
640         pStateSet->AddState(AccessibleStateType::ENABLED);
641         pStateSet->AddState(AccessibleStateType::FOCUSABLE);
642         if (IsFocused())
643             pStateSet->AddState(AccessibleStateType::FOCUSED);
644         pStateSet->AddState(AccessibleStateType::MULTI_SELECTABLE);
645         pStateSet->AddState(AccessibleStateType::OPAQUE);
646         pStateSet->AddState(AccessibleStateType::SELECTABLE);
647         if (IsCompleteSheetSelected())
648             pStateSet->AddState(AccessibleStateType::SELECTED);
649         if (isShowing())
650             pStateSet->AddState(AccessibleStateType::SHOWING);
651         if (isVisible())
652             pStateSet->AddState(AccessibleStateType::VISIBLE);
653     }
654     return pStateSet;
655 }
656 
657     ///=====  XAccessibleSelection  ===========================================
658 
659 void SAL_CALL
660         ScAccessibleSpreadsheet::selectAccessibleChild( sal_Int32 nChildIndex )
661         throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
662 {
663     ScUnoGuard aGuard;
664     IsObjectValid();
665     if (nChildIndex < 0 || nChildIndex >= getAccessibleChildCount())
666         throw lang::IndexOutOfBoundsException();
667 
668     if (mpViewShell)
669     {
670         sal_Int32 nCol(getAccessibleColumn(nChildIndex));
671         sal_Int32 nRow(getAccessibleRow(nChildIndex));
672 
673         SelectCell(nRow, nCol, sal_False);
674     }
675 }
676 
677 void SAL_CALL
678         ScAccessibleSpreadsheet::clearAccessibleSelection(  )
679         throw (uno::RuntimeException)
680 {
681     ScUnoGuard aGuard;
682     IsObjectValid();
683     if (mpViewShell)
684     {
685         mpViewShell->Unmark();
686     }
687 }
688 
689 void SAL_CALL
690         ScAccessibleSpreadsheet::selectAllAccessibleChildren(  )
691         throw (uno::RuntimeException)
692 {
693     ScUnoGuard aGuard;
694     IsObjectValid();
695     if (mpViewShell)
696     {
697         mpViewShell->SelectAll();
698     }
699 }
700 
701 sal_Int32 SAL_CALL
702         ScAccessibleSpreadsheet::getSelectedAccessibleChildCount(  )
703         throw (uno::RuntimeException)
704 {
705     ScUnoGuard aGuard;
706     IsObjectValid();
707     sal_Int32 nResult(0);
708     if (mpViewShell)
709     {
710         if (!mpMarkedRanges)
711         {
712             mpMarkedRanges = new ScRangeList();
713             ScMarkData aMarkData(mpViewShell->GetViewData()->GetMarkData());
714             aMarkData.MarkToMulti();
715             aMarkData.FillRangeListWithMarks(mpMarkedRanges, sal_False);
716         }
717         // is possible, because there shouldn't be overlapped ranges in it
718         if (mpMarkedRanges)
719             nResult = mpMarkedRanges->GetCellCount();
720     }
721     return nResult;
722 }
723 
724 uno::Reference<XAccessible > SAL_CALL
725         ScAccessibleSpreadsheet::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex )
726         throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
727 {
728     ScUnoGuard aGuard;
729     IsObjectValid();
730     uno::Reference < XAccessible > xAccessible;
731     if (mpViewShell)
732     {
733         if (!mpMarkedRanges)
734         {
735             mpMarkedRanges = new ScRangeList();
736             mpViewShell->GetViewData()->GetMarkData().FillRangeListWithMarks(mpMarkedRanges, sal_False);
737         }
738         if (mpMarkedRanges)
739         {
740             if (!mpSortedMarkedCells)
741                 CreateSortedMarkedCells();
742             if (mpSortedMarkedCells)
743             {
744                 if ((nSelectedChildIndex < 0) ||
745                     (mpSortedMarkedCells->size() <= static_cast<sal_uInt32>(nSelectedChildIndex)))
746                     throw lang::IndexOutOfBoundsException();
747                 else
748                     xAccessible = getAccessibleCellAt((*mpSortedMarkedCells)[nSelectedChildIndex].Row(), (*mpSortedMarkedCells)[nSelectedChildIndex].Col());
749             }
750         }
751     }
752     return xAccessible;
753 }
754 
755 void SAL_CALL
756         ScAccessibleSpreadsheet::deselectAccessibleChild( sal_Int32 nChildIndex )
757         throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
758 {
759     ScUnoGuard aGuard;
760     IsObjectValid();
761 
762     if (nChildIndex < 0 || nChildIndex >= getAccessibleChildCount())
763         throw lang::IndexOutOfBoundsException();
764 
765     if (mpViewShell)
766     {
767         sal_Int32 nCol(getAccessibleColumn(nChildIndex));
768         sal_Int32 nRow(getAccessibleRow(nChildIndex));
769 
770         if (mpViewShell->GetViewData()->GetMarkData().IsCellMarked(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow)))
771             SelectCell(nRow, nCol, sal_True);
772     }
773 }
774 
775 void ScAccessibleSpreadsheet::SelectCell(sal_Int32 nRow, sal_Int32 nCol, sal_Bool bDeselect)
776 {
777     mpViewShell->SetTabNo( maRange.aStart.Tab() );
778 
779     mpViewShell->DoneBlockMode( sal_True ); // continue selecting
780     mpViewShell->InitBlockMode( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), maRange.aStart.Tab(), bDeselect, sal_False, sal_False );
781 
782     mpViewShell->SelectionChanged();
783 }
784 
785 void ScAccessibleSpreadsheet::CreateSortedMarkedCells()
786 {
787     mpSortedMarkedCells = new std::vector<ScMyAddress>();
788     mpSortedMarkedCells->reserve(mpMarkedRanges->GetCellCount());
789     ScRange* pRange = mpMarkedRanges->First();
790     while (pRange)
791     {
792         if (pRange->aStart.Tab() != pRange->aEnd.Tab())
793         {
794             if ((maActiveCell.Tab() >= pRange->aStart.Tab()) ||
795                 maActiveCell.Tab() <= pRange->aEnd.Tab())
796             {
797                 ScRange aRange(*pRange);
798                 aRange.aStart.SetTab(maActiveCell.Tab());
799                 aRange.aEnd.SetTab(maActiveCell.Tab());
800                 AddMarkedRange(aRange);
801             }
802             else
803             {
804                 DBG_ERROR("Range of wrong table");
805             }
806         }
807         else if(pRange->aStart.Tab() == maActiveCell.Tab())
808             AddMarkedRange(*pRange);
809         else
810         {
811             DBG_ERROR("Range of wrong table");
812         }
813         pRange = mpMarkedRanges->Next();
814     }
815     std::sort(mpSortedMarkedCells->begin(), mpSortedMarkedCells->end());
816 }
817 
818 void ScAccessibleSpreadsheet::AddMarkedRange(const ScRange& rRange)
819 {
820     for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
821     {
822         for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
823         {
824             ScMyAddress aCell(nCol, nRow, maActiveCell.Tab());
825             mpSortedMarkedCells->push_back(aCell);
826         }
827     }
828 }
829 
830     //=====  XServiceInfo  ====================================================
831 
832 ::rtl::OUString SAL_CALL ScAccessibleSpreadsheet::getImplementationName(void)
833         throw (uno::RuntimeException)
834 {
835     return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessibleSpreadsheet"));
836 }
837 
838 uno::Sequence< ::rtl::OUString> SAL_CALL
839     ScAccessibleSpreadsheet::getSupportedServiceNames (void)
840         throw (uno::RuntimeException)
841 {
842     uno::Sequence< ::rtl::OUString > aSequence = ScAccessibleTableBase::getSupportedServiceNames();
843     sal_Int32 nOldSize(aSequence.getLength());
844     aSequence.realloc(nOldSize + 1);
845     ::rtl::OUString* pNames = aSequence.getArray();
846 
847     pNames[nOldSize] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.AccessibleSpreadsheet"));
848 
849     return aSequence;
850 }
851 
852 //=====  XTypeProvider  =======================================================
853 
854 uno::Sequence<sal_Int8> SAL_CALL
855     ScAccessibleSpreadsheet::getImplementationId(void)
856     throw (uno::RuntimeException)
857 {
858     ScUnoGuard aGuard;
859     IsObjectValid();
860     static uno::Sequence<sal_Int8> aId;
861     if (aId.getLength() == 0)
862     {
863         aId.realloc (16);
864         rtl_createUuid (reinterpret_cast<sal_uInt8 *>(aId.getArray()), 0, sal_True);
865     }
866     return aId;
867 }
868 
869 ///=====  XAccessibleEventBroadcaster  =====================================
870 
871 void SAL_CALL ScAccessibleSpreadsheet::addEventListener(const uno::Reference<XAccessibleEventListener>& xListener)
872         throw (uno::RuntimeException)
873 {
874     ScUnoGuard aGuard;
875     IsObjectValid();
876     ScAccessibleTableBase::addEventListener(xListener);
877 
878     if (!mbIsFocusSend)
879     {
880         mbIsFocusSend = sal_True;
881         CommitFocusGained();
882 
883         AccessibleEventObject aEvent;
884         aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED;
885         aEvent.Source = uno::Reference< XAccessibleContext >(this);
886         aEvent.NewValue <<= getAccessibleCellAt(maActiveCell.Row(), maActiveCell.Col());
887 
888         CommitChange(aEvent);
889     }
890 }
891 
892     //====  internal  =========================================================
893 
894 Rectangle ScAccessibleSpreadsheet::GetBoundingBoxOnScreen() const
895     throw (uno::RuntimeException)
896 {
897     Rectangle aRect;
898     if (mpViewShell)
899     {
900         Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
901         if (pWindow)
902             aRect = pWindow->GetWindowExtentsRelative(NULL);
903     }
904     return aRect;
905 }
906 
907 Rectangle ScAccessibleSpreadsheet::GetBoundingBox() const
908     throw (uno::RuntimeException)
909 {
910     Rectangle aRect;
911     if (mpViewShell)
912     {
913         Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
914         if (pWindow)
915             //#101986#; extends to the same window, because the parent is the document and it has the same window
916             aRect = pWindow->GetWindowExtentsRelative(pWindow);
917     }
918     return aRect;
919 }
920 
921 sal_Bool ScAccessibleSpreadsheet::IsDefunc(
922     const uno::Reference<XAccessibleStateSet>& rxParentStates)
923 {
924     return ScAccessibleContextBase::IsDefunc() || (mpViewShell == NULL) || !getAccessibleParent().is() ||
925         (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC));
926 }
927 
928 sal_Bool ScAccessibleSpreadsheet::IsEditable(
929     const uno::Reference<XAccessibleStateSet>& /* rxParentStates */)
930 {
931     sal_Bool bProtected(sal_False);
932     if (mpDoc && mpDoc->IsTabProtected(maRange.aStart.Tab()))
933         bProtected = sal_True;
934     return !bProtected;
935 }
936 
937 sal_Bool ScAccessibleSpreadsheet::IsFocused()
938 {
939     sal_Bool bFocused(sal_False);
940     if (mpViewShell)
941     {
942         if (mpViewShell->GetViewData()->GetActivePart() == meSplitPos)
943             bFocused = mpViewShell->GetActiveWin()->HasFocus();
944     }
945     return bFocused;
946 }
947 
948 sal_Bool ScAccessibleSpreadsheet::IsCompleteSheetSelected()
949 {
950     sal_Bool bResult(sal_False);
951     if(mpViewShell)
952     {
953         //#103800#; use a copy of MarkData
954         ScMarkData aMarkData(mpViewShell->GetViewData()->GetMarkData());
955         aMarkData.MarkToMulti();
956         if (aMarkData.IsAllMarked(maRange))
957             bResult = sal_True;
958     }
959     return bResult;
960 }
961 
962 ScDocument* ScAccessibleSpreadsheet::GetDocument(ScTabViewShell* pViewShell)
963 {
964     ScDocument* pDoc = NULL;
965     if (pViewShell)
966         pDoc = pViewShell->GetViewData()->GetDocument();
967     return pDoc;
968 }
969 
970 Rectangle ScAccessibleSpreadsheet::GetVisArea(ScTabViewShell* pViewShell, ScSplitPos eSplitPos)
971 {
972     Rectangle aVisArea;
973     if (pViewShell)
974     {
975         Window* pWindow = pViewShell->GetWindowByPos(eSplitPos);
976         if (pWindow)
977         {
978             aVisArea.SetPos(pViewShell->GetViewData()->GetPixPos(eSplitPos));
979             aVisArea.SetSize(pWindow->GetSizePixel());
980         }
981     }
982     return aVisArea;
983 }
984 
985 Rectangle ScAccessibleSpreadsheet::GetVisCells(const Rectangle& rVisArea)
986 {
987     if (mpViewShell)
988     {
989         SCsCOL nStartX, nEndX;
990         SCsROW nStartY, nEndY;
991 
992         mpViewShell->GetViewData()->GetPosFromPixel( 1, 1, meSplitPos, nStartX, nStartY);
993         mpViewShell->GetViewData()->GetPosFromPixel( rVisArea.GetWidth(), rVisArea.GetHeight(), meSplitPos, nEndX, nEndY);
994 
995         return Rectangle(nStartX, nStartY, nEndX, nEndY);
996     }
997     else
998         return Rectangle();
999 }
1000