/* -*- 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 "PresenterAccessibility.hxx" #include "PresenterTextView.hxx" #include "PresenterConfigurationAccess.hxx" #include "PresenterNotesView.hxx" #include "PresenterPaneBase.hxx" #include "PresenterPaneContainer.hxx" #include "PresenterPaneFactory.hxx" #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::accessibility; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::drawing::framework; //===== PresenterAccessibleObject ============================================= namespace sdext::presenter { namespace { typedef ::cppu::WeakComponentImplHelper < css::accessibility::XAccessible, css::accessibility::XAccessibleContext, css::accessibility::XAccessibleComponent, css::accessibility::XAccessibleEventBroadcaster, css::awt::XWindowListener > PresenterAccessibleObjectInterfaceBase; } class PresenterAccessible::AccessibleObject : public ::cppu::BaseMutex, public PresenterAccessibleObjectInterfaceBase { public: AccessibleObject ( const css::lang::Locale& rLocale, const sal_Int16 nRole, const OUString& rsName); void LateInitialization(); virtual void SetWindow ( const css::uno::Reference& rxContentWindow, const css::uno::Reference& rxBorderWindow); void SetAccessibleParent (const css::uno::Reference& rxAccessibleParent); virtual void SAL_CALL disposing() override; void AddChild (const ::rtl::Reference& rpChild); void RemoveChild (const ::rtl::Reference& rpChild); void SetIsFocused (const bool bIsFocused); void SetAccessibleName (const OUString& rsName); void FireAccessibleEvent ( const sal_Int16 nEventId, const css::uno::Any& rOldValue, const css::uno::Any& rNewValue); void UpdateStateSet(); //----- XAccessible ------------------------------------------------------- virtual css::uno::Reference SAL_CALL getAccessibleContext() override; //----- XAccessibleContext ---------------------------------------------- virtual sal_Int32 SAL_CALL getAccessibleChildCount() override; virtual css::uno::Reference< css::accessibility::XAccessible> SAL_CALL getAccessibleChild (sal_Int32 nIndex) override; virtual css::uno::Reference< css::accessibility::XAccessible> SAL_CALL getAccessibleParent() override; virtual sal_Int32 SAL_CALL getAccessibleIndexInParent() override; virtual sal_Int16 SAL_CALL getAccessibleRole() override; virtual OUString SAL_CALL getAccessibleDescription() override; virtual OUString SAL_CALL getAccessibleName() override; virtual css::uno::Reference SAL_CALL getAccessibleRelationSet() override; virtual css::uno::Reference SAL_CALL getAccessibleStateSet() override; virtual css::lang::Locale SAL_CALL getLocale() override; //----- XAccessibleComponent -------------------------------------------- virtual sal_Bool SAL_CALL containsPoint ( const css::awt::Point& aPoint) override; virtual css::uno::Reference SAL_CALL getAccessibleAtPoint ( const css::awt::Point& aPoint) override; virtual css::awt::Rectangle SAL_CALL getBounds() override; virtual css::awt::Point SAL_CALL getLocation() override; virtual css::awt::Point SAL_CALL getLocationOnScreen() override; virtual css::awt::Size SAL_CALL getSize() override; virtual void SAL_CALL grabFocus() override; virtual sal_Int32 SAL_CALL getForeground() override; virtual sal_Int32 SAL_CALL getBackground() override; //----- XAccessibleEventBroadcaster -------------------------------------- virtual void SAL_CALL addAccessibleEventListener ( const css::uno::Reference& rxListener) override; virtual void SAL_CALL removeAccessibleEventListener ( const css::uno::Reference& rxListener) override; //----- XWindowListener --------------------------------------------------- virtual void SAL_CALL windowResized (const css::awt::WindowEvent& rEvent) override; virtual void SAL_CALL windowMoved (const css::awt::WindowEvent& rEvent) override; virtual void SAL_CALL windowShown (const css::lang::EventObject& rEvent) override; virtual void SAL_CALL windowHidden (const css::lang::EventObject& rEvent) override; //----- XEventListener ---------------------------------------------------- virtual void SAL_CALL disposing (const css::lang::EventObject& rEvent) override; protected: OUString msName; css::uno::Reference mxContentWindow; css::uno::Reference mxBorderWindow; const css::lang::Locale maLocale; const sal_Int16 mnRole; sal_uInt32 mnStateSet; bool mbIsFocused; css::uno::Reference mxParentAccessible; ::std::vector > maChildren; ::std::vector > maListeners; virtual awt::Point GetRelativeLocation(); virtual awt::Size GetSize(); virtual awt::Point GetAbsoluteParentLocation(); virtual bool GetWindowState (const sal_Int16 nType) const; void UpdateState (const sal_Int16 aState, const bool bValue); /// @throws css::lang::DisposedException void ThrowIfDisposed() const; }; //===== AccessibleStateSet ==================================================== namespace { typedef ::cppu::WeakComponentImplHelper < css::accessibility::XAccessibleStateSet > AccessibleStateSetInterfaceBase; class AccessibleStateSet : public ::cppu::BaseMutex, public AccessibleStateSetInterfaceBase { public: explicit AccessibleStateSet (const sal_Int32 nStateSet); static sal_uInt32 GetStateMask (const sal_Int16 nType); //----- XAccessibleStateSet ----------------------------------------------- virtual sal_Bool SAL_CALL isEmpty() override; virtual sal_Bool SAL_CALL contains (sal_Int16 nState) override; virtual sal_Bool SAL_CALL containsAll (const css::uno::Sequence& rStateSet) override; virtual css::uno::Sequence SAL_CALL getStates() override; private: const sal_Int32 mnStateSet; }; //===== AccessibleRelationSet ================================================= typedef ::cppu::WeakComponentImplHelper < css::accessibility::XAccessibleRelationSet > AccessibleRelationSetInterfaceBase; class AccessibleRelationSet : public ::cppu::BaseMutex, public AccessibleRelationSetInterfaceBase { public: AccessibleRelationSet(); void AddRelation ( const sal_Int16 nRelationType, const Reference& rxObject); //----- XAccessibleRelationSet -------------------------------------------- virtual sal_Int32 SAL_CALL getRelationCount() override; virtual AccessibleRelation SAL_CALL getRelation (sal_Int32 nIndex) override; virtual sal_Bool SAL_CALL containsRelation (sal_Int16 nRelationType) override; virtual AccessibleRelation SAL_CALL getRelationByType (sal_Int16 nRelationType) override; private: ::std::vector maRelations; }; //===== PresenterAccessibleParagraph ========================================== typedef ::cppu::ImplInheritanceHelper < PresenterAccessible::AccessibleObject, css::accessibility::XAccessibleText > PresenterAccessibleParagraphInterfaceBase; } class PresenterAccessible::AccessibleParagraph : public PresenterAccessibleParagraphInterfaceBase { public: AccessibleParagraph ( const css::lang::Locale& rLocale, const OUString& rsName, const SharedPresenterTextParagraph& rpParagraph, const sal_Int32 nParagraphIndex); //----- XAccessibleContext ------------------------------------------------ virtual css::uno::Reference SAL_CALL getAccessibleRelationSet() override; //----- XAccessibleText --------------------------------------------------- virtual sal_Int32 SAL_CALL getCaretPosition() override; virtual sal_Bool SAL_CALL setCaretPosition (sal_Int32 nIndex) override; virtual sal_Unicode SAL_CALL getCharacter (sal_Int32 nIndex) override; virtual css::uno::Sequence SAL_CALL getCharacterAttributes ( ::sal_Int32 nIndex, const css::uno::Sequence& rRequestedAttributes) override; virtual css::awt::Rectangle SAL_CALL getCharacterBounds (sal_Int32 nIndex) override; virtual sal_Int32 SAL_CALL getCharacterCount() override; virtual sal_Int32 SAL_CALL getIndexAtPoint (const css::awt::Point& rPoint) override; virtual OUString SAL_CALL getSelectedText() override; virtual sal_Int32 SAL_CALL getSelectionStart() override; virtual sal_Int32 SAL_CALL getSelectionEnd() override; virtual sal_Bool SAL_CALL setSelection (sal_Int32 nStartIndex, sal_Int32 nEndIndex) override; virtual OUString SAL_CALL getText() override; virtual OUString SAL_CALL getTextRange ( sal_Int32 nStartIndex, sal_Int32 nEndIndex) override; virtual css::accessibility::TextSegment SAL_CALL getTextAtIndex ( sal_Int32 nIndex, sal_Int16 nTextType) override; virtual css::accessibility::TextSegment SAL_CALL getTextBeforeIndex ( sal_Int32 nIndex, sal_Int16 nTextType) override; virtual css::accessibility::TextSegment SAL_CALL getTextBehindIndex ( sal_Int32 nIndex, sal_Int16 nTextType) override; virtual sal_Bool SAL_CALL copyText (sal_Int32 nStartIndex, sal_Int32 nEndIndex) override; virtual sal_Bool SAL_CALL scrollSubstringTo( sal_Int32 nStartIndex, sal_Int32 nEndIndex, css::accessibility::AccessibleScrollType aScrollType) override; protected: virtual awt::Point GetRelativeLocation() override; virtual awt::Size GetSize() override; virtual awt::Point GetAbsoluteParentLocation() override; virtual bool GetWindowState (const sal_Int16 nType) const override; private: SharedPresenterTextParagraph mpParagraph; const sal_Int32 mnParagraphIndex; }; //===== AccessibleConsole ===================================================== namespace { class AccessibleConsole { public: static rtl::Reference Create ( const css::uno::Reference& rxContext, const lang::Locale& rLocale) { OUString sName ("Presenter Console"); PresenterConfigurationAccess aConfiguration ( rxContext, "/org.openoffice.Office.PresenterScreen/", PresenterConfigurationAccess::READ_ONLY); aConfiguration.GetConfigurationNode("Presenter/Accessibility/Console/String") >>= sName; rtl::Reference pObject ( new PresenterAccessible::AccessibleObject( rLocale, AccessibleRole::PANEL, sName)); pObject->LateInitialization(); pObject->UpdateStateSet(); return pObject; } }; //===== AccessiblePreview ===================================================== class AccessiblePreview { public: static rtl::Reference Create ( const Reference& rxContext, const lang::Locale& rLocale, const Reference& rxContentWindow, const Reference& rxBorderWindow) { OUString sName ("Presenter Notes Window"); { PresenterConfigurationAccess aConfiguration ( rxContext, "/org.openoffice.Office.PresenterScreen/", PresenterConfigurationAccess::READ_ONLY); aConfiguration.GetConfigurationNode("Presenter/Accessibility/Preview/String") >>= sName; } rtl::Reference pObject ( new PresenterAccessible::AccessibleObject( rLocale, AccessibleRole::LABEL, sName)); pObject->LateInitialization(); pObject->UpdateStateSet(); pObject->SetWindow(rxContentWindow, rxBorderWindow); return pObject; } }; //===== AccessibleNotes ======================================================= class AccessibleNotes : public PresenterAccessible::AccessibleObject { public: AccessibleNotes ( const css::lang::Locale& rLocale, const OUString& rsName); static rtl::Reference Create ( const css::uno::Reference& rxContext, const lang::Locale& rLocale, const Reference& rxContentWindow, const Reference& rxBorderWindow, const std::shared_ptr& rpTextView); void SetTextView (const std::shared_ptr& rpTextView); virtual void SetWindow ( const css::uno::Reference& rxContentWindow, const css::uno::Reference& rxBorderWindow) override; private: std::shared_ptr mpTextView; void NotifyCaretChange ( const sal_Int32 nOldParagraphIndex, const sal_Int32 nOldCharacterIndex, const sal_Int32 nNewParagraphIndex, const sal_Int32 nNewCharacterIndex); }; //===== AccessibleFocusManager ================================================ /** A singleton class that makes sure that only one accessibility object in the PresenterConsole hierarchy has the focus. */ class AccessibleFocusManager { public: static std::shared_ptr const & Instance(); void AddFocusableObject (const ::rtl::Reference& rpObject); void RemoveFocusableObject (const ::rtl::Reference& rpObject); void FocusObject (const ::rtl::Reference& rpObject); ~AccessibleFocusManager(); private: static std::shared_ptr mpInstance; ::std::vector > maFocusableObjects; bool m_isInDtor = false; AccessibleFocusManager(); }; } //===== PresenterAccessible =================================================== PresenterAccessible::PresenterAccessible ( const css::uno::Reference& rxContext, const ::rtl::Reference& rpPresenterController, const Reference& rxMainPane) : PresenterAccessibleInterfaceBase(m_aMutex), mxComponentContext(rxContext), mpPresenterController(rpPresenterController), mxMainPane(rxMainPane, UNO_QUERY) { if (mxMainPane.is()) mxMainPane->setAccessible(this); } PresenterAccessible::~PresenterAccessible() { } PresenterPaneContainer::SharedPaneDescriptor PresenterAccessible::GetPreviewPane() const { PresenterPaneContainer::SharedPaneDescriptor pPreviewPane; if ( ! mpPresenterController.is()) return pPreviewPane; rtl::Reference pContainer (mpPresenterController->GetPaneContainer()); if ( ! pContainer.is()) return pPreviewPane; pPreviewPane = pContainer->FindPaneURL(PresenterPaneFactory::msCurrentSlidePreviewPaneURL); Reference xPreviewPane; if (pPreviewPane) xPreviewPane = pPreviewPane->mxPane.get(); if ( ! xPreviewPane.is()) { pPreviewPane = pContainer->FindPaneURL(PresenterPaneFactory::msSlideSorterPaneURL); } return pPreviewPane; } void PresenterAccessible::UpdateAccessibilityHierarchy() { if ( ! mpPresenterController.is()) return; Reference xConfigurationController( mpPresenterController->GetConfigurationController()); if ( ! xConfigurationController.is()) return; rtl::Reference pPaneContainer ( mpPresenterController->GetPaneContainer()); if ( ! pPaneContainer.is()) return; if ( ! mpAccessibleConsole.is()) return; // Get the preview pane (standard or notes view) or the slide overview // pane. PresenterPaneContainer::SharedPaneDescriptor pPreviewPane(GetPreviewPane()); Reference xPreviewPane; if (pPreviewPane) xPreviewPane = pPreviewPane->mxPane.get(); // Get the notes pane. PresenterPaneContainer::SharedPaneDescriptor pNotesPane( pPaneContainer->FindPaneURL(PresenterPaneFactory::msNotesPaneURL)); Reference xNotesPane; if (pNotesPane) xNotesPane = pNotesPane->mxPane.get(); // Get the notes view. Reference xNotesView; if (pNotesPane) xNotesView = pNotesPane->mxView; rtl::Reference pNotesView ( dynamic_cast(xNotesView.get())); UpdateAccessibilityHierarchy( pPreviewPane ? pPreviewPane->mxContentWindow : Reference(), pPreviewPane ? pPreviewPane->mxBorderWindow : Reference(), (pPreviewPane&&pPreviewPane->mxPane.is()) ? pPreviewPane->mxPane->GetTitle() : OUString(), pNotesPane ? pNotesPane->mxContentWindow : Reference(), pNotesPane ? pNotesPane->mxBorderWindow : Reference(), pNotesView.is() ? pNotesView->GetTextView() : std::shared_ptr()); } void PresenterAccessible::UpdateAccessibilityHierarchy ( const Reference& rxPreviewContentWindow, const Reference& rxPreviewBorderWindow, const OUString& rsTitle, const Reference& rxNotesContentWindow, const Reference& rxNotesBorderWindow, const std::shared_ptr& rpNotesTextView) { if ( ! mpAccessibleConsole.is()) return; if (mxPreviewContentWindow != rxPreviewContentWindow) { if (mpAccessiblePreview.is()) { mpAccessibleConsole->RemoveChild(mpAccessiblePreview); mpAccessiblePreview = nullptr; } mxPreviewContentWindow = rxPreviewContentWindow; mxPreviewBorderWindow = rxPreviewBorderWindow; if (mxPreviewContentWindow.is()) { mpAccessiblePreview = AccessiblePreview::Create( mxComponentContext, lang::Locale(), mxPreviewContentWindow, mxPreviewBorderWindow); mpAccessibleConsole->AddChild(mpAccessiblePreview); mpAccessiblePreview->SetAccessibleName(rsTitle); } } if (mxNotesContentWindow == rxNotesContentWindow) return; if (mpAccessibleNotes.is()) { mpAccessibleConsole->RemoveChild(mpAccessibleNotes); mpAccessibleNotes = nullptr; } mxNotesContentWindow = rxNotesContentWindow; mxNotesBorderWindow = rxNotesBorderWindow; if (mxNotesContentWindow.is()) { mpAccessibleNotes = AccessibleNotes::Create( mxComponentContext, lang::Locale(), mxNotesContentWindow, mxNotesBorderWindow, rpNotesTextView); mpAccessibleConsole->AddChild(mpAccessibleNotes); } } void PresenterAccessible::NotifyCurrentSlideChange () { if (mpAccessiblePreview.is()) { PresenterPaneContainer::SharedPaneDescriptor pPreviewPane (GetPreviewPane()); mpAccessiblePreview->SetAccessibleName( pPreviewPane&&pPreviewPane->mxPane.is() ? pPreviewPane->mxPane->GetTitle() : OUString()); } // Play some focus ping-pong to trigger AT tools. //AccessibleFocusManager::Instance()->FocusObject(mpAccessibleConsole); AccessibleFocusManager::Instance()->FocusObject(mpAccessiblePreview); } void SAL_CALL PresenterAccessible::disposing() { UpdateAccessibilityHierarchy( nullptr, nullptr, OUString(), nullptr, nullptr, std::shared_ptr()); if (mxMainWindow.is()) { mxMainWindow->removeFocusListener(this); if (mxMainPane.is()) mxMainPane->setAccessible(nullptr); } mpAccessiblePreview = nullptr; mpAccessibleNotes = nullptr; mpAccessibleConsole = nullptr; } //----- XAccessible ----------------------------------------------------------- Reference SAL_CALL PresenterAccessible::getAccessibleContext() { if ( ! mpAccessibleConsole.is()) { Reference xMainPane (mxMainPane, UNO_QUERY); if (xMainPane.is()) { mxMainWindow = xMainPane->getWindow(); mxMainWindow->addFocusListener(this); } mpAccessibleConsole = AccessibleConsole::Create( mxComponentContext, css::lang::Locale()); mpAccessibleConsole->SetWindow(mxMainWindow, nullptr); mpAccessibleConsole->SetAccessibleParent(mxAccessibleParent); UpdateAccessibilityHierarchy(); if (mpPresenterController.is()) mpPresenterController->SetAccessibilityActiveState(true); } return mpAccessibleConsole->getAccessibleContext(); } //----- XFocusListener ---------------------------------------------------- void SAL_CALL PresenterAccessible::focusGained (const css::awt::FocusEvent&) { SAL_INFO("sdext.presenter", __func__ << ": PresenterAccessible::focusGained at " << this << " and window " << mxMainWindow.get()); AccessibleFocusManager::Instance()->FocusObject(mpAccessibleConsole); } void SAL_CALL PresenterAccessible::focusLost (const css::awt::FocusEvent&) { SAL_INFO("sdext.presenter", __func__ << ": PresenterAccessible::focusLost at " << this); AccessibleFocusManager::Instance()->FocusObject(nullptr); } //----- XEventListener ---------------------------------------------------- void SAL_CALL PresenterAccessible::disposing (const css::lang::EventObject& rEvent) { if (rEvent.Source == mxMainWindow) mxMainWindow = nullptr; } //----- XInitialize ----------------------------------------------------------- void SAL_CALL PresenterAccessible::initialize (const css::uno::Sequence& rArguments) { if (rArguments.hasElements()) { mxAccessibleParent.set(rArguments[0], UNO_QUERY); if (mpAccessibleConsole.is()) mpAccessibleConsole->SetAccessibleParent(mxAccessibleParent); } } //===== PresenterAccessible::AccessibleObject ========================================= PresenterAccessible::AccessibleObject::AccessibleObject ( const lang::Locale& rLocale, const sal_Int16 nRole, const OUString& rsName) : PresenterAccessibleObjectInterfaceBase(m_aMutex), msName(rsName), maLocale(rLocale), mnRole(nRole), mnStateSet(0), mbIsFocused(false) { } void PresenterAccessible::AccessibleObject::LateInitialization() { AccessibleFocusManager::Instance()->AddFocusableObject(this); } void PresenterAccessible::AccessibleObject::SetWindow ( const Reference& rxContentWindow, const Reference& rxBorderWindow) { Reference xContentWindow (rxContentWindow, UNO_QUERY); if (mxContentWindow.get() == xContentWindow.get()) return; if (mxContentWindow.is()) { mxContentWindow->removeWindowListener(this); } mxContentWindow = xContentWindow; mxBorderWindow.set(rxBorderWindow, UNO_QUERY); if (mxContentWindow.is()) { mxContentWindow->addWindowListener(this); } UpdateStateSet(); } void PresenterAccessible::AccessibleObject::SetAccessibleParent ( const Reference& rxAccessibleParent) { mxParentAccessible = rxAccessibleParent; } void SAL_CALL PresenterAccessible::AccessibleObject::disposing() { AccessibleFocusManager::Instance()->RemoveFocusableObject(this); SetWindow(nullptr, nullptr); } //----- XAccessible ------------------------------------------------------- Reference SAL_CALL PresenterAccessible::AccessibleObject::getAccessibleContext() { ThrowIfDisposed(); return this; } //----- XAccessibleContext ---------------------------------------------- sal_Int32 SAL_CALL PresenterAccessible::AccessibleObject::getAccessibleChildCount() { ThrowIfDisposed(); const sal_Int32 nChildCount (maChildren.size()); return nChildCount; } Reference SAL_CALL PresenterAccessible::AccessibleObject::getAccessibleChild (sal_Int32 nIndex) { ThrowIfDisposed(); if (nIndex<0 || o3tl::make_unsigned(nIndex)>=maChildren.size()) throw lang::IndexOutOfBoundsException("invalid child index", static_cast(this)); return maChildren[nIndex]; } Reference SAL_CALL PresenterAccessible::AccessibleObject::getAccessibleParent() { ThrowIfDisposed(); return mxParentAccessible; } sal_Int32 SAL_CALL PresenterAccessible::AccessibleObject::getAccessibleIndexInParent() { ThrowIfDisposed(); const Reference xThis (this); if (mxParentAccessible.is()) { const Reference xContext (mxParentAccessible->getAccessibleContext()); for (sal_Int32 nIndex=0,nCount=xContext->getAccessibleChildCount(); nIndexgetAccessibleChild(nIndex) == xThis) return nIndex; } } return 0; } sal_Int16 SAL_CALL PresenterAccessible::AccessibleObject::getAccessibleRole() { ThrowIfDisposed(); return mnRole; } OUString SAL_CALL PresenterAccessible::AccessibleObject::getAccessibleDescription() { ThrowIfDisposed(); return msName; } OUString SAL_CALL PresenterAccessible::AccessibleObject::getAccessibleName() { ThrowIfDisposed(); return msName; } Reference SAL_CALL PresenterAccessible::AccessibleObject::getAccessibleRelationSet() { ThrowIfDisposed(); return nullptr; } Reference SAL_CALL PresenterAccessible::AccessibleObject::getAccessibleStateSet() { ThrowIfDisposed(); return Reference(new AccessibleStateSet(mnStateSet)); } lang::Locale SAL_CALL PresenterAccessible::AccessibleObject::getLocale() { ThrowIfDisposed(); if (mxParentAccessible.is()) { Reference xParentContext (mxParentAccessible->getAccessibleContext()); if (xParentContext.is()) return xParentContext->getLocale(); } return maLocale; } //----- XAccessibleComponent ------------------------------------------------ sal_Bool SAL_CALL PresenterAccessible::AccessibleObject::containsPoint ( const awt::Point& rPoint) { ThrowIfDisposed(); if (mxContentWindow.is()) { const awt::Rectangle aBox (getBounds()); return rPoint.X>=aBox.X && rPoint.Y>=aBox.Y && rPoint.X SAL_CALL PresenterAccessible::AccessibleObject::getAccessibleAtPoint (const awt::Point&) { ThrowIfDisposed(); return Reference(); } awt::Rectangle SAL_CALL PresenterAccessible::AccessibleObject::getBounds() { ThrowIfDisposed(); const awt::Point aLocation (GetRelativeLocation()); const awt::Size aSize (GetSize()); return awt::Rectangle (aLocation.X, aLocation.Y, aSize.Width, aSize.Height); } awt::Point SAL_CALL PresenterAccessible::AccessibleObject::getLocation() { ThrowIfDisposed(); const awt::Point aLocation (GetRelativeLocation()); return aLocation; } awt::Point SAL_CALL PresenterAccessible::AccessibleObject::getLocationOnScreen() { ThrowIfDisposed(); awt::Point aRelativeLocation (GetRelativeLocation()); awt::Point aParentLocationOnScreen (GetAbsoluteParentLocation()); return awt::Point( aRelativeLocation.X + aParentLocationOnScreen.X, aRelativeLocation.Y + aParentLocationOnScreen.Y); } awt::Size SAL_CALL PresenterAccessible::AccessibleObject::getSize() { ThrowIfDisposed(); const awt::Size aSize (GetSize()); return aSize; } void SAL_CALL PresenterAccessible::AccessibleObject::grabFocus() { ThrowIfDisposed(); if (mxBorderWindow.is()) mxBorderWindow->setFocus(); else if (mxContentWindow.is()) mxContentWindow->setFocus(); } sal_Int32 SAL_CALL PresenterAccessible::AccessibleObject::getForeground() { ThrowIfDisposed(); return 0x00ffffff; } sal_Int32 SAL_CALL PresenterAccessible::AccessibleObject::getBackground() { ThrowIfDisposed(); return 0x00000000; } //----- XAccessibleEventBroadcaster ------------------------------------------- void SAL_CALL PresenterAccessible::AccessibleObject::addAccessibleEventListener ( const Reference& rxListener) { if (!rxListener.is()) return; const osl::MutexGuard aGuard(m_aMutex); if (rBHelper.bDisposed || rBHelper.bInDispose) { uno::Reference xThis (static_cast(this), UNO_QUERY); rxListener->disposing (lang::EventObject(xThis)); } else { maListeners.push_back(rxListener); } } void SAL_CALL PresenterAccessible::AccessibleObject::removeAccessibleEventListener ( const Reference& rxListener) { ThrowIfDisposed(); if (rxListener.is()) { const osl::MutexGuard aGuard(m_aMutex); auto const it(std::remove(maListeners.begin(), maListeners.end(), rxListener)); if (it != maListeners.end()) { maListeners.erase(it); } } } //----- XWindowListener --------------------------------------------------- void SAL_CALL PresenterAccessible::AccessibleObject::windowResized ( const css::awt::WindowEvent&) { FireAccessibleEvent(AccessibleEventId::BOUNDRECT_CHANGED, Any(), Any()); } void SAL_CALL PresenterAccessible::AccessibleObject::windowMoved ( const css::awt::WindowEvent&) { FireAccessibleEvent(AccessibleEventId::BOUNDRECT_CHANGED, Any(), Any()); } void SAL_CALL PresenterAccessible::AccessibleObject::windowShown ( const css::lang::EventObject&) { UpdateStateSet(); } void SAL_CALL PresenterAccessible::AccessibleObject::windowHidden ( const css::lang::EventObject&) { UpdateStateSet(); } //----- XEventListener -------------------------------------------------------- void SAL_CALL PresenterAccessible::AccessibleObject::disposing (const css::lang::EventObject& rEvent) { if (rEvent.Source == mxContentWindow) { mxContentWindow = nullptr; mxBorderWindow = nullptr; } else { SetWindow(nullptr, nullptr); } } //----- private --------------------------------------------------------------- bool PresenterAccessible::AccessibleObject::GetWindowState (const sal_Int16 nType) const { switch (nType) { case AccessibleStateType::ENABLED: return mxContentWindow.is() && mxContentWindow->isEnabled(); case AccessibleStateType::FOCUSABLE: return true; case AccessibleStateType::FOCUSED: return mbIsFocused; case AccessibleStateType::SHOWING: return mxContentWindow.is() && mxContentWindow->isVisible(); default: return false; } } void PresenterAccessible::AccessibleObject::UpdateStateSet() { UpdateState(AccessibleStateType::FOCUSABLE, true); UpdateState(AccessibleStateType::VISIBLE, true); UpdateState(AccessibleStateType::ENABLED, true); UpdateState(AccessibleStateType::MULTI_LINE, true); UpdateState(AccessibleStateType::SENSITIVE, true); UpdateState(AccessibleStateType::ENABLED, GetWindowState(AccessibleStateType::ENABLED)); UpdateState(AccessibleStateType::FOCUSED, GetWindowState(AccessibleStateType::FOCUSED)); UpdateState(AccessibleStateType::SHOWING, GetWindowState(AccessibleStateType::SHOWING)); // UpdateState(AccessibleStateType::ACTIVE, GetWindowState(AccessibleStateType::ACTIVE)); } void PresenterAccessible::AccessibleObject::UpdateState( const sal_Int16 nState, const bool bValue) { const sal_uInt32 nStateMask (AccessibleStateSet::GetStateMask(nState)); if (((mnStateSet & nStateMask) != 0) == bValue) return; if (bValue) { mnStateSet |= nStateMask; FireAccessibleEvent(AccessibleEventId::STATE_CHANGED, Any(), Any(nState)); } else { mnStateSet &= ~nStateMask; FireAccessibleEvent(AccessibleEventId::STATE_CHANGED, Any(nState), Any()); } } void PresenterAccessible::AccessibleObject::AddChild ( const ::rtl::Reference& rpChild) { maChildren.push_back(rpChild); rpChild->SetAccessibleParent(this); FireAccessibleEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN, Any(), Any()); } void PresenterAccessible::AccessibleObject::RemoveChild ( const ::rtl::Reference& rpChild) { rpChild->SetAccessibleParent(Reference()); maChildren.erase(::std::find(maChildren.begin(), maChildren.end(), rpChild)); FireAccessibleEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN, Any(), Any()); } void PresenterAccessible::AccessibleObject::SetIsFocused (const bool bIsFocused) { if (mbIsFocused != bIsFocused) { mbIsFocused = bIsFocused; UpdateStateSet(); } } void PresenterAccessible::AccessibleObject::SetAccessibleName (const OUString& rsName) { if (msName != rsName) { const OUString sOldName(msName); msName = rsName; FireAccessibleEvent(AccessibleEventId::NAME_CHANGED, Any(sOldName), Any(msName)); } } void PresenterAccessible::AccessibleObject::FireAccessibleEvent ( const sal_Int16 nEventId, const uno::Any& rOldValue, const uno::Any& rNewValue ) { AccessibleEventObject aEventObject; aEventObject.Source = Reference(this); aEventObject.EventId = nEventId; aEventObject.NewValue = rNewValue; aEventObject.OldValue = rOldValue; ::std::vector > aListenerCopy(maListeners); for (const auto& rxListener : aListenerCopy) { try { rxListener->notifyEvent(aEventObject); } catch (const lang::DisposedException&) { // Listener has been disposed and should have been removed // already. removeAccessibleEventListener(rxListener); } catch (const Exception&) { // Ignore all other exceptions and assume that they are // caused by a temporary problem. } } } awt::Point PresenterAccessible::AccessibleObject::GetRelativeLocation() { awt::Point aLocation; if (mxContentWindow.is()) { const awt::Rectangle aContentBox (mxContentWindow->getPosSize()); aLocation.X = aContentBox.X; aLocation.Y = aContentBox.Y; if (mxBorderWindow.is()) { const awt::Rectangle aBorderBox (mxBorderWindow->getPosSize()); aLocation.X += aBorderBox.X; aLocation.Y += aBorderBox.Y; } } return aLocation; } awt::Size PresenterAccessible::AccessibleObject::GetSize() { if (mxContentWindow.is()) { const awt::Rectangle aBox (mxContentWindow->getPosSize()); return awt::Size(aBox.Width, aBox.Height); } else return awt::Size(); } awt::Point PresenterAccessible::AccessibleObject::GetAbsoluteParentLocation() { Reference xParentComponent; if (mxParentAccessible.is()) xParentComponent.set( mxParentAccessible->getAccessibleContext(), UNO_QUERY); if (xParentComponent.is()) return xParentComponent->getLocationOnScreen(); else return awt::Point(); } void PresenterAccessible::AccessibleObject::ThrowIfDisposed() const { if (rBHelper.bDisposed || rBHelper.bInDispose) throw lang::DisposedException("object has already been disposed", uno::Reference(const_cast(static_cast(this)))); } //===== AccessibleStateSet ==================================================== AccessibleStateSet::AccessibleStateSet (const sal_Int32 nStateSet) : AccessibleStateSetInterfaceBase(m_aMutex), mnStateSet (nStateSet) { } sal_uInt32 AccessibleStateSet::GetStateMask (const sal_Int16 nState) { if (nState<0 || o3tl::make_unsigned(nState)>=sizeof(sal_uInt32)*8) { throw RuntimeException("AccessibleStateSet::GetStateMask: invalid state"); } return 1<& rStateSet) { return std::none_of(rStateSet.begin(), rStateSet.end(), [this](const sal_Int16 nState) { return (mnStateSet & GetStateMask(nState)) == 0; }); } css::uno::Sequence SAL_CALL AccessibleStateSet::getStates() { ::std::vector aStates; aStates.reserve(sizeof(mnStateSet)*8); for (sal_uInt16 nIndex=0; nIndex(aStates.data(), aStates.size()); } //===== AccessibleRelationSet ================================================= AccessibleRelationSet::AccessibleRelationSet() : AccessibleRelationSetInterfaceBase(m_aMutex) { } void AccessibleRelationSet::AddRelation ( const sal_Int16 nRelationType, const Reference& rxObject) { maRelations.emplace_back(); maRelations.back().RelationType = nRelationType; maRelations.back().TargetSet = { rxObject }; } //----- XAccessibleRelationSet ------------------------------------------------ sal_Int32 SAL_CALL AccessibleRelationSet::getRelationCount() { return maRelations.size(); } AccessibleRelation SAL_CALL AccessibleRelationSet::getRelation (sal_Int32 nIndex) { if (nIndex<0 && o3tl::make_unsigned(nIndex)>=maRelations.size()) return AccessibleRelation(); else return maRelations[nIndex]; } sal_Bool SAL_CALL AccessibleRelationSet::containsRelation (sal_Int16 nRelationType) { return std::any_of(maRelations.begin(), maRelations.end(), [nRelationType](const AccessibleRelation& rRelation) { return rRelation.RelationType == nRelationType; }); } AccessibleRelation SAL_CALL AccessibleRelationSet::getRelationByType (sal_Int16 nRelationType) { auto iRelation = std::find_if(maRelations.begin(), maRelations.end(), [nRelationType](const AccessibleRelation& rRelation) { return rRelation.RelationType == nRelationType; }); if (iRelation != maRelations.end()) return *iRelation; return AccessibleRelation(); } //===== PresenterAccessible::AccessibleParagraph ============================== PresenterAccessible::AccessibleParagraph::AccessibleParagraph ( const lang::Locale& rLocale, const OUString& rsName, const SharedPresenterTextParagraph& rpParagraph, const sal_Int32 nParagraphIndex) : PresenterAccessibleParagraphInterfaceBase(rLocale, AccessibleRole::PARAGRAPH, rsName), mpParagraph(rpParagraph), mnParagraphIndex(nParagraphIndex) { } //----- XAccessibleContext ---------------------------------------------------- Reference SAL_CALL PresenterAccessible::AccessibleParagraph::getAccessibleRelationSet() { ThrowIfDisposed(); rtl::Reference pSet (new AccessibleRelationSet); if (mxParentAccessible.is()) { Reference xParentContext (mxParentAccessible->getAccessibleContext()); if (xParentContext.is()) { if (mnParagraphIndex>0) pSet->AddRelation( AccessibleRelationType::CONTENT_FLOWS_FROM, xParentContext->getAccessibleChild(mnParagraphIndex-1)); if (mnParagraphIndexgetAccessibleChildCount()-1) pSet->AddRelation( AccessibleRelationType::CONTENT_FLOWS_TO, xParentContext->getAccessibleChild(mnParagraphIndex+1)); } } return pSet; } //----- XAccessibleText ------------------------------------------------------- sal_Int32 SAL_CALL PresenterAccessible::AccessibleParagraph::getCaretPosition() { ThrowIfDisposed(); sal_Int32 nPosition (-1); if (mpParagraph) nPosition = mpParagraph->GetCaretPosition(); return nPosition; } sal_Bool SAL_CALL PresenterAccessible::AccessibleParagraph::setCaretPosition (sal_Int32 nIndex) { ThrowIfDisposed(); if (mpParagraph) { mpParagraph->SetCaretPosition(nIndex); return true; } else return false; } sal_Unicode SAL_CALL PresenterAccessible::AccessibleParagraph::getCharacter (sal_Int32 nIndex) { ThrowIfDisposed(); if (!mpParagraph) throw lang::IndexOutOfBoundsException("no text support in current mode", static_cast(this)); return mpParagraph->GetCharacter(nIndex); } Sequence SAL_CALL PresenterAccessible::AccessibleParagraph::getCharacterAttributes ( ::sal_Int32 nIndex, const css::uno::Sequence& rRequestedAttributes) { ThrowIfDisposed(); #if OSL_DEBUG_LEVEL > 0 SAL_INFO( "sdext.presenter", __func__ << " at " << this << ", " << nIndex << " returns empty set" ); for (sal_Int32 nAttributeIndex(0), nAttributeCount(rRequestedAttributes.getLength()); nAttributeIndex < nAttributeCount; ++nAttributeIndex) { SAL_INFO( "sdext.presenter", " requested attribute " << nAttributeIndex << " is " << rRequestedAttributes[nAttributeIndex] ); } #else (void)nIndex; (void)rRequestedAttributes; #endif // Character properties are not supported. return Sequence(); } awt::Rectangle SAL_CALL PresenterAccessible::AccessibleParagraph::getCharacterBounds ( sal_Int32 nIndex) { ThrowIfDisposed(); awt::Rectangle aCharacterBox; if (nIndex < 0) { throw lang::IndexOutOfBoundsException("invalid text index", static_cast(this)); } else if (mpParagraph) { aCharacterBox = mpParagraph->GetCharacterBounds(nIndex, false); // Convert coordinates relative to the window origin into absolute // screen coordinates. const awt::Point aWindowLocationOnScreen (getLocationOnScreen()); aCharacterBox.X += aWindowLocationOnScreen.X; aCharacterBox.Y += aWindowLocationOnScreen.Y; } else { throw lang::IndexOutOfBoundsException("no text support in current mode", static_cast(this)); } return aCharacterBox; } sal_Int32 SAL_CALL PresenterAccessible::AccessibleParagraph::getCharacterCount() { ThrowIfDisposed(); sal_Int32 nCount (0); if (mpParagraph) nCount = mpParagraph->GetCharacterCount(); return nCount; } sal_Int32 SAL_CALL PresenterAccessible::AccessibleParagraph::getIndexAtPoint ( const css::awt::Point& ) { ThrowIfDisposed(); return -1; } OUString SAL_CALL PresenterAccessible::AccessibleParagraph::getSelectedText() { ThrowIfDisposed(); return getTextRange(getSelectionStart(), getSelectionEnd()); } sal_Int32 SAL_CALL PresenterAccessible::AccessibleParagraph::getSelectionStart() { ThrowIfDisposed(); return getCaretPosition(); } sal_Int32 SAL_CALL PresenterAccessible::AccessibleParagraph::getSelectionEnd() { ThrowIfDisposed(); return getCaretPosition(); } sal_Bool SAL_CALL PresenterAccessible::AccessibleParagraph::setSelection ( sal_Int32 nStartIndex, sal_Int32) { ThrowIfDisposed(); return setCaretPosition(nStartIndex); } OUString SAL_CALL PresenterAccessible::AccessibleParagraph::getText() { ThrowIfDisposed(); OUString sText; if (mpParagraph) sText = mpParagraph->GetText(); return sText; } OUString SAL_CALL PresenterAccessible::AccessibleParagraph::getTextRange ( sal_Int32 nLocalStartIndex, sal_Int32 nLocalEndIndex) { ThrowIfDisposed(); OUString sText; if (mpParagraph) { const TextSegment aSegment ( mpParagraph->CreateTextSegment(nLocalStartIndex, nLocalEndIndex)); sText = aSegment.SegmentText; } return sText; } TextSegment SAL_CALL PresenterAccessible::AccessibleParagraph::getTextAtIndex ( sal_Int32 nLocalCharacterIndex, sal_Int16 nTextType) { ThrowIfDisposed(); TextSegment aSegment; if (mpParagraph) aSegment = mpParagraph->GetTextSegment(0, nLocalCharacterIndex, nTextType); return aSegment; } TextSegment SAL_CALL PresenterAccessible::AccessibleParagraph::getTextBeforeIndex ( sal_Int32 nLocalCharacterIndex, sal_Int16 nTextType) { ThrowIfDisposed(); TextSegment aSegment; if (mpParagraph) aSegment = mpParagraph->GetTextSegment(-1, nLocalCharacterIndex, nTextType); return aSegment; } TextSegment SAL_CALL PresenterAccessible::AccessibleParagraph::getTextBehindIndex ( sal_Int32 nLocalCharacterIndex, sal_Int16 nTextType) { ThrowIfDisposed(); TextSegment aSegment; if (mpParagraph) aSegment = mpParagraph->GetTextSegment(+1, nLocalCharacterIndex, nTextType); return aSegment; } sal_Bool SAL_CALL PresenterAccessible::AccessibleParagraph::copyText ( sal_Int32, sal_Int32) { ThrowIfDisposed(); // Return false because copying to clipboard is not supported. // It IS supported in the notes view. There is no need to duplicate // this here. return false; } sal_Bool SAL_CALL PresenterAccessible::AccessibleParagraph::scrollSubstringTo( sal_Int32, sal_Int32, AccessibleScrollType) { return false; } //----- protected ------------------------------------------------------------- awt::Point PresenterAccessible::AccessibleParagraph::GetRelativeLocation() { awt::Point aLocation (AccessibleObject::GetRelativeLocation()); if (mpParagraph) { const awt::Point aParagraphLocation (mpParagraph->GetRelativeLocation()); aLocation.X += aParagraphLocation.X; aLocation.Y += aParagraphLocation.Y; } return aLocation; } awt::Size PresenterAccessible::AccessibleParagraph::GetSize() { if (mpParagraph) return mpParagraph->GetSize(); else return AccessibleObject::GetSize(); } awt::Point PresenterAccessible::AccessibleParagraph::GetAbsoluteParentLocation() { if (mxParentAccessible.is()) { Reference xParentContext = mxParentAccessible->getAccessibleContext(); if (xParentContext.is()) { Reference xGrandParentComponent( xParentContext->getAccessibleParent(), UNO_QUERY); if (xGrandParentComponent.is()) return xGrandParentComponent->getLocationOnScreen(); } } return awt::Point(); } bool PresenterAccessible::AccessibleParagraph::GetWindowState (const sal_Int16 nType) const { switch (nType) { case AccessibleStateType::EDITABLE: return bool(mpParagraph); case AccessibleStateType::ACTIVE: return true; default: return AccessibleObject::GetWindowState(nType); } } //===== AccessibleNotes ======================================================= AccessibleNotes::AccessibleNotes ( const css::lang::Locale& rLocale, const OUString& rsName) : AccessibleObject(rLocale,AccessibleRole::PANEL,rsName) { } rtl::Reference AccessibleNotes::Create ( const css::uno::Reference& rxContext, const lang::Locale& rLocale, const Reference& rxContentWindow, const Reference& rxBorderWindow, const std::shared_ptr& rpTextView) { OUString sName ("Presenter Notes Text"); { PresenterConfigurationAccess aConfiguration ( rxContext, "/org.openoffice.Office.PresenterScreen/", PresenterConfigurationAccess::READ_ONLY); aConfiguration.GetConfigurationNode("Presenter/Accessibility/Notes/String") >>= sName; } rtl::Reference pObject ( new AccessibleNotes( rLocale, sName)); pObject->LateInitialization(); pObject->SetTextView(rpTextView); pObject->UpdateStateSet(); pObject->SetWindow(rxContentWindow, rxBorderWindow); return pObject; } void AccessibleNotes::SetTextView ( const std::shared_ptr& rpTextView) { ::std::vector > aChildren; // Release any listeners to the current text view. if (mpTextView) { mpTextView->GetCaret()->SetCaretMotionBroadcaster( ::std::function()); mpTextView->SetTextChangeBroadcaster( ::std::function()); } mpTextView = rpTextView; if (!mpTextView) return; // Create a new set of children, one for each paragraph. const sal_Int32 nParagraphCount (mpTextView->GetParagraphCount()); for (sal_Int32 nIndex=0; nIndex pParagraph ( new PresenterAccessible::AccessibleParagraph( css::lang::Locale(), "Paragraph"+OUString::number(nIndex), rpTextView->GetParagraph(nIndex), nIndex)); pParagraph->LateInitialization(); pParagraph->SetWindow(mxContentWindow, mxBorderWindow); pParagraph->SetAccessibleParent(this); aChildren.emplace_back(pParagraph.get()); } maChildren.swap(aChildren); FireAccessibleEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN, Any(), Any()); // Dispose the old children. (This will remove them from the focus // manager). for (const auto& rxChild : aChildren) { Reference xComponent = rxChild; if (xComponent.is()) xComponent->dispose(); } // This class acts as a controller of who broadcasts caret motion // events and handles text changes. Register the corresponding // listeners here. mpTextView->GetCaret()->SetCaretMotionBroadcaster( [this](sal_Int32 a, sal_Int32 b, sal_Int32 c, sal_Int32 d) { return this->NotifyCaretChange(a, b, c, d); }); mpTextView->SetTextChangeBroadcaster( [this]() { return SetTextView(mpTextView); }); } void AccessibleNotes::SetWindow ( const css::uno::Reference& rxContentWindow, const css::uno::Reference& rxBorderWindow) { AccessibleObject::SetWindow(rxContentWindow, rxBorderWindow); // Set the windows at the children as well, so that every paragraph can // setup its geometry. for (auto& rxChild : maChildren) { rxChild->SetWindow(rxContentWindow, rxBorderWindow); } } void AccessibleNotes::NotifyCaretChange ( const sal_Int32 nOldParagraphIndex, const sal_Int32 nOldCharacterIndex, const sal_Int32 nNewParagraphIndex, const sal_Int32 nNewCharacterIndex) { AccessibleFocusManager::Instance()->FocusObject( nNewParagraphIndex >= 0 ? maChildren[nNewParagraphIndex] : this); if (nOldParagraphIndex != nNewParagraphIndex) { // Moved caret from one paragraph to another (or showed or // hid the caret). Move focus from one accessible // paragraph to another. if (nOldParagraphIndex >= 0) { maChildren[nOldParagraphIndex]->FireAccessibleEvent( AccessibleEventId::CARET_CHANGED, Any(nOldCharacterIndex), Any(sal_Int32(-1))); } if (nNewParagraphIndex >= 0) { maChildren[nNewParagraphIndex]->FireAccessibleEvent( AccessibleEventId::CARET_CHANGED, Any(sal_Int32(-1)), Any(nNewCharacterIndex)); } } else if (nNewParagraphIndex >= 0) { // Caret moved inside one paragraph. maChildren[nNewParagraphIndex]->FireAccessibleEvent( AccessibleEventId::CARET_CHANGED, Any(nOldCharacterIndex), Any(nNewCharacterIndex)); } } //===== AccessibleFocusManager ================================================ std::shared_ptr AccessibleFocusManager::mpInstance; std::shared_ptr const & AccessibleFocusManager::Instance() { if ( ! mpInstance) { mpInstance.reset(new AccessibleFocusManager()); } return mpInstance; } AccessibleFocusManager::AccessibleFocusManager() { } AccessibleFocusManager::~AccessibleFocusManager() { // copy member to stack, then drop it - otherwise will get use-after-free // from AccessibleObject::disposing(), it will call ~Reference *twice* auto const temp(std::move(maFocusableObjects)); (void) temp; m_isInDtor = true; } void AccessibleFocusManager::AddFocusableObject ( const ::rtl::Reference& rpObject) { OSL_ASSERT(rpObject.is()); OSL_ASSERT(::std::find(maFocusableObjects.begin(),maFocusableObjects.end(), rpObject)==maFocusableObjects.end()); maFocusableObjects.push_back(rpObject); } void AccessibleFocusManager::RemoveFocusableObject ( const ::rtl::Reference& rpObject) { ::std::vector >::iterator iObject ( ::std::find(maFocusableObjects.begin(),maFocusableObjects.end(), rpObject)); if (iObject != maFocusableObjects.end()) maFocusableObjects.erase(iObject); else { OSL_ASSERT(m_isInDtor); // in dtor, was removed already } } void AccessibleFocusManager::FocusObject ( const ::rtl::Reference& rpObject) { // Remove the focus of any of the other focusable objects. for (auto& rxObject : maFocusableObjects) { if (rxObject!=rpObject) rxObject->SetIsFocused(false); } if (rpObject.is()) rpObject->SetIsFocused(true); } } // end of namespace ::sd::presenter /* vim:set shiftwidth=4 softtabstop=4 expandtab: */