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_accessibility.hxx" 30 #include <accessibility/standard/vclxaccessiblebox.hxx> 31 #include <accessibility/standard/vclxaccessibletextfield.hxx> 32 #include <accessibility/standard/vclxaccessibleedit.hxx> 33 #include <accessibility/standard/vclxaccessiblelist.hxx> 34 #include <accessibility/helper/listboxhelper.hxx> 35 36 #include <unotools/accessiblestatesethelper.hxx> 37 #include <com/sun/star/accessibility/AccessibleStateType.hpp> 38 #include <com/sun/star/accessibility/AccessibleEventId.hpp> 39 #include <com/sun/star/accessibility/AccessibleRole.hpp> 40 #include <vcl/svapp.hxx> 41 #include <vcl/combobox.hxx> 42 #include <vcl/lstbox.hxx> 43 #include <accessibility/helper/accresmgr.hxx> 44 #include <accessibility/helper/accessiblestrings.hrc> 45 46 using namespace ::com::sun::star; 47 using namespace ::com::sun::star::uno; 48 using namespace ::com::sun::star::lang; 49 using namespace ::com::sun::star::beans; 50 using namespace ::com::sun::star::accessibility; 51 52 VCLXAccessibleBox::VCLXAccessibleBox (VCLXWindow* pVCLWindow, BoxType aType, bool bIsDropDownBox) 53 : VCLXAccessibleComponent (pVCLWindow), 54 m_aBoxType (aType), 55 m_bIsDropDownBox (bIsDropDownBox), 56 m_nIndexInParent (DEFAULT_INDEX_IN_PARENT) 57 { 58 // Set up the flags that indicate which children this object has. 59 m_bHasListChild = true; 60 61 // A text field is not present for non drop down list boxes. 62 if ((m_aBoxType==LISTBOX) && ! m_bIsDropDownBox) 63 m_bHasTextChild = false; 64 else 65 m_bHasTextChild = true; 66 } 67 68 VCLXAccessibleBox::~VCLXAccessibleBox (void) 69 { 70 } 71 72 void VCLXAccessibleBox::ProcessWindowChildEvent( const VclWindowEvent& rVclWindowEvent ) 73 { 74 uno::Any aOldValue, aNewValue; 75 uno::Reference<XAccessible> xAcc; 76 77 switch ( rVclWindowEvent.GetId() ) 78 { 79 case VCLEVENT_WINDOW_SHOW: 80 case VCLEVENT_WINDOW_HIDE: 81 { 82 Window* pChildWindow = (Window *) rVclWindowEvent.GetData(); 83 // Just compare to the combo box text field. All other children 84 // are identical to this object in which case this object will 85 // be removed in a short time. 86 if (m_aBoxType==COMBOBOX) 87 { 88 ComboBox* pComboBox = static_cast<ComboBox*>(GetWindow()); 89 if ( ( pComboBox != NULL ) && ( pChildWindow != NULL ) ) 90 if (pChildWindow == pComboBox->GetSubEdit()) 91 { 92 if (rVclWindowEvent.GetId() == VCLEVENT_WINDOW_SHOW) 93 { 94 // Instantiate text field. 95 getAccessibleChild (0); 96 aNewValue <<= m_xText; 97 } 98 else 99 { 100 // Release text field. 101 aOldValue <<= m_xText; 102 m_xText = NULL; 103 } 104 // Tell the listeners about the new/removed child. 105 NotifyAccessibleEvent ( 106 AccessibleEventId::CHILD, 107 aOldValue, aNewValue); 108 } 109 110 } 111 } 112 break; 113 114 default: 115 VCLXAccessibleComponent::ProcessWindowChildEvent (rVclWindowEvent); 116 } 117 } 118 119 void VCLXAccessibleBox::ProcessWindowEvent (const VclWindowEvent& rVclWindowEvent) 120 { 121 switch ( rVclWindowEvent.GetId() ) 122 { 123 case VCLEVENT_DROPDOWN_OPEN: 124 case VCLEVENT_DROPDOWN_CLOSE: 125 case VCLEVENT_LISTBOX_DOUBLECLICK: 126 case VCLEVENT_LISTBOX_SCROLLED: 127 case VCLEVENT_LISTBOX_SELECT: 128 case VCLEVENT_LISTBOX_ITEMADDED: 129 case VCLEVENT_LISTBOX_ITEMREMOVED: 130 case VCLEVENT_COMBOBOX_ITEMADDED: 131 case VCLEVENT_COMBOBOX_ITEMREMOVED: 132 case VCLEVENT_COMBOBOX_SCROLLED: 133 { 134 // Forward the call to the list child. 135 VCLXAccessibleList* pList = static_cast<VCLXAccessibleList*>(m_xList.get()); 136 if ( pList == NULL ) 137 { 138 getAccessibleChild ( m_bHasTextChild ? 1 : 0 ); 139 pList = static_cast<VCLXAccessibleList*>(m_xList.get()); 140 } 141 if ( pList != NULL ) 142 pList->ProcessWindowEvent (rVclWindowEvent); 143 break; 144 } 145 146 case VCLEVENT_COMBOBOX_SELECT: 147 case VCLEVENT_COMBOBOX_DESELECT: 148 { 149 // Selection is handled by VCLXAccessibleList which operates on 150 // the same VCL object as this box does. In case of the 151 // combobox, however, we have to help the list with providing 152 // the text of the currently selected item. 153 VCLXAccessibleList* pList = static_cast<VCLXAccessibleList*>(m_xList.get()); 154 if (pList != NULL && m_xText.is()) 155 { 156 Reference<XAccessibleText> xText (m_xText->getAccessibleContext(), UNO_QUERY); 157 if ( xText.is() ) 158 { 159 ::rtl::OUString sText = xText->getSelectedText(); 160 if ( !sText.getLength() ) 161 sText = xText->getText(); 162 pList->UpdateSelection (sText); 163 } 164 } 165 break; 166 } 167 168 case VCLEVENT_EDIT_MODIFY: 169 case VCLEVENT_EDIT_SELECTIONCHANGED: 170 // Modify/Selection events are handled by the combo box instead of 171 // directly by the edit field (Why?). Therefore, delegate this 172 // call to the edit field. 173 if (m_aBoxType==COMBOBOX) 174 { 175 if (m_xText.is()) 176 { 177 Reference<XAccessibleContext> xContext = m_xText->getAccessibleContext(); 178 VCLXAccessibleEdit* pEdit = static_cast<VCLXAccessibleEdit*>(xContext.get()); 179 if (pEdit != NULL) 180 pEdit->ProcessWindowEvent (rVclWindowEvent); 181 } 182 } 183 break; 184 185 default: 186 VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent ); 187 } 188 } 189 190 IMPLEMENT_FORWARD_XINTERFACE2(VCLXAccessibleBox, VCLXAccessibleComponent, VCLXAccessibleBox_BASE) 191 IMPLEMENT_FORWARD_XTYPEPROVIDER2(VCLXAccessibleBox, VCLXAccessibleComponent, VCLXAccessibleBox_BASE) 192 193 //===== XAccessible ========================================================= 194 195 Reference< XAccessibleContext > SAL_CALL VCLXAccessibleBox::getAccessibleContext( ) 196 throw (RuntimeException) 197 { 198 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); 199 200 return this; 201 } 202 203 //===== XAccessibleContext ================================================== 204 205 sal_Int32 SAL_CALL VCLXAccessibleBox::getAccessibleChildCount (void) 206 throw (RuntimeException) 207 { 208 vos::OGuard aSolarGuard( Application::GetSolarMutex() ); 209 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); 210 211 // Usually a box has a text field and a list of items as its children. 212 // Non drop down list boxes have no text field. Additionally check 213 // whether the object is valid. 214 sal_Int32 nCount = 0; 215 if (IsValid()) 216 nCount += (m_bHasTextChild?1:0) + (m_bHasListChild?1:0); 217 else 218 { 219 // Object not valid anymore. Release references to children. 220 m_bHasTextChild = false; 221 m_xText = NULL; 222 m_bHasListChild = false; 223 m_xList = NULL; 224 } 225 226 return nCount; 227 } 228 229 Reference<XAccessible> SAL_CALL VCLXAccessibleBox::getAccessibleChild (sal_Int32 i) 230 throw (IndexOutOfBoundsException, RuntimeException) 231 { 232 vos::OGuard aSolarGuard( Application::GetSolarMutex() ); 233 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); 234 235 if (i<0 || i>=getAccessibleChildCount()) 236 throw IndexOutOfBoundsException(); 237 238 Reference< XAccessible > xChild; 239 if (IsValid()) 240 { 241 if (i==1 || ! m_bHasTextChild) 242 { 243 // List. 244 if ( ! m_xList.is()) 245 { 246 VCLXAccessibleList* pList = new VCLXAccessibleList ( GetVCLXWindow(), 247 (m_aBoxType == LISTBOX ? VCLXAccessibleList::LISTBOX : VCLXAccessibleList::COMBOBOX), 248 this); 249 pList->SetIndexInParent (i); 250 m_xList = pList; 251 } 252 xChild = m_xList; 253 } 254 else 255 { 256 // Text Field. 257 if ( ! m_xText.is()) 258 { 259 if (m_aBoxType==COMBOBOX) 260 { 261 ComboBox* pComboBox = static_cast<ComboBox*>(GetWindow()); 262 if (pComboBox!=NULL && pComboBox->GetSubEdit()!=NULL) 263 m_xText = pComboBox->GetSubEdit()->GetAccessible(); 264 } 265 else if (m_bIsDropDownBox) 266 m_xText = new VCLXAccessibleTextField (GetVCLXWindow(),this); 267 } 268 xChild = m_xText; 269 } 270 } 271 272 return xChild; 273 } 274 275 sal_Int16 SAL_CALL VCLXAccessibleBox::getAccessibleRole (void) throw (RuntimeException) 276 { 277 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); 278 279 // Return the role <const>COMBO_BOX</const> for both VCL combo boxes and 280 // VCL list boxes in DropDown-Mode else <const>PANEL</const>. 281 // This way the Java bridge has not to handle both independently. 282 return m_bIsDropDownBox ? AccessibleRole::COMBO_BOX : AccessibleRole::PANEL; 283 } 284 285 sal_Int32 SAL_CALL VCLXAccessibleBox::getAccessibleIndexInParent (void) 286 throw (::com::sun::star::uno::RuntimeException) 287 { 288 if (m_nIndexInParent != DEFAULT_INDEX_IN_PARENT) 289 return m_nIndexInParent; 290 else 291 return VCLXAccessibleComponent::getAccessibleIndexInParent(); 292 } 293 294 //===== XAccessibleAction =================================================== 295 296 sal_Int32 SAL_CALL VCLXAccessibleBox::getAccessibleActionCount (void) 297 throw (RuntimeException) 298 { 299 ::osl::Guard< ::osl::Mutex> aGuard (GetMutex()); 300 301 // There is one action for drop down boxes (toggle popup) and none for 302 // the other boxes. 303 return m_bIsDropDownBox ? 1 : 0; 304 } 305 306 sal_Bool SAL_CALL VCLXAccessibleBox::doAccessibleAction (sal_Int32 nIndex) 307 throw (IndexOutOfBoundsException, RuntimeException) 308 { 309 sal_Bool bNotify = sal_False; 310 311 { 312 vos::OGuard aSolarGuard( Application::GetSolarMutex() ); 313 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); 314 315 if (nIndex<0 || nIndex>=getAccessibleActionCount()) 316 throw ::com::sun::star::lang::IndexOutOfBoundsException(); 317 318 if (m_aBoxType == COMBOBOX) 319 { 320 ComboBox* pComboBox = static_cast< ComboBox* >( GetWindow() ); 321 if (pComboBox != NULL) 322 { 323 pComboBox->ToggleDropDown(); 324 bNotify = sal_True; 325 } 326 } 327 else if (m_aBoxType == LISTBOX) 328 { 329 ListBox* pListBox = static_cast< ListBox* >( GetWindow() ); 330 if (pListBox != NULL) 331 { 332 pListBox->ToggleDropDown(); 333 bNotify = sal_True; 334 } 335 } 336 } 337 338 if (bNotify) 339 NotifyAccessibleEvent (AccessibleEventId::ACTION_CHANGED, Any(), Any()); 340 341 return bNotify; 342 } 343 344 ::rtl::OUString SAL_CALL VCLXAccessibleBox::getAccessibleActionDescription (sal_Int32 nIndex) 345 throw (IndexOutOfBoundsException, RuntimeException) 346 { 347 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); 348 if (nIndex<0 || nIndex>=getAccessibleActionCount()) 349 throw ::com::sun::star::lang::IndexOutOfBoundsException(); 350 return TK_RES_STRING( RID_STR_ACC_ACTION_TOGGLEPOPUP); 351 } 352 353 Reference< XAccessibleKeyBinding > VCLXAccessibleBox::getAccessibleActionKeyBinding( sal_Int32 nIndex ) 354 throw (IndexOutOfBoundsException, RuntimeException) 355 { 356 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); 357 358 Reference< XAccessibleKeyBinding > xRet; 359 360 if (nIndex<0 || nIndex>=getAccessibleActionCount()) 361 throw ::com::sun::star::lang::IndexOutOfBoundsException(); 362 363 // ... which key? 364 return xRet; 365 } 366 367 //===== XComponent ========================================================== 368 369 void SAL_CALL VCLXAccessibleBox::disposing (void) 370 { 371 VCLXAccessibleComponent::disposing(); 372 } 373 374