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