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
OAccessibleMenuItemComponent(Menu * pParent,sal_uInt16 nItemPos,Menu * pMenu)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
~OAccessibleMenuItemComponent()75 OAccessibleMenuItemComponent::~OAccessibleMenuItemComponent()
76 {
77 }
78
79 // -----------------------------------------------------------------------------
80
IsEnabled()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
IsVisible()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
Select()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
DeSelect()124 void OAccessibleMenuItemComponent::DeSelect()
125 {
126 if ( m_pParent && IsSelected() )
127 m_pParent->DeHighlight();
128 }
129
130 // -----------------------------------------------------------------------------
131
Click()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
SetItemPos(sal_uInt16 nItemPos)180 void OAccessibleMenuItemComponent::SetItemPos( sal_uInt16 nItemPos )
181 {
182 m_nItemPos = nItemPos;
183 }
184
185 // -----------------------------------------------------------------------------
186
SetAccessibleName(const::rtl::OUString & sAccessibleName)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
GetAccessibleName()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.isEmpty() )
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
SetItemText(const::rtl::OUString & sItemText)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
GetItemText()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
FillAccessibleStateSet(utl::AccessibleStateSetHelper & rStateSet)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
implGetBounds()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
disposing()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
getAccessibleChildCount()328 sal_Int32 OAccessibleMenuItemComponent::getAccessibleChildCount() throw (RuntimeException)
329 {
330 OExternalLockGuard aGuard( this );
331
332 return 0;
333 }
334
335 // -----------------------------------------------------------------------------
336
getAccessibleChild(sal_Int32 i)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
getAccessibleParent()349 Reference< XAccessible > OAccessibleMenuItemComponent::getAccessibleParent( ) throw (RuntimeException)
350 {
351 OExternalLockGuard aGuard( this );
352
353 return m_pParent->GetAccessible();
354 }
355
356 // -----------------------------------------------------------------------------
357
getAccessibleIndexInParent()358 sal_Int32 OAccessibleMenuItemComponent::getAccessibleIndexInParent( ) throw (RuntimeException)
359 {
360 OExternalLockGuard aGuard( this );
361
362 return m_nItemPos;
363 }
364
365 // -----------------------------------------------------------------------------
366
getAccessibleRole()367 sal_Int16 OAccessibleMenuItemComponent::getAccessibleRole( ) throw (RuntimeException)
368 {
369 OExternalLockGuard aGuard( this );
370
371 return AccessibleRole::UNKNOWN;
372 }
373
374 // -----------------------------------------------------------------------------
375
getAccessibleDescription()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
getAccessibleName()389 ::rtl::OUString OAccessibleMenuItemComponent::getAccessibleName( ) throw (RuntimeException)
390 {
391 OExternalLockGuard aGuard( this );
392
393 return m_sAccessibleName;
394 }
395
396 // -----------------------------------------------------------------------------
397
getAccessibleRelationSet()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
getLocale()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
getAccessibleAtPoint(const awt::Point &)420 Reference< XAccessible > OAccessibleMenuItemComponent::getAccessibleAtPoint( const awt::Point& ) throw (RuntimeException)
421 {
422 OExternalLockGuard aGuard( this );
423
424 return Reference< XAccessible >();
425 }
426
427 // -----------------------------------------------------------------------------
428
grabFocus()429 void OAccessibleMenuItemComponent::grabFocus( ) throw (RuntimeException)
430 {
431 // no focus for items
432 }
433
434 // -----------------------------------------------------------------------------
435
getForeground()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
getBackground()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
getFont()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
getTitledBorderText()492 ::rtl::OUString OAccessibleMenuItemComponent::getTitledBorderText( ) throw (RuntimeException)
493 {
494 OExternalLockGuard aGuard( this );
495
496 return ::rtl::OUString();
497 }
498
499 // -----------------------------------------------------------------------------
500
getToolTipText()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
IsMenuHideDisabledEntries()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