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 <cppuhelper/supportsservice.hxx>
30 #include <unotools/accessiblestatesethelper.hxx>
31 #include <unotools/accessiblerelationsethelper.hxx>
32 #include <osl/mutex.hxx>
33 #include <vcl/svapp.hxx>
34 #include <vcl/settings.hxx>
35 #include <svx/frmsel.hxx>
36 #include <svx/dialmgr.hxx>
37 #include "editeng/unolingu.hxx"
39 #include <svx/dialogs.hrc>
45 using ::com::sun::star::uno::Any
;
46 using ::com::sun::star::uno::UNO_QUERY
;
47 using ::com::sun::star::uno::Reference
;
48 using ::com::sun::star::uno::Sequence
;
49 using ::com::sun::star::uno::RuntimeException
;
50 using ::com::sun::star::uno::XInterface
;
51 using ::com::sun::star::lang::Locale
;
52 using ::com::sun::star::lang::EventObject
;
53 using ::com::sun::star::beans::XPropertyChangeListener
;
54 using ::com::sun::star::awt::XFocusListener
;
56 using namespace ::com::sun::star::accessibility
;
58 namespace AwtKey
= ::com::sun::star::awt::Key
;
59 namespace AwtKeyModifier
= ::com::sun::star::awt::KeyModifier
;
60 namespace AwtFocusChangeReason
= ::com::sun::star::awt::FocusChangeReason
;
62 typedef ::com::sun::star::awt::Point AwtPoint
;
63 typedef ::com::sun::star::awt::Size AwtSize
;
64 typedef ::com::sun::star::awt::Rectangle AwtRectangle
;
65 typedef ::com::sun::star::awt::KeyEvent AwtKeyEvent
;
66 typedef ::com::sun::star::awt::FocusEvent AwtFocusEvent
;
70 AccFrameSelector::AccFrameSelector( FrameSelector
& rFrameSel
, FrameBorderType eBorder
) :
71 Resource( SVX_RES( RID_SVXSTR_BORDER_CONTROL
) ),
72 mpFrameSel( &rFrameSel
),
74 maFocusListeners( maFocusMutex
),
75 maPropertyListeners( maPropertyMutex
),
76 maNames( SVX_RES( ARR_TEXTS
) ),
77 maDescriptions( SVX_RES(ARR_DESCRIPTIONS
) ),
84 mpFrameSel
->AddEventListener( LINK( this, AccFrameSelector
, WindowEventListener
) );
90 AccFrameSelector::~AccFrameSelector()
92 RemoveFrameSelEventListener();
97 void AccFrameSelector::RemoveFrameSelEventListener()
101 mpFrameSel
->RemoveEventListener( LINK( this, AccFrameSelector
, WindowEventListener
) );
107 Reference
< XAccessibleContext
> AccFrameSelector::getAccessibleContext( )
108 throw (RuntimeException
, std::exception
)
115 sal_Int32
AccFrameSelector::getAccessibleChildCount( ) throw (RuntimeException
, std::exception
)
117 SolarMutexGuard aGuard
;
119 return (meBorder
== FRAMEBORDER_NONE
) ? mpFrameSel
->GetEnabledBorderCount() : 0;
122 Reference
< XAccessible
> AccFrameSelector::getAccessibleChild( sal_Int32 i
)
123 throw (RuntimeException
, std::exception
)
125 SolarMutexGuard aGuard
;
127 Reference
< XAccessible
> xRet
;
128 if( meBorder
== FRAMEBORDER_NONE
)
129 xRet
= mpFrameSel
->GetChildAccessible( i
);
131 throw RuntimeException();
135 Reference
< XAccessible
> AccFrameSelector::getAccessibleParent( )
136 throw (RuntimeException
, std::exception
)
138 SolarMutexGuard aGuard
;
140 Reference
< XAccessible
> xRet
;
141 if(meBorder
== FRAMEBORDER_NONE
)
142 xRet
= mpFrameSel
->GetParent()->GetAccessible( true );
144 xRet
= mpFrameSel
->CreateAccessible();
148 sal_Int32
AccFrameSelector::getAccessibleIndexInParent( )
149 throw (RuntimeException
, std::exception
)
151 SolarMutexGuard aGuard
;
155 if( meBorder
== FRAMEBORDER_NONE
)
157 vcl::Window
* pTabPage
= mpFrameSel
->GetParent();
158 sal_Int32 nChildren
= pTabPage
->GetChildCount();
159 for( nIdx
= 0; nIdx
< nChildren
; ++nIdx
)
160 if( pTabPage
->GetChild( static_cast< sal_uInt16
>( nIdx
) ) == mpFrameSel
)
164 nIdx
= mpFrameSel
->GetEnabledBorderIndex( meBorder
);
167 throw RuntimeException();
171 sal_Int16
AccFrameSelector::getAccessibleRole( ) throw (RuntimeException
, std::exception
)
173 return meBorder
== FRAMEBORDER_NONE
? AccessibleRole::OPTION_PANE
: AccessibleRole::CHECK_BOX
;
176 OUString
AccFrameSelector::getAccessibleDescription( )
177 throw (RuntimeException
, std::exception
)
179 SolarMutexGuard aGuard
;
181 return maDescriptions
.GetString(meBorder
);
184 OUString
AccFrameSelector::getAccessibleName( )
185 throw (RuntimeException
, std::exception
)
187 SolarMutexGuard aGuard
;
189 return maNames
.GetString(meBorder
);
192 Reference
< XAccessibleRelationSet
> AccFrameSelector::getAccessibleRelationSet( )
193 throw (RuntimeException
, std::exception
)
195 SolarMutexGuard aGuard
;
197 utl::AccessibleRelationSetHelper
* pHelper
;
198 Reference
< XAccessibleRelationSet
> xRet
= pHelper
= new utl::AccessibleRelationSetHelper
;
199 if(meBorder
== FRAMEBORDER_NONE
)
201 //add the label relation
202 vcl::Window
*pLabeledBy
= mpFrameSel
->GetAccessibleRelationLabeledBy();
203 if ( pLabeledBy
&& pLabeledBy
!= mpFrameSel
)
205 AccessibleRelation aLabelRelation
;
206 aLabelRelation
.RelationType
= AccessibleRelationType::LABELED_BY
;
207 aLabelRelation
.TargetSet
.realloc(1);
208 aLabelRelation
.TargetSet
.getArray()[0] = pLabeledBy
->GetAccessible();
209 pHelper
->AddRelation(aLabelRelation
);
211 vcl::Window
* pMemberOf
= mpFrameSel
->GetAccessibleRelationMemberOf();
212 if ( pMemberOf
&& pMemberOf
!= mpFrameSel
)
214 AccessibleRelation aMemberOfRelation
;
215 aMemberOfRelation
.RelationType
= AccessibleRelationType::MEMBER_OF
;
216 aMemberOfRelation
.TargetSet
.realloc(1);
217 aMemberOfRelation
.TargetSet
.getArray()[0] = pMemberOf
->GetAccessible();
218 pHelper
->AddRelation(aMemberOfRelation
);
224 Reference
< XAccessibleStateSet
> AccFrameSelector::getAccessibleStateSet( )
225 throw (RuntimeException
, std::exception
)
227 SolarMutexGuard aGuard
;
228 utl::AccessibleStateSetHelper
* pStateSetHelper
= new utl::AccessibleStateSetHelper
;
229 Reference
< XAccessibleStateSet
> xRet
= pStateSetHelper
;
232 pStateSetHelper
->AddState(AccessibleStateType::DEFUNC
);
235 const sal_Int16 aStandardStates
[] =
237 AccessibleStateType::EDITABLE
,
238 AccessibleStateType::FOCUSABLE
,
239 AccessibleStateType::MULTI_SELECTABLE
,
240 AccessibleStateType::SELECTABLE
,
241 AccessibleStateType::SHOWING
,
242 AccessibleStateType::VISIBLE
,
243 AccessibleStateType::OPAQUE
,
245 sal_Int16 nState
= 0;
246 while(aStandardStates
[nState
])
248 pStateSetHelper
->AddState(aStandardStates
[nState
++]);
250 if(mpFrameSel
->IsEnabled())
252 pStateSetHelper
->AddState(AccessibleStateType::ENABLED
);
253 pStateSetHelper
->AddState(AccessibleStateType::SENSITIVE
);
256 bool bIsParent
= meBorder
== FRAMEBORDER_NONE
;
257 if(mpFrameSel
->HasFocus() &&
258 (bIsParent
|| mpFrameSel
->IsBorderSelected(meBorder
)))
260 pStateSetHelper
->AddState(AccessibleStateType::ACTIVE
);
261 pStateSetHelper
->AddState(AccessibleStateType::FOCUSED
);
262 pStateSetHelper
->AddState(AccessibleStateType::SELECTED
);
268 Locale
AccFrameSelector::getLocale( )
269 throw (IllegalAccessibleComponentStateException
, RuntimeException
, std::exception
)
271 return Application::GetSettings().GetUILanguageTag().getLocale();
274 sal_Bool
AccFrameSelector::containsPoint( const AwtPoint
& aPt
)
275 throw (RuntimeException
, std::exception
)
277 SolarMutexGuard aGuard
;
279 //aPt is relative to the frame selector
280 return mpFrameSel
->ContainsClickPoint( Point( aPt
.X
, aPt
.Y
) );
283 Reference
< XAccessible
> AccFrameSelector::getAccessibleAtPoint(
284 const AwtPoint
& aPt
)
285 throw (RuntimeException
, std::exception
)
287 SolarMutexGuard aGuard
;
289 //aPt is relative to the frame selector
290 return mpFrameSel
->GetChildAccessible( Point( aPt
.X
, aPt
.Y
) );
293 AwtRectangle
AccFrameSelector::getBounds( ) throw (RuntimeException
, std::exception
)
295 SolarMutexGuard aGuard
;
301 case FRAMEBORDER_NONE
:
302 aSz
= mpFrameSel
->GetSizePixel();
303 aPos
= mpFrameSel
->GetPosPixel();
306 const Rectangle aSpot
= mpFrameSel
->GetClickBoundRect( meBorder
);
307 aPos
= aSpot
.TopLeft();
308 aSz
= aSpot
.GetSize();
313 aRet
.Width
= aSz
.Width();
314 aRet
.Height
= aSz
.Height();
320 AwtPoint
AccFrameSelector::getLocation( ) throw (RuntimeException
, std::exception
)
322 SolarMutexGuard aGuard
;
327 case FRAMEBORDER_NONE
:
328 aPos
= mpFrameSel
->GetPosPixel();
331 const Rectangle aSpot
= mpFrameSel
->GetClickBoundRect( meBorder
);
332 aPos
= aSpot
.TopLeft();
334 AwtPoint
aRet(aPos
.X(), aPos
.Y());
340 AwtPoint
AccFrameSelector::getLocationOnScreen( ) throw (RuntimeException
, std::exception
)
342 SolarMutexGuard aGuard
;
347 case FRAMEBORDER_NONE
:
348 aPos
= mpFrameSel
->GetPosPixel();
351 const Rectangle aSpot
= mpFrameSel
->GetClickBoundRect( meBorder
);
352 aPos
= aSpot
.TopLeft();
354 aPos
= mpFrameSel
->OutputToAbsoluteScreenPixel( aPos
);
355 AwtPoint
aRet(aPos
.X(), aPos
.Y());
361 AwtSize
AccFrameSelector::getSize( ) throw (RuntimeException
, std::exception
)
363 SolarMutexGuard aGuard
;
368 case FRAMEBORDER_NONE
:
369 aSz
= mpFrameSel
->GetSizePixel();
372 const Rectangle aSpot
= mpFrameSel
->GetClickBoundRect( meBorder
);
373 aSz
= aSpot
.GetSize();
375 AwtSize
aRet(aSz
.Width(), aSz
.Height());
379 void AccFrameSelector::grabFocus( ) throw (RuntimeException
, std::exception
)
381 SolarMutexGuard aGuard
;
383 mpFrameSel
->GrabFocus();
386 sal_Int32
AccFrameSelector::getForeground( )
387 throw (RuntimeException
, std::exception
)
389 SolarMutexGuard aGuard
;
391 return mpFrameSel
->GetControlForeground().GetColor();
394 sal_Int32
AccFrameSelector::getBackground( )
395 throw (RuntimeException
, std::exception
)
397 SolarMutexGuard aGuard
;
399 return mpFrameSel
->GetControlBackground().GetColor();
402 void AccFrameSelector::addAccessibleEventListener( const Reference
< XAccessibleEventListener
>& xListener
) throw (RuntimeException
, std::exception
)
404 SolarMutexGuard aGuard
;
406 if ( xListener
.is() )
410 mnClientId
= ::comphelper::AccessibleEventNotifier::registerClient();
412 ::comphelper::AccessibleEventNotifier::addEventListener( mnClientId
, xListener
);
416 void AccFrameSelector::removeAccessibleEventListener( const Reference
< XAccessibleEventListener
>& xListener
) throw (RuntimeException
, std::exception
)
418 SolarMutexGuard aGuard
;
420 if ( xListener
.is() && mnClientId
!= 0 &&
421 ::comphelper::AccessibleEventNotifier::removeEventListener( mnClientId
, xListener
) == 0 )
423 // no listeners anymore
424 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
425 // and at least to us not firing any events anymore, in case somebody calls
426 // NotifyAccessibleEvent, again
427 ::comphelper::AccessibleEventNotifier::TClientId
nId( mnClientId
);
429 ::comphelper::AccessibleEventNotifier::revokeClient( nId
);
433 OUString
AccFrameSelector::getImplementationName( ) throw (RuntimeException
, std::exception
)
435 return OUString("AccFrameSelector");
438 sal_Bool
AccFrameSelector::supportsService( const OUString
& rServiceName
)
439 throw (RuntimeException
, std::exception
)
441 return cppu::supportsService(this, rServiceName
);
444 Sequence
< OUString
> AccFrameSelector::getSupportedServiceNames( )
445 throw (RuntimeException
, std::exception
)
447 Sequence
< OUString
> aRet(3);
448 OUString
* pArray
= aRet
.getArray();
449 pArray
[0] = "Accessible";
450 pArray
[1] = "AccessibleContext";
451 pArray
[2] = "AccessibleComponent";
455 void AccFrameSelector::IsValid() throw (RuntimeException
)
458 throw RuntimeException();
461 void AccFrameSelector::NotifyFocusListeners(bool bGetFocus
)
463 SolarMutexGuard aGuard
;
464 AwtFocusEvent aEvent
;
465 aEvent
.FocusFlags
= 0;
468 sal_uInt16 nFocusFlags
= mpFrameSel
->GetGetFocusFlags();
469 if(nFocusFlags
&GETFOCUS_TAB
)
470 aEvent
.FocusFlags
|= AwtFocusChangeReason::TAB
;
471 if(nFocusFlags
&GETFOCUS_CURSOR
)
472 aEvent
.FocusFlags
|= AwtFocusChangeReason::CURSOR
;
473 if(nFocusFlags
&GETFOCUS_MNEMONIC
)
474 aEvent
.FocusFlags
|= AwtFocusChangeReason::MNEMONIC
;
475 if(nFocusFlags
&GETFOCUS_FORWARD
)
476 aEvent
.FocusFlags
|= AwtFocusChangeReason::FORWARD
;
477 if(nFocusFlags
&GETFOCUS_BACKWARD
)
478 aEvent
.FocusFlags
|= AwtFocusChangeReason::BACKWARD
;
479 if(nFocusFlags
&GETFOCUS_AROUND
)
480 aEvent
.FocusFlags
|= AwtFocusChangeReason::AROUND
;
481 if(nFocusFlags
&GETFOCUS_UNIQUEMNEMONIC
)
482 aEvent
.FocusFlags
|= AwtFocusChangeReason::UNIQUEMNEMONIC
;
484 aEvent
.Temporary
= sal_False
;
486 Reference
< XAccessibleContext
> xThis( this );
487 aEvent
.Source
= xThis
;
489 ::cppu::OInterfaceIteratorHelper
aIter( maFocusListeners
);
490 while( aIter
.hasMoreElements() )
492 Reference
< XFocusListener
> xListener( aIter
.next(), UNO_QUERY
);
494 xListener
->focusGained( aEvent
);
496 xListener
->focusLost( aEvent
);
502 IMPL_LINK( AccFrameSelector
, WindowEventListener
, VclSimpleEvent
*, pEvent
)
504 VclWindowEvent
* pWinEvent
= dynamic_cast< VclWindowEvent
* >( pEvent
);
505 DBG_ASSERT( pWinEvent
, "AccFrameSelector::WindowEventListener - unknown window event" );
508 vcl::Window
* pWindow
= pWinEvent
->GetWindow();
509 DBG_ASSERT( pWindow
, "AccFrameSelector::WindowEventListener: no window!" );
510 if ( !pWindow
->IsAccessibilityEventsSuppressed() || ( pWinEvent
->GetId() == VCLEVENT_OBJECT_DYING
) )
512 ProcessWindowEvent( *pWinEvent
);
521 void AccFrameSelector::ProcessWindowEvent( const VclWindowEvent
& rVclWindowEvent
)
523 switch ( rVclWindowEvent
.GetId() )
525 case VCLEVENT_WINDOW_GETFOCUS
:
527 if ( meBorder
== FRAMEBORDER_NONE
)
529 Any aOldValue
, aNewValue
;
530 aNewValue
<<= AccessibleStateType::FOCUSED
;
531 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
535 case VCLEVENT_WINDOW_LOSEFOCUS
:
537 if ( meBorder
== FRAMEBORDER_NONE
)
539 Any aOldValue
, aNewValue
;
540 aOldValue
<<= AccessibleStateType::FOCUSED
;
541 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
554 void AccFrameSelector::NotifyAccessibleEvent( const sal_Int16 _nEventId
,
555 const Any
& _rOldValue
, const Any
& _rNewValue
)
559 Reference
< XInterface
> xSource( *this );
560 AccessibleEventObject
aEvent( xSource
, _nEventId
, _rNewValue
, _rOldValue
);
561 ::comphelper::AccessibleEventNotifier::addEvent( mnClientId
, aEvent
);
567 void AccFrameSelector::Invalidate()
569 RemoveFrameSelEventListener();
572 Reference
< XAccessibleContext
> xThis( this );
573 aEvent
.Source
= xThis
;
574 maFocusListeners
.disposeAndClear( aEvent
);
575 maPropertyListeners
.disposeAndClear( aEvent
);
583 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */