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