/************************************************************** * * 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 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ #include "precompiled_sdext.hxx" #include "PresenterAccessibility.hxx" #include "PresenterTextView.hxx" #include "PresenterConfigurationAccess.hxx" #include "PresenterNotesView.hxx" #include "PresenterPaneBase.hxx" #include "PresenterPaneContainer.hxx" #include "PresenterPaneFactory.hxx" #include "PresenterViewFactory.hxx" #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; using ::rtl::OUString; #define A2S(s) (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s))) #define VERBOSE //===== PresenterAccessibleObject ============================================= namespace sdext { namespace presenter { namespace { typedef ::cppu::WeakComponentImplHelper5 < cssa::XAccessible, cssa::XAccessibleContext, cssa::XAccessibleComponent, cssa::XAccessibleEventBroadcaster, css::awt::XWindowListener > PresenterAccessibleObjectInterfaceBase; } class PresenterAccessible::AccessibleObject : public ::cppu::BaseMutex, public PresenterAccessibleObjectInterfaceBase { public: AccessibleObject ( const css::lang::Locale aLocale, const sal_Int16 nRole, const ::rtl::OUString& rsName); void LateInitialization (void); virtual ~AccessibleObject (void); virtual void SetWindow ( const cssu::Reference& rxContentWindow, const cssu::Reference& rxBorderWindow); void SetAccessibleParent (const cssu::Reference& rxAccessibleParent); virtual void SAL_CALL disposing (void); void NotifyCurrentSlideChange (const sal_Int32 nCurrentSlideIndex); void AddChild (const ::rtl::Reference& rpChild); void RemoveChild (const ::rtl::Reference& rpChild); void SetIsFocused (const bool bIsFocused); void SetAccessibleName (const ::rtl::OUString& rsName); void FireAccessibleEvent ( const sal_Int16 nEventId, const cssu::Any& rOldValue, const cssu::Any& rNewValue); void UpdateStateSet (void); //----- XAccessible ------------------------------------------------------- virtual cssu::Reference SAL_CALL getAccessibleContext (void) throw (cssu::RuntimeException); //----- XAccessibleContext ------------------------------------------------ virtual sal_Int32 SAL_CALL getAccessibleChildCount (void) throw (cssu::RuntimeException); virtual cssu::Reference< cssa::XAccessible> SAL_CALL getAccessibleChild (sal_Int32 nIndex) throw (css::lang::IndexOutOfBoundsException, cssu::RuntimeException); virtual cssu::Reference< cssa::XAccessible> SAL_CALL getAccessibleParent (void) throw (cssu::RuntimeException); virtual sal_Int32 SAL_CALL getAccessibleIndexInParent (void) throw (cssu::RuntimeException); virtual sal_Int16 SAL_CALL getAccessibleRole (void) throw (cssu::RuntimeException); virtual ::rtl::OUString SAL_CALL getAccessibleDescription (void) throw (cssu::RuntimeException); virtual ::rtl::OUString SAL_CALL getAccessibleName (void) throw (cssu::RuntimeException); virtual cssu::Reference SAL_CALL getAccessibleRelationSet (void) throw (cssu::RuntimeException); virtual cssu::Reference SAL_CALL getAccessibleStateSet (void) throw (cssu::RuntimeException); virtual css::lang::Locale SAL_CALL getLocale (void) throw (cssu::RuntimeException, cssa::IllegalAccessibleComponentStateException); //----- XAccessibleComponent ---------------------------------------------- virtual sal_Bool SAL_CALL containsPoint ( const css::awt::Point& aPoint) throw (cssu::RuntimeException); virtual cssu::Reference SAL_CALL getAccessibleAtPoint ( const css::awt::Point& aPoint) throw (cssu::RuntimeException); virtual css::awt::Rectangle SAL_CALL getBounds (void) throw (cssu::RuntimeException); virtual css::awt::Point SAL_CALL getLocation (void) throw (cssu::RuntimeException); virtual css::awt::Point SAL_CALL getLocationOnScreen (void) throw (cssu::RuntimeException); virtual css::awt::Size SAL_CALL getSize (void) throw (cssu::RuntimeException); virtual void SAL_CALL grabFocus (void) throw (cssu::RuntimeException); virtual sal_Int32 SAL_CALL getForeground (void) throw (cssu::RuntimeException); virtual sal_Int32 SAL_CALL getBackground (void) throw (cssu::RuntimeException); //----- XAccessibleEventBroadcaster --------------------------------------- virtual void SAL_CALL addEventListener ( const cssu::Reference& rxListener) throw (cssu::RuntimeException); virtual void SAL_CALL removeEventListener ( const cssu::Reference& rxListener) throw (cssu::RuntimeException); using PresenterAccessibleObjectInterfaceBase::addEventListener; using PresenterAccessibleObjectInterfaceBase::removeEventListener; //----- XWindowListener --------------------------------------------------- virtual void SAL_CALL windowResized (const css::awt::WindowEvent& rEvent) throw (cssu::RuntimeException); virtual void SAL_CALL windowMoved (const css::awt::WindowEvent& rEvent) throw (cssu::RuntimeException); virtual void SAL_CALL windowShown (const css::lang::EventObject& rEvent) throw (cssu::RuntimeException); virtual void SAL_CALL windowHidden (const css::lang::EventObject& rEvent) throw (cssu::RuntimeException); //----- XEventListener ---------------------------------------------------- virtual void SAL_CALL disposing (const css::lang::EventObject& rEvent) throw (cssu::RuntimeException); protected: ::rtl::OUString msName; cssu::Reference mxContentWindow; cssu::Reference mxBorderWindow; const css::lang::Locale maLocale; const sal_Int16 mnRole; sal_uInt32 mnStateSet; bool mbIsFocused; cssu::Reference mxParentAccessible; ::std::vector > maChildren; ::std::vector > maListeners; virtual awt::Point GetRelativeLocation (void); virtual awt::Size GetSize (void); virtual awt::Point GetAbsoluteParentLocation (void); virtual bool GetWindowState (const sal_Int16 nType) const; void UpdateState (const sal_Int16 aState, const bool bValue); sal_Bool IsDisposed (void) const; void ThrowIfDisposed (void) const throw (css::lang::DisposedException); enum ExceptionType { ET_Runtime, ET_Disposed, ET_IndexOutOfBounds }; void ThrowException (const sal_Char* pMessage, const ExceptionType eExceptionType) const; }; //===== AccessibleStateSet ==================================================== namespace { typedef ::cppu::WeakComponentImplHelper1 < cssa::XAccessibleStateSet > AccessibleStateSetInterfaceBase; } class AccessibleStateSet : public ::cppu::BaseMutex, public AccessibleStateSetInterfaceBase { public: AccessibleStateSet (const sal_Int32 nStateSet); virtual ~AccessibleStateSet (void); static sal_uInt32 GetStateMask (const sal_Int16 nType); //----- XAccessibleStateSet ----------------------------------------------- virtual sal_Bool SAL_CALL isEmpty (void) throw (cssu::RuntimeException); virtual sal_Bool SAL_CALL contains (sal_Int16 nState) throw (cssu::RuntimeException); virtual sal_Bool SAL_CALL containsAll (const cssu::Sequence& rStateSet) throw (cssu::RuntimeException); virtual cssu::Sequence SAL_CALL getStates (void) throw (cssu::RuntimeException); private: const sal_Int32 mnStateSet; }; //===== AccessibleRelationSet ================================================= namespace { typedef ::cppu::WeakComponentImplHelper1 < cssa::XAccessibleRelationSet > AccessibleRelationSetInterfaceBase; } class AccessibleRelationSet : public ::cppu::BaseMutex, public AccessibleRelationSetInterfaceBase { public: AccessibleRelationSet (void); virtual ~AccessibleRelationSet (void); void AddRelation ( const sal_Int16 nRelationType, const Reference& rxObject); //----- XAccessibleRelationSet -------------------------------------------- virtual sal_Int32 SAL_CALL getRelationCount (void) throw (cssu::RuntimeException); virtual AccessibleRelation SAL_CALL getRelation (sal_Int32 nIndex) throw (cssu::RuntimeException, css::lang::IndexOutOfBoundsException); virtual sal_Bool SAL_CALL containsRelation (sal_Int16 nRelationType) throw (cssu::RuntimeException); virtual AccessibleRelation SAL_CALL getRelationByType (sal_Int16 nRelationType) throw (cssu::RuntimeException); private: ::std::vector maRelations; }; //===== PresenterAccessibleParagraph ========================================== namespace { typedef ::cppu::ImplInheritanceHelper1 < PresenterAccessible::AccessibleObject, cssa::XAccessibleText > PresenterAccessibleParagraphInterfaceBase; } class PresenterAccessible::AccessibleParagraph : public PresenterAccessibleParagraphInterfaceBase { public: AccessibleParagraph ( const css::lang::Locale aLocale, const sal_Int16 nRole, const ::rtl::OUString& rsName, const SharedPresenterTextParagraph& rpParagraph, const sal_Int32 nParagraphIndex); virtual ~AccessibleParagraph (void); //----- XAccessibleContext ------------------------------------------------ virtual cssu::Reference SAL_CALL getAccessibleRelationSet (void) throw (cssu::RuntimeException); //----- XAccessibleText --------------------------------------------------- virtual sal_Int32 SAL_CALL getCaretPosition (void) throw (cssu::RuntimeException); virtual sal_Bool SAL_CALL setCaretPosition (sal_Int32 nIndex) throw (::com::sun::star::lang::IndexOutOfBoundsException, cssu::RuntimeException); virtual sal_Unicode SAL_CALL getCharacter (sal_Int32 nIndex) throw (::com::sun::star::lang::IndexOutOfBoundsException, cssu::RuntimeException); virtual cssu::Sequence SAL_CALL getCharacterAttributes ( ::sal_Int32 nIndex, const cssu::Sequence& rRequestedAttributes) throw (css::lang::IndexOutOfBoundsException, cssu::RuntimeException); virtual css::awt::Rectangle SAL_CALL getCharacterBounds (sal_Int32 nIndex) throw (css::lang::IndexOutOfBoundsException, cssu::RuntimeException); virtual sal_Int32 SAL_CALL getCharacterCount (void) throw (cssu::RuntimeException); virtual sal_Int32 SAL_CALL getIndexAtPoint (const css::awt::Point& rPoint) throw (cssu::RuntimeException); virtual ::rtl::OUString SAL_CALL getSelectedText (void) throw (cssu::RuntimeException); virtual sal_Int32 SAL_CALL getSelectionStart (void) throw (cssu::RuntimeException); virtual sal_Int32 SAL_CALL getSelectionEnd (void) throw (cssu::RuntimeException); virtual sal_Bool SAL_CALL setSelection (sal_Int32 nStartIndex, sal_Int32 nEndIndex) throw (css::lang::IndexOutOfBoundsException, cssu::RuntimeException); virtual ::rtl::OUString SAL_CALL getText (void) throw (cssu::RuntimeException); virtual ::rtl::OUString SAL_CALL getTextRange ( sal_Int32 nStartIndex, sal_Int32 nEndIndex) throw (css::lang::IndexOutOfBoundsException, cssu::RuntimeException); virtual cssa::TextSegment SAL_CALL getTextAtIndex ( sal_Int32 nIndex, sal_Int16 nTextType) throw (css::lang::IndexOutOfBoundsException, css::lang::IllegalArgumentException, cssu::RuntimeException); virtual cssa::TextSegment SAL_CALL getTextBeforeIndex ( sal_Int32 nIndex, sal_Int16 nTextType) throw (css::lang::IndexOutOfBoundsException, css::lang::IllegalArgumentException, cssu::RuntimeException); virtual cssa::TextSegment SAL_CALL getTextBehindIndex ( sal_Int32 nIndex, sal_Int16 nTextType) throw (css::lang::IndexOutOfBoundsException, css::lang::IllegalArgumentException, cssu::RuntimeException); virtual ::sal_Bool SAL_CALL copyText (sal_Int32 nStartIndex, sal_Int32 nEndIndex) throw (css::lang::IndexOutOfBoundsException, cssu::RuntimeException); protected: virtual awt::Point GetRelativeLocation (void); virtual awt::Size GetSize (void); virtual awt::Point GetAbsoluteParentLocation (void); virtual bool GetWindowState (const sal_Int16 nType) const; private: SharedPresenterTextParagraph mpParagraph; const sal_Int32 mnParagraphIndex; }; //===== AccessibleConsole ===================================================== class AccessibleConsole { public: static rtl::Reference Create ( const css::uno::Reference& rxContext, const lang::Locale aLocale) { OUString sName (A2S("Presenter Console")); PresenterConfigurationAccess aConfiguration ( rxContext, OUString::createFromAscii("/org.openoffice.Office.PresenterScreen/"), PresenterConfigurationAccess::READ_ONLY); aConfiguration.GetConfigurationNode(A2S("Presenter/Accessibility/Console/String")) >>= sName; rtl::Reference pObject ( new PresenterAccessible::AccessibleObject( aLocale, AccessibleRole::PANEL, sName)); pObject->LateInitialization(); pObject->UpdateStateSet(); return pObject; } }; //===== AccessiblePreview ===================================================== class AccessiblePreview { public: static rtl::Reference Create ( const Reference& rxContext, const lang::Locale aLocale, const Reference& rxContentWindow, const Reference& rxBorderWindow) { OUString sName (A2S("Presenter Notes Window")); { PresenterConfigurationAccess aConfiguration ( rxContext, OUString::createFromAscii("/org.openoffice.Office.PresenterScreen/"), PresenterConfigurationAccess::READ_ONLY); aConfiguration.GetConfigurationNode(A2S("Presenter/Accessibility/Preview/String")) >>= sName; } rtl::Reference pObject ( new PresenterAccessible::AccessibleObject( aLocale, 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 aLocale, const sal_Int16 nRole, const ::rtl::OUString& rsName); static rtl::Reference Create ( const css::uno::Reference& rxContext, const lang::Locale aLocale, const Reference& rxContentWindow, const Reference& rxBorderWindow, const ::boost::shared_ptr& rpTextView); void SetTextView (const ::boost::shared_ptr& rpTextView); virtual void SetWindow ( const cssu::Reference& rxContentWindow, const cssu::Reference& rxBorderWindow); private: ::boost::shared_ptr mpTextView; void NotifyCaretChange ( const sal_Int32 nOldParagraphIndex, const sal_Int32 nOldCharacterIndex, const sal_Int32 nNewParagraphIndex, const sal_Int32 nNewCharacterIndex); void HandleTextChange (void); }; //===== AccessibleFocusManager ================================================ /** A singleton class that makes sure that only one accessibility object in the PresenterConsole hierarchy has the focus. */ class AccessibleFocusManager { public: static ::boost::shared_ptr Instance (void); void AddFocusableObject (const ::rtl::Reference& rpObject); void RemoveFocusableObject (const ::rtl::Reference& rpObject); void FocusObject (const ::rtl::Reference& rpObject); private: static ::boost::shared_ptr mpInstance; ::std::vector > maFocusableObjects; AccessibleFocusManager (void); }; //===== PresenterAccessible =================================================== PresenterAccessible::PresenterAccessible ( const css::uno::Reference& rxContext, const ::rtl::Reference& rpPresenterController, const Reference& rxMainPane) : PresenterAccessibleInterfaceBase(m_aMutex), mxComponentContext(rxContext), mpPresenterController(rpPresenterController), mxMainPaneId(rxMainPane.is() ? rxMainPane->getResourceId() : Reference()), mxMainPane(rxMainPane, UNO_QUERY), mxMainWindow(), mxPreviewContentWindow(), mxPreviewBorderWindow(), mxNotesContentWindow(), mxNotesBorderWindow(), mpAccessibleConsole(), mpAccessiblePreview(), mpAccessibleNotes(), mxAccessibleParent() { if (mxMainPane.is()) mxMainPane->setAccessible(this); } PresenterAccessible::~PresenterAccessible (void) { } PresenterPaneContainer::SharedPaneDescriptor PresenterAccessible::GetPreviewPane (void) 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 (void) { 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() : ::boost::shared_ptr()); } void PresenterAccessible::UpdateAccessibilityHierarchy ( const Reference& rxPreviewContentWindow, const Reference& rxPreviewBorderWindow, const ::rtl::OUString& rsTitle, const Reference& rxNotesContentWindow, const Reference& rxNotesBorderWindow, const ::boost::shared_ptr& rpNotesTextView) { if ( ! mpAccessibleConsole.is()) return; if (mxPreviewContentWindow != rxPreviewContentWindow) { if (mpAccessiblePreview.is()) { mpAccessibleConsole->RemoveChild(mpAccessiblePreview); mpAccessiblePreview = NULL; } mxPreviewContentWindow = rxPreviewContentWindow; mxPreviewBorderWindow = rxPreviewBorderWindow; if (mxPreviewContentWindow.is()) { mpAccessiblePreview = AccessiblePreview::Create( mxComponentContext, lang::Locale(), mxPreviewContentWindow, mxPreviewBorderWindow); mpAccessibleConsole->AddChild(mpAccessiblePreview); mpAccessiblePreview->SetAccessibleName(rsTitle); } } if (mxNotesContentWindow != rxNotesContentWindow) { if (mpAccessibleNotes.is()) { mpAccessibleConsole->RemoveChild(mpAccessibleConsole.get()); mpAccessibleNotes = NULL; } mxNotesContentWindow = rxNotesContentWindow; mxNotesBorderWindow = rxNotesBorderWindow; if (mxNotesContentWindow.is()) { mpAccessibleNotes = AccessibleNotes::Create( mxComponentContext, lang::Locale(), mxNotesContentWindow, mxNotesBorderWindow, rpNotesTextView); mpAccessibleConsole->AddChild(mpAccessibleNotes.get()); } } } void PresenterAccessible::NotifyCurrentSlideChange ( const sal_Int32 nCurrentSlideIndex, const sal_Int32 nSlideCount) { (void)nCurrentSlideIndex; (void)nSlideCount; if (mpAccessiblePreview.is()) { PresenterPaneContainer::SharedPaneDescriptor pPreviewPane (GetPreviewPane()); mpAccessiblePreview->SetAccessibleName( (pPreviewPane&&pPreviewPane->mxPane.is() ? pPreviewPane->mxPane->GetTitle() : rtl::OUString())); } // Play some focus ping-pong to trigger AT tools. //AccessibleFocusManager::Instance()->FocusObject(mpAccessibleConsole); AccessibleFocusManager::Instance()->FocusObject(mpAccessiblePreview); } bool PresenterAccessible::IsAccessibilityActive (void) const { return mpAccessibleConsole.is(); } void SAL_CALL PresenterAccessible::disposing (void) { UpdateAccessibilityHierarchy( NULL, NULL, OUString(), NULL, NULL, ::boost::shared_ptr()); if (mxMainWindow.is()) { mxMainWindow->removeFocusListener(this); if (mxMainPane.is()) mxMainPane->setAccessible(NULL); } mpAccessiblePreview = NULL; mpAccessibleNotes = NULL; mpAccessibleConsole = NULL; } //----- XAccessible ----------------------------------------------------------- Reference SAL_CALL PresenterAccessible::getAccessibleContext (void) throw (cssu::RuntimeException) { if ( ! mpAccessibleConsole.is()) { Reference xMainPane (mxMainPane, UNO_QUERY); if (xMainPane.is()) { mxMainWindow = Reference(xMainPane->getWindow(), UNO_QUERY); mxMainWindow->addFocusListener(this); } mpAccessibleConsole = AccessibleConsole::Create( mxComponentContext, css::lang::Locale()); mpAccessibleConsole->SetWindow(mxMainWindow, NULL); mpAccessibleConsole->SetAccessibleParent(mxAccessibleParent); UpdateAccessibilityHierarchy(); if (mpPresenterController.is()) mpPresenterController->SetAccessibilityActiveState(true); } return mpAccessibleConsole->getAccessibleContext(); } //----- XFocusListener ---------------------------------------------------- void SAL_CALL PresenterAccessible::focusGained (const css::awt::FocusEvent& rEvent) throw (cssu::RuntimeException) { (void)rEvent; #ifdef VERBOSE OSL_TRACE("PresenterAccessible::focusGained at %x and window %x\r", this, mxMainWindow.get()); #endif AccessibleFocusManager::Instance()->FocusObject(mpAccessibleConsole); } void SAL_CALL PresenterAccessible::focusLost (const css::awt::FocusEvent& rEvent) throw (cssu::RuntimeException) { (void)rEvent; #ifdef VERBOSE OSL_TRACE("PresenterAccessible::focusLost at %x\r", this); #endif AccessibleFocusManager::Instance()->FocusObject(NULL); } //----- XEventListener ---------------------------------------------------- void SAL_CALL PresenterAccessible::disposing (const css::lang::EventObject& rEvent) throw (cssu::RuntimeException) { if (rEvent.Source == mxMainWindow) mxMainWindow = NULL; } //----- XInitialize ----------------------------------------------------------- void SAL_CALL PresenterAccessible::initialize (const cssu::Sequence& rArguments) throw (cssu::RuntimeException) { if (rArguments.getLength() >= 1) { mxAccessibleParent = Reference(rArguments[0], UNO_QUERY); if (mpAccessibleConsole.is()) mpAccessibleConsole->SetAccessibleParent(mxAccessibleParent); } } //===== PresenterAccessible::AccessibleObject ========================================= PresenterAccessible::AccessibleObject::AccessibleObject ( const lang::Locale aLocale, const sal_Int16 nRole, const OUString& rsName) : PresenterAccessibleObjectInterfaceBase(m_aMutex), msName(rsName), mxContentWindow(), mxBorderWindow(), maLocale(aLocale), mnRole(nRole), mnStateSet(0), mbIsFocused(false), mxParentAccessible(), maChildren(), maListeners() { } void PresenterAccessible::AccessibleObject::LateInitialization (void) { AccessibleFocusManager::Instance()->AddFocusableObject(this); } PresenterAccessible::AccessibleObject::~AccessibleObject (void) { } void PresenterAccessible::AccessibleObject::SetWindow ( const Reference& rxContentWindow, const Reference& rxBorderWindow) { Reference xContentWindow (rxContentWindow, UNO_QUERY); if (mxContentWindow.get() != xContentWindow.get()) { if (mxContentWindow.is()) { mxContentWindow->removeWindowListener(this); } mxContentWindow = xContentWindow; mxBorderWindow = Reference(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 (void) { AccessibleFocusManager::Instance()->RemoveFocusableObject(this); SetWindow(NULL, NULL); } //----- XAccessible ------------------------------------------------------- Reference SAL_CALL PresenterAccessible::AccessibleObject::getAccessibleContext (void) throw (RuntimeException) { ThrowIfDisposed(); return this; } //----- XAccessibleContext ------------------------------------------------ sal_Int32 SAL_CALL PresenterAccessible::AccessibleObject::getAccessibleChildCount (void) throw (cssu::RuntimeException) { ThrowIfDisposed(); const sal_Int32 nChildCount (maChildren.size()); return nChildCount; } Reference SAL_CALL PresenterAccessible::AccessibleObject::getAccessibleChild (sal_Int32 nIndex) throw (lang::IndexOutOfBoundsException, RuntimeException) { ThrowIfDisposed(); if (nIndex<0 || nIndex>=sal_Int32(maChildren.size())) ThrowException("invalid child index", ET_IndexOutOfBounds); return Reference(maChildren[nIndex].get()); } Reference SAL_CALL PresenterAccessible::AccessibleObject::getAccessibleParent (void) throw (RuntimeException) { ThrowIfDisposed(); return mxParentAccessible; } sal_Int32 SAL_CALL PresenterAccessible::AccessibleObject::getAccessibleIndexInParent (void) throw (RuntimeException) { 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 (void) throw (RuntimeException) { ThrowIfDisposed(); return mnRole; } OUString SAL_CALL PresenterAccessible::AccessibleObject::getAccessibleDescription (void) throw (RuntimeException) { ThrowIfDisposed(); return msName; } OUString SAL_CALL PresenterAccessible::AccessibleObject::getAccessibleName (void) throw (cssu::RuntimeException) { ThrowIfDisposed(); return msName; } Reference SAL_CALL PresenterAccessible::AccessibleObject::getAccessibleRelationSet (void) throw (RuntimeException) { ThrowIfDisposed(); return NULL; } Reference SAL_CALL PresenterAccessible::AccessibleObject::getAccessibleStateSet (void) throw (RuntimeException) { ThrowIfDisposed(); return Reference(new AccessibleStateSet(mnStateSet)); } lang::Locale SAL_CALL PresenterAccessible::AccessibleObject::getLocale (void) throw (RuntimeException, IllegalAccessibleComponentStateException) { 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) throw (RuntimeException) { 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& rPoint) throw (RuntimeException) { (void)rPoint; ThrowIfDisposed(); return Reference(); } awt::Rectangle SAL_CALL PresenterAccessible::AccessibleObject::getBounds (void) throw (RuntimeException) { ThrowIfDisposed(); awt::Rectangle aBox; 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 (void) throw (RuntimeException) { ThrowIfDisposed(); const awt::Point aLocation (GetRelativeLocation()); return aLocation; } awt::Point SAL_CALL PresenterAccessible::AccessibleObject::getLocationOnScreen (void) throw (RuntimeException) { 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 (void) throw (RuntimeException) { ThrowIfDisposed(); const awt::Size aSize (GetSize()); return aSize; } void SAL_CALL PresenterAccessible::AccessibleObject::grabFocus (void) throw (RuntimeException) { ThrowIfDisposed(); if (mxBorderWindow.is()) mxBorderWindow->setFocus(); else if (mxContentWindow.is()) mxContentWindow->setFocus(); } sal_Int32 SAL_CALL PresenterAccessible::AccessibleObject::getForeground (void) throw (RuntimeException) { ThrowIfDisposed(); return 0x00ffffff; } sal_Int32 SAL_CALL PresenterAccessible::AccessibleObject::getBackground (void) throw (RuntimeException) { ThrowIfDisposed(); return 0x00000000; } //----- XAccessibleEventBroadcaster --------------------------------------- void SAL_CALL PresenterAccessible::AccessibleObject::addEventListener ( const Reference& rxListener) throw (RuntimeException) { if (rxListener.is()) { const osl::MutexGuard aGuard(m_aMutex); if (IsDisposed()) { uno::Reference xThis (static_cast(this), UNO_QUERY); rxListener->disposing (lang::EventObject(xThis)); } else { maListeners.push_back(rxListener); } } } void SAL_CALL PresenterAccessible::AccessibleObject::removeEventListener ( const Reference& rxListener) throw (RuntimeException) { ThrowIfDisposed(); if (rxListener.is()) { const osl::MutexGuard aGuard(m_aMutex); maListeners.erase(std::remove(maListeners.begin(), maListeners.end(), rxListener)); } } //----- XWindowListener --------------------------------------------------- void SAL_CALL PresenterAccessible::AccessibleObject::windowResized ( const css::awt::WindowEvent& rEvent) throw (cssu::RuntimeException) { (void)rEvent; FireAccessibleEvent(AccessibleEventId::BOUNDRECT_CHANGED, Any(), Any()); } void SAL_CALL PresenterAccessible::AccessibleObject::windowMoved ( const css::awt::WindowEvent& rEvent) throw (cssu::RuntimeException) { (void)rEvent; FireAccessibleEvent(AccessibleEventId::BOUNDRECT_CHANGED, Any(), Any()); } void SAL_CALL PresenterAccessible::AccessibleObject::windowShown ( const css::lang::EventObject& rEvent) throw (cssu::RuntimeException) { (void)rEvent; UpdateStateSet(); } void SAL_CALL PresenterAccessible::AccessibleObject::windowHidden ( const css::lang::EventObject& rEvent) throw (cssu::RuntimeException) { (void)rEvent; UpdateStateSet(); } //----- XEventListener -------------------------------------------------------- void SAL_CALL PresenterAccessible::AccessibleObject::disposing (const css::lang::EventObject& rEvent) throw (cssu::RuntimeException) { if (rEvent.Source == mxContentWindow) { mxContentWindow = NULL; mxBorderWindow = NULL; } else { SetWindow(NULL, NULL); } } //----- 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 (void) { 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) { 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 ::rtl::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 (::std::vector >::const_iterator iListener(aListenerCopy.begin()), iEnd(aListenerCopy.end()); iListener!=iEnd; ++iListener) { try { (*iListener)->notifyEvent(aEventObject); } catch(lang::DisposedException&) { // Listener has been disposed and should have been removed // already. removeEventListener(*iListener); } catch(Exception&) { // Ignore all other exceptions and assume that they are // caused by a temporary problem. } } } awt::Point PresenterAccessible::AccessibleObject::GetRelativeLocation (void) { 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 (void) { 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 (void) { Reference xParentComponent; if (mxParentAccessible.is()) xParentComponent = Reference( mxParentAccessible->getAccessibleContext(), UNO_QUERY); if (xParentComponent.is()) return xParentComponent->getLocationOnScreen(); else return awt::Point(); } sal_Bool PresenterAccessible::AccessibleObject::IsDisposed (void) const { return (rBHelper.bDisposed || rBHelper.bInDispose); } void PresenterAccessible::AccessibleObject::ThrowIfDisposed (void) const throw (lang::DisposedException) { if (rBHelper.bDisposed || rBHelper.bInDispose) ThrowException("object has already been disposed", ET_Disposed); } void PresenterAccessible::AccessibleObject::ThrowException ( const sal_Char* pMessage, const ExceptionType eExceptionType) const { const OUString sMessage (OUString(A2S("PresenterAccessible: ")) + OUString(A2S(pMessage))); const Reference xObject ( const_cast(static_cast(this))); switch (eExceptionType) { default: case ET_Runtime: throw RuntimeException(sMessage, xObject); case ET_Disposed: throw lang::DisposedException(sMessage, xObject); case ET_IndexOutOfBounds: throw lang::IndexOutOfBoundsException(sMessage, xObject); } } //===== AccessibleStateSet ==================================================== AccessibleStateSet::AccessibleStateSet (const sal_Int32 nStateSet) : AccessibleStateSetInterfaceBase(m_aMutex), mnStateSet (nStateSet) { } AccessibleStateSet::~AccessibleStateSet (void) { } sal_uInt32 AccessibleStateSet::GetStateMask (const sal_Int16 nState) { if (nState<0 || nState>=sal_Int16(sizeof(sal_uInt32)*8)) { throw RuntimeException(A2S("AccessibleStateSet::GetStateMask: invalid state"), NULL); } return 1<& rStateSet) throw (cssu::RuntimeException) { for (sal_Int32 nIndex=0,nCount=rStateSet.getLength(); nIndex SAL_CALL AccessibleStateSet::getStates (void) throw (cssu::RuntimeException) { ::std::vector aStates; aStates.reserve(sizeof(mnStateSet)*8); for (sal_uInt16 nIndex=0; nIndex(&aStates.front(), aStates.size()); } //===== AccessibleRelationSet ================================================= AccessibleRelationSet::AccessibleRelationSet (void) : AccessibleRelationSetInterfaceBase(m_aMutex), maRelations() { } AccessibleRelationSet::~AccessibleRelationSet (void) { } void AccessibleRelationSet::AddRelation ( const sal_Int16 nRelationType, const Reference& rxObject) { maRelations.resize(maRelations.size()+1); maRelations.back().RelationType = nRelationType; maRelations.back().TargetSet.realloc(1); maRelations.back().TargetSet[0] = rxObject; } //----- XAccessibleRelationSet ------------------------------------------------ sal_Int32 SAL_CALL AccessibleRelationSet::getRelationCount (void) throw (cssu::RuntimeException) { return maRelations.size(); } AccessibleRelation SAL_CALL AccessibleRelationSet::getRelation (sal_Int32 nIndex) throw (cssu::RuntimeException, css::lang::IndexOutOfBoundsException) { if (nIndex<0 && sal_uInt32(nIndex)>=maRelations.size()) return AccessibleRelation(); else return maRelations[nIndex]; } sal_Bool SAL_CALL AccessibleRelationSet::containsRelation (sal_Int16 nRelationType) throw (cssu::RuntimeException) { for (::std::vector::const_iterator iRelation(maRelations.begin()); iRelation!=maRelations.end(); ++iRelation) { if (iRelation->RelationType == nRelationType) return sal_True; } return sal_False; } AccessibleRelation SAL_CALL AccessibleRelationSet::getRelationByType (sal_Int16 nRelationType) throw (cssu::RuntimeException) { for (::std::vector::const_iterator iRelation(maRelations.begin()); iRelation!=maRelations.end(); ++iRelation) { if (iRelation->RelationType == nRelationType) return *iRelation; } return AccessibleRelation(); } //===== PresenterAccessible::AccessibleParagraph ============================== PresenterAccessible::AccessibleParagraph::AccessibleParagraph ( const lang::Locale aLocale, const sal_Int16 nRole, const OUString& rsName, const SharedPresenterTextParagraph& rpParagraph, const sal_Int32 nParagraphIndex) : PresenterAccessibleParagraphInterfaceBase(aLocale, nRole, rsName), mpParagraph(rpParagraph), mnParagraphIndex(nParagraphIndex) { } PresenterAccessible::AccessibleParagraph::~AccessibleParagraph (void) { } //----- XAccessibleContext ---------------------------------------------------- Reference SAL_CALL PresenterAccessible::AccessibleParagraph::getAccessibleRelationSet (void) throw (RuntimeException) { 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 Reference(pSet.get()); } //----- XAccessibleText ------------------------------------------------------- sal_Int32 SAL_CALL PresenterAccessible::AccessibleParagraph::getCaretPosition (void) throw (cssu::RuntimeException) { ThrowIfDisposed(); sal_Int32 nPosition (-1); if (mpParagraph) nPosition = mpParagraph->GetCaretPosition(); return nPosition; } sal_Bool SAL_CALL PresenterAccessible::AccessibleParagraph::setCaretPosition (sal_Int32 nIndex) throw (::com::sun::star::lang::IndexOutOfBoundsException, cssu::RuntimeException) { ThrowIfDisposed(); if (mpParagraph) { mpParagraph->SetCaretPosition(nIndex); return sal_True; } else return sal_False; } sal_Unicode SAL_CALL PresenterAccessible::AccessibleParagraph::getCharacter (sal_Int32 nIndex) throw (::com::sun::star::lang::IndexOutOfBoundsException, cssu::RuntimeException) { ThrowIfDisposed(); if (mpParagraph) return mpParagraph->GetCharacter(nIndex); else { ThrowException("no text support in current mode", ET_IndexOutOfBounds); // The method above throws an exception and the following line is // never reached. But there is at least one compiler that can not // detect this and we need the return to make it happy. return sal_Unicode(); } } Sequence SAL_CALL PresenterAccessible::AccessibleParagraph::getCharacterAttributes ( ::sal_Int32 nIndex, const cssu::Sequence& rRequestedAttributes) throw (css::lang::IndexOutOfBoundsException, cssu::RuntimeException) { ThrowIfDisposed(); #ifdef VERBOSE OSL_TRACE("PresenterAccessible::AccessibleParagraph::getCharacterAttributes at %x,%d returns empty set\r", this,nIndex); for (sal_Int32 nAttributeIndex(0),nAttributeCount(rRequestedAttributes.getLength()); nAttributeIndex(); } awt::Rectangle SAL_CALL PresenterAccessible::AccessibleParagraph::getCharacterBounds ( sal_Int32 nIndex) throw (css::lang::IndexOutOfBoundsException, cssu::RuntimeException) { ThrowIfDisposed(); awt::Rectangle aCharacterBox; if (nIndex < 0) { ThrowException("invalid text index", ET_IndexOutOfBounds); } 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 { ThrowException("no text support in current mode", ET_IndexOutOfBounds); } return aCharacterBox; } sal_Int32 SAL_CALL PresenterAccessible::AccessibleParagraph::getCharacterCount (void) throw (cssu::RuntimeException) { ThrowIfDisposed(); sal_Int32 nCount (0); if (mpParagraph) nCount = mpParagraph->GetCharacterCount(); return nCount; } sal_Int32 SAL_CALL PresenterAccessible::AccessibleParagraph::getIndexAtPoint ( const css::awt::Point& rPoint) throw (cssu::RuntimeException) { ThrowIfDisposed(); sal_Int32 nIndex (-1); if (mpParagraph) nIndex = mpParagraph->GetIndexAtPoint(rPoint); return nIndex; } ::rtl::OUString SAL_CALL PresenterAccessible::AccessibleParagraph::getSelectedText (void) throw (cssu::RuntimeException) { ThrowIfDisposed(); return getTextRange(getSelectionStart(), getSelectionEnd()); } sal_Int32 SAL_CALL PresenterAccessible::AccessibleParagraph::getSelectionStart (void) throw (cssu::RuntimeException) { ThrowIfDisposed(); return getCaretPosition(); } sal_Int32 SAL_CALL PresenterAccessible::AccessibleParagraph::getSelectionEnd (void) throw (cssu::RuntimeException) { ThrowIfDisposed(); return getCaretPosition(); } sal_Bool SAL_CALL PresenterAccessible::AccessibleParagraph::setSelection ( sal_Int32 nStartIndex, sal_Int32 nEndIndex) throw (css::lang::IndexOutOfBoundsException, cssu::RuntimeException) { (void)nEndIndex; ThrowIfDisposed(); return setCaretPosition(nStartIndex); } ::rtl::OUString SAL_CALL PresenterAccessible::AccessibleParagraph::getText (void) throw (cssu::RuntimeException) { ThrowIfDisposed(); ::rtl::OUString sText; if (mpParagraph) sText = mpParagraph->GetText(); return sText; } ::rtl::OUString SAL_CALL PresenterAccessible::AccessibleParagraph::getTextRange ( sal_Int32 nLocalStartIndex, sal_Int32 nLocalEndIndex) throw (css::lang::IndexOutOfBoundsException, cssu::RuntimeException) { ThrowIfDisposed(); ::rtl::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) throw (css::lang::IndexOutOfBoundsException, css::lang::IllegalArgumentException, cssu::RuntimeException) { 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) throw (css::lang::IndexOutOfBoundsException, css::lang::IllegalArgumentException, cssu::RuntimeException) { 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) throw (css::lang::IndexOutOfBoundsException, css::lang::IllegalArgumentException, cssu::RuntimeException) { ThrowIfDisposed(); TextSegment aSegment; if (mpParagraph) aSegment = mpParagraph->GetTextSegment(+1, nLocalCharacterIndex, nTextType); return aSegment; } sal_Bool SAL_CALL PresenterAccessible::AccessibleParagraph::copyText ( sal_Int32 nStartIndex, sal_Int32 nEndIndex) throw (css::lang::IndexOutOfBoundsException, cssu::RuntimeException) { 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. (void)nStartIndex; (void)nEndIndex; return sal_False; } //----- protected ------------------------------------------------------------- awt::Point PresenterAccessible::AccessibleParagraph::GetRelativeLocation (void) { 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 (void) { if (mpParagraph) return mpParagraph->GetSize(); else return AccessibleObject::GetSize(); } awt::Point PresenterAccessible::AccessibleParagraph::GetAbsoluteParentLocation (void) { if (mxParentAccessible.is()) { Reference xParentContext( mxParentAccessible->getAccessibleContext(), UNO_QUERY); 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 mpParagraph.get()!=NULL; case AccessibleStateType::ACTIVE: return true; default: return AccessibleObject::GetWindowState(nType); } } //===== AccessibleNotes ======================================================= AccessibleNotes::AccessibleNotes ( const css::lang::Locale aLocale, const sal_Int16 nRole, const ::rtl::OUString& rsName) : AccessibleObject(aLocale,nRole,rsName), mpTextView() { } rtl::Reference AccessibleNotes::Create ( const css::uno::Reference& rxContext, const lang::Locale aLocale, const Reference& rxContentWindow, const Reference& rxBorderWindow, const ::boost::shared_ptr& rpTextView) { OUString sName (A2S("Presenter Notes Text")); { PresenterConfigurationAccess aConfiguration ( rxContext, OUString::createFromAscii("/org.openoffice.Office.PresenterScreen/"), PresenterConfigurationAccess::READ_ONLY); aConfiguration.GetConfigurationNode(A2S("Presenter/Accessibility/Notes/String")) >>= sName; } rtl::Reference pObject ( new AccessibleNotes( aLocale, AccessibleRole::PANEL, sName)); pObject->LateInitialization(); pObject->SetTextView(rpTextView); pObject->UpdateStateSet(); pObject->SetWindow(rxContentWindow, rxBorderWindow); return rtl::Reference(pObject.get()); } void AccessibleNotes::SetTextView ( const ::boost::shared_ptr& rpTextView) { ::std::vector > aChildren; // Release any listeners to the current text view. if (mpTextView) { mpTextView->GetCaret()->SetCaretMotionBroadcaster( ::boost::function()); mpTextView->SetTextChangeBroadcaster( ::boost::function()); } mpTextView = rpTextView; if (mpTextView) { // 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(), AccessibleRole::PARAGRAPH, A2S("Paragraph")+OUString::valueOf(nIndex), rpTextView->GetParagraph(nIndex), nIndex)); pParagraph->LateInitialization(); pParagraph->SetWindow( Reference(mxContentWindow, UNO_QUERY), Reference(mxBorderWindow, UNO_QUERY)); pParagraph->SetAccessibleParent(this); aChildren.push_back( rtl::Reference(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 (std::vector >::const_iterator iChild(aChildren.begin()), iEnd(aChildren.end()); iChild!=iEnd; ++iChild) { Reference xComponent (static_cast(iChild->get()), UNO_QUERY); 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( ::boost::bind(&AccessibleNotes::NotifyCaretChange, this, _1, _2, _3, _4)); mpTextView->SetTextChangeBroadcaster( ::boost::bind(&AccessibleNotes::HandleTextChange, this)); } } void AccessibleNotes::SetWindow ( const cssu::Reference& rxContentWindow, const cssu::Reference& rxBorderWindow) { AccessibleObject::SetWindow(rxContentWindow, rxBorderWindow); // Set the windows at the children as well, so that every paragraph can // setup its geometry. for (::std::vector >::const_iterator iChild(maChildren.begin()), iEnd(maChildren.end()); iChild!=iEnd; ++iChild) { (*iChild)->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)); } } void AccessibleNotes::HandleTextChange (void) { SetTextView(mpTextView); } //===== AccessibleFocusManager ================================================ ::boost::shared_ptr AccessibleFocusManager::mpInstance; ::boost::shared_ptr AccessibleFocusManager::Instance (void) { if ( ! mpInstance) { mpInstance.reset(new AccessibleFocusManager()); } return mpInstance; } AccessibleFocusManager::AccessibleFocusManager (void) : maFocusableObjects() { } 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(iObject!=maFocusableObjects.end()); } } void AccessibleFocusManager::FocusObject ( const ::rtl::Reference& rpObject) { // Remove the focus of any of the other focusable objects. for (::std::vector >::const_iterator iObject (maFocusableObjects.begin()), iEnd (maFocusableObjects.end()); iObject != iEnd; ++iObject) { if (*iObject!=rpObject) (*iObject)->SetIsFocused(false); } if (rpObject.is()) rpObject->SetIsFocused(true); } } } // end of namespace ::sd::presenter