1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_vcl.hxx" 30 31 #include "vcl/svapp.hxx" 32 #include "vcl/window.hxx" 33 #include "vcl/toolbox.hxx" 34 #include "vcl/menu.hxx" 35 36 #include "aqua/aqua11yfocustracker.hxx" 37 38 #include "documentfocuslistener.hxx" 39 40 #include <com/sun/star/accessibility/XAccessibleContext.hpp> 41 #include <com/sun/star/accessibility/XAccessibleSelection.hpp> 42 #include <com/sun/star/accessibility/XAccessibleStateSet.hpp> 43 #include <com/sun/star/accessibility/AccessibleStateType.hpp> 44 #include <com/sun/star/accessibility/AccessibleRole.hpp> 45 46 using namespace ::com::sun::star::accessibility; 47 using namespace ::com::sun::star::uno; 48 49 //------------------------------------------------------------------------------ 50 51 static inline Window * 52 getWindow(const ::VclSimpleEvent *pEvent) 53 { 54 return static_cast< const ::VclWindowEvent *> (pEvent)->GetWindow(); 55 } 56 57 58 //------------------------------------------------------------------------------ 59 60 // callback function for Application::addEventListener 61 62 long AquaA11yFocusTracker::WindowEventHandler(AquaA11yFocusTracker *pFocusTracker, ::VclSimpleEvent const *pEvent) 63 { 64 switch (pEvent->GetId()) 65 { 66 case VCLEVENT_WINDOW_PAINT: 67 pFocusTracker-> toolbox_open_floater( getWindow(pEvent) ); 68 break; 69 case VCLEVENT_WINDOW_GETFOCUS: 70 pFocusTracker->window_got_focus( getWindow(pEvent) ); 71 break; 72 case VCLEVENT_OBJECT_DYING: 73 pFocusTracker->m_aDocumentWindowList.erase( getWindow(pEvent) ); 74 // intentional pass through .. 75 case VCLEVENT_TOOLBOX_HIGHLIGHTOFF: 76 pFocusTracker->toolbox_highlight_off( getWindow(pEvent) ); 77 break; 78 case VCLEVENT_TOOLBOX_HIGHLIGHT: 79 pFocusTracker->toolbox_highlight_on( getWindow(pEvent) ); 80 break; 81 case VCLEVENT_TABPAGE_ACTIVATE: 82 pFocusTracker->tabpage_activated( getWindow(pEvent) ); 83 break; 84 case VCLEVENT_MENU_HIGHLIGHT: 85 pFocusTracker->menu_highlighted( static_cast < const VclMenuEvent * > (pEvent) ); 86 break; 87 default: 88 break; 89 }; 90 91 return 0; 92 } 93 94 //------------------------------------------------------------------------------ 95 96 AquaA11yFocusTracker::AquaA11yFocusTracker() : 97 m_aWindowEventLink(this, (PSTUB) WindowEventHandler), 98 m_xDocumentFocusListener(new DocumentFocusListener(*this)) 99 { 100 Application::AddEventListener(m_aWindowEventLink); 101 window_got_focus(Application::GetFocusWindow()); 102 } 103 104 //------------------------------------------------------------------------------ 105 106 void AquaA11yFocusTracker::setFocusedObject(const Reference< XAccessible >& xAccessible) 107 { 108 if( xAccessible != m_xFocusedObject ) 109 { 110 m_xFocusedObject = xAccessible; 111 112 if( m_aFocusListener.is() ) 113 m_aFocusListener->focusedObjectChanged(xAccessible); 114 } 115 } 116 117 //------------------------------------------------------------------------------ 118 119 void AquaA11yFocusTracker::notify_toolbox_item_focus(ToolBox *pToolBox) 120 { 121 Reference< XAccessible > xAccessible( pToolBox->GetAccessible() ); 122 123 if( xAccessible.is() ) 124 { 125 Reference< XAccessibleContext > xContext(xAccessible->getAccessibleContext()); 126 127 if( xContext.is() ) 128 { 129 sal_Int32 nPos = pToolBox->GetItemPos( pToolBox->GetHighlightItemId() ); 130 if( nPos != TOOLBOX_ITEM_NOTFOUND ) 131 setFocusedObject( xContext->getAccessibleChild( nPos ) ); 132 } 133 } 134 } 135 136 //------------------------------------------------------------------------------ 137 138 void AquaA11yFocusTracker::toolbox_open_floater(Window *pWindow) 139 { 140 bool bToolboxFound = false; 141 bool bFloatingWindowFound = false; 142 Window * pFloatingWindow = NULL; 143 while ( pWindow != NULL ) { 144 if ( pWindow->GetType() == WINDOW_TOOLBOX ) { 145 bToolboxFound = true; 146 } else if ( pWindow->GetType() == WINDOW_FLOATINGWINDOW ) { 147 bFloatingWindowFound = true; 148 pFloatingWindow = pWindow; 149 } 150 pWindow = pWindow->GetParent(); 151 } 152 if ( bToolboxFound && bFloatingWindowFound ) { 153 Reference < XAccessible > rxAccessible = pFloatingWindow -> GetAccessible(); 154 if ( ! rxAccessible.is() ) { 155 return; 156 } 157 Reference < XAccessibleContext > rxContext = rxAccessible -> getAccessibleContext(); 158 if ( ! rxContext.is() ) { 159 return; 160 } 161 if ( rxContext -> getAccessibleChildCount() > 0 ) { 162 Reference < XAccessible > rxAccessibleChild = rxContext -> getAccessibleChild( 0 ); 163 if ( ! rxAccessibleChild.is() ) { 164 return; 165 } 166 setFocusedObject ( rxAccessibleChild ); 167 } 168 } 169 } 170 171 //------------------------------------------------------------------------------ 172 173 void AquaA11yFocusTracker::toolbox_highlight_on(Window *pWindow) 174 { 175 // Make sure either the toolbox or its parent toolbox has the focus 176 if ( ! pWindow->HasFocus() ) 177 { 178 ToolBox* pToolBoxParent = dynamic_cast< ToolBox * >( pWindow->GetParent() ); 179 if ( ! pToolBoxParent || ! pToolBoxParent->HasFocus() ) 180 return; 181 } 182 183 notify_toolbox_item_focus(static_cast <ToolBox *> (pWindow)); 184 } 185 186 //------------------------------------------------------------------------------ 187 188 void AquaA11yFocusTracker::toolbox_highlight_off(Window *pWindow) 189 { 190 ToolBox* pToolBoxParent = dynamic_cast< ToolBox * >( pWindow->GetParent() ); 191 192 // Notify when leaving sub toolboxes 193 if( pToolBoxParent && pToolBoxParent->HasFocus() ) 194 notify_toolbox_item_focus( pToolBoxParent ); 195 } 196 197 //------------------------------------------------------------------------------ 198 199 void AquaA11yFocusTracker::tabpage_activated(Window *pWindow) 200 { 201 Reference< XAccessible > xAccessible( pWindow->GetAccessible() ); 202 203 if( xAccessible.is() ) 204 { 205 Reference< XAccessibleSelection > xSelection(xAccessible->getAccessibleContext(), UNO_QUERY); 206 207 if( xSelection.is() ) 208 setFocusedObject( xSelection->getSelectedAccessibleChild(0) ); 209 } 210 } 211 212 //------------------------------------------------------------------------------ 213 214 void AquaA11yFocusTracker::menu_highlighted(const VclMenuEvent *pEvent) 215 { 216 Menu * pMenu = pEvent->GetMenu(); 217 218 if( pMenu ) 219 { 220 Reference< XAccessible > xAccessible( pMenu->GetAccessible() ); 221 222 if( xAccessible.is() ) 223 setFocusedObject( xAccessible ); 224 } 225 } 226 227 //------------------------------------------------------------------------------ 228 229 void AquaA11yFocusTracker::window_got_focus(Window *pWindow) 230 { 231 // The menu bar is handled through VCLEVENT_MENU_HIGHLIGHTED 232 if( ! pWindow || !pWindow->IsReallyVisible() || pWindow->GetType() == WINDOW_MENUBARWINDOW ) 233 return; 234 235 // ToolBoxes are handled through VCLEVENT_TOOLBOX_HIGHLIGHT 236 if( pWindow->GetType() == WINDOW_TOOLBOX ) 237 return; 238 239 if( pWindow->GetType() == WINDOW_TABCONTROL ) 240 { 241 tabpage_activated( pWindow ); 242 return; 243 } 244 245 Reference< XAccessible > xAccessible(pWindow->GetAccessible()); 246 247 if( ! xAccessible.is() ) 248 return; 249 250 Reference< XAccessibleContext > xContext = xAccessible->getAccessibleContext(); 251 252 if( ! xContext.is() ) 253 return; 254 255 Reference< XAccessibleStateSet > xStateSet = xContext->getAccessibleStateSet(); 256 257 if( ! xStateSet.is() ) 258 return; 259 260 /* the UNO ToolBox wrapper does not (yet?) support XAccessibleSelection, so we 261 * need to add listeners to the children instead of re-using the tabpage stuff 262 */ 263 if( xStateSet->contains(AccessibleStateType::FOCUSED) && (pWindow->GetType() != WINDOW_TREELISTBOX) ) 264 { 265 setFocusedObject( xAccessible ); 266 } 267 else 268 { 269 if( m_aDocumentWindowList.find(pWindow) == m_aDocumentWindowList.end() ) 270 { 271 m_aDocumentWindowList.insert(pWindow); 272 m_xDocumentFocusListener->attachRecursive(xAccessible, xContext, xStateSet); 273 } 274 #ifdef ENABLE_TRACING 275 else 276 fprintf(stderr, "Window %p already in the list\n", pWindow ); 277 #endif 278 } 279 } 280