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