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