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