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 
213 	return sName;
214 }
215 
216 // -----------------------------------------------------------------------------
217 
218 void OAccessibleMenuItemComponent::SetItemText( const ::rtl::OUString& sItemText )
219 {
220     Any aOldValue, aNewValue;
221     if ( OCommonAccessibleText::implInitTextChangedEvent( m_sItemText, sItemText, aOldValue, aNewValue ) )
222     {
223         m_sItemText = sItemText;
224         NotifyAccessibleEvent( AccessibleEventId::TEXT_CHANGED, aOldValue, aNewValue );
225     }
226 }
227 
228 // -----------------------------------------------------------------------------
229 
230 ::rtl::OUString OAccessibleMenuItemComponent::GetItemText()
231 {
232 	::rtl::OUString sText;
233 	if ( m_pParent )
234 		sText = OutputDevice::GetNonMnemonicString( m_pParent->GetItemText( m_pParent->GetItemId( m_nItemPos ) ) );
235 
236 	return sText;
237 }
238 
239 // -----------------------------------------------------------------------------
240 
241 void OAccessibleMenuItemComponent::FillAccessibleStateSet( utl::AccessibleStateSetHelper& rStateSet )
242 {
243 	if ( IsEnabled() )
244     {
245         rStateSet.AddState( AccessibleStateType::ENABLED );
246         rStateSet.AddState( AccessibleStateType::SENSITIVE );
247     }
248 
249     if ( IsVisible() )
250     {
251         rStateSet.AddState( AccessibleStateType::VISIBLE );
252         rStateSet.AddState( AccessibleStateType::SHOWING );
253     }
254 
255     rStateSet.AddState( AccessibleStateType::OPAQUE );
256 }
257 
258 // -----------------------------------------------------------------------------
259 // OCommonAccessibleComponent
260 // -----------------------------------------------------------------------------
261 
262 awt::Rectangle OAccessibleMenuItemComponent::implGetBounds() throw (RuntimeException)
263 {
264 	awt::Rectangle aBounds( 0, 0, 0, 0 );
265 
266 	if ( m_pParent )
267 	{
268 		// get bounding rectangle of the item relative to the containing window
269 		aBounds = AWTRectangle( m_pParent->GetBoundingRectangle( m_nItemPos ) );
270 
271 		// get position of containing window in screen coordinates
272 		Window* pWindow = m_pParent->GetWindow();
273 		if ( pWindow )
274 		{
275 			Rectangle aRect = pWindow->GetWindowExtentsRelative( NULL );
276 			awt::Point aWindowScreenLoc = AWTPoint( aRect.TopLeft() );
277 
278 			// get position of accessible parent in screen coordinates
279 			Reference< XAccessible > xParent = getAccessibleParent();
280 			if ( xParent.is() )
281 			{
282 				Reference< XAccessibleComponent > xParentComponent( xParent->getAccessibleContext(), UNO_QUERY );
283 				if ( xParentComponent.is() )
284 				{
285 					awt::Point aParentScreenLoc = xParentComponent->getLocationOnScreen();
286 
287 					// calculate bounding rectangle of the item relative to the accessible parent
288 					aBounds.X += aWindowScreenLoc.X - aParentScreenLoc.X;
289 					aBounds.Y += aWindowScreenLoc.Y - aParentScreenLoc.Y;
290 				}
291 			}
292 		}
293 	}
294 
295 	return aBounds;
296 }
297 
298 // -----------------------------------------------------------------------------
299 // XComponent
300 // -----------------------------------------------------------------------------
301 
302 void SAL_CALL OAccessibleMenuItemComponent::disposing()
303 {
304 	OAccessibleMenuBaseComponent::disposing();
305 
306 	m_pParent = NULL;
307 	m_sAccessibleName = ::rtl::OUString();
308 	m_sItemText = ::rtl::OUString();
309 }
310 
311 // -----------------------------------------------------------------------------
312 // XAccessibleContext
313 // -----------------------------------------------------------------------------
314 
315 sal_Int32 OAccessibleMenuItemComponent::getAccessibleChildCount() throw (RuntimeException)
316 {
317 	OExternalLockGuard aGuard( this );
318 
319 	return 0;
320 }
321 
322 // -----------------------------------------------------------------------------
323 
324 Reference< XAccessible > OAccessibleMenuItemComponent::getAccessibleChild( sal_Int32 i ) throw (IndexOutOfBoundsException, RuntimeException)
325 {
326 	OExternalLockGuard aGuard( this );
327 
328 	if ( i < 0 || i >= getAccessibleChildCount() )
329 		throw IndexOutOfBoundsException();
330 
331 	return Reference< XAccessible >();
332 }
333 
334 // -----------------------------------------------------------------------------
335 
336 Reference< XAccessible > OAccessibleMenuItemComponent::getAccessibleParent(  ) throw (RuntimeException)
337 {
338 	OExternalLockGuard aGuard( this );
339 
340 	return m_pParent->GetAccessible();
341 }
342 
343 // -----------------------------------------------------------------------------
344 
345 sal_Int32 OAccessibleMenuItemComponent::getAccessibleIndexInParent(  ) throw (RuntimeException)
346 {
347 	OExternalLockGuard aGuard( this );
348 
349 	return m_nItemPos;
350 }
351 
352 // -----------------------------------------------------------------------------
353 
354 sal_Int16 OAccessibleMenuItemComponent::getAccessibleRole(  ) throw (RuntimeException)
355 {
356 	OExternalLockGuard aGuard( this );
357 
358 	return AccessibleRole::UNKNOWN;
359 }
360 
361 // -----------------------------------------------------------------------------
362 
363 ::rtl::OUString OAccessibleMenuItemComponent::getAccessibleDescription(	) throw (RuntimeException)
364 {
365 	OExternalLockGuard aGuard( this );
366 
367 	::rtl::OUString sDescription;
368 	if ( m_pParent )
369 		sDescription = m_pParent->GetHelpText( m_pParent->GetItemId( m_nItemPos ) );
370 
371 	return sDescription;
372 }
373 
374 // -----------------------------------------------------------------------------
375 
376 ::rtl::OUString OAccessibleMenuItemComponent::getAccessibleName(  ) throw (RuntimeException)
377 {
378 	OExternalLockGuard aGuard( this );
379 
380 	return m_sAccessibleName;
381 }
382 
383 // -----------------------------------------------------------------------------
384 
385 Reference< XAccessibleRelationSet > OAccessibleMenuItemComponent::getAccessibleRelationSet(  ) throw (RuntimeException)
386 {
387 	OExternalLockGuard aGuard( this );
388 
389     utl::AccessibleRelationSetHelper* pRelationSetHelper = new utl::AccessibleRelationSetHelper;
390 	Reference< XAccessibleRelationSet > xSet = pRelationSetHelper;
391     return xSet;
392 }
393 
394 // -----------------------------------------------------------------------------
395 
396 Locale OAccessibleMenuItemComponent::getLocale(  ) throw (IllegalAccessibleComponentStateException, RuntimeException)
397 {
398 	OExternalLockGuard aGuard( this );
399 
400 	return Application::GetSettings().GetLocale();
401 }
402 
403 // -----------------------------------------------------------------------------
404 // XAccessibleComponent
405 // -----------------------------------------------------------------------------
406 
407 Reference< XAccessible > OAccessibleMenuItemComponent::getAccessibleAtPoint( const awt::Point& ) throw (RuntimeException)
408 {
409 	OExternalLockGuard aGuard( this );
410 
411 	return Reference< XAccessible >();
412 }
413 
414 // -----------------------------------------------------------------------------
415 
416 void OAccessibleMenuItemComponent::grabFocus(  ) throw (RuntimeException)
417 {
418 	// no focus for items
419 }
420 
421 // -----------------------------------------------------------------------------
422 
423 sal_Int32 OAccessibleMenuItemComponent::getForeground(	) throw (RuntimeException)
424 {
425 	OExternalLockGuard aGuard( this );
426 
427 	sal_Int32 nColor = 0;
428 	Reference< XAccessible > xParent = getAccessibleParent();
429 	if ( xParent.is() )
430 	{
431 		Reference< XAccessibleComponent > xParentComp( xParent->getAccessibleContext(), UNO_QUERY );
432 		if ( xParentComp.is() )
433 			nColor = xParentComp->getForeground();
434 	}
435 
436 	return nColor;
437 }
438 
439 // -----------------------------------------------------------------------------
440 
441 sal_Int32 OAccessibleMenuItemComponent::getBackground(  ) throw (RuntimeException)
442 {
443 	OExternalLockGuard aGuard( this );
444 
445 	sal_Int32 nColor = 0;
446 	Reference< XAccessible > xParent = getAccessibleParent();
447 	if ( xParent.is() )
448 	{
449 		Reference< XAccessibleComponent > xParentComp( xParent->getAccessibleContext(), UNO_QUERY );
450 		if ( xParentComp.is() )
451 			nColor = xParentComp->getBackground();
452 	}
453 
454 	return nColor;
455 }
456 
457 // -----------------------------------------------------------------------------
458 // XAccessibleExtendedComponent
459 // -----------------------------------------------------------------------------
460 
461 Reference< awt::XFont > OAccessibleMenuItemComponent::getFont(  ) throw (RuntimeException)
462 {
463 	OExternalLockGuard aGuard( this );
464 
465 	Reference< awt::XFont > xFont;
466 	Reference< XAccessible > xParent = getAccessibleParent();
467 	if ( xParent.is() )
468 	{
469 		Reference< XAccessibleExtendedComponent > xParentComp( xParent->getAccessibleContext(), UNO_QUERY );
470 		if ( xParentComp.is() )
471 			xFont = xParentComp->getFont();
472 	}
473 
474 	return xFont;
475 }
476 
477 // -----------------------------------------------------------------------------
478 
479 ::rtl::OUString OAccessibleMenuItemComponent::getTitledBorderText(  ) throw (RuntimeException)
480 {
481 	OExternalLockGuard aGuard( this );
482 
483 	return ::rtl::OUString();
484 }
485 
486 // -----------------------------------------------------------------------------
487 
488 ::rtl::OUString OAccessibleMenuItemComponent::getToolTipText(  ) throw (RuntimeException)
489 {
490 	OExternalLockGuard aGuard( this );
491 
492 	::rtl::OUString sRet;
493 	if ( m_pParent )
494 		sRet = m_pParent->GetTipHelpText( m_pParent->GetItemId( m_nItemPos ) );
495 
496 	return sRet;
497 }
498 
499 // -----------------------------------------------------------------------------
500