8b9e502480
Change-Id: I1992d1ffbbc80efe9749ebd254971a0a92a10019 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/124386 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
1849 lines
56 KiB
C++
1849 lines
56 KiB
C++
/* -*- 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 <com/sun/star/accessibility/AccessibleEventId.hpp>
|
|
#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
|
|
#include <com/sun/star/accessibility/AccessibleRole.hpp>
|
|
#include <com/sun/star/accessibility/AccessibleScrollType.hpp>
|
|
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
|
|
#include <com/sun/star/accessibility/XAccessibleComponent.hpp>
|
|
#include <com/sun/star/accessibility/XAccessibleContext.hpp>
|
|
#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
|
|
#include <com/sun/star/accessibility/XAccessibleText.hpp>
|
|
#include <com/sun/star/awt/XWindow2.hpp>
|
|
#include <com/sun/star/drawing/framework/XPane.hpp>
|
|
#include <com/sun/star/drawing/framework/XView.hpp>
|
|
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
|
|
#include <cppuhelper/compbase.hxx>
|
|
#include <cppuhelper/implbase.hxx>
|
|
#include <o3tl/safeint.hxx>
|
|
#include <sal/log.hxx>
|
|
|
|
#include <algorithm>
|
|
|
|
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<css::awt::XWindow>& rxContentWindow,
|
|
const css::uno::Reference<css::awt::XWindow>& rxBorderWindow);
|
|
void SetAccessibleParent (const css::uno::Reference<css::accessibility::XAccessible>& rxAccessibleParent);
|
|
|
|
virtual void SAL_CALL disposing() override;
|
|
|
|
void AddChild (const ::rtl::Reference<AccessibleObject>& rpChild);
|
|
void RemoveChild (const ::rtl::Reference<AccessibleObject>& 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<css::accessibility::XAccessibleContext> 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<css::accessibility::XAccessibleRelationSet> SAL_CALL
|
|
getAccessibleRelationSet() override;
|
|
|
|
virtual css::uno::Reference<css::accessibility::XAccessibleStateSet> 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<css::accessibility::XAccessible> 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<css::accessibility::XAccessibleEventListener>& rxListener) override;
|
|
|
|
virtual void SAL_CALL removeAccessibleEventListener (
|
|
const css::uno::Reference<css::accessibility::XAccessibleEventListener>& 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<css::awt::XWindow2> mxContentWindow;
|
|
css::uno::Reference<css::awt::XWindow2> mxBorderWindow;
|
|
const css::lang::Locale maLocale;
|
|
const sal_Int16 mnRole;
|
|
sal_uInt32 mnStateSet;
|
|
bool mbIsFocused;
|
|
css::uno::Reference<css::accessibility::XAccessible> mxParentAccessible;
|
|
::std::vector<rtl::Reference<AccessibleObject> > maChildren;
|
|
::std::vector<Reference<XAccessibleEventListener> > 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<sal_Int16>& rStateSet) override;
|
|
|
|
virtual css::uno::Sequence<sal_Int16> 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<XInterface>& 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<AccessibleRelation> 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<css::accessibility::XAccessibleRelationSet> 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<css::beans::PropertyValue> SAL_CALL
|
|
getCharacterAttributes (
|
|
::sal_Int32 nIndex,
|
|
const css::uno::Sequence<OUString>& 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<PresenterAccessible::AccessibleObject> Create (
|
|
const css::uno::Reference<css::uno::XComponentContext>& 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<PresenterAccessible::AccessibleObject> pObject (
|
|
new PresenterAccessible::AccessibleObject(
|
|
rLocale, AccessibleRole::PANEL, sName));
|
|
pObject->LateInitialization();
|
|
pObject->UpdateStateSet();
|
|
|
|
return pObject;
|
|
}
|
|
};
|
|
|
|
//===== AccessiblePreview =====================================================
|
|
|
|
class AccessiblePreview
|
|
{
|
|
public:
|
|
static rtl::Reference<PresenterAccessible::AccessibleObject> Create (
|
|
const Reference<css::uno::XComponentContext>& rxContext,
|
|
const lang::Locale& rLocale,
|
|
const Reference<awt::XWindow>& rxContentWindow,
|
|
const Reference<awt::XWindow>& 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<PresenterAccessible::AccessibleObject> 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<PresenterAccessible::AccessibleObject> Create (
|
|
const css::uno::Reference<css::uno::XComponentContext>& rxContext,
|
|
const lang::Locale& rLocale,
|
|
const Reference<awt::XWindow>& rxContentWindow,
|
|
const Reference<awt::XWindow>& rxBorderWindow,
|
|
const std::shared_ptr<PresenterTextView>& rpTextView);
|
|
|
|
void SetTextView (const std::shared_ptr<PresenterTextView>& rpTextView);
|
|
|
|
virtual void SetWindow (
|
|
const css::uno::Reference<css::awt::XWindow>& rxContentWindow,
|
|
const css::uno::Reference<css::awt::XWindow>& rxBorderWindow) override;
|
|
|
|
private:
|
|
std::shared_ptr<PresenterTextView> 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<AccessibleFocusManager> const & Instance();
|
|
|
|
void AddFocusableObject (const ::rtl::Reference<PresenterAccessible::AccessibleObject>& rpObject);
|
|
void RemoveFocusableObject (const ::rtl::Reference<PresenterAccessible::AccessibleObject>& rpObject);
|
|
|
|
void FocusObject (const ::rtl::Reference<PresenterAccessible::AccessibleObject>& rpObject);
|
|
|
|
~AccessibleFocusManager();
|
|
|
|
private:
|
|
static std::shared_ptr<AccessibleFocusManager> mpInstance;
|
|
::std::vector<rtl::Reference<PresenterAccessible::AccessibleObject> > maFocusableObjects;
|
|
bool m_isInDtor = false;
|
|
|
|
AccessibleFocusManager();
|
|
};
|
|
|
|
}
|
|
|
|
//===== PresenterAccessible ===================================================
|
|
|
|
PresenterAccessible::PresenterAccessible (
|
|
const css::uno::Reference<css::uno::XComponentContext>& rxContext,
|
|
const ::rtl::Reference<PresenterController>& rpPresenterController,
|
|
const Reference<drawing::framework::XPane>& 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<PresenterPaneContainer> pContainer (mpPresenterController->GetPaneContainer());
|
|
if ( ! pContainer.is())
|
|
return pPreviewPane;
|
|
|
|
pPreviewPane = pContainer->FindPaneURL(PresenterPaneFactory::msCurrentSlidePreviewPaneURL);
|
|
Reference<drawing::framework::XPane> 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<drawing::framework::XConfigurationController> xConfigurationController(
|
|
mpPresenterController->GetConfigurationController());
|
|
if ( ! xConfigurationController.is())
|
|
return;
|
|
|
|
rtl::Reference<PresenterPaneContainer> 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<drawing::framework::XPane> xPreviewPane;
|
|
if (pPreviewPane)
|
|
xPreviewPane = pPreviewPane->mxPane.get();
|
|
|
|
// Get the notes pane.
|
|
PresenterPaneContainer::SharedPaneDescriptor pNotesPane(
|
|
pPaneContainer->FindPaneURL(PresenterPaneFactory::msNotesPaneURL));
|
|
Reference<drawing::framework::XPane> xNotesPane;
|
|
if (pNotesPane)
|
|
xNotesPane = pNotesPane->mxPane.get();
|
|
|
|
// Get the notes view.
|
|
Reference<drawing::framework::XView> xNotesView;
|
|
if (pNotesPane)
|
|
xNotesView = pNotesPane->mxView;
|
|
rtl::Reference<PresenterNotesView> pNotesView (
|
|
dynamic_cast<PresenterNotesView*>(xNotesView.get()));
|
|
|
|
UpdateAccessibilityHierarchy(
|
|
pPreviewPane ? pPreviewPane->mxContentWindow : Reference<awt::XWindow>(),
|
|
pPreviewPane ? pPreviewPane->mxBorderWindow : Reference<awt::XWindow>(),
|
|
(pPreviewPane&&pPreviewPane->mxPane.is()) ? pPreviewPane->mxPane->GetTitle() : OUString(),
|
|
pNotesPane ? pNotesPane->mxContentWindow : Reference<awt::XWindow>(),
|
|
pNotesPane ? pNotesPane->mxBorderWindow : Reference<awt::XWindow>(),
|
|
pNotesView.is()
|
|
? pNotesView->GetTextView()
|
|
: std::shared_ptr<PresenterTextView>());
|
|
}
|
|
|
|
void PresenterAccessible::UpdateAccessibilityHierarchy (
|
|
const Reference<awt::XWindow>& rxPreviewContentWindow,
|
|
const Reference<awt::XWindow>& rxPreviewBorderWindow,
|
|
const OUString& rsTitle,
|
|
const Reference<awt::XWindow>& rxNotesContentWindow,
|
|
const Reference<awt::XWindow>& rxNotesBorderWindow,
|
|
const std::shared_ptr<PresenterTextView>& 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<PresenterTextView>());
|
|
|
|
if (mxMainWindow.is())
|
|
{
|
|
mxMainWindow->removeFocusListener(this);
|
|
|
|
if (mxMainPane.is())
|
|
mxMainPane->setAccessible(nullptr);
|
|
}
|
|
|
|
mpAccessiblePreview = nullptr;
|
|
mpAccessibleNotes = nullptr;
|
|
mpAccessibleConsole = nullptr;
|
|
}
|
|
|
|
//----- XAccessible -----------------------------------------------------------
|
|
|
|
Reference<XAccessibleContext> SAL_CALL PresenterAccessible::getAccessibleContext()
|
|
{
|
|
if ( ! mpAccessibleConsole.is())
|
|
{
|
|
Reference<XPane> 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<css::uno::Any>& 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<awt::XWindow>& rxContentWindow,
|
|
const Reference<awt::XWindow>& rxBorderWindow)
|
|
{
|
|
Reference<awt::XWindow2> 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<XAccessible>& rxAccessibleParent)
|
|
{
|
|
mxParentAccessible = rxAccessibleParent;
|
|
}
|
|
|
|
void SAL_CALL PresenterAccessible::AccessibleObject::disposing()
|
|
{
|
|
AccessibleFocusManager::Instance()->RemoveFocusableObject(this);
|
|
SetWindow(nullptr, nullptr);
|
|
}
|
|
|
|
//----- XAccessible -------------------------------------------------------
|
|
|
|
Reference<XAccessibleContext> 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<XAccessible> SAL_CALL
|
|
PresenterAccessible::AccessibleObject::getAccessibleChild (sal_Int32 nIndex)
|
|
{
|
|
ThrowIfDisposed();
|
|
|
|
if (nIndex<0 || nIndex>=sal_Int32(maChildren.size()))
|
|
throw lang::IndexOutOfBoundsException("invalid child index", static_cast<uno::XWeak*>(this));
|
|
|
|
return maChildren[nIndex];
|
|
}
|
|
|
|
Reference<XAccessible> SAL_CALL
|
|
PresenterAccessible::AccessibleObject::getAccessibleParent()
|
|
{
|
|
ThrowIfDisposed();
|
|
|
|
return mxParentAccessible;
|
|
}
|
|
|
|
sal_Int32 SAL_CALL
|
|
PresenterAccessible::AccessibleObject::getAccessibleIndexInParent()
|
|
{
|
|
ThrowIfDisposed();
|
|
|
|
const Reference<XAccessible> xThis (this);
|
|
if (mxParentAccessible.is())
|
|
{
|
|
const Reference<XAccessibleContext> xContext (mxParentAccessible->getAccessibleContext());
|
|
for (sal_Int32 nIndex=0,nCount=xContext->getAccessibleChildCount();
|
|
nIndex<nCount;
|
|
++nIndex)
|
|
{
|
|
if (xContext->getAccessibleChild(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<XAccessibleRelationSet> SAL_CALL
|
|
PresenterAccessible::AccessibleObject::getAccessibleRelationSet()
|
|
{
|
|
ThrowIfDisposed();
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
Reference<XAccessibleStateSet> SAL_CALL
|
|
PresenterAccessible::AccessibleObject::getAccessibleStateSet()
|
|
{
|
|
ThrowIfDisposed();
|
|
|
|
return Reference<XAccessibleStateSet>(new AccessibleStateSet(mnStateSet));
|
|
}
|
|
|
|
lang::Locale SAL_CALL
|
|
PresenterAccessible::AccessibleObject::getLocale()
|
|
{
|
|
ThrowIfDisposed();
|
|
|
|
if (mxParentAccessible.is())
|
|
{
|
|
Reference<XAccessibleContext> 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<aBox.X+aBox.Width
|
|
&& rPoint.Y<aBox.Y+aBox.Height;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
Reference<XAccessible> SAL_CALL
|
|
PresenterAccessible::AccessibleObject::getAccessibleAtPoint (const awt::Point&)
|
|
{
|
|
ThrowIfDisposed();
|
|
|
|
return Reference<XAccessible>();
|
|
}
|
|
|
|
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<XAccessibleEventListener>& rxListener)
|
|
{
|
|
if (!rxListener.is())
|
|
return;
|
|
|
|
const osl::MutexGuard aGuard(m_aMutex);
|
|
|
|
if (rBHelper.bDisposed || rBHelper.bInDispose)
|
|
{
|
|
uno::Reference<uno::XInterface> xThis (static_cast<XWeak*>(this), UNO_QUERY);
|
|
rxListener->disposing (lang::EventObject(xThis));
|
|
}
|
|
else
|
|
{
|
|
maListeners.push_back(rxListener);
|
|
}
|
|
}
|
|
|
|
void SAL_CALL PresenterAccessible::AccessibleObject::removeAccessibleEventListener (
|
|
const Reference<XAccessibleEventListener>& 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<AccessibleObject>& rpChild)
|
|
{
|
|
maChildren.push_back(rpChild);
|
|
rpChild->SetAccessibleParent(this);
|
|
FireAccessibleEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN, Any(), Any());
|
|
}
|
|
|
|
void PresenterAccessible::AccessibleObject::RemoveChild (
|
|
const ::rtl::Reference<AccessibleObject>& rpChild)
|
|
{
|
|
rpChild->SetAccessibleParent(Reference<XAccessible>());
|
|
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<XWeak>(this);
|
|
aEventObject.EventId = nEventId;
|
|
aEventObject.NewValue = rNewValue;
|
|
aEventObject.OldValue = rOldValue;
|
|
|
|
::std::vector<Reference<XAccessibleEventListener> > 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<XAccessibleComponent> 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<uno::XInterface>(const_cast<uno::XWeak*>(static_cast<uno::XWeak const *>(this))));
|
|
}
|
|
|
|
//===== AccessibleStateSet ====================================================
|
|
|
|
AccessibleStateSet::AccessibleStateSet (const sal_Int32 nStateSet)
|
|
: AccessibleStateSetInterfaceBase(m_aMutex),
|
|
mnStateSet (nStateSet)
|
|
{
|
|
}
|
|
|
|
sal_uInt32 AccessibleStateSet::GetStateMask (const sal_Int16 nState)
|
|
{
|
|
if (nState<0 || nState>=sal_Int16(sizeof(sal_uInt32)*8))
|
|
{
|
|
throw RuntimeException("AccessibleStateSet::GetStateMask: invalid state");
|
|
}
|
|
|
|
return 1<<nState;
|
|
}
|
|
|
|
//----- XAccessibleStateSet ---------------------------------------------------
|
|
|
|
sal_Bool SAL_CALL AccessibleStateSet::isEmpty()
|
|
{
|
|
return mnStateSet==0;
|
|
}
|
|
|
|
sal_Bool SAL_CALL AccessibleStateSet::contains (sal_Int16 nState)
|
|
{
|
|
return (mnStateSet & GetStateMask(nState)) != 0;
|
|
}
|
|
|
|
sal_Bool SAL_CALL AccessibleStateSet::containsAll (const css::uno::Sequence<sal_Int16>& rStateSet)
|
|
{
|
|
return std::none_of(rStateSet.begin(), rStateSet.end(),
|
|
[this](const sal_Int16 nState) { return (mnStateSet & GetStateMask(nState)) == 0; });
|
|
}
|
|
|
|
css::uno::Sequence<sal_Int16> SAL_CALL AccessibleStateSet::getStates()
|
|
{
|
|
::std::vector<sal_Int16> aStates;
|
|
aStates.reserve(sizeof(mnStateSet)*8);
|
|
for (sal_uInt16 nIndex=0; nIndex<sizeof(mnStateSet)*8; ++nIndex)
|
|
if ((mnStateSet & GetStateMask(nIndex)) != 0)
|
|
aStates.push_back(nIndex);
|
|
return Sequence<sal_Int16>(aStates.data(), aStates.size());
|
|
}
|
|
|
|
//===== AccessibleRelationSet =================================================
|
|
|
|
AccessibleRelationSet::AccessibleRelationSet()
|
|
: AccessibleRelationSetInterfaceBase(m_aMutex)
|
|
{
|
|
}
|
|
|
|
void AccessibleRelationSet::AddRelation (
|
|
const sal_Int16 nRelationType,
|
|
const Reference<XInterface>& 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<XAccessibleRelationSet> SAL_CALL
|
|
PresenterAccessible::AccessibleParagraph::getAccessibleRelationSet()
|
|
{
|
|
ThrowIfDisposed();
|
|
|
|
rtl::Reference<AccessibleRelationSet> pSet (new AccessibleRelationSet);
|
|
|
|
if (mxParentAccessible.is())
|
|
{
|
|
Reference<XAccessibleContext> xParentContext (mxParentAccessible->getAccessibleContext());
|
|
if (xParentContext.is())
|
|
{
|
|
if (mnParagraphIndex>0)
|
|
pSet->AddRelation(
|
|
AccessibleRelationType::CONTENT_FLOWS_FROM,
|
|
xParentContext->getAccessibleChild(mnParagraphIndex-1));
|
|
|
|
if (mnParagraphIndex<xParentContext->getAccessibleChildCount()-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<uno::XWeak*>(this));
|
|
return mpParagraph->GetCharacter(nIndex);
|
|
}
|
|
|
|
Sequence<css::beans::PropertyValue> SAL_CALL
|
|
PresenterAccessible::AccessibleParagraph::getCharacterAttributes (
|
|
::sal_Int32 nIndex,
|
|
const css::uno::Sequence<OUString>& 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<css::beans::PropertyValue>();
|
|
}
|
|
|
|
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<uno::XWeak*>(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<uno::XWeak*>(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<XAccessibleContext> xParentContext =
|
|
mxParentAccessible->getAccessibleContext();
|
|
if (xParentContext.is())
|
|
{
|
|
Reference<XAccessibleComponent> 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<PresenterAccessible::AccessibleObject> AccessibleNotes::Create (
|
|
const css::uno::Reference<css::uno::XComponentContext>& rxContext,
|
|
const lang::Locale& rLocale,
|
|
const Reference<awt::XWindow>& rxContentWindow,
|
|
const Reference<awt::XWindow>& rxBorderWindow,
|
|
const std::shared_ptr<PresenterTextView>& 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<AccessibleNotes> 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<PresenterTextView>& rpTextView)
|
|
{
|
|
::std::vector<rtl::Reference<PresenterAccessible::AccessibleObject> > aChildren;
|
|
|
|
// Release any listeners to the current text view.
|
|
if (mpTextView)
|
|
{
|
|
mpTextView->GetCaret()->SetCaretMotionBroadcaster(
|
|
::std::function<void (sal_Int32,sal_Int32,sal_Int32,sal_Int32)>());
|
|
mpTextView->SetTextChangeBroadcaster(
|
|
::std::function<void ()>());
|
|
}
|
|
|
|
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<nParagraphCount; ++nIndex)
|
|
{
|
|
rtl::Reference<PresenterAccessible::AccessibleParagraph> 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<lang::XComponent> 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<css::awt::XWindow>& rxContentWindow,
|
|
const css::uno::Reference<css::awt::XWindow>& 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> AccessibleFocusManager::mpInstance;
|
|
|
|
std::shared_ptr<AccessibleFocusManager> 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<PresenterAccessible::AccessibleObject>& 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<PresenterAccessible::AccessibleObject>& rpObject)
|
|
{
|
|
::std::vector<rtl::Reference<PresenterAccessible::AccessibleObject> >::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<PresenterAccessible::AccessibleObject>& 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: */
|