tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / Accessibility / AccessibleDocumentPagePreview.cxx
blob5ba18208d1106f16553a4e2aad2f83cd9cef1705
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <AccessibleDocumentPagePreview.hxx>
21 #include <AccessiblePreviewTable.hxx>
22 #include <AccessiblePageHeader.hxx>
23 #include <AccessibilityHints.hxx>
24 #include <AccessibleText.hxx>
25 #include <document.hxx>
26 #include <prevwsh.hxx>
27 #include <prevloc.hxx>
28 #include <drwlayer.hxx>
29 #include <editsrc.hxx>
30 #include <scresid.hxx>
31 #include <strings.hrc>
32 #include <strings.hxx>
33 #include <preview.hxx>
34 #include <postit.hxx>
36 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
37 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
38 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
39 #include <comphelper/sequence.hxx>
41 #include <tools/gen.hxx>
42 #include <svx/fmview.hxx>
43 #include <svx/svdpage.hxx>
44 #include <svx/svdobj.hxx>
45 #include <svx/AccessibleTextHelper.hxx>
46 #include <svx/AccessibleShape.hxx>
47 #include <svx/AccessibleShapeInfo.hxx>
48 #include <svx/IAccessibleParent.hxx>
49 #include <svx/IAccessibleViewForwarder.hxx>
50 #include <svx/ShapeTypeHandler.hxx>
51 #include <toolkit/helper/vclunohelper.hxx>
52 #include <vcl/svapp.hxx>
53 #include <vcl/unohelp.hxx>
54 #include <sfx2/docfile.hxx>
56 #include <vector>
57 #include <algorithm>
58 #include <memory>
59 #include <utility>
61 using namespace ::com::sun::star;
62 using namespace ::com::sun::star::accessibility;
64 typedef std::vector< uno::Reference< XAccessible > > ScXAccVector;
66 namespace {
68 struct ScAccNote
70 OUString maNoteText;
71 tools::Rectangle maRect;
72 ScAddress maNoteCell;
73 ::accessibility::AccessibleTextHelper* mpTextHelper;
74 sal_Int32 mnParaCount;
75 bool mbMarkNote;
77 ScAccNote()
78 : mpTextHelper(nullptr)
79 , mnParaCount(0)
80 , mbMarkNote(false)
87 class ScNotesChildren
89 public:
90 ScNotesChildren(ScPreviewShell* pViewShell, ScAccessibleDocumentPagePreview* pAccDoc);
91 ~ScNotesChildren();
92 void Init(const tools::Rectangle& rVisRect, sal_Int32 nOffset);
94 sal_Int32 GetChildrenCount() const { return mnParagraphs;}
95 uno::Reference<XAccessible> GetChild(sal_Int32 nIndex) const;
96 uno::Reference<XAccessible> GetAt(const awt::Point& rPoint) const;
98 void DataChanged(const tools::Rectangle& rVisRect);
100 private:
101 ScPreviewShell* mpViewShell;
102 ScAccessibleDocumentPagePreview* mpAccDoc;
103 typedef std::vector<ScAccNote> ScAccNotes;
104 mutable ScAccNotes maNotes;
105 mutable ScAccNotes maMarks;
106 sal_Int32 mnParagraphs;
107 sal_Int32 mnOffset;
109 ::accessibility::AccessibleTextHelper* CreateTextHelper(const OUString& rString, const tools::Rectangle& rVisRect, const ScAddress& aCellPos, bool bMarkNote, sal_Int32 nChildOffset) const;
110 sal_Int32 AddNotes(const ScPreviewLocationData& rData, const tools::Rectangle& rVisRect, bool bMark, ScAccNotes& rNotes);
112 static sal_Int8 CompareCell(const ScAddress& aCell1, const ScAddress& aCell2);
113 static void CollectChildren(const ScAccNote& rNote, ScXAccVector& rVector);
114 sal_Int32 CheckChanges(const ScPreviewLocationData& rData, const tools::Rectangle& rVisRect,
115 bool bMark, ScAccNotes& rOldNotes, ScAccNotes& rNewNotes,
116 ScXAccVector& rOldParas, ScXAccVector& rNewParas);
118 inline ScDocument* GetDocument() const;
121 ScNotesChildren::ScNotesChildren(ScPreviewShell* pViewShell, ScAccessibleDocumentPagePreview* pAccDoc)
122 : mpViewShell(pViewShell),
123 mpAccDoc(pAccDoc),
124 mnParagraphs(0),
125 mnOffset(0)
129 ScNotesChildren::~ScNotesChildren()
131 for (auto & i : maNotes)
132 if (i.mpTextHelper)
134 delete i.mpTextHelper;
135 i.mpTextHelper = nullptr;
137 for (auto & i : maMarks)
138 if (i.mpTextHelper)
140 delete i.mpTextHelper;
141 i.mpTextHelper = nullptr;
145 ::accessibility::AccessibleTextHelper* ScNotesChildren::CreateTextHelper(const OUString& rString, const tools::Rectangle& rVisRect, const ScAddress& aCellPos, bool bMarkNote, sal_Int32 nChildOffset) const
147 ::accessibility::AccessibleTextHelper* pTextHelper = new ::accessibility::AccessibleTextHelper(std::make_unique<ScAccessibilityEditSource>(std::make_unique<ScAccessibleNoteTextData>(mpViewShell, rString, aCellPos, bMarkNote)));
148 pTextHelper->SetEventSource(mpAccDoc);
149 pTextHelper->SetStartIndex(nChildOffset);
150 pTextHelper->SetOffset(rVisRect.TopLeft());
152 return pTextHelper;
155 sal_Int32 ScNotesChildren::AddNotes(const ScPreviewLocationData& rData, const tools::Rectangle& rVisRect, bool bMark, ScAccNotes& rNotes)
157 sal_Int32 nCount = rData.GetNoteCountInRange(rVisRect, bMark);
159 rNotes.reserve(nCount);
161 sal_Int32 nParagraphs(0);
162 ScDocument* pDoc = GetDocument();
163 if (pDoc)
165 ScAccNote aNote;
166 aNote.mbMarkNote = bMark;
167 if (bMark)
168 aNote.mnParaCount = 1;
169 for (sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex)
171 if (rData.GetNoteInRange(rVisRect, nIndex, bMark, aNote.maNoteCell, aNote.maRect))
173 if (bMark)
175 // Document not needed, because only the cell address, but not the tablename is needed
176 aNote.maNoteText = aNote.maNoteCell.Format(ScRefFlags::VALID);
178 else
180 if( ScPostIt* pNote = pDoc->GetNote( aNote.maNoteCell ) )
181 aNote.maNoteText = pNote->GetText();
182 aNote.mpTextHelper = CreateTextHelper(aNote.maNoteText, aNote.maRect, aNote.maNoteCell, aNote.mbMarkNote, nParagraphs + mnOffset);
183 if (aNote.mpTextHelper)
184 aNote.mnParaCount = aNote.mpTextHelper->GetChildCount();
186 nParagraphs += aNote.mnParaCount;
187 rNotes.push_back(aNote);
191 return nParagraphs;
194 void ScNotesChildren::Init(const tools::Rectangle& rVisRect, sal_Int32 nOffset)
196 if (mpViewShell && !mnParagraphs)
198 mnOffset = nOffset;
199 const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
201 mnParagraphs = AddNotes(rData, rVisRect, false, maMarks);
202 mnParagraphs += AddNotes(rData, rVisRect, true, maNotes);
206 namespace {
208 struct ScParaFound
210 sal_Int32 mnIndex;
211 explicit ScParaFound(sal_Int32 nIndex) : mnIndex(nIndex) {}
212 bool operator() (const ScAccNote& rNote)
214 bool bResult(false);
215 if (rNote.mnParaCount > mnIndex)
216 bResult = true;
217 else
218 mnIndex -= rNote.mnParaCount;
219 return bResult;
225 uno::Reference<XAccessible> ScNotesChildren::GetChild(sal_Int32 nIndex) const
227 uno::Reference<XAccessible> xAccessible;
229 if (nIndex < mnParagraphs)
231 if (nIndex < static_cast<sal_Int32>(maMarks.size()))
233 ScAccNotes::iterator aEndItr = maMarks.end();
234 ScParaFound aParaFound(nIndex);
235 ScAccNotes::iterator aItr = std::find_if(maMarks.begin(), aEndItr, aParaFound);
236 if (aItr != aEndItr)
238 OSL_ENSURE((aItr->maNoteCell == maMarks[nIndex].maNoteCell) && (aItr->mbMarkNote == maMarks[nIndex].mbMarkNote), "wrong note found");
239 if (!aItr->mpTextHelper)
240 aItr->mpTextHelper = CreateTextHelper(maMarks[nIndex].maNoteText, maMarks[nIndex].maRect, maMarks[nIndex].maNoteCell, maMarks[nIndex].mbMarkNote, nIndex + mnOffset); // the marks are the first and every mark has only one paragraph
241 xAccessible = aItr->mpTextHelper->GetChild(aParaFound.mnIndex + aItr->mpTextHelper->GetStartIndex());
243 else
245 OSL_FAIL("wrong note found");
248 else
250 nIndex -= maMarks.size();
251 ScAccNotes::iterator aEndItr = maNotes.end();
252 ScParaFound aParaFound(nIndex);
253 ScAccNotes::iterator aItr = std::find_if(maNotes.begin(), aEndItr, aParaFound);
254 if (aEndItr != aItr)
256 if (!aItr->mpTextHelper)
257 aItr->mpTextHelper = CreateTextHelper(aItr->maNoteText, aItr->maRect, aItr->maNoteCell, aItr->mbMarkNote, (nIndex - aParaFound.mnIndex) + mnOffset + maMarks.size());
258 xAccessible = aItr->mpTextHelper->GetChild(aParaFound.mnIndex + aItr->mpTextHelper->GetStartIndex());
263 return xAccessible;
266 namespace {
268 struct ScPointFound
270 tools::Rectangle maPoint;
271 sal_Int32 mnParagraphs;
272 explicit ScPointFound(const Point& rPoint) : maPoint(rPoint, Size(0, 0)), mnParagraphs(0) {}
273 bool operator() (const ScAccNote& rNote)
275 bool bResult(false);
276 if (maPoint.Contains(rNote.maRect))
277 bResult = true;
278 else
279 mnParagraphs += rNote.mnParaCount;
280 return bResult;
286 uno::Reference<XAccessible> ScNotesChildren::GetAt(const awt::Point& rPoint) const
288 uno::Reference<XAccessible> xAccessible;
290 ScPointFound aPointFound(Point(rPoint.X, rPoint.Y));
292 ScAccNotes::iterator aEndItr = maMarks.end();
293 ScAccNotes::iterator aItr = std::find_if(maMarks.begin(), aEndItr, aPointFound);
294 if (aEndItr == aItr)
296 aEndItr = maNotes.end();
297 aItr = std::find_if(maNotes.begin(), aEndItr, aPointFound);
299 if (aEndItr != aItr)
301 if (!aItr->mpTextHelper)
302 aItr->mpTextHelper = CreateTextHelper(aItr->maNoteText, aItr->maRect, aItr->maNoteCell, aItr->mbMarkNote, aPointFound.mnParagraphs + mnOffset);
303 xAccessible = aItr->mpTextHelper->GetAt(rPoint);
306 return xAccessible;
309 sal_Int8 ScNotesChildren::CompareCell(const ScAddress& aCell1, const ScAddress& aCell2)
311 OSL_ENSURE(aCell1.Tab() == aCell2.Tab(), "the notes should be on the same table");
312 sal_Int8 nResult(0);
313 if (aCell1 != aCell2)
315 if (aCell1.Row() == aCell2.Row())
316 nResult = (aCell1.Col() < aCell2.Col()) ? -1 : 1;
317 else
318 nResult = (aCell1.Row() < aCell2.Row()) ? -1 : 1;
320 return nResult;
323 void ScNotesChildren::CollectChildren(const ScAccNote& rNote, ScXAccVector& rVector)
325 if (rNote.mpTextHelper)
326 for (sal_Int32 i = 0; i < rNote.mnParaCount; ++i)
327 rVector.push_back(rNote.mpTextHelper->GetChild(i + rNote.mpTextHelper->GetStartIndex()));
330 sal_Int32 ScNotesChildren::CheckChanges(const ScPreviewLocationData& rData,
331 const tools::Rectangle& rVisRect, bool bMark, ScAccNotes& rOldNotes,
332 ScAccNotes& rNewNotes, ScXAccVector& rOldParas, ScXAccVector& rNewParas)
334 sal_Int32 nCount = rData.GetNoteCountInRange(rVisRect, bMark);
336 rNewNotes.reserve(nCount);
338 sal_Int32 nParagraphs(0);
339 ScDocument* pDoc = GetDocument();
340 if (pDoc)
342 ScAccNote aNote;
343 aNote.mbMarkNote = bMark;
344 if (bMark)
345 aNote.mnParaCount = 1;
346 ScAccNotes::iterator aItr = rOldNotes.begin();
347 ScAccNotes::iterator aEndItr = rOldNotes.end();
348 bool bAddNote(false);
349 for (sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex)
351 if (rData.GetNoteInRange(rVisRect, nIndex, bMark, aNote.maNoteCell, aNote.maRect))
353 if (bMark)
355 // Document not needed, because only the cell address, but not the tablename is needed
356 aNote.maNoteText = aNote.maNoteCell.Format(ScRefFlags::VALID);
358 else
360 if( ScPostIt* pNote = pDoc->GetNote( aNote.maNoteCell ) )
361 aNote.maNoteText = pNote->GetText();
364 sal_Int8 nCompare(-1); // if there are no more old children it is always a new one
365 if (aItr != aEndItr)
366 nCompare = CompareCell(aNote.maNoteCell, aItr->maNoteCell);
367 if (nCompare == 0)
369 if (aNote.maNoteText == aItr->maNoteText)
371 aNote.mpTextHelper = aItr->mpTextHelper;
372 if (aNote.maRect != aItr->maRect) // set new VisArea
374 aNote.mpTextHelper->SetOffset(aNote.maRect.TopLeft());
375 aNote.mpTextHelper->UpdateChildren();
376 //OSL_ENSURE(aItr->maRect.GetSize() == aNote.maRect.GetSize(), "size should be the same, because the text is not changed");
377 // could be changed, because only a part of the note is visible
380 else
382 aNote.mpTextHelper = CreateTextHelper(aNote.maNoteText, aNote.maRect, aNote.maNoteCell, aNote.mbMarkNote, nParagraphs + mnOffset);
383 if (aNote.mpTextHelper)
384 aNote.mnParaCount = aNote.mpTextHelper->GetChildCount();
385 // collect removed children
386 CollectChildren(*aItr, rOldParas);
387 delete aItr->mpTextHelper;
388 aItr->mpTextHelper = nullptr;;
389 // collect new children
390 CollectChildren(aNote, rNewParas);
392 bAddNote = true;
393 // not necessary, because this branch should not be reached if it is the end
394 //if (aItr != aEndItr)
395 ++aItr;
397 else if (nCompare < 0)
399 aNote.mpTextHelper = CreateTextHelper(aNote.maNoteText, aNote.maRect, aNote.maNoteCell, aNote.mbMarkNote, nParagraphs + mnOffset);
400 if (aNote.mpTextHelper)
401 aNote.mnParaCount = aNote.mpTextHelper->GetChildCount();
402 // collect new children
403 CollectChildren(aNote, rNewParas);
404 bAddNote = true;
406 else
408 // collect removed children
409 CollectChildren(*aItr, rOldParas);
410 delete aItr->mpTextHelper;
411 aItr->mpTextHelper = nullptr;
413 // no note to add
414 // not necessary, because this branch should not be reached if it is the end
415 //if (aItr != aEndItr)
416 ++aItr;
418 if (bAddNote)
420 nParagraphs += aNote.mnParaCount;
421 rNewNotes.push_back(aNote);
422 bAddNote = false;
427 return nParagraphs;
430 namespace {
432 struct ScChildGone
434 ScAccessibleDocumentPagePreview* mpAccDoc;
435 explicit ScChildGone(ScAccessibleDocumentPagePreview* pAccDoc) : mpAccDoc(pAccDoc) {}
436 void operator() (const uno::Reference<XAccessible>& xAccessible) const
438 if (mpAccDoc)
440 AccessibleEventObject aEvent;
441 aEvent.EventId = AccessibleEventId::CHILD;
442 aEvent.Source = uno::Reference< XAccessibleContext >(mpAccDoc);
443 aEvent.OldValue <<= xAccessible;
444 aEvent.IndexHint = -1;
446 mpAccDoc->CommitChange(aEvent); // gone child - event
451 struct ScChildNew
453 ScAccessibleDocumentPagePreview* mpAccDoc;
454 explicit ScChildNew(ScAccessibleDocumentPagePreview* pAccDoc) : mpAccDoc(pAccDoc) {}
455 void operator() (const uno::Reference<XAccessible>& xAccessible) const
457 if (mpAccDoc)
459 AccessibleEventObject aEvent;
460 aEvent.EventId = AccessibleEventId::CHILD;
461 aEvent.Source = uno::Reference< XAccessibleContext >(mpAccDoc);
462 aEvent.NewValue <<= xAccessible;
463 aEvent.IndexHint = -1;
465 mpAccDoc->CommitChange(aEvent); // new child - event
472 void ScNotesChildren::DataChanged(const tools::Rectangle& rVisRect)
474 if (!(mpViewShell && mpAccDoc))
475 return;
477 ScXAccVector aNewParas;
478 ScXAccVector aOldParas;
480 ScAccNotes aNewMarks;
481 mnParagraphs = CheckChanges(mpViewShell->GetLocationData(), rVisRect, true, maMarks, aNewMarks, aOldParas, aNewParas);
482 maMarks = std::move(aNewMarks);
485 ScAccNotes aNewNotes;
486 mnParagraphs += CheckChanges(mpViewShell->GetLocationData(), rVisRect, false, maNotes, aNewNotes, aOldParas, aNewParas);
487 maNotes = std::move(aNewNotes);
490 std::for_each(aOldParas.begin(), aOldParas.end(), ScChildGone(mpAccDoc));
491 std::for_each(aNewParas.begin(), aNewParas.end(), ScChildNew(mpAccDoc));
494 inline ScDocument* ScNotesChildren::GetDocument() const
496 ScDocument* pDoc = nullptr;
497 if (mpViewShell)
498 pDoc = &mpViewShell->GetDocument();
499 return pDoc;
502 namespace {
504 class ScIAccessibleViewForwarder : public ::accessibility::IAccessibleViewForwarder
506 public:
507 ScIAccessibleViewForwarder();
508 ScIAccessibleViewForwarder(ScPreviewShell* pViewShell,
509 ScAccessibleDocumentPagePreview* pAccDoc,
510 const MapMode& aMapMode);
512 ///===== IAccessibleViewForwarder ========================================
514 virtual tools::Rectangle GetVisibleArea() const override;
515 virtual Point LogicToPixel (const Point& rPoint) const override;
516 virtual Size LogicToPixel (const Size& rSize) const override;
518 private:
519 ScPreviewShell* mpViewShell;
520 ScAccessibleDocumentPagePreview* mpAccDoc;
521 MapMode maMapMode;
526 ScIAccessibleViewForwarder::ScIAccessibleViewForwarder()
527 : mpViewShell(nullptr), mpAccDoc(nullptr)
531 ScIAccessibleViewForwarder::ScIAccessibleViewForwarder(ScPreviewShell* pViewShell,
532 ScAccessibleDocumentPagePreview* pAccDoc,
533 const MapMode& aMapMode)
534 : mpViewShell(pViewShell),
535 mpAccDoc(pAccDoc),
536 maMapMode(aMapMode)
540 ///===== IAccessibleViewForwarder ========================================
542 tools::Rectangle ScIAccessibleViewForwarder::GetVisibleArea() const
544 SolarMutexGuard aGuard;
545 tools::Rectangle aVisRect;
546 vcl::Window* pWin = mpViewShell->GetWindow();
547 if (pWin)
549 aVisRect.SetSize(pWin->GetOutputSizePixel());
550 aVisRect.SetPos(Point(0, 0));
552 aVisRect = pWin->PixelToLogic(aVisRect, maMapMode);
555 return aVisRect;
558 Point ScIAccessibleViewForwarder::LogicToPixel (const Point& rPoint) const
560 SolarMutexGuard aGuard;
561 Point aPoint;
562 vcl::Window* pWin = mpViewShell->GetWindow();
563 if (pWin && mpAccDoc)
565 tools::Rectangle aRect(mpAccDoc->GetBoundingBoxOnScreen());
566 aPoint = pWin->LogicToPixel(rPoint, maMapMode) + aRect.TopLeft();
569 return aPoint;
572 Size ScIAccessibleViewForwarder::LogicToPixel (const Size& rSize) const
574 SolarMutexGuard aGuard;
575 Size aSize;
576 vcl::Window* pWin = mpViewShell->GetWindow();
577 if (pWin)
578 aSize = pWin->LogicToPixel(rSize, maMapMode);
579 return aSize;
582 namespace {
584 struct ScShapeChild
586 ScShapeChild()
587 : mnRangeId(0)
590 ScShapeChild(ScShapeChild const &) = delete;
591 ScShapeChild(ScShapeChild &&) = default;
592 ~ScShapeChild();
593 ScShapeChild & operator =(ScShapeChild const &) = delete;
594 ScShapeChild & operator =(ScShapeChild && other) {
595 std::swap(mpAccShape, other.mpAccShape);
596 mxShape = std::move(other.mxShape);
597 mnRangeId = other.mnRangeId;
598 return *this;
601 mutable rtl::Reference< ::accessibility::AccessibleShape > mpAccShape;
602 css::uno::Reference< css::drawing::XShape > mxShape;
603 sal_Int32 mnRangeId;
608 ScShapeChild::~ScShapeChild()
610 if (mpAccShape.is())
612 mpAccShape->dispose();
616 namespace {
618 struct ScShapeChildLess
620 bool operator()(const ScShapeChild& rChild1, const ScShapeChild& rChild2) const
622 bool bResult(false);
623 if (rChild1.mxShape.is() && rChild2.mxShape.is())
624 bResult = (rChild1.mxShape.get() < rChild2.mxShape.get());
625 return bResult;
631 typedef std::vector<ScShapeChild> ScShapeChildVec;
633 namespace {
635 struct ScShapeRange
637 ScShapeRange() = default;
638 ScShapeRange(ScShapeRange const &) = delete;
639 ScShapeRange(ScShapeRange &&) = default;
640 ScShapeRange & operator =(ScShapeRange const &) = delete;
641 ScShapeRange & operator =(ScShapeRange &&) = default;
643 ScShapeChildVec maBackShapes;
644 ScShapeChildVec maForeShapes; // inclusive internal shapes
645 ScShapeChildVec maControls;
646 ScIAccessibleViewForwarder maViewForwarder;
651 typedef std::vector<ScShapeRange> ScShapeRangeVec;
653 class ScShapeChildren : public ::accessibility::IAccessibleParent
655 public:
656 ScShapeChildren(ScPreviewShell* pViewShell, ScAccessibleDocumentPagePreview* pAccDoc);
658 ///===== IAccessibleParent ==============================================
660 virtual bool ReplaceChild (
661 ::accessibility::AccessibleShape* pCurrentChild,
662 const css::uno::Reference< css::drawing::XShape >& _rxShape,
663 const tools::Long _nIndex,
664 const ::accessibility::AccessibleShapeTreeInfo& _rShapeTreeInfo
665 ) override;
667 ///===== Internal ========================================================
669 void Init();
671 sal_Int32 GetBackShapeCount() const;
672 uno::Reference<XAccessible> GetBackShape(sal_Int32 nIndex) const;
673 sal_Int32 GetForeShapeCount() const;
674 uno::Reference<XAccessible> GetForeShape(sal_Int32 nIndex) const;
675 sal_Int32 GetControlCount() const;
676 uno::Reference<XAccessible> GetControl(sal_Int32 nIndex) const;
677 uno::Reference<XAccessible> GetForegroundShapeAt(const awt::Point& rPoint) const; // inclusive controls
678 uno::Reference<XAccessible> GetBackgroundShapeAt(const awt::Point& rPoint) const;
680 void DataChanged();
681 void VisAreaChanged() const;
683 private:
684 ScAccessibleDocumentPagePreview* mpAccDoc;
685 ScPreviewShell* mpViewShell;
686 ScShapeRangeVec maShapeRanges;
688 void FindChanged(ScShapeChildVec& aOld, ScShapeChildVec& aNew) const;
689 void FindChanged(ScShapeRange& aOld, ScShapeRange& aNew) const;
690 ::accessibility::AccessibleShape* GetAccShape(const ScShapeChild& rShape) const;
691 ::accessibility::AccessibleShape* GetAccShape(const ScShapeChildVec& rShapes, sal_Int32 nIndex) const;
692 void FillShapes(const tools::Rectangle& aPixelPaintRect, const MapMode& aMapMode, sal_uInt8 nRangeId);
694 // void AddShape(const uno::Reference<drawing::XShape>& xShape, SdrLayerID aLayerID);
695 // void RemoveShape(const uno::Reference<drawing::XShape>& xShape, SdrLayerID aLayerID);
696 SdrPage* GetDrawPage() const;
699 ScShapeChildren::ScShapeChildren(ScPreviewShell* pViewShell, ScAccessibleDocumentPagePreview* pAccDoc)
701 mpAccDoc(pAccDoc),
702 mpViewShell(pViewShell),
703 maShapeRanges(SC_PREVIEW_MAXRANGES)
707 void ScShapeChildren::FindChanged(ScShapeChildVec& rOld, ScShapeChildVec& rNew) const
709 ScShapeChildVec::iterator aOldItr = rOld.begin();
710 ScShapeChildVec::iterator aOldEnd = rOld.end();
711 ScShapeChildVec::const_iterator aNewItr = rNew.begin();
712 ScShapeChildVec::const_iterator aNewEnd = rNew.end();
713 uno::Reference<XAccessible> xAcc;
714 while ((aNewItr != aNewEnd) && (aOldItr != aOldEnd))
716 if (aNewItr->mxShape.get() == aOldItr->mxShape.get())
718 ++aOldItr;
719 ++aNewItr;
721 else if (aNewItr->mxShape.get() < aOldItr->mxShape.get())
723 xAcc = GetAccShape(*aNewItr);
724 AccessibleEventObject aEvent;
725 aEvent.Source = uno::Reference<XAccessibleContext> (mpAccDoc);
726 aEvent.EventId = AccessibleEventId::CHILD;
727 aEvent.NewValue <<= xAcc;
728 aEvent.IndexHint = -1;
729 mpAccDoc->CommitChange(aEvent);
730 ++aNewItr;
732 else
734 xAcc = GetAccShape(*aOldItr);
735 AccessibleEventObject aEvent;
736 aEvent.Source = uno::Reference<XAccessibleContext> (mpAccDoc);
737 aEvent.EventId = AccessibleEventId::CHILD;
738 aEvent.OldValue <<= xAcc;
739 aEvent.IndexHint = -1;
740 mpAccDoc->CommitChange(aEvent);
741 ++aOldItr;
744 while (aOldItr != aOldEnd)
746 xAcc = GetAccShape(*aOldItr);
747 AccessibleEventObject aEvent;
748 aEvent.Source = uno::Reference<XAccessibleContext> (mpAccDoc);
749 aEvent.EventId = AccessibleEventId::CHILD;
750 aEvent.OldValue <<= xAcc;
751 aEvent.IndexHint = -1;
752 mpAccDoc->CommitChange(aEvent);
753 ++aOldItr;
755 while (aNewItr != aNewEnd)
757 xAcc = GetAccShape(*aNewItr);
758 AccessibleEventObject aEvent;
759 aEvent.Source = uno::Reference<XAccessibleContext> (mpAccDoc);
760 aEvent.EventId = AccessibleEventId::CHILD;
761 aEvent.NewValue <<= xAcc;
762 aEvent.IndexHint = -1;
763 mpAccDoc->CommitChange(aEvent);
764 ++aNewItr;
768 void ScShapeChildren::FindChanged(ScShapeRange& rOld, ScShapeRange& rNew) const
770 FindChanged(rOld.maBackShapes, rNew.maBackShapes);
771 FindChanged(rOld.maForeShapes, rNew.maForeShapes);
772 FindChanged(rOld.maControls, rNew.maControls);
775 void ScShapeChildren::DataChanged()
777 ScShapeRangeVec aOldShapeRanges(std::move(maShapeRanges));
778 maShapeRanges.clear();
779 maShapeRanges.resize(SC_PREVIEW_MAXRANGES);
780 Init();
781 for (sal_Int32 i = 0; i < SC_PREVIEW_MAXRANGES; ++i)
783 FindChanged(aOldShapeRanges[i], maShapeRanges[i]);
787 namespace
789 struct ScVisAreaChanged
791 void operator() (const ScShapeChild& rAccShapeData) const
793 if (rAccShapeData.mpAccShape.is())
795 rAccShapeData.mpAccShape->ViewForwarderChanged();
801 void ScShapeChildren::VisAreaChanged() const
803 for (auto const& shape : maShapeRanges)
805 ScVisAreaChanged aVisAreaChanged;
806 std::for_each(shape.maBackShapes.begin(), shape.maBackShapes.end(), aVisAreaChanged);
807 std::for_each(shape.maControls.begin(), shape.maControls.end(), aVisAreaChanged);
808 std::for_each(shape.maForeShapes.begin(), shape.maForeShapes.end(), aVisAreaChanged);
812 ///===== IAccessibleParent ==============================================
814 bool ScShapeChildren::ReplaceChild (::accessibility::AccessibleShape* /* pCurrentChild */,
815 const css::uno::Reference< css::drawing::XShape >& /* _rxShape */,
816 const tools::Long /* _nIndex */, const ::accessibility::AccessibleShapeTreeInfo& /* _rShapeTreeInfo */)
818 OSL_FAIL("should not be called in the page preview");
819 return false;
822 ///===== Internal ========================================================
824 void ScShapeChildren::Init()
826 if(!mpViewShell)
827 return;
829 const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
830 MapMode aMapMode;
831 tools::Rectangle aPixelPaintRect;
832 sal_uInt8 nRangeId;
833 sal_uInt16 nCount(rData.GetDrawRanges());
834 for (sal_uInt16 i = 0; i < nCount; ++i)
836 rData.GetDrawRange(i, aPixelPaintRect, aMapMode, nRangeId);
837 FillShapes(aPixelPaintRect, aMapMode, nRangeId);
841 sal_Int32 ScShapeChildren::GetBackShapeCount() const
843 sal_Int32 nCount(0);
844 for (auto const& shape : maShapeRanges)
845 nCount += shape.maBackShapes.size();
846 return nCount;
849 uno::Reference<XAccessible> ScShapeChildren::GetBackShape(sal_Int32 nIndex) const
851 uno::Reference<XAccessible> xAccessible;
852 for (const auto& rShapeRange : maShapeRanges)
854 sal_Int32 nCount(rShapeRange.maBackShapes.size());
855 if(nIndex < nCount)
856 xAccessible = GetAccShape(rShapeRange.maBackShapes, nIndex);
857 nIndex -= nCount;
858 if (xAccessible.is())
859 break;
862 if (nIndex >= 0)
863 throw lang::IndexOutOfBoundsException();
865 return xAccessible;
868 sal_Int32 ScShapeChildren::GetForeShapeCount() const
870 sal_Int32 nCount(0);
871 for (auto const& shape : maShapeRanges)
872 nCount += shape.maForeShapes.size();
873 return nCount;
876 uno::Reference<XAccessible> ScShapeChildren::GetForeShape(sal_Int32 nIndex) const
878 uno::Reference<XAccessible> xAccessible;
879 for (const auto& rShapeRange : maShapeRanges)
881 sal_Int32 nCount(rShapeRange.maForeShapes.size());
882 if(nIndex < nCount)
883 xAccessible = GetAccShape(rShapeRange.maForeShapes, nIndex);
884 nIndex -= nCount;
885 if (xAccessible.is())
886 break;
889 if (nIndex >= 0)
890 throw lang::IndexOutOfBoundsException();
892 return xAccessible;
895 sal_Int32 ScShapeChildren::GetControlCount() const
897 sal_Int32 nCount(0);
898 for (auto const& shape : maShapeRanges)
899 nCount += shape.maControls.size();
900 return nCount;
903 uno::Reference<XAccessible> ScShapeChildren::GetControl(sal_Int32 nIndex) const
905 uno::Reference<XAccessible> xAccessible;
906 for (const auto& rShapeRange : maShapeRanges)
908 sal_Int32 nCount(rShapeRange.maControls.size());
909 if(nIndex < nCount)
910 xAccessible = GetAccShape(rShapeRange.maControls, nIndex);
911 nIndex -= nCount;
912 if (xAccessible.is())
913 break;
916 if (nIndex >= 0)
917 throw lang::IndexOutOfBoundsException();
919 return xAccessible;
922 namespace {
924 struct ScShapePointFound
926 Point maPoint;
927 explicit ScShapePointFound(const awt::Point& rPoint)
928 : maPoint(vcl::unohelper::ConvertToVCLPoint(rPoint))
931 bool operator() (const ScShapeChild& rShape)
933 bool bResult(false);
934 if (vcl::unohelper::ConvertToVCLRect(rShape.mpAccShape->getBounds()).Contains(maPoint))
935 bResult = true;
936 return bResult;
942 uno::Reference<XAccessible> ScShapeChildren::GetForegroundShapeAt(const awt::Point& rPoint) const //inclusive Controls
944 uno::Reference<XAccessible> xAcc;
946 for(const auto& rShapeRange : maShapeRanges)
948 ScShapeChildVec::const_iterator aFindItr = std::find_if(rShapeRange.maForeShapes.begin(), rShapeRange.maForeShapes.end(), ScShapePointFound(rPoint));
949 if (aFindItr != rShapeRange.maForeShapes.end())
950 xAcc = GetAccShape(*aFindItr);
951 else
953 ScShapeChildVec::const_iterator aCtrlItr = std::find_if(rShapeRange.maControls.begin(), rShapeRange.maControls.end(), ScShapePointFound(rPoint));
954 if (aCtrlItr != rShapeRange.maControls.end())
955 xAcc = GetAccShape(*aCtrlItr);
958 if (xAcc.is())
959 break;
962 return xAcc;
965 uno::Reference<XAccessible> ScShapeChildren::GetBackgroundShapeAt(const awt::Point& rPoint) const
967 uno::Reference<XAccessible> xAcc;
969 for(const auto& rShapeRange : maShapeRanges)
971 ScShapeChildVec::const_iterator aFindItr = std::find_if(rShapeRange.maBackShapes.begin(), rShapeRange.maBackShapes.end(), ScShapePointFound(rPoint));
972 if (aFindItr != rShapeRange.maBackShapes.end())
973 xAcc = GetAccShape(*aFindItr);
974 if (xAcc.is())
975 break;
978 return xAcc;
981 ::accessibility::AccessibleShape* ScShapeChildren::GetAccShape(const ScShapeChild& rShape) const
983 if (!rShape.mpAccShape.is())
985 ::accessibility::ShapeTypeHandler& rShapeHandler = ::accessibility::ShapeTypeHandler::Instance();
986 ::accessibility::AccessibleShapeInfo aShapeInfo(rShape.mxShape, mpAccDoc);
988 if (mpViewShell)
990 ::accessibility::AccessibleShapeTreeInfo aShapeTreeInfo;
991 aShapeTreeInfo.SetSdrView(mpViewShell->GetPreview()->GetDrawView());
992 aShapeTreeInfo.SetController(nullptr);
993 aShapeTreeInfo.SetWindow(mpViewShell->GetWindow());
994 aShapeTreeInfo.SetViewForwarder(&(maShapeRanges[rShape.mnRangeId].maViewForwarder));
995 rShape.mpAccShape = rShapeHandler.CreateAccessibleObject(aShapeInfo, aShapeTreeInfo);
996 if (rShape.mpAccShape.is())
998 rShape.mpAccShape->Init();
1002 return rShape.mpAccShape.get();
1005 ::accessibility::AccessibleShape* ScShapeChildren::GetAccShape(const ScShapeChildVec& rShapes, sal_Int32 nIndex) const
1007 return GetAccShape(rShapes[nIndex]);
1010 void ScShapeChildren::FillShapes(const tools::Rectangle& aPixelPaintRect, const MapMode& aMapMode, sal_uInt8 nRangeId)
1012 OSL_ENSURE(nRangeId < maShapeRanges.size(), "this is not a valid range for draw objects");
1013 SdrPage* pPage = GetDrawPage();
1014 vcl::Window* pWin = mpViewShell->GetWindow();
1015 if (!(pPage && pWin))
1016 return;
1018 bool bForeAdded(false);
1019 bool bBackAdded(false);
1020 bool bControlAdded(false);
1021 tools::Rectangle aClippedPixelPaintRect(aPixelPaintRect);
1022 if (mpAccDoc)
1024 tools::Rectangle aRect2(Point(0,0), mpAccDoc->GetBoundingBoxOnScreen().GetSize());
1025 aClippedPixelPaintRect = aPixelPaintRect.GetIntersection(aRect2);
1027 maShapeRanges[nRangeId].maViewForwarder = ScIAccessibleViewForwarder(mpViewShell, mpAccDoc, aMapMode);
1028 for (const rtl::Reference<SdrObject>& pObj : *pPage)
1030 uno::Reference< drawing::XShape > xShape(pObj->getUnoShape(), uno::UNO_QUERY);
1031 if (xShape.is())
1033 tools::Rectangle aRect(pWin->LogicToPixel(
1034 tools::Rectangle(vcl::unohelper::ConvertToVCLPoint(xShape->getPosition()),
1035 vcl::unohelper::ConvertToVCLSize(xShape->getSize())), aMapMode));
1036 if(!aClippedPixelPaintRect.GetIntersection(aRect).IsEmpty())
1038 ScShapeChild aShape;
1039 aShape.mxShape = std::move(xShape);
1040 aShape.mnRangeId = nRangeId;
1041 if (pObj->GetLayer().anyOf(SC_LAYER_INTERN, SC_LAYER_FRONT))
1043 maShapeRanges[nRangeId].maForeShapes.push_back(std::move(aShape));
1044 bForeAdded = true;
1046 else if (pObj->GetLayer() == SC_LAYER_BACK)
1048 maShapeRanges[nRangeId].maBackShapes.push_back(std::move(aShape));
1049 bBackAdded = true;
1051 else if (pObj->GetLayer() == SC_LAYER_CONTROLS)
1053 maShapeRanges[nRangeId].maControls.push_back(std::move(aShape));
1054 bControlAdded = true;
1056 else
1058 OSL_FAIL("I don't know this layer.");
1063 if (bForeAdded)
1064 std::sort(maShapeRanges[nRangeId].maForeShapes.begin(), maShapeRanges[nRangeId].maForeShapes.end(),ScShapeChildLess());
1065 if (bBackAdded)
1066 std::sort(maShapeRanges[nRangeId].maBackShapes.begin(), maShapeRanges[nRangeId].maBackShapes.end(),ScShapeChildLess());
1067 if (bControlAdded)
1068 std::sort(maShapeRanges[nRangeId].maControls.begin(), maShapeRanges[nRangeId].maControls.end(),ScShapeChildLess());
1071 SdrPage* ScShapeChildren::GetDrawPage() const
1073 SCTAB nTab( mpViewShell->GetLocationData().GetPrintTab() );
1074 SdrPage* pDrawPage = nullptr;
1075 ScDocument& rDoc = mpViewShell->GetDocument();
1076 if (rDoc.GetDrawLayer())
1078 ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
1079 if (pDrawLayer->HasObjects() && (pDrawLayer->GetPageCount() > nTab))
1080 pDrawPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(static_cast<sal_Int16>(nTab)));
1082 return pDrawPage;
1085 namespace {
1087 struct ScPagePreviewCountData
1089 // order is background shapes, header, table or notes, footer, foreground shapes, controls
1091 tools::Rectangle aVisRect;
1092 tools::Long nBackShapes;
1093 tools::Long nHeaders;
1094 tools::Long nTables;
1095 tools::Long nNoteParagraphs;
1096 tools::Long nFooters;
1097 tools::Long nForeShapes;
1098 tools::Long nControls;
1100 ScPagePreviewCountData( const ScPreviewLocationData& rData, const vcl::Window* pSizeWindow,
1101 const ScNotesChildren* pNotesChildren, const ScShapeChildren* pShapeChildren );
1103 tools::Long GetTotal() const
1105 return nBackShapes + nHeaders + nTables + nNoteParagraphs + nFooters + nForeShapes + nControls;
1111 ScPagePreviewCountData::ScPagePreviewCountData( const ScPreviewLocationData& rData,
1112 const vcl::Window* pSizeWindow, const ScNotesChildren* pNotesChildren,
1113 const ScShapeChildren* pShapeChildren) :
1114 nBackShapes( 0 ),
1115 nHeaders( 0 ),
1116 nTables( 0 ),
1117 nNoteParagraphs( 0 ),
1118 nFooters( 0 ),
1119 nForeShapes( 0 ),
1120 nControls( 0 )
1122 Size aOutputSize;
1123 if ( pSizeWindow )
1124 aOutputSize = pSizeWindow->GetOutputSizePixel();
1125 aVisRect = tools::Rectangle( Point(), aOutputSize );
1127 tools::Rectangle aObjRect;
1129 if ( rData.GetHeaderPosition( aObjRect ) && aObjRect.Overlaps( aVisRect ) )
1130 nHeaders = 1;
1132 if ( rData.GetFooterPosition( aObjRect ) && aObjRect.Overlaps( aVisRect ) )
1133 nFooters = 1;
1135 if ( rData.HasCellsInRange( aVisRect ) )
1136 nTables = 1;
1138 //! shapes...
1139 nBackShapes = pShapeChildren->GetBackShapeCount();
1140 nForeShapes = pShapeChildren->GetForeShapeCount();
1141 nControls = pShapeChildren->GetControlCount();
1143 // there are only notes if there is no table
1144 if (nTables == 0)
1145 nNoteParagraphs = pNotesChildren->GetChildrenCount();
1148 //===== internal ========================================================
1150 ScAccessibleDocumentPagePreview::ScAccessibleDocumentPagePreview(
1151 const uno::Reference<XAccessible>& rxParent, ScPreviewShell* pViewShell ) :
1152 ScAccessibleDocumentBase(rxParent),
1153 mpViewShell(pViewShell)
1155 if (pViewShell)
1156 pViewShell->AddAccessibilityObject(*this);
1160 ScAccessibleDocumentPagePreview::~ScAccessibleDocumentPagePreview()
1162 if (!ScAccessibleDocumentBase::IsDefunc() && !rBHelper.bInDispose)
1164 // increment refcount to prevent double call off dtor
1165 osl_atomic_increment( &m_refCount );
1166 // call dispose to inform object which have a weak reference to this object
1167 dispose();
1171 void SAL_CALL ScAccessibleDocumentPagePreview::disposing()
1173 SolarMutexGuard aGuard;
1174 mpTable.clear();
1175 mpHeader.clear();
1176 mpFooter.clear();
1178 if (mpViewShell)
1180 mpViewShell->RemoveAccessibilityObject(*this);
1181 mpViewShell = nullptr;
1184 // no need to Dispose the AccessibleTextHelper,
1185 // as long as mpNotesChildren are destructed here
1186 mpNotesChildren.reset();
1188 mpShapeChildren.reset();
1190 ScAccessibleDocumentBase::disposing();
1193 //===== SfxListener =====================================================
1195 void ScAccessibleDocumentPagePreview::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
1197 if ( rHint.GetId() == SfxHintId::ScAccWinFocusLost )
1199 CommitFocusLost();
1201 else if ( rHint.GetId() == SfxHintId::ScAccGridWinFocusLost )
1203 CommitFocusLost();
1205 else if ( rHint.GetId() == SfxHintId::ScAccWinFocusGot )
1207 CommitFocusGained();
1209 else if ( rHint.GetId() == SfxHintId::ScAccGridWinFocusGot )
1211 CommitFocusGained();
1213 else if (rHint.GetId() == SfxHintId::ScDataChanged)
1215 // only notify if child exist, otherwise it is not necessary
1216 if (mpTable.is()) // if there is no table there is nothing to notify, because no one recognizes the change
1219 uno::Reference<XAccessible> xAcc = mpTable;
1220 AccessibleEventObject aEvent;
1221 aEvent.EventId = AccessibleEventId::CHILD;
1222 aEvent.Source = uno::Reference< XAccessibleContext >(this);
1223 aEvent.OldValue <<= xAcc;
1224 aEvent.IndexHint = -1;
1225 CommitChange(aEvent);
1228 mpTable->dispose();
1229 mpTable.clear();
1232 Size aOutputSize;
1233 vcl::Window* pSizeWindow = mpViewShell->GetWindow();
1234 if ( pSizeWindow )
1235 aOutputSize = pSizeWindow->GetOutputSizePixel();
1236 tools::Rectangle aVisRect( Point(), aOutputSize );
1237 GetNotesChildren()->DataChanged(aVisRect);
1239 GetShapeChildren()->DataChanged();
1241 const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
1242 ScPagePreviewCountData aCount( rData, mpViewShell->GetWindow(), GetNotesChildren(), GetShapeChildren() );
1244 if (aCount.nTables > 0)
1246 //! order is background shapes, header, table or notes, footer, foreground shapes, controls
1247 sal_Int32 nIndex (aCount.nBackShapes + aCount.nHeaders);
1249 mpTable = new ScAccessiblePreviewTable( this, mpViewShell, nIndex );
1250 mpTable->Init();
1253 uno::Reference<XAccessible> xAcc = mpTable;
1254 AccessibleEventObject aEvent;
1255 aEvent.EventId = AccessibleEventId::CHILD;
1256 aEvent.Source = uno::Reference< XAccessibleContext >(this);
1257 aEvent.NewValue <<= xAcc;
1258 aEvent.IndexHint = -1;
1259 CommitChange(aEvent);
1263 else if (rHint.GetId() == SfxHintId::ScAccVisAreaChanged)
1265 Size aOutputSize;
1266 vcl::Window* pSizeWindow = mpViewShell->GetWindow();
1267 if ( pSizeWindow )
1268 aOutputSize = pSizeWindow->GetOutputSizePixel();
1269 tools::Rectangle aVisRect( Point(), aOutputSize );
1270 GetNotesChildren()->DataChanged(aVisRect);
1272 GetShapeChildren()->VisAreaChanged();
1274 AccessibleEventObject aEvent;
1275 aEvent.EventId = AccessibleEventId::VISIBLE_DATA_CHANGED;
1276 aEvent.Source = uno::Reference< XAccessibleContext >(this);
1277 CommitChange(aEvent);
1279 ScAccessibleDocumentBase::Notify(rBC, rHint);
1282 //===== XAccessibleComponent ============================================
1284 uno::Reference< XAccessible > SAL_CALL ScAccessibleDocumentPagePreview::getAccessibleAtPoint( const awt::Point& rPoint )
1286 uno::Reference<XAccessible> xAccessible;
1287 if (containsPoint(rPoint))
1289 SolarMutexGuard aGuard;
1290 IsObjectValid();
1292 if ( mpViewShell )
1294 xAccessible = GetShapeChildren()->GetForegroundShapeAt(rPoint);
1295 if (!xAccessible.is())
1297 const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
1298 ScPagePreviewCountData aCount( rData, mpViewShell->GetWindow(), GetNotesChildren(), GetShapeChildren() );
1300 if ( !mpTable.is() && (aCount.nTables > 0) )
1302 //! order is background shapes, header, table or notes, footer, foreground shapes, controls
1303 sal_Int32 nIndex (aCount.nBackShapes + aCount.nHeaders);
1305 mpTable = new ScAccessiblePreviewTable( this, mpViewShell, nIndex );
1306 mpTable->Init();
1308 if (mpTable.is()
1309 && vcl::unohelper::ConvertToVCLRect(mpTable->getBounds())
1310 .Contains(vcl::unohelper::ConvertToVCLPoint(rPoint)))
1311 xAccessible = mpTable.get();
1313 if (!xAccessible.is())
1314 xAccessible = GetNotesChildren()->GetAt(rPoint);
1315 if (!xAccessible.is())
1317 if (!mpHeader.is() || !mpFooter.is())
1319 const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
1320 ScPagePreviewCountData aCount( rData, mpViewShell->GetWindow(), GetNotesChildren(), GetShapeChildren() );
1322 if (!mpHeader.is())
1324 mpHeader = new ScAccessiblePageHeader( this, mpViewShell, true, aCount.nBackShapes + aCount.nHeaders - 1);
1326 if (!mpFooter.is())
1328 mpFooter = new ScAccessiblePageHeader( this, mpViewShell, false, aCount.nBackShapes + aCount.nHeaders + aCount.nTables + aCount.nNoteParagraphs + aCount.nFooters - 1 );
1332 Point aPoint(vcl::unohelper::ConvertToVCLPoint(rPoint));
1334 if (vcl::unohelper::ConvertToVCLRect(mpHeader->getBounds()).Contains(aPoint))
1335 xAccessible = mpHeader.get();
1336 else if (vcl::unohelper::ConvertToVCLRect(mpFooter->getBounds()).Contains(aPoint))
1337 xAccessible = mpFooter.get();
1339 if (!xAccessible.is())
1340 xAccessible = GetShapeChildren()->GetBackgroundShapeAt(rPoint);
1344 return xAccessible;
1347 void SAL_CALL ScAccessibleDocumentPagePreview::grabFocus()
1349 SolarMutexGuard aGuard;
1350 IsObjectValid();
1351 if (getAccessibleParent().is())
1353 uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY);
1354 if (xAccessibleComponent.is())
1356 // just grab the focus for the window
1357 xAccessibleComponent->grabFocus();
1362 //===== XAccessibleContext ==============================================
1364 sal_Int64 SAL_CALL ScAccessibleDocumentPagePreview::getAccessibleChildCount()
1366 SolarMutexGuard aGuard;
1367 IsObjectValid();
1369 sal_Int64 nRet = 0;
1370 if ( mpViewShell )
1372 ScPagePreviewCountData aCount( mpViewShell->GetLocationData(), mpViewShell->GetWindow(), GetNotesChildren(), GetShapeChildren() );
1373 nRet = aCount.GetTotal();
1376 return nRet;
1379 uno::Reference<XAccessible> SAL_CALL ScAccessibleDocumentPagePreview::getAccessibleChild(sal_Int64 nIndex)
1381 SolarMutexGuard aGuard;
1382 IsObjectValid();
1383 uno::Reference<XAccessible> xAccessible;
1385 if ( mpViewShell )
1387 const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
1388 ScPagePreviewCountData aCount( rData, mpViewShell->GetWindow(), GetNotesChildren(), GetShapeChildren() );
1390 if ( nIndex < aCount.nBackShapes )
1392 xAccessible = GetShapeChildren()->GetBackShape(nIndex);
1394 else if ( nIndex < aCount.nBackShapes + aCount.nHeaders )
1396 if ( !mpHeader.is() )
1398 mpHeader = new ScAccessiblePageHeader( this, mpViewShell, true, nIndex );
1401 xAccessible = mpHeader.get();
1403 else if ( nIndex < aCount.nBackShapes + aCount.nHeaders + aCount.nTables )
1405 if ( !mpTable.is() )
1407 mpTable = new ScAccessiblePreviewTable( this, mpViewShell, nIndex );
1408 mpTable->Init();
1410 xAccessible = mpTable.get();
1412 else if ( nIndex < aCount.nBackShapes + aCount.nHeaders + aCount.nNoteParagraphs )
1414 xAccessible = GetNotesChildren()->GetChild(nIndex - aCount.nBackShapes - aCount.nHeaders);
1416 else if ( nIndex < aCount.nBackShapes + aCount.nHeaders + aCount.nTables + aCount.nNoteParagraphs + aCount.nFooters )
1418 if ( !mpFooter.is() )
1420 mpFooter = new ScAccessiblePageHeader( this, mpViewShell, false, nIndex );
1422 xAccessible = mpFooter.get();
1424 else
1426 sal_Int64 nIdx(nIndex - (aCount.nBackShapes + aCount.nHeaders + aCount.nTables + aCount.nNoteParagraphs + aCount.nFooters));
1427 if (nIdx < aCount.nForeShapes)
1428 xAccessible = GetShapeChildren()->GetForeShape(nIdx);
1429 else
1430 xAccessible = GetShapeChildren()->GetControl(nIdx - aCount.nForeShapes);
1434 if ( !xAccessible.is() )
1435 throw lang::IndexOutOfBoundsException();
1437 return xAccessible;
1440 /// Return the set of current states.
1441 sal_Int64 SAL_CALL ScAccessibleDocumentPagePreview::getAccessibleStateSet()
1443 SolarMutexGuard aGuard;
1444 sal_Int64 nParentStates = 0;
1445 if (getAccessibleParent().is())
1447 uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
1448 nParentStates = xParentContext->getAccessibleStateSet();
1450 sal_Int64 nStateSet = 0;
1451 if (IsDefunc(nParentStates))
1452 nStateSet |= AccessibleStateType::DEFUNC;
1453 else
1455 // never editable
1456 nStateSet |= AccessibleStateType::ENABLED;
1457 nStateSet |= AccessibleStateType::OPAQUE;
1458 if (isShowing())
1459 nStateSet |= AccessibleStateType::SHOWING;
1460 if (isVisible())
1461 nStateSet |= AccessibleStateType::VISIBLE;
1463 return nStateSet;
1466 //===== XServiceInfo ====================================================
1468 OUString SAL_CALL ScAccessibleDocumentPagePreview::getImplementationName()
1470 return u"ScAccessibleDocumentPagePreview"_ustr;
1473 uno::Sequence< OUString> SAL_CALL ScAccessibleDocumentPagePreview::getSupportedServiceNames()
1475 const css::uno::Sequence<OUString> vals { u"com.sun.star.AccessibleSpreadsheetPageView"_ustr };
1476 return comphelper::concatSequences(ScAccessibleContextBase::getSupportedServiceNames(), vals);
1479 //===== XTypeProvider =======================================================
1481 uno::Sequence<sal_Int8> SAL_CALL
1482 ScAccessibleDocumentPagePreview::getImplementationId()
1484 return css::uno::Sequence<sal_Int8>();
1487 //===== internal ========================================================
1489 OUString ScAccessibleDocumentPagePreview::createAccessibleDescription()
1491 return STR_ACC_PREVIEWDOC_DESCR;
1494 OUString ScAccessibleDocumentPagePreview::createAccessibleName()
1496 OUString sName = ScResId(STR_ACC_PREVIEWDOC_NAME);
1497 return sName;
1500 AbsoluteScreenPixelRectangle ScAccessibleDocumentPagePreview::GetBoundingBoxOnScreen() const
1502 AbsoluteScreenPixelRectangle aRect;
1503 if (mpViewShell)
1505 vcl::Window* pWindow = mpViewShell->GetWindow();
1506 if (pWindow)
1507 aRect = pWindow->GetWindowExtentsAbsolute();
1509 return aRect;
1512 tools::Rectangle ScAccessibleDocumentPagePreview::GetBoundingBox() const
1514 tools::Rectangle aRect;
1515 if (mpViewShell)
1517 vcl::Window* pWindow = mpViewShell->GetWindow();
1518 if (pWindow)
1519 aRect = pWindow->GetWindowExtentsRelative(*pWindow->GetAccessibleParentWindow());
1521 return aRect;
1524 bool ScAccessibleDocumentPagePreview::IsDefunc(sal_Int64 nParentStates)
1526 return ScAccessibleContextBase::IsDefunc() || !getAccessibleParent().is() ||
1527 (nParentStates & AccessibleStateType::DEFUNC);
1530 ScNotesChildren* ScAccessibleDocumentPagePreview::GetNotesChildren()
1532 if (!mpNotesChildren && mpViewShell)
1534 mpNotesChildren.reset( new ScNotesChildren(mpViewShell, this) );
1536 const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
1537 ScPagePreviewCountData aCount( rData, mpViewShell->GetWindow(), GetNotesChildren(), GetShapeChildren() );
1539 //! order is background shapes, header, table or notes, footer, foreground shapes, controls
1540 mpNotesChildren->Init(aCount.aVisRect, aCount.nBackShapes + aCount.nHeaders);
1542 return mpNotesChildren.get();
1545 ScShapeChildren* ScAccessibleDocumentPagePreview::GetShapeChildren()
1547 if (!mpShapeChildren && mpViewShell)
1549 mpShapeChildren.reset( new ScShapeChildren(mpViewShell, this) );
1550 mpShapeChildren->Init();
1553 return mpShapeChildren.get();
1556 OUString ScAccessibleDocumentPagePreview::getAccessibleName()
1558 SolarMutexGuard g;
1560 OUString aName = ScResId(STR_ACC_DOC_SPREADSHEET);
1561 ScDocument& rScDoc = mpViewShell->GetDocument();
1563 ScDocShell* pObjSh = rScDoc.GetDocumentShell();
1564 if (!pObjSh)
1565 return aName;
1567 OUString aFileName;
1568 SfxMedium* pMed = pObjSh->GetMedium();
1569 if (pMed)
1570 aFileName = pMed->GetName();
1572 if (aFileName.isEmpty())
1573 aFileName = pObjSh->GetTitle(SFX_TITLE_APINAME);
1575 if (!aFileName.isEmpty())
1577 aName = aFileName + " - " + aName + ScResId(STR_ACC_DOC_PREVIEW_SUFFIX);
1581 return aName;
1584 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */