1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <AccessibleDrawDocumentView.hxx>
21 #include <com/sun/star/drawing/ShapeCollection.hpp>
22 #include <com/sun/star/drawing/XDrawView.hpp>
23 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
24 #include <com/sun/star/drawing/XShapes.hpp>
25 #include <com/sun/star/beans/XPropertySet.hpp>
26 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
27 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
28 #include <com/sun/star/frame/XController.hpp>
29 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
30 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
31 #include <com/sun/star/view/XSelectionSupplier.hpp>
32 #include <cppuhelper/queryinterface.hxx>
33 #include <comphelper/processfactory.hxx>
34 #include <sal/log.hxx>
35 #include <tools/debug.hxx>
37 #include <svx/AccessibleShape.hxx>
38 #include <svx/ChildrenManager.hxx>
39 #include <svx/svdobj.hxx>
40 #include <vcl/svapp.hxx>
42 #include <ViewShell.hxx>
44 #include <DrawDocShell.hxx>
45 #include <drawdoc.hxx>
47 #include <slideshow.hxx>
48 #include <anminfo.hxx>
49 #include <AccessiblePageShape.hxx>
51 #include <strings.hrc>
52 #include <sdresid.hxx>
53 #include <osl/mutex.hxx>
55 using namespace ::com::sun::star
;
56 using namespace ::com::sun::star::uno
;
57 using namespace ::com::sun::star::accessibility
;
59 namespace accessibility
{
63 struct XShapePosCompareHelper
65 bool operator() ( const uno::Reference
<drawing::XShape
>& xshape1
,
66 const uno::Reference
<drawing::XShape
>& xshape2
) const
68 // modify the compare method to return the Z-Order, not layout order
69 SdrObject
* pObj1
= SdrObject::getSdrObjectFromXShape(xshape1
);
70 SdrObject
* pObj2
= SdrObject::getSdrObjectFromXShape(xshape2
);
72 return pObj1
->GetOrdNum() < pObj2
->GetOrdNum();
80 //===== internal ============================================================
82 AccessibleDrawDocumentView::AccessibleDrawDocumentView (
83 ::sd::Window
* pSdWindow
,
84 ::sd::ViewShell
* pViewShell
,
85 const uno::Reference
<frame::XController
>& rxController
,
86 const uno::Reference
<XAccessible
>& rxParent
)
87 : AccessibleDocumentViewBase (pSdWindow
, pViewShell
, rxController
, rxParent
),
88 mpSdViewSh( pViewShell
)
90 UpdateAccessibleName();
93 AccessibleDrawDocumentView::~AccessibleDrawDocumentView()
95 DBG_ASSERT (rBHelper
.bDisposed
|| rBHelper
.bInDispose
,
96 "~AccessibleDrawDocumentView: object has not been disposed");
99 void AccessibleDrawDocumentView::Init()
101 AccessibleDocumentViewBase::Init ();
103 // Determine the list of shapes on the current page.
104 uno::Reference
<drawing::XShapes
> xShapeList
;
105 uno::Reference
<drawing::XDrawView
> xView (mxController
, uno::UNO_QUERY
);
107 xShapeList
= xView
->getCurrentPage();
109 // Create the children manager.
110 mpChildrenManager
.reset(new ChildrenManager(this, xShapeList
, maShapeTreeInfo
, *this));
112 rtl::Reference
<AccessiblePageShape
> xPage(CreateDrawPageShape());
116 mpChildrenManager
->AddAccessibleShape (xPage
);
117 mpChildrenManager
->Update ();
120 mpChildrenManager
->UpdateSelection ();
123 void AccessibleDrawDocumentView::ViewForwarderChanged()
125 AccessibleDocumentViewBase::ViewForwarderChanged();
126 if (mpChildrenManager
!= nullptr)
127 mpChildrenManager
->ViewForwarderChanged();
130 /** The page shape is created on every call at the moment (provided that
131 everything goes well).
133 rtl::Reference
<AccessiblePageShape
> AccessibleDrawDocumentView::CreateDrawPageShape()
135 rtl::Reference
<AccessiblePageShape
> xShape
;
137 // Create a shape that represents the actual draw page.
138 uno::Reference
<drawing::XDrawView
> xView (mxController
, uno::UNO_QUERY
);
141 uno::Reference
<beans::XPropertySet
> xSet (
142 uno::Reference
<beans::XPropertySet
> (xView
->getCurrentPage(), uno::UNO_QUERY
));
145 // Create a rectangle shape that will represent the draw page.
146 uno::Reference
<lang::XMultiServiceFactory
> xFactory (mxModel
, uno::UNO_QUERY
);
147 uno::Reference
<drawing::XShape
> xRectangle
;
149 xRectangle
.set(xFactory
->createInstance ("com.sun.star.drawing.RectangleShape"),
152 // Set the shape's size and position.
156 awt::Point aPosition
;
159 // Set size and position of the shape to those of the draw
161 aValue
= xSet
->getPropertyValue ("BorderLeft");
162 aValue
>>= aPosition
.X
;
163 aValue
= xSet
->getPropertyValue ("BorderTop");
164 aValue
>>= aPosition
.Y
;
165 xRectangle
->setPosition (aPosition
);
167 aValue
= xSet
->getPropertyValue ("Width");
168 aValue
>>= aSize
.Width
;
169 aValue
= xSet
->getPropertyValue ("Height");
170 aValue
>>= aSize
.Height
;
171 xRectangle
->setSize (aSize
);
173 // Create the accessible object for the shape and
175 xShape
= new AccessiblePageShape (
176 xView
->getCurrentPage(), this, maShapeTreeInfo
);
183 //===== XAccessibleContext ==================================================
186 AccessibleDrawDocumentView::getAccessibleChildCount()
190 sal_Int64 nChildCount
= AccessibleDocumentViewBase::getAccessibleChildCount();
192 // Forward request to children manager.
193 if (mpChildrenManager
!= nullptr)
194 nChildCount
+= mpChildrenManager
->GetChildCount();
199 uno::Reference
<XAccessible
> SAL_CALL
200 AccessibleDrawDocumentView::getAccessibleChild (sal_Int64 nIndex
)
204 ::osl::ClearableMutexGuard
aGuard (m_aMutex
);
206 // Take care of children of the base class.
207 sal_Int64 nCount
= AccessibleDocumentViewBase::getAccessibleChildCount();
211 return AccessibleDocumentViewBase::getAccessibleChild(nIndex
);
216 // Create a copy of the pointer to the children manager and release the
217 // mutex before calling any of its methods.
218 ChildrenManager
* pChildrenManager
= mpChildrenManager
.get();
221 // Forward request to children manager.
222 if (pChildrenManager
== nullptr)
223 throw lang::IndexOutOfBoundsException (
224 "no accessible child with index " + OUString::number(nIndex
),
225 static_cast<uno::XWeak
*>(this));
227 return pChildrenManager
->GetChild (nIndex
);
231 AccessibleDrawDocumentView::getAccessibleName()
235 OUString sName
= SdResId(SID_SD_A11Y_D_PRESENTATION
);
236 ::sd::View
* pSdView
= static_cast< ::sd::View
* >( maShapeTreeInfo
.GetSdrView() );
239 SdDrawDocument
& rDoc
= pSdView
->GetDoc();
240 OUString sFileName
= rDoc
.getDocAccTitle();
241 if ( !sFileName
.getLength() )
243 ::sd::DrawDocShell
* pDocSh
= pSdView
->GetDocSh();
246 sFileName
= pDocSh
->GetTitle( SFX_TITLE_APINAME
);
251 if(rDoc
.getDocReadOnly())
253 sReadOnly
= SdResId(SID_SD_A11Y_D_PRESENTATION_READONLY
);
256 if ( sFileName
.getLength() )
258 sName
= sFileName
+ sReadOnly
+ " - " + sName
;
265 //===== XEventListener ======================================================
268 AccessibleDrawDocumentView::disposing (const lang::EventObject
& rEventObject
)
272 AccessibleDocumentViewBase::disposing (rEventObject
);
273 if (rEventObject
.Source
== mxModel
)
275 ::osl::Guard
< ::osl::Mutex
> aGuard (::osl::Mutex::getGlobalMutex());
276 // maShapeTreeInfo has been modified in base class.
277 if (mpChildrenManager
!= nullptr)
278 mpChildrenManager
->SetInfo (maShapeTreeInfo
);
282 //===== XPropertyChangeListener =============================================
285 AccessibleDrawDocumentView::propertyChange (const beans::PropertyChangeEvent
& rEventObject
)
289 AccessibleDocumentViewBase::propertyChange (rEventObject
);
291 // add page switch event for slide show mode
292 if (rEventObject
.PropertyName
== "CurrentPage" ||
293 rEventObject
.PropertyName
== "PageChange")
295 // Update the accessible name to reflect the current slide.
296 UpdateAccessibleName();
298 // The current page changed. Update the children manager accordingly.
299 uno::Reference
<drawing::XDrawView
> xView (mxController
, uno::UNO_QUERY
);
300 if (xView
.is() && mpChildrenManager
!=nullptr)
302 // Inform the children manager to forget all children and give
304 mpChildrenManager
->ClearAccessibleShapeList ();
305 mpChildrenManager
->SetShapeList (xView
->getCurrentPage());
307 rtl::Reference
<AccessiblePageShape
> xPage(CreateDrawPageShape ());
311 mpChildrenManager
->AddAccessibleShape (xPage
);
312 mpChildrenManager
->Update (false);
316 SAL_WARN("sd", "View invalid");
317 CommitChange(AccessibleEventId::PAGE_CHANGED
,rEventObject
.NewValue
,rEventObject
.OldValue
, -1);
319 else if ( rEventObject
.PropertyName
== "VisibleArea" )
321 if (mpChildrenManager
!= nullptr)
322 mpChildrenManager
->ViewForwarderChanged();
324 else if (rEventObject
.PropertyName
== "ActiveLayer")
326 CommitChange(AccessibleEventId::PAGE_CHANGED
,rEventObject
.NewValue
,rEventObject
.OldValue
, -1);
328 else if (rEventObject
.PropertyName
== "UpdateAcc")
330 // The current page changed. Update the children manager accordingly.
331 uno::Reference
<drawing::XDrawView
> xView (mxController
, uno::UNO_QUERY
);
332 if (xView
.is() && mpChildrenManager
!=nullptr)
334 // Inform the children manager to forget all children and give
336 mpChildrenManager
->ClearAccessibleShapeList ();
337 // update the slide show page's accessible info
338 //mpChildrenManager->SetShapeList (uno::Reference<drawing::XShapes> (
339 // xView->getCurrentPage(), uno::UNO_QUERY));
340 rtl::Reference
< sd::SlideShow
> xSlideshow( sd::SlideShow::GetSlideShow( mpSdViewSh
->GetViewShellBase() ) );
341 if( xSlideshow
.is() && xSlideshow
->isRunning() && xSlideshow
->isFullScreen() )
343 css::uno::Reference
< drawing::XDrawPage
> xSlide
;
344 // MT IA2: Not used...
345 // sal_Int32 currentPageIndex = xSlideshow->getCurrentPageIndex();
346 css::uno::Reference
< css::presentation::XSlideShowController
> xSlideController
= xSlideshow
->getController();
347 if( xSlideController
.is() )
349 xSlide
= xSlideController
->getCurrentSlide();
352 mpChildrenManager
->SetShapeList (xSlide
);
356 rtl::Reference
<AccessiblePageShape
> xPage(CreateDrawPageShape ());
360 mpChildrenManager
->AddAccessibleShape (xPage
);
361 mpChildrenManager
->Update (false);
367 SAL_INFO("sd", "unhandled");
374 AccessibleDrawDocumentView::getImplementationName()
376 return "AccessibleDrawDocumentView";
379 css::uno::Sequence
< OUString
> SAL_CALL
380 AccessibleDrawDocumentView::getSupportedServiceNames()
383 const css::uno::Sequence
<OUString
> vals
{ "com.sun.star.drawing.AccessibleDrawDocumentView" };
384 uno::Sequence
<OUString
> aServiceNames
=
385 AccessibleDocumentViewBase::getSupportedServiceNames();
387 return comphelper::concatSequences(aServiceNames
, vals
);
390 //===== XInterface ==========================================================
393 AccessibleDrawDocumentView::queryInterface (const uno::Type
& rType
)
395 uno::Any aReturn
= AccessibleDocumentViewBase::queryInterface (rType
);
396 if ( ! aReturn
.hasValue())
397 aReturn
= ::cppu::queryInterface (rType
,
398 static_cast<XAccessibleGroupPosition
*>(this)
404 AccessibleDrawDocumentView::acquire()
407 AccessibleDocumentViewBase::acquire ();
410 AccessibleDrawDocumentView::release()
413 AccessibleDocumentViewBase::release ();
415 //===== XAccessibleGroupPosition =========================================
416 uno::Sequence
< sal_Int32
> SAL_CALL
417 AccessibleDrawDocumentView::getGroupPosition( const uno::Any
& rAny
)
421 // we will return the:
422 // [0] group level(always be 0 now)
423 // [1] similar items counts in the group
424 // [2] the position of the object in the group
425 uno::Sequence
< sal_Int32
> aRet( 3 );
426 //get the xShape of the current selected drawing object
427 uno::Reference
<XAccessibleContext
> xAccContent
;
428 rAny
>>= xAccContent
;
429 if ( !xAccContent
.is() )
433 AccessibleShape
* pAcc
= comphelper::getFromUnoTunnel
<AccessibleShape
>( xAccContent
);
438 uno::Reference
< drawing::XShape
> xCurShape
= pAcc
->GetXShape();
439 if ( !xCurShape
.is() )
443 //find all the child in the page, insert them into a vector and sort
444 if ( mpChildrenManager
== nullptr )
448 std::vector
< uno::Reference
<drawing::XShape
> > vXShapes
;
449 sal_Int32 nCount
= mpChildrenManager
->GetChildCount();
450 //get pointer of SdView & SdrPageView for further use.
451 SdrPageView
* pPV
= nullptr;
452 ::sd::View
* pSdView
= nullptr;
455 pSdView
= mpSdViewSh
->GetView();
456 pPV
= pSdView
->GetSdrPageView();
458 for ( sal_Int32 i
= 0; i
< nCount
; i
++ )
460 uno::Reference
< drawing::XShape
> xShape
= mpChildrenManager
->GetChildShape(i
);
463 //if the object is visible in the page, we add it into the group list.
464 SdrObject
* pObj
= SdrObject::getSdrObjectFromXShape(xShape
);
465 if ( pObj
&& pPV
&& pSdView
&& pSdView
->IsObjMarkable( pObj
, pPV
) )
467 vXShapes
.push_back( xShape
);
471 std::sort( vXShapes
.begin(), vXShapes
.end(), XShapePosCompareHelper() );
472 //get the index of the selected object in the group
473 auto aIter
= std::find_if(vXShapes
.begin(), vXShapes
.end(),
474 [&xCurShape
](const uno::Reference
<drawing::XShape
>& rxShape
) { return rxShape
.get() == xCurShape
.get(); });
475 if (aIter
!= vXShapes
.end())
477 sal_Int32
* pArray
= aRet
.getArray();
478 pArray
[0] = 1; //it should be 1 based, not 0 based.
479 pArray
[1] = vXShapes
.size();
480 pArray
[2] = static_cast<sal_Int32
>(std::distance(vXShapes
.begin(), aIter
)) + 1; //we start counting position from 1
485 OUString
AccessibleDrawDocumentView::getObjectLink( const uno::Any
& rAny
)
490 //get the xShape of the current selected drawing object
491 uno::Reference
<XAccessibleContext
> xAccContent
;
492 rAny
>>= xAccContent
;
493 if ( !xAccContent
.is() )
497 AccessibleShape
* pAcc
= comphelper::getFromUnoTunnel
<AccessibleShape
>( xAccContent
);
502 uno::Reference
< drawing::XShape
> xCurShape
= pAcc
->GetXShape();
503 if ( !xCurShape
.is() )
507 SdrObject
* pObj
= SdrObject::getSdrObjectFromXShape(xCurShape
);
510 SdAnimationInfo
* pInfo
= SdDrawDocument::GetShapeUserData(*pObj
);
511 if( pInfo
&& (pInfo
->meClickAction
== presentation::ClickAction_DOCUMENT
) )
512 aRet
= pInfo
->GetBookmark();
517 /// Create a name for this view.
518 OUString
AccessibleDrawDocumentView::CreateAccessibleName()
522 uno::Reference
<lang::XServiceInfo
> xInfo (mxController
, uno::UNO_QUERY
);
525 uno::Sequence
< OUString
> aServices( xInfo
->getSupportedServiceNames() );
526 OUString sFirstService
= aServices
[0];
527 if ( sFirstService
== "com.sun.star.drawing.DrawingDocumentDrawView" )
529 if( aServices
.getLength() >= 2 && aServices
[1] == "com.sun.star.presentation.PresentationView")
531 SolarMutexGuard aGuard
;
533 sName
= SdResId(SID_SD_A11Y_I_DRAWVIEW_N
);
537 SolarMutexGuard aGuard
;
539 sName
= SdResId(SID_SD_A11Y_D_DRAWVIEW_N
);
542 else if ( sFirstService
== "com.sun.star.presentation.NotesView" )
544 SolarMutexGuard aGuard
;
546 sName
= SdResId(SID_SD_A11Y_I_NOTESVIEW_N
);
548 else if ( sFirstService
== "com.sun.star.presentation.HandoutView" )
550 SolarMutexGuard aGuard
;
552 sName
= SdResId(SID_SD_A11Y_I_HANDOUTVIEW_N
);
556 sName
= sFirstService
;
561 sName
= "AccessibleDrawDocumentView";
566 /** Return selection state of specified child
569 AccessibleDrawDocumentView::implIsSelected( sal_Int64 nAccessibleChildIndex
)
571 const SolarMutexGuard aSolarGuard
;
572 uno::Reference
< view::XSelectionSupplier
> xSel( mxController
, uno::UNO_QUERY
);
575 OSL_ENSURE( 0 <= nAccessibleChildIndex
, "AccessibleDrawDocumentView::implIsSelected: invalid index!" );
577 if( xSel
.is() && ( 0 <= nAccessibleChildIndex
) )
579 uno::Any
aAny( xSel
->getSelection() );
580 uno::Reference
< drawing::XShapes
> xShapes
;
586 AccessibleShape
* pAcc
= comphelper::getFromUnoTunnel
<AccessibleShape
>( getAccessibleChild( nAccessibleChildIndex
) );
590 uno::Reference
< drawing::XShape
> xShape( pAcc
->GetXShape() );
594 for( sal_Int32 i
= 0, nCount
= xShapes
->getCount(); ( i
< nCount
) && !bRet
; ++i
)
595 if( xShapes
->getByIndex( i
) == xShape
)
605 /** Select or deselect the specified shapes. The corresponding accessible
606 shapes are notified over the selection change listeners registered with
607 the XSelectionSupplier of the controller.
610 AccessibleDrawDocumentView::implSelect( sal_Int64 nAccessibleChildIndex
, bool bSelect
)
612 const SolarMutexGuard aSolarGuard
;
613 uno::Reference
< view::XSelectionSupplier
> xSel( mxController
, uno::UNO_QUERY
);
620 if( ACCESSIBLE_SELECTION_CHILD_ALL
== nAccessibleChildIndex
)
622 // Select or deselect all children.
625 xSel
->select( aAny
);
628 uno::Reference
< drawing::XShapes
> xShapes
= drawing::ShapeCollection::create(
629 comphelper::getProcessComponentContext());
631 for(sal_Int64 i
= 0, nCount
= getAccessibleChildCount(); i
< nCount
; ++i
)
633 AccessibleShape
* pAcc
= comphelper::getFromUnoTunnel
<AccessibleShape
>( getAccessibleChild( i
) );
635 if( pAcc
&& pAcc
->GetXShape().is() )
636 xShapes
->add( pAcc
->GetXShape() );
639 if( xShapes
->getCount() )
641 xSel
->select( Any(xShapes
) );
645 else if( nAccessibleChildIndex
>= 0 )
647 // Select or deselect only the child with index
648 // nAccessibleChildIndex.
650 AccessibleShape
* pAcc
= comphelper::getFromUnoTunnel
<AccessibleShape
>(
651 getAccessibleChild( nAccessibleChildIndex
));
653 // Add or remove the shape that is made accessible from the
654 // selection of the controller.
657 uno::Reference
< drawing::XShape
> xShape( pAcc
->GetXShape() );
661 uno::Reference
< drawing::XShapes
> xShapes
;
664 aAny
= xSel
->getSelection();
667 // Search shape to be selected in current selection.
670 sal_Int32 nCount
= xShapes
->getCount();
671 for (sal_Int32 i
=0; ( i
< nCount
) && !bFound
; ++i
)
672 if( xShapes
->getByIndex( i
) == xShape
)
676 // Create an empty selection to add the shape to.
677 xShapes
= drawing::ShapeCollection::create(
678 comphelper::getProcessComponentContext());
680 // Update the selection.
681 if( !bFound
&& bSelect
)
682 xShapes
->add( xShape
);
683 else if( bFound
&& !bSelect
)
684 xShapes
->remove( xShape
);
686 xSel
->select( Any(xShapes
) );
692 void AccessibleDrawDocumentView::Activated()
694 if (mpChildrenManager
== nullptr)
697 bool bChange
= false;
698 // When none of the children has the focus then claim it for the
700 if ( ! mpChildrenManager
->HasFocus())
702 SetState (AccessibleStateType::FOCUSED
);
706 ResetState (AccessibleStateType::FOCUSED
);
707 mpChildrenManager
->UpdateSelection();
708 // if the child gets focus in UpdateSelection(), needs to reset the focus on document.
709 if (mpChildrenManager
->HasFocus() && bChange
)
710 ResetState (AccessibleStateType::FOCUSED
);
713 void AccessibleDrawDocumentView::Deactivated()
715 if (mpChildrenManager
!= nullptr)
716 mpChildrenManager
->RemoveFocus();
717 ResetState (AccessibleStateType::FOCUSED
);
720 void AccessibleDrawDocumentView::impl_dispose()
722 mpChildrenManager
.reset();
723 AccessibleDocumentViewBase::impl_dispose();
726 /** This method is called from the component helper base class while
729 void SAL_CALL
AccessibleDrawDocumentView::disposing()
731 // Release resources.
732 mpChildrenManager
.reset();
734 // Forward call to base classes.
735 AccessibleDocumentViewBase::disposing ();
738 void AccessibleDrawDocumentView::UpdateAccessibleName()
740 OUString
sNewName (CreateAccessibleName() + ": ");
742 // Add the number of the current slide.
743 uno::Reference
<drawing::XDrawView
> xView (mxController
, uno::UNO_QUERY
);
746 uno::Reference
<beans::XPropertySet
> xProperties (xView
->getCurrentPage(), UNO_QUERY
);
747 if (xProperties
.is())
750 sal_Int16
nPageNumber (0);
751 if (xProperties
->getPropertyValue("Number") >>= nPageNumber
)
753 sNewName
+= OUString::number(nPageNumber
);
756 catch (const beans::UnknownPropertyException
&)
761 // Add the number of pages/slides.
762 Reference
<drawing::XDrawPagesSupplier
> xPagesSupplier (mxModel
, UNO_QUERY
);
763 if (xPagesSupplier
.is())
765 Reference
<container::XIndexAccess
> xPages
= xPagesSupplier
->getDrawPages();
768 sNewName
+= " / " + OUString::number(xPages
->getCount());
772 SetAccessibleName (sNewName
, AutomaticallyCreated
);
775 } // end of namespace accessibility
777 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */