bump product version to 5.0.4.1
[LibreOffice.git] / svx / source / accessibility / AccessibleFrameSelector.cxx
blob40c175fb3976c0783fd6f7b5f7e041107459ff62
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
40 #include "frmsel.hrc"
42 namespace svx {
43 namespace a11y {
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 ),
73 meBorder( eBorder ),
74 maFocusListeners( maFocusMutex ),
75 maPropertyListeners( maPropertyMutex ),
76 maNames( SVX_RES( ARR_TEXTS ) ),
77 maDescriptions( SVX_RES(ARR_DESCRIPTIONS ) ),
78 mnClientId( 0 )
80 FreeResource();
82 if ( mpFrameSel )
84 mpFrameSel->AddEventListener( LINK( this, AccFrameSelector, WindowEventListener ) );
90 AccFrameSelector::~AccFrameSelector()
92 RemoveFrameSelEventListener();
97 void AccFrameSelector::RemoveFrameSelEventListener()
99 if ( mpFrameSel )
101 mpFrameSel->RemoveEventListener( LINK( this, AccFrameSelector, WindowEventListener ) );
107 Reference< XAccessibleContext > AccFrameSelector::getAccessibleContext( )
108 throw (RuntimeException, std::exception)
110 return this;
115 sal_Int32 AccFrameSelector::getAccessibleChildCount( ) throw (RuntimeException, std::exception)
117 SolarMutexGuard aGuard;
118 IsValid();
119 return (meBorder == FRAMEBORDER_NONE) ? mpFrameSel->GetEnabledBorderCount() : 0;
122 Reference< XAccessible > AccFrameSelector::getAccessibleChild( sal_Int32 i )
123 throw (RuntimeException, std::exception)
125 SolarMutexGuard aGuard;
126 IsValid();
127 Reference< XAccessible > xRet;
128 if( meBorder == FRAMEBORDER_NONE )
129 xRet = mpFrameSel->GetChildAccessible( i );
130 if( !xRet.is() )
131 throw RuntimeException();
132 return xRet;
135 Reference< XAccessible > AccFrameSelector::getAccessibleParent( )
136 throw (RuntimeException, std::exception)
138 SolarMutexGuard aGuard;
139 IsValid();
140 Reference< XAccessible > xRet;
141 if(meBorder == FRAMEBORDER_NONE)
142 xRet = mpFrameSel->GetParent()->GetAccessible( true );
143 else
144 xRet = mpFrameSel->CreateAccessible();
145 return xRet;
148 sal_Int32 AccFrameSelector::getAccessibleIndexInParent( )
149 throw (RuntimeException, std::exception)
151 SolarMutexGuard aGuard;
152 IsValid();
154 sal_Int32 nIdx = 0;
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 )
161 break;
163 else
164 nIdx = mpFrameSel->GetEnabledBorderIndex( meBorder );
166 if( nIdx < 0 )
167 throw RuntimeException();
168 return nIdx;
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;
180 IsValid();
181 return maDescriptions.GetString(meBorder);
184 OUString AccFrameSelector::getAccessibleName( )
185 throw (RuntimeException, std::exception)
187 SolarMutexGuard aGuard;
188 IsValid();
189 return maNames.GetString(meBorder);
192 Reference< XAccessibleRelationSet > AccFrameSelector::getAccessibleRelationSet( )
193 throw (RuntimeException, std::exception)
195 SolarMutexGuard aGuard;
196 IsValid();
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);
221 return xRet;
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;
231 if(!mpFrameSel)
232 pStateSetHelper->AddState(AccessibleStateType::DEFUNC);
233 else
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);
265 return xRet;
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;
278 IsValid();
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;
288 IsValid();
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;
296 IsValid();
297 Size aSz;
298 Point aPos;
299 switch(meBorder)
301 case FRAMEBORDER_NONE:
302 aSz = mpFrameSel->GetSizePixel();
303 aPos = mpFrameSel->GetPosPixel();
304 break;
305 default:
306 const Rectangle aSpot = mpFrameSel->GetClickBoundRect( meBorder );
307 aPos = aSpot.TopLeft();
308 aSz = aSpot.GetSize();
310 AwtRectangle aRet;
311 aRet.X = aPos.X();
312 aRet.Y = aPos.Y();
313 aRet.Width = aSz.Width();
314 aRet.Height = aSz.Height();
315 return aRet;
320 AwtPoint AccFrameSelector::getLocation( ) throw (RuntimeException, std::exception)
322 SolarMutexGuard aGuard;
323 IsValid();
324 Point aPos;
325 switch(meBorder)
327 case FRAMEBORDER_NONE:
328 aPos = mpFrameSel->GetPosPixel();
329 break;
330 default:
331 const Rectangle aSpot = mpFrameSel->GetClickBoundRect( meBorder );
332 aPos = aSpot.TopLeft();
334 AwtPoint aRet(aPos.X(), aPos.Y());
335 return aRet;
340 AwtPoint AccFrameSelector::getLocationOnScreen( ) throw (RuntimeException, std::exception)
342 SolarMutexGuard aGuard;
343 IsValid();
344 Point aPos;
345 switch(meBorder)
347 case FRAMEBORDER_NONE:
348 aPos = mpFrameSel->GetPosPixel();
349 break;
350 default:
351 const Rectangle aSpot = mpFrameSel->GetClickBoundRect( meBorder );
352 aPos = aSpot.TopLeft();
354 aPos = mpFrameSel->OutputToAbsoluteScreenPixel( aPos );
355 AwtPoint aRet(aPos.X(), aPos.Y());
356 return aRet;
361 AwtSize AccFrameSelector::getSize( ) throw (RuntimeException, std::exception)
363 SolarMutexGuard aGuard;
364 IsValid();
365 Size aSz;
366 switch(meBorder)
368 case FRAMEBORDER_NONE:
369 aSz = mpFrameSel->GetSizePixel();
370 break;
371 default:
372 const Rectangle aSpot = mpFrameSel->GetClickBoundRect( meBorder );
373 aSz = aSpot.GetSize();
375 AwtSize aRet(aSz.Width(), aSz.Height());
376 return aRet;
379 void AccFrameSelector::grabFocus( ) throw (RuntimeException, std::exception)
381 SolarMutexGuard aGuard;
382 IsValid();
383 mpFrameSel->GrabFocus();
386 sal_Int32 AccFrameSelector::getForeground( )
387 throw (RuntimeException, std::exception)
389 SolarMutexGuard aGuard;
390 IsValid();
391 return mpFrameSel->GetControlForeground().GetColor();
394 sal_Int32 AccFrameSelector::getBackground( )
395 throw (RuntimeException, std::exception)
397 SolarMutexGuard aGuard;
398 IsValid();
399 return mpFrameSel->GetControlBackground().GetColor();
402 void AccFrameSelector::addAccessibleEventListener( const Reference< XAccessibleEventListener >& xListener ) throw (RuntimeException, std::exception)
404 SolarMutexGuard aGuard;
406 if ( xListener.is() )
408 if ( !mnClientId )
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 );
428 mnClientId = 0;
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";
452 return aRet;
455 void AccFrameSelector::IsValid() throw (RuntimeException)
457 if(!mpFrameSel)
458 throw RuntimeException();
461 void AccFrameSelector::NotifyFocusListeners(bool bGetFocus)
463 SolarMutexGuard aGuard;
464 AwtFocusEvent aEvent;
465 aEvent.FocusFlags = 0;
466 if(bGetFocus)
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 );
493 if(bGetFocus)
494 xListener->focusGained( aEvent );
495 else
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" );
506 if ( pWinEvent )
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 );
516 return 0;
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 );
534 break;
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 );
544 break;
545 default:
548 break;
554 void AccFrameSelector::NotifyAccessibleEvent( const sal_Int16 _nEventId,
555 const Any& _rOldValue, const Any& _rNewValue )
557 if ( mnClientId )
559 Reference< XInterface > xSource( *this );
560 AccessibleEventObject aEvent( xSource, _nEventId, _rNewValue, _rOldValue );
561 ::comphelper::AccessibleEventNotifier::addEvent( mnClientId, aEvent );
567 void AccFrameSelector::Invalidate()
569 RemoveFrameSelEventListener();
570 mpFrameSel = 0;
571 EventObject aEvent;
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: */