/**************************************************************
 * 
 * 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 <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/XAccessibleComponent.hpp>
#include <com/sun/star/accessibility/XAccessibleContext.hpp>
#include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
#include <com/sun/star/accessibility/XAccessibleText.hpp>
#include <com/sun/star/drawing/framework/ResourceId.hpp>
#include <com/sun/star/drawing/framework/XPane.hpp>
#include <com/sun/star/drawing/framework/XView.hpp>
#include <cppuhelper/compbase1.hxx>
#include <cppuhelper/compbase5.hxx>
#include <cppuhelper/implbase1.hxx>
#include <boost/bind.hpp>

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<css::awt::XWindow>& rxContentWindow,
        const cssu::Reference<css::awt::XWindow>& rxBorderWindow);
    void SetAccessibleParent (const cssu::Reference<cssa::XAccessible>& rxAccessibleParent);

    virtual void SAL_CALL disposing (void);

    void NotifyCurrentSlideChange (const sal_Int32 nCurrentSlideIndex);

    void AddChild (const ::rtl::Reference<AccessibleObject>& rpChild);
    void RemoveChild (const ::rtl::Reference<AccessibleObject>& 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<cssa::XAccessibleContext> 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<cssa::XAccessibleRelationSet> SAL_CALL
    	getAccessibleRelationSet (void)
        throw (cssu::RuntimeException);

	virtual cssu::Reference<cssa::XAccessibleStateSet> 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<cssa::XAccessible> 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<cssa::XAccessibleEventListener>& rxListener) 
        throw (cssu::RuntimeException);

    virtual void SAL_CALL removeEventListener ( 
            const cssu::Reference<cssa::XAccessibleEventListener>& 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<css::awt::XWindow2> mxContentWindow;
    cssu::Reference<css::awt::XWindow2> mxBorderWindow;
    const css::lang::Locale maLocale;
    const sal_Int16 mnRole;
    sal_uInt32 mnStateSet;
    bool mbIsFocused;
    cssu::Reference<cssa::XAccessible> mxParentAccessible;
    ::std::vector<rtl::Reference<AccessibleObject> > maChildren;
    ::std::vector<Reference<XAccessibleEventListener> > 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<sal_Int16>& rStateSet)
        throw (cssu::RuntimeException);

    virtual cssu::Sequence<sal_Int16> 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<XInterface>& 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<AccessibleRelation> 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<cssa::XAccessibleRelationSet> 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<css::beans::PropertyValue> SAL_CALL
        getCharacterAttributes (
            ::sal_Int32 nIndex,
            const cssu::Sequence<rtl::OUString>& 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<PresenterAccessible::AccessibleObject> Create (
        const css::uno::Reference<css::uno::XComponentContext>& rxContext,
        const lang::Locale aLocale)
    {
        OUString sName (A2S("Presenter Console"));
        PresenterConfigurationAccess aConfiguration (
            rxContext,
            OUString::createFromAscii("/org.openoffice.Office.extension.PresenterScreen/"),
            PresenterConfigurationAccess::READ_ONLY);
        aConfiguration.GetConfigurationNode(A2S("Presenter/Accessibility/Console/String"))
            >>= sName;

        rtl::Reference<PresenterAccessible::AccessibleObject> pObject (
            new PresenterAccessible::AccessibleObject(
                aLocale, 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 aLocale,
        const Reference<awt::XWindow>& rxContentWindow,
        const Reference<awt::XWindow>& rxBorderWindow)
    {
        OUString sName (A2S("Presenter Notes Window"));
        {
            PresenterConfigurationAccess aConfiguration (
                rxContext,
                OUString::createFromAscii("/org.openoffice.Office.extension.PresenterScreen/"),
                PresenterConfigurationAccess::READ_ONLY);
            aConfiguration.GetConfigurationNode(A2S("Presenter/Accessibility/Preview/String"))
                >>= sName;
        }
        
        rtl::Reference<PresenterAccessible::AccessibleObject> 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<PresenterAccessible::AccessibleObject> Create (
        const css::uno::Reference<css::uno::XComponentContext>& rxContext,
        const lang::Locale aLocale,
        const Reference<awt::XWindow>& rxContentWindow,
        const Reference<awt::XWindow>& rxBorderWindow,
        const ::boost::shared_ptr<PresenterTextView>& rpTextView);
    
    void SetTextView (const ::boost::shared_ptr<PresenterTextView>& rpTextView);

    virtual void SetWindow (
        const cssu::Reference<css::awt::XWindow>& rxContentWindow,
        const cssu::Reference<css::awt::XWindow>& rxBorderWindow);

private:
    ::boost::shared_ptr<PresenterTextView> 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<AccessibleFocusManager> Instance (void);

    void AddFocusableObject (const ::rtl::Reference<PresenterAccessible::AccessibleObject>& rpObject);
    void RemoveFocusableObject (const ::rtl::Reference<PresenterAccessible::AccessibleObject>& rpObject);

    void FocusObject (const ::rtl::Reference<PresenterAccessible::AccessibleObject>& rpObject);

private:
    static ::boost::shared_ptr<AccessibleFocusManager> mpInstance;
    ::std::vector<rtl::Reference<PresenterAccessible::AccessibleObject> > maFocusableObjects;

    AccessibleFocusManager (void);
};




//===== 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),
      mxMainPaneId(rxMainPane.is() ? rxMainPane->getResourceId() : Reference<XResourceId>()),
      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<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 (void)
{
    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()
            : ::boost::shared_ptr<PresenterTextView>());
}





void PresenterAccessible::UpdateAccessibilityHierarchy (
    const Reference<awt::XWindow>& rxPreviewContentWindow,
    const Reference<awt::XWindow>& rxPreviewBorderWindow,
    const ::rtl::OUString& rsTitle,
    const Reference<awt::XWindow>& rxNotesContentWindow,
    const Reference<awt::XWindow>& rxNotesBorderWindow,
    const ::boost::shared_ptr<PresenterTextView>& 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<PresenterTextView>());

    if (mxMainWindow.is())
    {
        mxMainWindow->removeFocusListener(this);

        if (mxMainPane.is())
            mxMainPane->setAccessible(NULL);
    }
    
    mpAccessiblePreview = NULL;
    mpAccessibleNotes = NULL;
    mpAccessibleConsole = NULL;
}




//----- XAccessible -----------------------------------------------------------

Reference<XAccessibleContext> SAL_CALL PresenterAccessible::getAccessibleContext (void) 
    throw (cssu::RuntimeException)
{
    if ( ! mpAccessibleConsole.is())
    {
        Reference<XPane> xMainPane (mxMainPane, UNO_QUERY);
        if (xMainPane.is())
        {
            mxMainWindow = Reference<awt::XWindow>(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<cssu::Any>& rArguments)
    throw (cssu::RuntimeException)
{
    if (rArguments.getLength() >= 1)
    {
        mxAccessibleParent = Reference<XAccessible>(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<awt::XWindow>& rxContentWindow,
    const Reference<awt::XWindow>& rxBorderWindow)
{
    Reference<awt::XWindow2> xContentWindow (rxContentWindow, UNO_QUERY);

    if (mxContentWindow.get() != xContentWindow.get())
    {
        if (mxContentWindow.is())
        {
            mxContentWindow->removeWindowListener(this);
        }
        
        mxContentWindow = xContentWindow;
        mxBorderWindow = Reference<awt::XWindow2>(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 (void)
{
    AccessibleFocusManager::Instance()->RemoveFocusableObject(this);
    SetWindow(NULL, NULL);
}




//----- XAccessible -------------------------------------------------------

Reference<XAccessibleContext> 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<XAccessible> 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<XAccessible>(maChildren[nIndex].get());
}




Reference<XAccessible> SAL_CALL
    PresenterAccessible::AccessibleObject::getAccessibleParent (void)
    throw (RuntimeException)
{
    ThrowIfDisposed();

    return mxParentAccessible;
}




sal_Int32 SAL_CALL
    PresenterAccessible::AccessibleObject::getAccessibleIndexInParent (void)
    throw (RuntimeException)
{
    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 (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<XAccessibleRelationSet> SAL_CALL
    PresenterAccessible::AccessibleObject::getAccessibleRelationSet (void)
    throw (RuntimeException)
{
    ThrowIfDisposed();

    return NULL;
}




Reference<XAccessibleStateSet> SAL_CALL
    PresenterAccessible::AccessibleObject::getAccessibleStateSet (void)
    throw (RuntimeException)
{
    ThrowIfDisposed();

    return Reference<XAccessibleStateSet>(new AccessibleStateSet(mnStateSet));
}




lang::Locale SAL_CALL
    PresenterAccessible::AccessibleObject::getLocale (void)
    throw (RuntimeException,
        IllegalAccessibleComponentStateException)
{
    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) 
    throw (RuntimeException)
{
    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& rPoint)
    throw (RuntimeException)
{
    (void)rPoint;
    ThrowIfDisposed();

    return Reference<XAccessible>();
}




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<XAccessibleEventListener>& rxListener) 
    throw (RuntimeException)
{
	if (rxListener.is())
    {
        const osl::MutexGuard aGuard(m_aMutex);

        if (IsDisposed())
        {
            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::removeEventListener ( 
    const Reference<XAccessibleEventListener>& 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<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 ::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<XWeak>(this);
    aEventObject.EventId = nEventId;
    aEventObject.NewValue = rNewValue;
    aEventObject.OldValue = rOldValue;

    ::std::vector<Reference<XAccessibleEventListener> > aListenerCopy(maListeners);
    for (::std::vector<Reference<XAccessibleEventListener> >::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<XAccessibleComponent> xParentComponent;
    if (mxParentAccessible.is())
        xParentComponent = Reference<XAccessibleComponent>(
            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<XInterface> xObject (
        const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(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<<nState;
}




//----- XAccessibleStateSet ---------------------------------------------------

sal_Bool SAL_CALL AccessibleStateSet::isEmpty (void)
    throw (cssu::RuntimeException)
{
    return mnStateSet==0;
}




sal_Bool SAL_CALL AccessibleStateSet::contains (sal_Int16 nState)
    throw (cssu::RuntimeException)
{
    return (mnStateSet & GetStateMask(nState)) != 0;
}




sal_Bool SAL_CALL AccessibleStateSet::containsAll (const cssu::Sequence<sal_Int16>& rStateSet)
    throw (cssu::RuntimeException)
{
    for (sal_Int32 nIndex=0,nCount=rStateSet.getLength(); nIndex<nCount; ++nIndex)
    {
        if ((mnStateSet & GetStateMask(rStateSet[nIndex])) == 0)
            return sal_False;
    }
    return sal_True;
}




cssu::Sequence<sal_Int16> SAL_CALL AccessibleStateSet::getStates (void)
    throw (cssu::RuntimeException)
{
    ::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.front(), aStates.size());
}




//===== AccessibleRelationSet =================================================

AccessibleRelationSet::AccessibleRelationSet (void)
    : AccessibleRelationSetInterfaceBase(m_aMutex),
      maRelations()
{
}




AccessibleRelationSet::~AccessibleRelationSet (void)
{
}




void AccessibleRelationSet::AddRelation (
    const sal_Int16 nRelationType,
    const Reference<XInterface>& 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<AccessibleRelation>::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<AccessibleRelation>::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<XAccessibleRelationSet> SAL_CALL
    PresenterAccessible::AccessibleParagraph::getAccessibleRelationSet (void)
    throw (RuntimeException)
{
    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 Reference<XAccessibleRelationSet>(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<css::beans::PropertyValue> SAL_CALL
    PresenterAccessible::AccessibleParagraph::getCharacterAttributes (
        ::sal_Int32 nIndex,
        const cssu::Sequence<rtl::OUString>& 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<nAttributeCount;
         ++nAttributeIndex)
    {
        OSL_TRACE("    requested attribute %d is %s\r",
            nAttributeIndex,
            OUStringToOString(rRequestedAttributes[nAttributeIndex], RTL_TEXTENCODING_UTF8).getStr());
    }
#endif

    // Character properties are not supported.
    (void)nIndex;
    (void)rRequestedAttributes;
    return Sequence<css::beans::PropertyValue>();
}




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<XAccessibleContext> xParentContext(
            mxParentAccessible->getAccessibleContext(), UNO_QUERY);
        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 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<PresenterAccessible::AccessibleObject> AccessibleNotes::Create (
    const css::uno::Reference<css::uno::XComponentContext>& rxContext,
    const lang::Locale aLocale,
    const Reference<awt::XWindow>& rxContentWindow,
    const Reference<awt::XWindow>& rxBorderWindow,
    const ::boost::shared_ptr<PresenterTextView>& rpTextView)
{
    OUString sName (A2S("Presenter Notes Text"));
    {
        PresenterConfigurationAccess aConfiguration (
            rxContext,
            OUString::createFromAscii("/org.openoffice.Office.extension.PresenterScreen/"),
            PresenterConfigurationAccess::READ_ONLY);
        aConfiguration.GetConfigurationNode(A2S("Presenter/Accessibility/Notes/String"))
            >>= sName;
    }

    rtl::Reference<AccessibleNotes> pObject (
        new AccessibleNotes(
            aLocale,
            AccessibleRole::PANEL,
            sName));
    pObject->LateInitialization();
    pObject->SetTextView(rpTextView);
    pObject->UpdateStateSet();
    pObject->SetWindow(rxContentWindow, rxBorderWindow);

    return rtl::Reference<PresenterAccessible::AccessibleObject>(pObject.get());
}



    
void AccessibleNotes::SetTextView (
    const ::boost::shared_ptr<PresenterTextView>& rpTextView)
{
    ::std::vector<rtl::Reference<PresenterAccessible::AccessibleObject> > aChildren;

    // Release any listeners to the current text view.
    if (mpTextView)
    {
        mpTextView->GetCaret()->SetCaretMotionBroadcaster(
            ::boost::function<void(sal_Int32,sal_Int32,sal_Int32,sal_Int32)>());
        mpTextView->SetTextChangeBroadcaster(
            ::boost::function<void(void)>());
    }
    
    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<nParagraphCount; ++nIndex)
        {
            rtl::Reference<PresenterAccessible::AccessibleParagraph> pParagraph (
                new PresenterAccessible::AccessibleParagraph(
                    css::lang::Locale(),
                    AccessibleRole::PARAGRAPH,
                    A2S("Paragraph")+OUString::valueOf(nIndex),
                    rpTextView->GetParagraph(nIndex),
                    nIndex));
            pParagraph->LateInitialization();
            pParagraph->SetWindow(
                Reference<awt::XWindow>(mxContentWindow, UNO_QUERY),
                Reference<awt::XWindow>(mxBorderWindow, UNO_QUERY));
            pParagraph->SetAccessibleParent(this);
            aChildren.push_back(
                rtl::Reference<PresenterAccessible::AccessibleObject>(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<rtl::Reference<AccessibleObject> >::const_iterator
                 iChild(aChildren.begin()), iEnd(aChildren.end());
             iChild!=iEnd;
             ++iChild)
        {
            Reference<lang::XComponent> xComponent (static_cast<XWeak*>(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<css::awt::XWindow>& rxContentWindow,
    const cssu::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 (::std::vector<rtl::Reference<AccessibleObject> >::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 focuse 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> AccessibleFocusManager::mpInstance;

::boost::shared_ptr<AccessibleFocusManager> AccessibleFocusManager::Instance (void)
{
    if ( ! mpInstance)
    {
        mpInstance.reset(new AccessibleFocusManager());
    }
    return mpInstance;
}




AccessibleFocusManager::AccessibleFocusManager (void)
    : maFocusableObjects()
{
}




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(iObject!=maFocusableObjects.end());
    }
}




void AccessibleFocusManager::FocusObject (
    const ::rtl::Reference<PresenterAccessible::AccessibleObject>& rpObject)
{
    // Remove the focus of any of the other focusable objects.
    for (::std::vector<rtl::Reference<PresenterAccessible::AccessibleObject> >::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
