1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "AccessibleFrameSelector.hxx"
21 #include <com/sun/star/awt/KeyEvent.hpp>
22 #include <com/sun/star/awt/KeyModifier.hpp>
23 #include <com/sun/star/awt/Key.hpp>
24 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
25 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
26 #include <com/sun/star/accessibility/AccessibleRole.hpp>
27 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
28 #include <com/sun/star/awt/FocusChangeReason.hpp>
29 #include <unotools/accessiblestatesethelper.hxx>
30 #include <unotools/accessiblerelationsethelper.hxx>
31 #include <osl/mutex.hxx>
32 #include <vcl/svapp.hxx>
33 #include <svx/frmsel.hxx>
34 #include <svx/dialmgr.hxx>
35 #include "editeng/unolingu.hxx"
37 #include <svx/dialogs.hrc>
41 #define MNEMONIC_CHAR ((sal_Unicode)'~')
47 using ::com::sun::star::uno::Any
;
48 using ::com::sun::star::uno::UNO_QUERY
;
49 using ::com::sun::star::uno::Reference
;
50 using ::com::sun::star::uno::Sequence
;
51 using ::com::sun::star::uno::RuntimeException
;
52 using ::com::sun::star::uno::XInterface
;
53 using ::com::sun::star::lang::Locale
;
54 using ::com::sun::star::lang::EventObject
;
55 using ::com::sun::star::beans::XPropertyChangeListener
;
56 using ::com::sun::star::awt::XFocusListener
;
58 using namespace ::com::sun::star::accessibility
;
60 namespace AwtKey
= ::com::sun::star::awt::Key
;
61 namespace AwtKeyModifier
= ::com::sun::star::awt::KeyModifier
;
62 namespace AwtFocusChangeReason
= ::com::sun::star::awt::FocusChangeReason
;
64 typedef ::com::sun::star::awt::Point AwtPoint
;
65 typedef ::com::sun::star::awt::Size AwtSize
;
66 typedef ::com::sun::star::awt::Rectangle AwtRectangle
;
67 typedef ::com::sun::star::awt::KeyEvent AwtKeyEvent
;
68 typedef ::com::sun::star::awt::FocusEvent AwtFocusEvent
;
70 // ============================================================================
72 AccFrameSelector::AccFrameSelector( FrameSelector
& rFrameSel
, FrameBorderType eBorder
) :
73 Resource( SVX_RES( RID_SVXSTR_BORDER_CONTROL
) ),
74 mpFrameSel( &rFrameSel
),
76 maFocusListeners( maFocusMutex
),
77 maPropertyListeners( maPropertyMutex
),
78 maNames( SVX_RES( ARR_TEXTS
) ),
79 maDescriptions( SVX_RES(ARR_DESCRIPTIONS
) ),
86 mpFrameSel
->AddEventListener( LINK( this, AccFrameSelector
, WindowEventListener
) );
90 // ----------------------------------------------------------------------------
92 AccFrameSelector::~AccFrameSelector()
94 RemoveFrameSelEventListener();
97 // ----------------------------------------------------------------------------
99 void AccFrameSelector::RemoveFrameSelEventListener()
103 mpFrameSel
->RemoveEventListener( LINK( this, AccFrameSelector
, WindowEventListener
) );
107 // ----------------------------------------------------------------------------
109 Reference
< XAccessibleContext
> AccFrameSelector::getAccessibleContext( )
110 throw (RuntimeException
)
115 // ----------------------------------------------------------------------------
117 sal_Int32
AccFrameSelector::getAccessibleChildCount( ) throw (RuntimeException
)
119 SolarMutexGuard aGuard
;
121 return (meBorder
== FRAMEBORDER_NONE
) ? mpFrameSel
->GetEnabledBorderCount() : 0;
124 // ----------------------------------------------------------------------------
126 Reference
< XAccessible
> AccFrameSelector::getAccessibleChild( sal_Int32 i
)
127 throw (RuntimeException
)
129 SolarMutexGuard aGuard
;
131 Reference
< XAccessible
> xRet
;
132 if( meBorder
== FRAMEBORDER_NONE
)
133 xRet
= mpFrameSel
->GetChildAccessible( i
);
135 throw RuntimeException();
139 // ----------------------------------------------------------------------------
141 Reference
< XAccessible
> AccFrameSelector::getAccessibleParent( )
142 throw (RuntimeException
)
144 SolarMutexGuard aGuard
;
146 Reference
< XAccessible
> xRet
;
147 if(meBorder
== FRAMEBORDER_NONE
)
148 xRet
= mpFrameSel
->GetParent()->GetAccessible( sal_True
);
150 xRet
= mpFrameSel
->CreateAccessible();
154 // ----------------------------------------------------------------------------
156 sal_Int32
AccFrameSelector::getAccessibleIndexInParent( )
157 throw (RuntimeException
)
159 SolarMutexGuard aGuard
;
163 if( meBorder
== FRAMEBORDER_NONE
)
165 Window
* pTabPage
= mpFrameSel
->GetParent();
166 sal_Int32 nChildren
= pTabPage
->GetChildCount();
167 for( nIdx
= 0; nIdx
< nChildren
; ++nIdx
)
168 if( pTabPage
->GetChild( static_cast< sal_uInt16
>( nIdx
) ) == mpFrameSel
)
172 nIdx
= mpFrameSel
->GetEnabledBorderIndex( meBorder
);
175 throw RuntimeException();
179 // ----------------------------------------------------------------------------
181 sal_Int16
AccFrameSelector::getAccessibleRole( ) throw (RuntimeException
)
183 return AccessibleRole::OPTION_PANE
;
186 // ----------------------------------------------------------------------------
188 OUString
AccFrameSelector::getAccessibleDescription( )
189 throw (RuntimeException
)
191 SolarMutexGuard aGuard
;
193 return maDescriptions
.GetString(meBorder
);
196 // ----------------------------------------------------------------------------
198 OUString
AccFrameSelector::getAccessibleName( )
199 throw (RuntimeException
)
201 SolarMutexGuard aGuard
;
203 return maNames
.GetString(meBorder
);
206 // ----------------------------------------------------------------------------
208 Reference
< XAccessibleRelationSet
> AccFrameSelector::getAccessibleRelationSet( )
209 throw (RuntimeException
)
211 SolarMutexGuard aGuard
;
213 utl::AccessibleRelationSetHelper
* pHelper
;
214 Reference
< XAccessibleRelationSet
> xRet
= pHelper
= new utl::AccessibleRelationSetHelper
;
215 if(meBorder
== FRAMEBORDER_NONE
)
217 //add the label relation
218 Window
* pPrev
= mpFrameSel
->GetWindow( WINDOW_PREV
);
219 if(pPrev
&& WINDOW_FIXEDTEXT
== pPrev
->GetType())
221 AccessibleRelation aLabelRelation
;
222 aLabelRelation
.RelationType
= AccessibleRelationType::LABELED_BY
;
223 aLabelRelation
.TargetSet
.realloc(1);
224 aLabelRelation
.TargetSet
.getArray()[0] = pPrev
->GetAccessible();
225 pHelper
->AddRelation(aLabelRelation
);
231 // ----------------------------------------------------------------------------
233 Reference
< XAccessibleStateSet
> AccFrameSelector::getAccessibleStateSet( )
234 throw (RuntimeException
)
236 SolarMutexGuard aGuard
;
237 utl::AccessibleStateSetHelper
* pStateSetHelper
= new utl::AccessibleStateSetHelper
;
238 Reference
< XAccessibleStateSet
> xRet
= pStateSetHelper
;
241 pStateSetHelper
->AddState(AccessibleStateType::DEFUNC
);
244 const sal_Int16 aStandardStates
[] =
246 AccessibleStateType::EDITABLE
,
247 AccessibleStateType::FOCUSABLE
,
248 AccessibleStateType::MULTI_SELECTABLE
,
249 AccessibleStateType::SELECTABLE
,
250 AccessibleStateType::SHOWING
,
251 AccessibleStateType::VISIBLE
,
252 AccessibleStateType::OPAQUE
,
254 sal_Int16 nState
= 0;
255 while(aStandardStates
[nState
])
257 pStateSetHelper
->AddState(aStandardStates
[nState
++]);
259 if(mpFrameSel
->IsEnabled())
261 pStateSetHelper
->AddState(AccessibleStateType::ENABLED
);
262 pStateSetHelper
->AddState(AccessibleStateType::SENSITIVE
);
265 bool bIsParent
= meBorder
== FRAMEBORDER_NONE
;
266 if(mpFrameSel
->HasFocus() &&
267 (bIsParent
|| mpFrameSel
->IsBorderSelected(meBorder
)))
269 pStateSetHelper
->AddState(AccessibleStateType::ACTIVE
);
270 pStateSetHelper
->AddState(AccessibleStateType::FOCUSED
);
271 pStateSetHelper
->AddState(AccessibleStateType::SELECTED
);
277 // ----------------------------------------------------------------------------
279 Locale
AccFrameSelector::getLocale( )
280 throw (IllegalAccessibleComponentStateException
, RuntimeException
)
282 return Application::GetSettings().GetUILanguageTag().getLocale();
285 // ----------------------------------------------------------------------------
287 void AccFrameSelector::addPropertyChangeListener(
288 const Reference
< XPropertyChangeListener
>& xListener
)
289 throw (RuntimeException
)
291 maPropertyListeners
.addInterface( xListener
);
294 // ----------------------------------------------------------------------------
296 void AccFrameSelector::removePropertyChangeListener( const Reference
< XPropertyChangeListener
>& xListener
)
297 throw (RuntimeException
)
299 maPropertyListeners
.removeInterface( xListener
);
302 // ----------------------------------------------------------------------------
304 sal_Bool
AccFrameSelector::containsPoint( const AwtPoint
& aPt
)
305 throw (RuntimeException
)
307 SolarMutexGuard aGuard
;
309 //aPt is relative to the frame selector
310 return mpFrameSel
->ContainsClickPoint( Point( aPt
.X
, aPt
.Y
) );
313 // ----------------------------------------------------------------------------
315 Reference
< XAccessible
> AccFrameSelector::getAccessibleAtPoint(
316 const AwtPoint
& aPt
)
317 throw (RuntimeException
)
319 SolarMutexGuard aGuard
;
321 //aPt is relative to the frame selector
322 return mpFrameSel
->GetChildAccessible( Point( aPt
.X
, aPt
.Y
) );
325 AwtRectangle
AccFrameSelector::getBounds( ) throw (RuntimeException
)
327 SolarMutexGuard aGuard
;
333 case FRAMEBORDER_NONE
:
334 aSz
= mpFrameSel
->GetSizePixel();
335 aPos
= mpFrameSel
->GetPosPixel();
338 const Rectangle aSpot
= mpFrameSel
->GetClickBoundRect( meBorder
);
339 aPos
= aSpot
.TopLeft();
340 aSz
= aSpot
.GetSize();
345 aRet
.Width
= aSz
.Width();
346 aRet
.Height
= aSz
.Height();
350 // ----------------------------------------------------------------------------
352 AwtPoint
AccFrameSelector::getLocation( ) throw (RuntimeException
)
354 SolarMutexGuard aGuard
;
359 case FRAMEBORDER_NONE
:
360 aPos
= mpFrameSel
->GetPosPixel();
363 const Rectangle aSpot
= mpFrameSel
->GetClickBoundRect( meBorder
);
364 aPos
= aSpot
.TopLeft();
366 AwtPoint
aRet(aPos
.X(), aPos
.Y());
370 // ----------------------------------------------------------------------------
372 AwtPoint
AccFrameSelector::getLocationOnScreen( ) throw (RuntimeException
)
374 SolarMutexGuard aGuard
;
379 case FRAMEBORDER_NONE
:
380 aPos
= mpFrameSel
->GetPosPixel();
383 const Rectangle aSpot
= mpFrameSel
->GetClickBoundRect( meBorder
);
384 aPos
= aSpot
.TopLeft();
386 aPos
= mpFrameSel
->OutputToAbsoluteScreenPixel( aPos
);
387 AwtPoint
aRet(aPos
.X(), aPos
.Y());
391 // ----------------------------------------------------------------------------
393 AwtSize
AccFrameSelector::getSize( ) throw (RuntimeException
)
395 SolarMutexGuard aGuard
;
400 case FRAMEBORDER_NONE
:
401 aSz
= mpFrameSel
->GetSizePixel();
404 const Rectangle aSpot
= mpFrameSel
->GetClickBoundRect( meBorder
);
405 aSz
= aSpot
.GetSize();
407 AwtSize
aRet(aSz
.Width(), aSz
.Height());
411 // ----------------------------------------------------------------------------
413 sal_Bool
AccFrameSelector::isShowing( ) throw (RuntimeException
)
415 SolarMutexGuard aGuard
;
420 // ----------------------------------------------------------------------------
422 sal_Bool
AccFrameSelector::isVisible( ) throw (RuntimeException
)
424 SolarMutexGuard aGuard
;
429 // ----------------------------------------------------------------------------
431 sal_Bool
AccFrameSelector::isFocusTraversable( ) throw (RuntimeException
)
433 SolarMutexGuard aGuard
;
438 // ----------------------------------------------------------------------------
440 void AccFrameSelector::addFocusListener( const Reference
< XFocusListener
>& xListener
) throw (RuntimeException
)
442 maFocusListeners
.addInterface( xListener
);
445 // ----------------------------------------------------------------------------
447 void AccFrameSelector::removeFocusListener( const Reference
< XFocusListener
>& xListener
) throw (RuntimeException
)
449 maFocusListeners
.removeInterface( xListener
);
452 // ----------------------------------------------------------------------------
454 void AccFrameSelector::grabFocus( ) throw (RuntimeException
)
456 SolarMutexGuard aGuard
;
458 mpFrameSel
->GrabFocus();
461 // ----------------------------------------------------------------------------
463 Any
AccFrameSelector::getAccessibleKeyBinding( ) throw (RuntimeException
)
466 SolarMutexGuard aGuard
;
468 utl::AccessibleRelationSetHelper
* pHelper
;
469 Reference
< XAccessibleRelationSet
> xRet
= pHelper
= new utl::AccessibleRelationSetHelper
;
470 if(meBorder
== FRAMEBORDER_NONE
)
472 Window
* pPrev
= mpFrameSel
->GetWindow( WINDOW_PREV
);
473 if(pPrev
&& WINDOW_FIXEDTEXT
== pPrev
->GetType())
475 String sText
= pPrev
->GetText();
476 xub_StrLen nFound
= sText
.Search( MNEMONIC_CHAR
);
477 if(STRING_NOTFOUND
!= nFound
&& ++nFound
< sText
.Len())
479 sText
.ToUpperAscii();
480 sal_Unicode cChar
= sText
.GetChar(nFound
);
484 aEvent
.KeyChar
= cChar
;
486 if(cChar
>= 'A' && cChar
<= 'Z')
488 aEvent
.KeyCode
= AwtKey::A
+ cChar
- 'A';
490 aEvent
.Modifiers
= AwtKeyModifier::MOD2
;
498 // ----------------------------------------------------------------------------
500 sal_Int32
AccFrameSelector::getForeground( )
501 throw (RuntimeException
)
504 SolarMutexGuard aGuard
;
506 return mpFrameSel
->GetControlForeground().GetColor();
509 // ----------------------------------------------------------------------------
511 sal_Int32
AccFrameSelector::getBackground( )
512 throw (RuntimeException
)
515 SolarMutexGuard aGuard
;
517 return mpFrameSel
->GetControlBackground().GetColor();
520 // ----------------------------------------------------------------------------
522 void AccFrameSelector::addAccessibleEventListener( const Reference
< XAccessibleEventListener
>& xListener
) throw (RuntimeException
)
524 SolarMutexGuard aGuard
;
526 if ( xListener
.is() )
530 mnClientId
= ::comphelper::AccessibleEventNotifier::registerClient();
532 ::comphelper::AccessibleEventNotifier::addEventListener( mnClientId
, xListener
);
536 // ----------------------------------------------------------------------------
538 void AccFrameSelector::removeAccessibleEventListener( const Reference
< XAccessibleEventListener
>& xListener
) throw (RuntimeException
)
540 SolarMutexGuard aGuard
;
542 if ( xListener
.is() && mnClientId
!= 0 &&
543 ::comphelper::AccessibleEventNotifier::removeEventListener( mnClientId
, xListener
) == 0 )
545 // no listeners anymore
546 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
547 // and at least to us not firing any events anymore, in case somebody calls
548 // NotifyAccessibleEvent, again
549 ::comphelper::AccessibleEventNotifier::TClientId
nId( mnClientId
);
551 ::comphelper::AccessibleEventNotifier::revokeClient( nId
);
555 // ----------------------------------------------------------------------------
557 OUString
AccFrameSelector::getImplementationName( ) throw (RuntimeException
)
559 return OUString("AccFrameSelector");
562 // ----------------------------------------------------------------------------
564 const sal_Char sAccessible
[] = "Accessible";
565 const sal_Char sAccessibleContext
[] = "AccessibleContext";
566 const sal_Char sAccessibleComponent
[] = "AccessibleComponent";
568 sal_Bool
AccFrameSelector::supportsService( const OUString
& rServiceName
)
569 throw (RuntimeException
)
571 return rServiceName
.equalsAsciiL( sAccessible
, sizeof(sAccessible
)-1 ) ||
572 rServiceName
.equalsAsciiL( sAccessibleContext
, sizeof(sAccessibleContext
)-1 ) ||
573 rServiceName
.equalsAsciiL( sAccessibleComponent
, sizeof(sAccessibleComponent
)-1 );
576 // ----------------------------------------------------------------------------
578 Sequence
< OUString
> AccFrameSelector::getSupportedServiceNames( )
579 throw (RuntimeException
)
581 Sequence
< OUString
> aRet(3);
582 OUString
* pArray
= aRet
.getArray();
583 pArray
[0] = OUString( sAccessible
);
584 pArray
[1] = OUString( sAccessibleContext
);
585 pArray
[2] = OUString( sAccessibleComponent
);
589 // ----------------------------------------------------------------------------
591 void AccFrameSelector::IsValid() throw (RuntimeException
)
594 throw RuntimeException();
597 // ----------------------------------------------------------------------------
599 void AccFrameSelector::NotifyFocusListeners(sal_Bool bGetFocus
)
601 SolarMutexGuard aGuard
;
602 AwtFocusEvent aEvent
;
603 aEvent
.FocusFlags
= 0;
606 sal_uInt16 nFocusFlags
= mpFrameSel
->GetGetFocusFlags();
607 if(nFocusFlags
&GETFOCUS_TAB
)
608 aEvent
.FocusFlags
|= AwtFocusChangeReason::TAB
;
609 if(nFocusFlags
&GETFOCUS_CURSOR
)
610 aEvent
.FocusFlags
|= AwtFocusChangeReason::CURSOR
;
611 if(nFocusFlags
&GETFOCUS_MNEMONIC
)
612 aEvent
.FocusFlags
|= AwtFocusChangeReason::MNEMONIC
;
613 if(nFocusFlags
&GETFOCUS_FORWARD
)
614 aEvent
.FocusFlags
|= AwtFocusChangeReason::FORWARD
;
615 if(nFocusFlags
&GETFOCUS_BACKWARD
)
616 aEvent
.FocusFlags
|= AwtFocusChangeReason::BACKWARD
;
617 if(nFocusFlags
&GETFOCUS_AROUND
)
618 aEvent
.FocusFlags
|= AwtFocusChangeReason::AROUND
;
619 if(nFocusFlags
&GETFOCUS_UNIQUEMNEMONIC
)
620 aEvent
.FocusFlags
|= AwtFocusChangeReason::UNIQUEMNEMONIC
;
622 aEvent
.Temporary
= sal_False
;
624 Reference
< XAccessibleContext
> xThis( this );
625 aEvent
.Source
= xThis
;
627 ::cppu::OInterfaceIteratorHelper
aIter( maFocusListeners
);
628 while( aIter
.hasMoreElements() )
630 Reference
< XFocusListener
> xListener( aIter
.next(), UNO_QUERY
);
632 xListener
->focusGained( aEvent
);
634 xListener
->focusLost( aEvent
);
638 // ----------------------------------------------------------------------------
640 IMPL_LINK( AccFrameSelector
, WindowEventListener
, VclSimpleEvent
*, pEvent
)
642 VclWindowEvent
* pWinEvent
= dynamic_cast< VclWindowEvent
* >( pEvent
);
643 DBG_ASSERT( pWinEvent
, "AccFrameSelector::WindowEventListener - unknown window event" );
646 Window
* pWindow
= pWinEvent
->GetWindow();
647 DBG_ASSERT( pWindow
, "AccFrameSelector::WindowEventListener: no window!" );
648 if ( !pWindow
->IsAccessibilityEventsSuppressed() || ( pWinEvent
->GetId() == VCLEVENT_OBJECT_DYING
) )
650 ProcessWindowEvent( *pWinEvent
);
657 // ----------------------------------------------------------------------------
659 void AccFrameSelector::ProcessWindowEvent( const VclWindowEvent
& rVclWindowEvent
)
661 switch ( rVclWindowEvent
.GetId() )
663 case VCLEVENT_WINDOW_GETFOCUS
:
665 if ( meBorder
== FRAMEBORDER_NONE
)
667 Any aOldValue
, aNewValue
;
668 aNewValue
<<= AccessibleStateType::FOCUSED
;
669 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
673 case VCLEVENT_WINDOW_LOSEFOCUS
:
675 if ( meBorder
== FRAMEBORDER_NONE
)
677 Any aOldValue
, aNewValue
;
678 aOldValue
<<= AccessibleStateType::FOCUSED
;
679 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
690 // ----------------------------------------------------------------------------
692 void AccFrameSelector::NotifyAccessibleEvent( const sal_Int16 _nEventId
,
693 const Any
& _rOldValue
, const Any
& _rNewValue
)
697 Reference
< XInterface
> xSource( *this );
698 AccessibleEventObject
aEvent( xSource
, _nEventId
, _rNewValue
, _rOldValue
);
699 ::comphelper::AccessibleEventNotifier::addEvent( mnClientId
, aEvent
);
703 // ----------------------------------------------------------------------------
705 void AccFrameSelector::Invalidate()
707 RemoveFrameSelEventListener();
710 Reference
< XAccessibleContext
> xThis( this );
711 aEvent
.Source
= xThis
;
712 maFocusListeners
.disposeAndClear( aEvent
);
713 maPropertyListeners
.disposeAndClear( aEvent
);
716 // ============================================================================
721 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */