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