From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- .../accessibility/AccessibleDrawDocumentView.cxx | 777 +++++++++++++++++++++ 1 file changed, 777 insertions(+) create mode 100644 sd/source/ui/accessibility/AccessibleDrawDocumentView.cxx (limited to 'sd/source/ui/accessibility/AccessibleDrawDocumentView.cxx') diff --git a/sd/source/ui/accessibility/AccessibleDrawDocumentView.cxx b/sd/source/ui/accessibility/AccessibleDrawDocumentView.cxx new file mode 100644 index 000000000..f6111962a --- /dev/null +++ b/sd/source/ui/accessibility/AccessibleDrawDocumentView.cxx @@ -0,0 +1,777 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::accessibility; + +namespace accessibility { + +namespace { + +struct XShapePosCompareHelper +{ + bool operator() ( const uno::Reference& xshape1, + const uno::Reference& xshape2 ) const + { + // modify the compare method to return the Z-Order, not layout order + SdrObject* pObj1 = SdrObject::getSdrObjectFromXShape(xshape1); + SdrObject* pObj2 = SdrObject::getSdrObjectFromXShape(xshape2); + if(pObj1 && pObj2) + return pObj1->GetOrdNum() < pObj2->GetOrdNum(); + else + return false; + } +}; + +} + +//===== internal ============================================================ + +AccessibleDrawDocumentView::AccessibleDrawDocumentView ( + ::sd::Window* pSdWindow, + ::sd::ViewShell* pViewShell, + const uno::Reference& rxController, + const uno::Reference& rxParent) + : AccessibleDocumentViewBase (pSdWindow, pViewShell, rxController, rxParent), + mpSdViewSh( pViewShell ) +{ + UpdateAccessibleName(); +} + +AccessibleDrawDocumentView::~AccessibleDrawDocumentView() +{ + DBG_ASSERT (rBHelper.bDisposed || rBHelper.bInDispose, + "~AccessibleDrawDocumentView: object has not been disposed"); +} + +void AccessibleDrawDocumentView::Init() +{ + AccessibleDocumentViewBase::Init (); + + // Determine the list of shapes on the current page. + uno::Reference xShapeList; + uno::Reference xView (mxController, uno::UNO_QUERY); + if (xView.is()) + xShapeList = xView->getCurrentPage(); + + // Create the children manager. + mpChildrenManager.reset(new ChildrenManager(this, xShapeList, maShapeTreeInfo, *this)); + + rtl::Reference xPage(CreateDrawPageShape()); + if (xPage.is()) + { + xPage->Init(); + mpChildrenManager->AddAccessibleShape (xPage); + mpChildrenManager->Update (); + } + + mpChildrenManager->UpdateSelection (); +} + +void AccessibleDrawDocumentView::ViewForwarderChanged() +{ + AccessibleDocumentViewBase::ViewForwarderChanged(); + if (mpChildrenManager != nullptr) + mpChildrenManager->ViewForwarderChanged(); +} + +/** The page shape is created on every call at the moment (provided that + everything goes well). +*/ +rtl::Reference AccessibleDrawDocumentView::CreateDrawPageShape() +{ + rtl::Reference xShape; + + // Create a shape that represents the actual draw page. + uno::Reference xView (mxController, uno::UNO_QUERY); + if (xView.is()) + { + uno::Reference xSet ( + uno::Reference (xView->getCurrentPage(), uno::UNO_QUERY)); + if (xSet.is()) + { + // Create a rectangle shape that will represent the draw page. + uno::Reference xFactory (mxModel, uno::UNO_QUERY); + uno::Reference xRectangle; + if (xFactory.is()) + xRectangle.set(xFactory->createInstance ("com.sun.star.drawing.RectangleShape"), + uno::UNO_QUERY); + + // Set the shape's size and position. + if (xRectangle.is()) + { + uno::Any aValue; + awt::Point aPosition; + awt::Size aSize; + + // Set size and position of the shape to those of the draw + // page. + aValue = xSet->getPropertyValue ("BorderLeft"); + aValue >>= aPosition.X; + aValue = xSet->getPropertyValue ("BorderTop"); + aValue >>= aPosition.Y; + xRectangle->setPosition (aPosition); + + aValue = xSet->getPropertyValue ("Width"); + aValue >>= aSize.Width; + aValue = xSet->getPropertyValue ("Height"); + aValue >>= aSize.Height; + xRectangle->setSize (aSize); + + // Create the accessible object for the shape and + // initialize it. + xShape = new AccessiblePageShape ( + xView->getCurrentPage(), this, maShapeTreeInfo); + } + } + } + return xShape; +} + +//===== XAccessibleContext ================================================== + +sal_Int32 SAL_CALL + AccessibleDrawDocumentView::getAccessibleChildCount() +{ + ThrowIfDisposed (); + + tools::Long nChildCount = AccessibleDocumentViewBase::getAccessibleChildCount(); + + // Forward request to children manager. + if (mpChildrenManager != nullptr) + nChildCount += mpChildrenManager->GetChildCount(); + + return nChildCount; +} + +uno::Reference SAL_CALL + AccessibleDrawDocumentView::getAccessibleChild (sal_Int32 nIndex) +{ + ThrowIfDisposed (); + + ::osl::ClearableMutexGuard aGuard (m_aMutex); + + // Take care of children of the base class. + sal_Int32 nCount = AccessibleDocumentViewBase::getAccessibleChildCount(); + if (nCount > 0) + { + if (nIndex < nCount) + return AccessibleDocumentViewBase::getAccessibleChild(nIndex); + else + nIndex -= nCount; + } + + // Create a copy of the pointer to the children manager and release the + // mutex before calling any of its methods. + ChildrenManager* pChildrenManager = mpChildrenManager.get(); + aGuard.clear(); + + // Forward request to children manager. + if (pChildrenManager == nullptr) + throw lang::IndexOutOfBoundsException ( + "no accessible child with index " + OUString::number(nIndex), + static_cast(this)); + + return pChildrenManager->GetChild (nIndex); +} + +OUString SAL_CALL + AccessibleDrawDocumentView::getAccessibleName() +{ + SolarMutexGuard g; + + OUString sName = SdResId(SID_SD_A11Y_D_PRESENTATION); + ::sd::View* pSdView = static_cast< ::sd::View* >( maShapeTreeInfo.GetSdrView() ); + if ( pSdView ) + { + SdDrawDocument& rDoc = pSdView->GetDoc(); + OUString sFileName = rDoc.getDocAccTitle(); + if ( !sFileName.getLength() ) + { + ::sd::DrawDocShell* pDocSh = pSdView->GetDocSh(); + if ( pDocSh ) + { + sFileName = pDocSh->GetTitle( SFX_TITLE_APINAME ); + } + } + + OUString sReadOnly; + if(rDoc.getDocReadOnly()) + { + sReadOnly = SdResId(SID_SD_A11Y_D_PRESENTATION_READONLY); + } + + if ( sFileName.getLength() ) + { + sName = sFileName + sReadOnly + " - " + sName; + } + } + + return sName; +} + +//===== XEventListener ====================================================== + +void SAL_CALL + AccessibleDrawDocumentView::disposing (const lang::EventObject& rEventObject) +{ + ThrowIfDisposed (); + + AccessibleDocumentViewBase::disposing (rEventObject); + if (rEventObject.Source == mxModel) + { + ::osl::Guard< ::osl::Mutex> aGuard (::osl::Mutex::getGlobalMutex()); + // maShapeTreeInfo has been modified in base class. + if (mpChildrenManager != nullptr) + mpChildrenManager->SetInfo (maShapeTreeInfo); + } +} + +//===== XPropertyChangeListener ============================================= + +void SAL_CALL + AccessibleDrawDocumentView::propertyChange (const beans::PropertyChangeEvent& rEventObject) +{ + ThrowIfDisposed (); + + AccessibleDocumentViewBase::propertyChange (rEventObject); + + // add page switch event for slide show mode + if (rEventObject.PropertyName == "CurrentPage" || + rEventObject.PropertyName == "PageChange") + { + // Update the accessible name to reflect the current slide. + UpdateAccessibleName(); + + // The current page changed. Update the children manager accordingly. + uno::Reference xView (mxController, uno::UNO_QUERY); + if (xView.is() && mpChildrenManager!=nullptr) + { + // Inform the children manager to forget all children and give + // him the new ones. + mpChildrenManager->ClearAccessibleShapeList (); + mpChildrenManager->SetShapeList (xView->getCurrentPage()); + + rtl::Reference xPage(CreateDrawPageShape ()); + if (xPage.is()) + { + xPage->Init(); + mpChildrenManager->AddAccessibleShape (xPage); + mpChildrenManager->Update (false); + } + } + else + SAL_WARN("sd", "View invalid"); + CommitChange(AccessibleEventId::PAGE_CHANGED,rEventObject.NewValue,rEventObject.OldValue); + } + else if ( rEventObject.PropertyName == "VisibleArea" ) + { + if (mpChildrenManager != nullptr) + mpChildrenManager->ViewForwarderChanged(); + } + else if (rEventObject.PropertyName == "ActiveLayer") + { + CommitChange(AccessibleEventId::PAGE_CHANGED,rEventObject.NewValue,rEventObject.OldValue); + } + else if (rEventObject.PropertyName == "UpdateAcc") + { + // The current page changed. Update the children manager accordingly. + uno::Reference xView (mxController, uno::UNO_QUERY); + if (xView.is() && mpChildrenManager!=nullptr) + { + // Inform the children manager to forget all children and give + // him the new ones. + mpChildrenManager->ClearAccessibleShapeList (); + // update the slide show page's accessible info + //mpChildrenManager->SetShapeList (uno::Reference ( + // xView->getCurrentPage(), uno::UNO_QUERY)); + rtl::Reference< sd::SlideShow > xSlideshow( sd::SlideShow::GetSlideShow( mpSdViewSh->GetViewShellBase() ) ); + if( xSlideshow.is() && xSlideshow->isRunning() && xSlideshow->isFullScreen() ) + { + css::uno::Reference< drawing::XDrawPage > xSlide; + // MT IA2: Not used... + // sal_Int32 currentPageIndex = xSlideshow->getCurrentPageIndex(); + css::uno::Reference< css::presentation::XSlideShowController > xSlideController = xSlideshow->getController(); + if( xSlideController.is() ) + { + xSlide = xSlideController->getCurrentSlide(); + if (xSlide.is()) + { + mpChildrenManager->SetShapeList (xSlide); + } + } + } + rtl::Reference xPage(CreateDrawPageShape ()); + if (xPage.is()) + { + xPage->Init(); + mpChildrenManager->AddAccessibleShape (xPage); + mpChildrenManager->Update (false); + } + } + } + else + { + SAL_INFO("sd", "unhandled"); + } +} + +// XServiceInfo + +OUString SAL_CALL + AccessibleDrawDocumentView::getImplementationName() +{ + return "AccessibleDrawDocumentView"; +} + +css::uno::Sequence< OUString> SAL_CALL + AccessibleDrawDocumentView::getSupportedServiceNames() +{ + ThrowIfDisposed(); + const css::uno::Sequence vals { "com.sun.star.drawing.AccessibleDrawDocumentView" }; + uno::Sequence aServiceNames = + AccessibleDocumentViewBase::getSupportedServiceNames(); + + return comphelper::concatSequences(aServiceNames, vals); +} + +//===== XInterface ========================================================== + +uno::Any SAL_CALL + AccessibleDrawDocumentView::queryInterface (const uno::Type & rType) +{ + uno::Any aReturn = AccessibleDocumentViewBase::queryInterface (rType); + if ( ! aReturn.hasValue()) + aReturn = ::cppu::queryInterface (rType, + static_cast(this) + ); + return aReturn; +} + +void SAL_CALL + AccessibleDrawDocumentView::acquire() + noexcept +{ + AccessibleDocumentViewBase::acquire (); +} +void SAL_CALL + AccessibleDrawDocumentView::release() + noexcept +{ + AccessibleDocumentViewBase::release (); +} +//===== XAccessibleGroupPosition ========================================= +uno::Sequence< sal_Int32 > SAL_CALL + AccessibleDrawDocumentView::getGroupPosition( const uno::Any& rAny ) +{ + SolarMutexGuard g; + + // we will return the: + // [0] group level(always be 0 now) + // [1] similar items counts in the group + // [2] the position of the object in the group + uno::Sequence< sal_Int32 > aRet( 3 ); + //get the xShape of the current selected drawing object + uno::Reference xAccContent; + rAny >>= xAccContent; + if ( !xAccContent.is() ) + { + return aRet; + } + AccessibleShape* pAcc = comphelper::getFromUnoTunnel( xAccContent ); + if ( !pAcc ) + { + return aRet; + } + uno::Reference< drawing::XShape > xCurShape = pAcc->GetXShape(); + if ( !xCurShape.is() ) + { + return aRet; + } + //find all the child in the page, insert them into a vector and sort + if ( mpChildrenManager == nullptr ) + { + return aRet; + } + std::vector< uno::Reference > vXShapes; + sal_Int32 nCount = mpChildrenManager->GetChildCount(); + //get pointer of SdView & SdrPageView for further use. + SdrPageView* pPV = nullptr; + ::sd::View* pSdView = nullptr; + if ( mpSdViewSh ) + { + pSdView = mpSdViewSh->GetView(); + pPV = pSdView->GetSdrPageView(); + } + for ( sal_Int32 i = 0; i < nCount; i++ ) + { + uno::Reference< drawing::XShape > xShape = mpChildrenManager->GetChildShape(i); + if ( xShape.is() ) + { + //if the object is visible in the page, we add it into the group list. + SdrObject* pObj = SdrObject::getSdrObjectFromXShape(xShape); + if ( pObj && pPV && pSdView && pSdView->IsObjMarkable( pObj, pPV ) ) + { + vXShapes.push_back( xShape ); + } + } + } + std::sort( vXShapes.begin(), vXShapes.end(), XShapePosCompareHelper() ); + //get the index of the selected object in the group + auto aIter = std::find_if(vXShapes.begin(), vXShapes.end(), + [&xCurShape](const uno::Reference& rxShape) { return rxShape.get() == xCurShape.get(); }); + if (aIter != vXShapes.end()) + { + sal_Int32* pArray = aRet.getArray(); + pArray[0] = 1; //it should be 1 based, not 0 based. + pArray[1] = vXShapes.size(); + pArray[2] = static_cast(std::distance(vXShapes.begin(), aIter)) + 1; //we start counting position from 1 + } + return aRet; +} + +OUString AccessibleDrawDocumentView::getObjectLink( const uno::Any& rAny ) +{ + SolarMutexGuard g; + + OUString aRet; + //get the xShape of the current selected drawing object + uno::Reference xAccContent; + rAny >>= xAccContent; + if ( !xAccContent.is() ) + { + return aRet; + } + AccessibleShape* pAcc = comphelper::getFromUnoTunnel( xAccContent ); + if ( !pAcc ) + { + return aRet; + } + uno::Reference< drawing::XShape > xCurShape = pAcc->GetXShape(); + if ( !xCurShape.is() ) + { + return aRet; + } + SdrObject* pObj = SdrObject::getSdrObjectFromXShape(xCurShape); + if (pObj) + { + SdAnimationInfo* pInfo = SdDrawDocument::GetShapeUserData(*pObj); + if( pInfo && (pInfo->meClickAction == presentation::ClickAction_DOCUMENT) ) + aRet = pInfo->GetBookmark(); + } + return aRet; +} + +/// Create a name for this view. +OUString AccessibleDrawDocumentView::CreateAccessibleName() +{ + OUString sName; + + uno::Reference xInfo (mxController, uno::UNO_QUERY); + if (xInfo.is()) + { + uno::Sequence< OUString > aServices( xInfo->getSupportedServiceNames() ); + OUString sFirstService = aServices[0]; + if ( sFirstService == "com.sun.star.drawing.DrawingDocumentDrawView" ) + { + if( aServices.getLength() >= 2 && aServices[1] == "com.sun.star.presentation.PresentationView") + { + SolarMutexGuard aGuard; + + sName = SdResId(SID_SD_A11Y_I_DRAWVIEW_N); + } + else + { + SolarMutexGuard aGuard; + + sName = SdResId(SID_SD_A11Y_D_DRAWVIEW_N); + } + } + else if ( sFirstService == "com.sun.star.presentation.NotesView" ) + { + SolarMutexGuard aGuard; + + sName = SdResId(SID_SD_A11Y_I_NOTESVIEW_N); + } + else if ( sFirstService == "com.sun.star.presentation.HandoutView" ) + { + SolarMutexGuard aGuard; + + sName = SdResId(SID_SD_A11Y_I_HANDOUTVIEW_N); + } + else + { + sName = sFirstService; + } + } + else + { + sName = "AccessibleDrawDocumentView"; + } + return sName; +} + +/** Return selection state of specified child +*/ +bool + AccessibleDrawDocumentView::implIsSelected( sal_Int32 nAccessibleChildIndex ) +{ + const SolarMutexGuard aSolarGuard; + uno::Reference< view::XSelectionSupplier > xSel( mxController, uno::UNO_QUERY ); + bool bRet = false; + + OSL_ENSURE( 0 <= nAccessibleChildIndex, "AccessibleDrawDocumentView::implIsSelected: invalid index!" ); + + if( xSel.is() && ( 0 <= nAccessibleChildIndex ) ) + { + uno::Any aAny( xSel->getSelection() ); + uno::Reference< drawing::XShapes > xShapes; + + aAny >>= xShapes; + + if( xShapes.is() ) + { + AccessibleShape* pAcc = comphelper::getFromUnoTunnel( getAccessibleChild( nAccessibleChildIndex ) ); + + if( pAcc ) + { + uno::Reference< drawing::XShape > xShape( pAcc->GetXShape() ); + + if( xShape.is() ) + { + for( sal_Int32 i = 0, nCount = xShapes->getCount(); ( i < nCount ) && !bRet; ++i ) + if( xShapes->getByIndex( i ) == xShape ) + bRet = true; + } + } + } + } + + return bRet; +} + +/** Select or deselect the specified shapes. The corresponding accessible + shapes are notified over the selection change listeners registered with + the XSelectionSupplier of the controller. +*/ +void + AccessibleDrawDocumentView::implSelect( sal_Int32 nAccessibleChildIndex, bool bSelect ) +{ + const SolarMutexGuard aSolarGuard; + uno::Reference< view::XSelectionSupplier > xSel( mxController, uno::UNO_QUERY ); + + if( !xSel.is() ) + return; + + uno::Any aAny; + + if( ACCESSIBLE_SELECTION_CHILD_ALL == nAccessibleChildIndex ) + { + // Select or deselect all children. + + if( !bSelect ) + xSel->select( aAny ); + else + { + uno::Reference< drawing::XShapes > xShapes = drawing::ShapeCollection::create( + comphelper::getProcessComponentContext()); + + for(sal_Int32 i = 0, nCount = getAccessibleChildCount(); i < nCount; ++i ) + { + AccessibleShape* pAcc = comphelper::getFromUnoTunnel( getAccessibleChild( i ) ); + + if( pAcc && pAcc->GetXShape().is() ) + xShapes->add( pAcc->GetXShape() ); + } + + if( xShapes->getCount() ) + { + xSel->select( Any(xShapes) ); + } + } + } + else if( nAccessibleChildIndex >= 0 ) + { + // Select or deselect only the child with index + // nAccessibleChildIndex. + + AccessibleShape* pAcc = comphelper::getFromUnoTunnel( + getAccessibleChild( nAccessibleChildIndex )); + + // Add or remove the shape that is made accessible from the + // selection of the controller. + if( pAcc ) + { + uno::Reference< drawing::XShape > xShape( pAcc->GetXShape() ); + + if( xShape.is() ) + { + uno::Reference< drawing::XShapes > xShapes; + bool bFound = false; + + aAny = xSel->getSelection(); + aAny >>= xShapes; + + // Search shape to be selected in current selection. + if (xShapes.is()) + { + sal_Int32 nCount = xShapes->getCount(); + for (sal_Int32 i=0; ( i < nCount ) && !bFound; ++i ) + if( xShapes->getByIndex( i ) == xShape ) + bFound = true; + } + else + // Create an empty selection to add the shape to. + xShapes = drawing::ShapeCollection::create( + comphelper::getProcessComponentContext()); + + // Update the selection. + if( !bFound && bSelect ) + xShapes->add( xShape ); + else if( bFound && !bSelect ) + xShapes->remove( xShape ); + + xSel->select( Any(xShapes) ); + } + } + } +} + +void AccessibleDrawDocumentView::Activated() +{ + if (mpChildrenManager == nullptr) + return; + + bool bChange = false; + // When none of the children has the focus then claim it for the + // view. + if ( ! mpChildrenManager->HasFocus()) + { + SetState (AccessibleStateType::FOCUSED); + bChange = true; + } + else + ResetState (AccessibleStateType::FOCUSED); + mpChildrenManager->UpdateSelection(); + // if the child gets focus in UpdateSelection(), needs to reset the focus on document. + if (mpChildrenManager->HasFocus() && bChange) + ResetState (AccessibleStateType::FOCUSED); +} + +void AccessibleDrawDocumentView::Deactivated() +{ + if (mpChildrenManager != nullptr) + mpChildrenManager->RemoveFocus(); + ResetState (AccessibleStateType::FOCUSED); +} + +void AccessibleDrawDocumentView::impl_dispose() +{ + mpChildrenManager.reset(); + AccessibleDocumentViewBase::impl_dispose(); +} + +/** This method is called from the component helper base class while + disposing. +*/ +void SAL_CALL AccessibleDrawDocumentView::disposing() +{ + // Release resources. + mpChildrenManager.reset(); + + // Forward call to base classes. + AccessibleDocumentViewBase::disposing (); +} + +void AccessibleDrawDocumentView::UpdateAccessibleName() +{ + OUString sNewName (CreateAccessibleName() + ": "); + + // Add the number of the current slide. + uno::Reference xView (mxController, uno::UNO_QUERY); + if (xView.is()) + { + uno::Reference xProperties (xView->getCurrentPage(), UNO_QUERY); + if (xProperties.is()) + try + { + sal_Int16 nPageNumber (0); + if (xProperties->getPropertyValue("Number") >>= nPageNumber) + { + sNewName += OUString::number(nPageNumber); + } + } + catch (const beans::UnknownPropertyException&) + { + } + } + + // Add the number of pages/slides. + Reference xPagesSupplier (mxModel, UNO_QUERY); + if (xPagesSupplier.is()) + { + Reference xPages = xPagesSupplier->getDrawPages(); + if (xPages.is()) + { + sNewName += " / " + OUString::number(xPages->getCount()); + } + } + + SetAccessibleName (sNewName, AutomaticallyCreated); +} + +} // end of namespace accessibility + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3