blob: 98458a1b44c051261727d9e1970dd4d6b1f542c7 [file] [log] [blame]
/**************************************************************
*
* 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.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"
#include "vcl/svapp.hxx"
#include "vcl/window.hxx"
#include "vcl/toolbox.hxx"
#include "vcl/menu.hxx"
#include "aqua/aqua11yfocustracker.hxx"
#include "documentfocuslistener.hxx"
#include <com/sun/star/accessibility/XAccessibleContext.hpp>
#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
#include <com/sun/star/accessibility/XAccessibleStateSet.hpp>
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
#include <com/sun/star/accessibility/AccessibleRole.hpp>
using namespace ::com::sun::star::accessibility;
using namespace ::com::sun::star::uno;
//------------------------------------------------------------------------------
static inline Window *
getWindow(const ::VclSimpleEvent *pEvent)
{
return static_cast< const ::VclWindowEvent *> (pEvent)->GetWindow();
}
//------------------------------------------------------------------------------
// callback function for Application::addEventListener
long AquaA11yFocusTracker::WindowEventHandler(AquaA11yFocusTracker *pFocusTracker, ::VclSimpleEvent const *pEvent)
{
switch (pEvent->GetId())
{
case VCLEVENT_WINDOW_PAINT:
pFocusTracker-> toolbox_open_floater( getWindow(pEvent) );
break;
case VCLEVENT_WINDOW_GETFOCUS:
pFocusTracker->window_got_focus( getWindow(pEvent) );
break;
case VCLEVENT_OBJECT_DYING:
pFocusTracker->m_aDocumentWindowList.erase( getWindow(pEvent) );
// intentional pass through ..
case VCLEVENT_TOOLBOX_HIGHLIGHTOFF:
pFocusTracker->toolbox_highlight_off( getWindow(pEvent) );
break;
case VCLEVENT_TOOLBOX_HIGHLIGHT:
pFocusTracker->toolbox_highlight_on( getWindow(pEvent) );
break;
case VCLEVENT_TABPAGE_ACTIVATE:
pFocusTracker->tabpage_activated( getWindow(pEvent) );
break;
case VCLEVENT_MENU_HIGHLIGHT:
pFocusTracker->menu_highlighted( static_cast < const VclMenuEvent * > (pEvent) );
break;
default:
break;
};
return 0;
}
//------------------------------------------------------------------------------
AquaA11yFocusTracker::AquaA11yFocusTracker() :
m_aWindowEventLink(this, (PSTUB) WindowEventHandler),
m_xDocumentFocusListener(new DocumentFocusListener(*this))
{
Application::AddEventListener(m_aWindowEventLink);
window_got_focus(Application::GetFocusWindow());
}
//------------------------------------------------------------------------------
void AquaA11yFocusTracker::setFocusedObject(const Reference< XAccessible >& xAccessible)
{
if( xAccessible != m_xFocusedObject )
{
m_xFocusedObject = xAccessible;
if( m_aFocusListener.is() )
m_aFocusListener->focusedObjectChanged(xAccessible);
}
}
//------------------------------------------------------------------------------
void AquaA11yFocusTracker::notify_toolbox_item_focus(ToolBox *pToolBox)
{
Reference< XAccessible > xAccessible( pToolBox->GetAccessible() );
if( xAccessible.is() )
{
Reference< XAccessibleContext > xContext(xAccessible->getAccessibleContext());
if( xContext.is() )
{
sal_Int32 nPos = pToolBox->GetItemPos( pToolBox->GetHighlightItemId() );
if( nPos != TOOLBOX_ITEM_NOTFOUND )
setFocusedObject( xContext->getAccessibleChild( nPos ) );
}
}
}
//------------------------------------------------------------------------------
void AquaA11yFocusTracker::toolbox_open_floater(Window *pWindow)
{
bool bToolboxFound = false;
bool bFloatingWindowFound = false;
Window * pFloatingWindow = NULL;
while ( pWindow != NULL ) {
if ( pWindow->GetType() == WINDOW_TOOLBOX ) {
bToolboxFound = true;
} else if ( pWindow->GetType() == WINDOW_FLOATINGWINDOW ) {
bFloatingWindowFound = true;
pFloatingWindow = pWindow;
}
pWindow = pWindow->GetParent();
}
if ( bToolboxFound && bFloatingWindowFound ) {
Reference < XAccessible > rxAccessible = pFloatingWindow -> GetAccessible();
if ( ! rxAccessible.is() ) {
return;
}
Reference < XAccessibleContext > rxContext = rxAccessible -> getAccessibleContext();
if ( ! rxContext.is() ) {
return;
}
if ( rxContext -> getAccessibleChildCount() > 0 ) {
Reference < XAccessible > rxAccessibleChild = rxContext -> getAccessibleChild( 0 );
if ( ! rxAccessibleChild.is() ) {
return;
}
setFocusedObject ( rxAccessibleChild );
}
}
}
//------------------------------------------------------------------------------
void AquaA11yFocusTracker::toolbox_highlight_on(Window *pWindow)
{
// Make sure either the toolbox or its parent toolbox has the focus
if ( ! pWindow->HasFocus() )
{
ToolBox* pToolBoxParent = dynamic_cast< ToolBox * >( pWindow->GetParent() );
if ( ! pToolBoxParent || ! pToolBoxParent->HasFocus() )
return;
}
notify_toolbox_item_focus(static_cast <ToolBox *> (pWindow));
}
//------------------------------------------------------------------------------
void AquaA11yFocusTracker::toolbox_highlight_off(Window *pWindow)
{
ToolBox* pToolBoxParent = dynamic_cast< ToolBox * >( pWindow->GetParent() );
// Notify when leaving sub toolboxes
if( pToolBoxParent && pToolBoxParent->HasFocus() )
notify_toolbox_item_focus( pToolBoxParent );
}
//------------------------------------------------------------------------------
void AquaA11yFocusTracker::tabpage_activated(Window *pWindow)
{
Reference< XAccessible > xAccessible( pWindow->GetAccessible() );
if( xAccessible.is() )
{
Reference< XAccessibleSelection > xSelection(xAccessible->getAccessibleContext(), UNO_QUERY);
if( xSelection.is() )
setFocusedObject( xSelection->getSelectedAccessibleChild(0) );
}
}
//------------------------------------------------------------------------------
void AquaA11yFocusTracker::menu_highlighted(const VclMenuEvent *pEvent)
{
Menu * pMenu = pEvent->GetMenu();
if( pMenu )
{
Reference< XAccessible > xAccessible( pMenu->GetAccessible() );
if( xAccessible.is() )
setFocusedObject( xAccessible );
}
}
//------------------------------------------------------------------------------
void AquaA11yFocusTracker::window_got_focus(Window *pWindow)
{
// The menu bar is handled through VCLEVENT_MENU_HIGHLIGHTED
if( ! pWindow || !pWindow->IsReallyVisible() || pWindow->GetType() == WINDOW_MENUBARWINDOW )
return;
// ToolBoxes are handled through VCLEVENT_TOOLBOX_HIGHLIGHT
if( pWindow->GetType() == WINDOW_TOOLBOX )
return;
if( pWindow->GetType() == WINDOW_TABCONTROL )
{
tabpage_activated( pWindow );
return;
}
Reference< XAccessible > xAccessible(pWindow->GetAccessible());
if( ! xAccessible.is() )
return;
Reference< XAccessibleContext > xContext = xAccessible->getAccessibleContext();
if( ! xContext.is() )
return;
Reference< XAccessibleStateSet > xStateSet = xContext->getAccessibleStateSet();
if( ! xStateSet.is() )
return;
/* the UNO ToolBox wrapper does not (yet?) support XAccessibleSelection, so we
* need to add listeners to the children instead of re-using the tabpage stuff
*/
if( xStateSet->contains(AccessibleStateType::FOCUSED) && (pWindow->GetType() != WINDOW_TREELISTBOX) )
{
setFocusedObject( xAccessible );
}
else
{
if( m_aDocumentWindowList.find(pWindow) == m_aDocumentWindowList.end() )
{
m_aDocumentWindowList.insert(pWindow);
m_xDocumentFocusListener->attachRecursive(xAccessible, xContext, xStateSet);
}
#ifdef ENABLE_TRACING
else
fprintf(stderr, "Window %p already in the list\n", pWindow );
#endif
}
}