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/accessiblemenuitemcomponent.hxx> 27 28 29 #include <accessibility/helper/accresmgr.hxx> 30 #include <accessibility/helper/accessiblestrings.hrc> 31 #include <toolkit/awt/vclxwindows.hxx> 32 #include <toolkit/helper/externallock.hxx> 33 #include <toolkit/helper/convert.hxx> 34 35 #include <com/sun/star/accessibility/AccessibleEventId.hpp> 36 #include <com/sun/star/accessibility/AccessibleRole.hpp> 37 #include <com/sun/star/accessibility/AccessibleStateType.hpp> 38 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp> 39 #include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp> 40 41 #include <unotools/accessiblestatesethelper.hxx> 42 #include <unotools/accessiblerelationsethelper.hxx> 43 #include <cppuhelper/typeprovider.hxx> 44 #include <comphelper/sequence.hxx> 45 #include <comphelper/accessibletexthelper.hxx> 46 #include <vcl/svapp.hxx> 47 #include <vcl/window.hxx> 48 #include <vcl/menu.hxx> 49 #include <vcl/unohelp2.hxx> 50 51 52 using namespace ::com::sun::star::accessibility; 53 using namespace ::com::sun::star::uno; 54 using namespace ::com::sun::star::beans; 55 using namespace ::com::sun::star::lang; 56 using namespace ::com::sun::star; 57 using namespace ::comphelper; 58 59 60 // ----------------------------------------------------------------------------- 61 // class OAccessibleMenuItemComponent 62 // ----------------------------------------------------------------------------- 63 64 OAccessibleMenuItemComponent::OAccessibleMenuItemComponent( Menu* pParent, sal_uInt16 nItemPos, Menu* pMenu ) 65 :OAccessibleMenuBaseComponent( pMenu ) 66 ,m_pParent( pParent ) 67 ,m_nItemPos( nItemPos ) 68 { 69 m_sAccessibleName = GetAccessibleName(); 70 m_sItemText = GetItemText(); 71 } 72 73 // ----------------------------------------------------------------------------- 74 75 OAccessibleMenuItemComponent::~OAccessibleMenuItemComponent() 76 { 77 } 78 79 // ----------------------------------------------------------------------------- 80 81 sal_Bool OAccessibleMenuItemComponent::IsEnabled() 82 { 83 OExternalLockGuard aGuard( this ); 84 85 sal_Bool bEnabled = sal_False; 86 if ( m_pParent ) 87 bEnabled = m_pParent->IsItemEnabled( m_pParent->GetItemId( m_nItemPos ) ); 88 89 return bEnabled; 90 } 91 92 // ----------------------------------------------------------------------------- 93 94 sal_Bool OAccessibleMenuItemComponent::IsVisible() 95 { 96 sal_Bool bVisible = sal_False; 97 98 if ( m_pParent ) 99 bVisible = m_pParent->IsItemPosVisible( m_nItemPos ); 100 101 return bVisible; 102 } 103 104 // ----------------------------------------------------------------------------- 105 106 void OAccessibleMenuItemComponent::Select() 107 { 108 // open the parent menu 109 Reference< XAccessible > xParent( getAccessibleParent() ); 110 if ( xParent.is() ) 111 { 112 OAccessibleMenuBaseComponent* pComp = static_cast< OAccessibleMenuBaseComponent* >( xParent.get() ); 113 if ( pComp && pComp->getAccessibleRole() == AccessibleRole::MENU && !pComp->IsPopupMenuOpen() ) 114 pComp->Click(); 115 } 116 117 // highlight the menu item 118 if ( m_pParent ) 119 m_pParent->HighlightItem( m_nItemPos ); 120 } 121 122 // ----------------------------------------------------------------------------- 123 124 void OAccessibleMenuItemComponent::DeSelect() 125 { 126 if ( m_pParent && IsSelected() ) 127 m_pParent->DeHighlight(); 128 } 129 130 // ----------------------------------------------------------------------------- 131 132 void OAccessibleMenuItemComponent::Click() 133 { 134 // open the parent menu 135 Reference< XAccessible > xParent( getAccessibleParent() ); 136 if ( xParent.is() ) 137 { 138 OAccessibleMenuBaseComponent* pComp = static_cast< OAccessibleMenuBaseComponent* >( xParent.get() ); 139 if ( pComp && pComp->getAccessibleRole() == AccessibleRole::MENU && !pComp->IsPopupMenuOpen() ) 140 pComp->Click(); 141 } 142 143 // click the menu item 144 if ( m_pParent ) 145 { 146 Window* pWindow = m_pParent->GetWindow(); 147 if ( pWindow ) 148 { 149 // #102438# Menu items are not selectable 150 // Popup menus are executed asynchronously, triggered by a timer. 151 // As Menu::SelectItem only works, if the corresponding menu window is 152 // already created, we have to set the menu delay to 0, so 153 // that the popup menus are executed synchronously. 154 AllSettings aSettings = pWindow->GetSettings(); 155 MouseSettings aMouseSettings = aSettings.GetMouseSettings(); 156 sal_uLong nDelay = aMouseSettings.GetMenuDelay(); 157 aMouseSettings.SetMenuDelay( 0 ); 158 aSettings.SetMouseSettings( aMouseSettings ); 159 pWindow->SetSettings( aSettings ); 160 161 m_pParent->SelectItem( m_pParent->GetItemId( m_nItemPos ) ); 162 163 // meanwhile the window pointer may be invalid 164 pWindow = m_pParent->GetWindow(); 165 if ( pWindow ) 166 { 167 // set the menu delay back to the old value 168 aSettings = pWindow->GetSettings(); 169 aMouseSettings = aSettings.GetMouseSettings(); 170 aMouseSettings.SetMenuDelay( nDelay ); 171 aSettings.SetMouseSettings( aMouseSettings ); 172 pWindow->SetSettings( aSettings ); 173 } 174 } 175 } 176 } 177 178 // ----------------------------------------------------------------------------- 179 180 void OAccessibleMenuItemComponent::SetItemPos( sal_uInt16 nItemPos ) 181 { 182 m_nItemPos = nItemPos; 183 } 184 185 // ----------------------------------------------------------------------------- 186 187 void OAccessibleMenuItemComponent::SetAccessibleName( const ::rtl::OUString& sAccessibleName ) 188 { 189 if ( !m_sAccessibleName.equals( sAccessibleName ) ) 190 { 191 Any aOldValue, aNewValue; 192 aOldValue <<= m_sAccessibleName; 193 aNewValue <<= sAccessibleName; 194 m_sAccessibleName = sAccessibleName; 195 NotifyAccessibleEvent( AccessibleEventId::NAME_CHANGED, aOldValue, aNewValue ); 196 } 197 } 198 199 // ----------------------------------------------------------------------------- 200 201 ::rtl::OUString OAccessibleMenuItemComponent::GetAccessibleName() 202 { 203 ::rtl::OUString sName; 204 if ( m_pParent ) 205 { 206 sal_uInt16 nItemId = m_pParent->GetItemId( m_nItemPos ); 207 sName = m_pParent->GetAccessibleName( nItemId ); 208 if ( sName.getLength() == 0 ) 209 sName = m_pParent->GetItemText( nItemId ); 210 sName = OutputDevice::GetNonMnemonicString( sName ); 211 212 // IA2 CWS, MT: Is adding 5 blanks really before the accelname reasonable? And which Platform / Accessibility API does need it this way? ATK has API for this... 213 // Also, IAccessible2 has IAccessibleAction::keyBinding, so I doubt that this is needed. 214 // But if so, it needs to move to the IA2 bridge. 215 /* 216 ::rtl::OUString sAccName = m_pParent->GetAccelKey( nItemId ).GetName(); 217 if ( sAccName.getLength() ) 218 { 219 sName += ::rtl::OUString::createFromAscii(" "); 220 sName += aAccelName; 221 } 222 */ 223 } 224 225 return sName; 226 } 227 228 // ----------------------------------------------------------------------------- 229 230 void OAccessibleMenuItemComponent::SetItemText( const ::rtl::OUString& sItemText ) 231 { 232 Any aOldValue, aNewValue; 233 if ( OCommonAccessibleText::implInitTextChangedEvent( m_sItemText, sItemText, aOldValue, aNewValue ) ) 234 { 235 m_sItemText = sItemText; 236 NotifyAccessibleEvent( AccessibleEventId::TEXT_CHANGED, aOldValue, aNewValue ); 237 } 238 } 239 240 // ----------------------------------------------------------------------------- 241 242 ::rtl::OUString OAccessibleMenuItemComponent::GetItemText() 243 { 244 ::rtl::OUString sText; 245 if ( m_pParent ) 246 sText = OutputDevice::GetNonMnemonicString( m_pParent->GetItemText( m_pParent->GetItemId( m_nItemPos ) ) ); 247 248 return sText; 249 } 250 251 // ----------------------------------------------------------------------------- 252 253 void OAccessibleMenuItemComponent::FillAccessibleStateSet( utl::AccessibleStateSetHelper& rStateSet ) 254 { 255 sal_Bool bEnabled = IsEnabled(); 256 if ( bEnabled ) 257 { 258 rStateSet.AddState( AccessibleStateType::ENABLED ); 259 rStateSet.AddState( AccessibleStateType::SENSITIVE ); 260 } 261 262 if ( IsVisible() ) 263 { 264 rStateSet.AddState( AccessibleStateType::SHOWING ); 265 if( !IsMenuHideDisabledEntries() || bEnabled ) 266 rStateSet.AddState( AccessibleStateType::VISIBLE ); 267 } 268 rStateSet.AddState( AccessibleStateType::OPAQUE ); 269 } 270 271 // ----------------------------------------------------------------------------- 272 // OCommonAccessibleComponent 273 // ----------------------------------------------------------------------------- 274 275 awt::Rectangle OAccessibleMenuItemComponent::implGetBounds() throw (RuntimeException) 276 { 277 awt::Rectangle aBounds( 0, 0, 0, 0 ); 278 279 if ( m_pParent ) 280 { 281 // get bounding rectangle of the item relative to the containing window 282 aBounds = AWTRectangle( m_pParent->GetBoundingRectangle( m_nItemPos ) ); 283 284 // get position of containing window in screen coordinates 285 Window* pWindow = m_pParent->GetWindow(); 286 if ( pWindow ) 287 { 288 Rectangle aRect = pWindow->GetWindowExtentsRelative( NULL ); 289 awt::Point aWindowScreenLoc = AWTPoint( aRect.TopLeft() ); 290 291 // get position of accessible parent in screen coordinates 292 Reference< XAccessible > xParent = getAccessibleParent(); 293 if ( xParent.is() ) 294 { 295 Reference< XAccessibleComponent > xParentComponent( xParent->getAccessibleContext(), UNO_QUERY ); 296 if ( xParentComponent.is() ) 297 { 298 awt::Point aParentScreenLoc = xParentComponent->getLocationOnScreen(); 299 300 // calculate bounding rectangle of the item relative to the accessible parent 301 aBounds.X += aWindowScreenLoc.X - aParentScreenLoc.X; 302 aBounds.Y += aWindowScreenLoc.Y - aParentScreenLoc.Y; 303 } 304 } 305 } 306 } 307 308 return aBounds; 309 } 310 311 // ----------------------------------------------------------------------------- 312 // XComponent 313 // ----------------------------------------------------------------------------- 314 315 void SAL_CALL OAccessibleMenuItemComponent::disposing() 316 { 317 OAccessibleMenuBaseComponent::disposing(); 318 319 m_pParent = NULL; 320 m_sAccessibleName = ::rtl::OUString(); 321 m_sItemText = ::rtl::OUString(); 322 } 323 324 // ----------------------------------------------------------------------------- 325 // XAccessibleContext 326 // ----------------------------------------------------------------------------- 327 328 sal_Int32 OAccessibleMenuItemComponent::getAccessibleChildCount() throw (RuntimeException) 329 { 330 OExternalLockGuard aGuard( this ); 331 332 return 0; 333 } 334 335 // ----------------------------------------------------------------------------- 336 337 Reference< XAccessible > OAccessibleMenuItemComponent::getAccessibleChild( sal_Int32 i ) throw (IndexOutOfBoundsException, RuntimeException) 338 { 339 OExternalLockGuard aGuard( this ); 340 341 if ( i < 0 || i >= getAccessibleChildCount() ) 342 throw IndexOutOfBoundsException(); 343 344 return Reference< XAccessible >(); 345 } 346 347 // ----------------------------------------------------------------------------- 348 349 Reference< XAccessible > OAccessibleMenuItemComponent::getAccessibleParent( ) throw (RuntimeException) 350 { 351 OExternalLockGuard aGuard( this ); 352 353 return m_pParent->GetAccessible(); 354 } 355 356 // ----------------------------------------------------------------------------- 357 358 sal_Int32 OAccessibleMenuItemComponent::getAccessibleIndexInParent( ) throw (RuntimeException) 359 { 360 OExternalLockGuard aGuard( this ); 361 362 return m_nItemPos; 363 } 364 365 // ----------------------------------------------------------------------------- 366 367 sal_Int16 OAccessibleMenuItemComponent::getAccessibleRole( ) throw (RuntimeException) 368 { 369 OExternalLockGuard aGuard( this ); 370 371 return AccessibleRole::UNKNOWN; 372 } 373 374 // ----------------------------------------------------------------------------- 375 376 ::rtl::OUString OAccessibleMenuItemComponent::getAccessibleDescription( ) throw (RuntimeException) 377 { 378 OExternalLockGuard aGuard( this ); 379 380 ::rtl::OUString sDescription; 381 if ( m_pParent ) 382 sDescription = m_pParent->GetHelpText( m_pParent->GetItemId( m_nItemPos ) ); 383 384 return sDescription; 385 } 386 387 // ----------------------------------------------------------------------------- 388 389 ::rtl::OUString OAccessibleMenuItemComponent::getAccessibleName( ) throw (RuntimeException) 390 { 391 OExternalLockGuard aGuard( this ); 392 393 return m_sAccessibleName; 394 } 395 396 // ----------------------------------------------------------------------------- 397 398 Reference< XAccessibleRelationSet > OAccessibleMenuItemComponent::getAccessibleRelationSet( ) throw (RuntimeException) 399 { 400 OExternalLockGuard aGuard( this ); 401 402 utl::AccessibleRelationSetHelper* pRelationSetHelper = new utl::AccessibleRelationSetHelper; 403 Reference< XAccessibleRelationSet > xSet = pRelationSetHelper; 404 return xSet; 405 } 406 407 // ----------------------------------------------------------------------------- 408 409 Locale OAccessibleMenuItemComponent::getLocale( ) throw (IllegalAccessibleComponentStateException, RuntimeException) 410 { 411 OExternalLockGuard aGuard( this ); 412 413 return Application::GetSettings().GetLocale(); 414 } 415 416 // ----------------------------------------------------------------------------- 417 // XAccessibleComponent 418 // ----------------------------------------------------------------------------- 419 420 Reference< XAccessible > OAccessibleMenuItemComponent::getAccessibleAtPoint( const awt::Point& ) throw (RuntimeException) 421 { 422 OExternalLockGuard aGuard( this ); 423 424 return Reference< XAccessible >(); 425 } 426 427 // ----------------------------------------------------------------------------- 428 429 void OAccessibleMenuItemComponent::grabFocus( ) throw (RuntimeException) 430 { 431 // no focus for items 432 } 433 434 // ----------------------------------------------------------------------------- 435 436 sal_Int32 OAccessibleMenuItemComponent::getForeground( ) throw (RuntimeException) 437 { 438 OExternalLockGuard aGuard( this ); 439 440 sal_Int32 nColor = 0; 441 Reference< XAccessible > xParent = getAccessibleParent(); 442 if ( xParent.is() ) 443 { 444 Reference< XAccessibleComponent > xParentComp( xParent->getAccessibleContext(), UNO_QUERY ); 445 if ( xParentComp.is() ) 446 nColor = xParentComp->getForeground(); 447 } 448 449 return nColor; 450 } 451 452 // ----------------------------------------------------------------------------- 453 454 sal_Int32 OAccessibleMenuItemComponent::getBackground( ) throw (RuntimeException) 455 { 456 OExternalLockGuard aGuard( this ); 457 458 sal_Int32 nColor = 0; 459 Reference< XAccessible > xParent = getAccessibleParent(); 460 if ( xParent.is() ) 461 { 462 Reference< XAccessibleComponent > xParentComp( xParent->getAccessibleContext(), UNO_QUERY ); 463 if ( xParentComp.is() ) 464 nColor = xParentComp->getBackground(); 465 } 466 467 return nColor; 468 } 469 470 // ----------------------------------------------------------------------------- 471 // XAccessibleExtendedComponent 472 // ----------------------------------------------------------------------------- 473 474 Reference< awt::XFont > OAccessibleMenuItemComponent::getFont( ) throw (RuntimeException) 475 { 476 OExternalLockGuard aGuard( this ); 477 478 Reference< awt::XFont > xFont; 479 Reference< XAccessible > xParent = getAccessibleParent(); 480 if ( xParent.is() ) 481 { 482 Reference< XAccessibleExtendedComponent > xParentComp( xParent->getAccessibleContext(), UNO_QUERY ); 483 if ( xParentComp.is() ) 484 xFont = xParentComp->getFont(); 485 } 486 487 return xFont; 488 } 489 490 // ----------------------------------------------------------------------------- 491 492 ::rtl::OUString OAccessibleMenuItemComponent::getTitledBorderText( ) throw (RuntimeException) 493 { 494 OExternalLockGuard aGuard( this ); 495 496 return ::rtl::OUString(); 497 } 498 499 // ----------------------------------------------------------------------------- 500 501 ::rtl::OUString OAccessibleMenuItemComponent::getToolTipText( ) throw (RuntimeException) 502 { 503 OExternalLockGuard aGuard( this ); 504 505 ::rtl::OUString sRet; 506 if ( m_pParent ) 507 sRet = m_pParent->GetTipHelpText( m_pParent->GetItemId( m_nItemPos ) ); 508 509 return sRet; 510 } 511 512 // ----------------------------------------------------------------------------- 513 514 sal_Bool OAccessibleMenuItemComponent::IsMenuHideDisabledEntries() 515 { 516 if (m_pParent ) 517 { 518 if( m_pParent->GetMenuFlags() & MENU_FLAG_HIDEDISABLEDENTRIES) 519 { 520 return sal_True; 521 } 522 // IA2 CWS, but the menus shouldn't have different flags, and even if so, the GetStartedFromMenu shouldn't matter 523 /* 524 else if (m_pParent->GetStartedFromMenu() && 525 m_pParent->GetStartedFromMenu()->GetMenuFlags() & MENU_FLAG_HIDEDISABLEDENTRIES) 526 { 527 return sal_True; 528 } 529 */ 530 } 531 return sal_False; 532 } 533