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 <com/sun/star/accessibility/XAccessible.hpp>
21 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
22 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
23 #include <com/sun/star/accessibility/AccessibleRole.hpp>
24 #include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
26 #include <vcl/svapp.hxx>
28 #include "AccContainerEventListener.hxx"
29 #include "AccObjectManagerAgent.hxx"
30 #include "unomsaaevent.hxx"
32 using namespace com::sun::star::uno
;
33 using namespace com::sun::star::accessibility
;
35 AccContainerEventListener::AccContainerEventListener(com::sun::star::accessibility::XAccessible
* pAcc
, AccObjectManagerAgent
* Agent
)
36 :AccEventListener(pAcc
, Agent
)
40 AccContainerEventListener::~AccContainerEventListener()
45 * Uno's event notifier when event is captured
47 * @param AccessibleEventObject the event object which contains information about event
49 void AccContainerEventListener::notifyEvent( const ::com::sun::star::accessibility::AccessibleEventObject
& aEvent
)
50 throw (::com::sun::star::uno::RuntimeException
)
54 switch (aEvent
.EventId
)
56 case AccessibleEventId::CHILD
:
57 HandleChildChangedEvent(aEvent
.OldValue
, aEvent
.NewValue
);
59 case AccessibleEventId::SELECTION_CHANGED
:
60 HandleSelectionChangedEvent(aEvent
.OldValue
, aEvent
.NewValue
);
62 case AccessibleEventId::INVALIDATE_ALL_CHILDREN
:
63 HandleAllChildrenChangedEvent();
65 case AccessibleEventId::TEXT_CHANGED
:
66 HandleTextChangedEvent(aEvent
.OldValue
, aEvent
.NewValue
);
67 case AccessibleEventId::VISIBLE_DATA_CHANGED
:
68 HandleVisibleDataChangedEvent();
70 case AccessibleEventId::BOUNDRECT_CHANGED
:
71 HandleBoundrectChangedEvent();
73 case AccessibleEventId::STATE_CHANGED
:
74 HandleStateChangedEvent(aEvent
.OldValue
, aEvent
.NewValue
);
76 case AccessibleEventId::VALUE_CHANGED
:
77 HandleValueChangedEvent(aEvent
.OldValue
, aEvent
.NewValue
);
79 case AccessibleEventId::SELECTION_CHANGED_ADD
:
80 HandleSelectionChangedAddEvent(aEvent
.OldValue
, aEvent
.NewValue
);
82 case AccessibleEventId::SELECTION_CHANGED_REMOVE
:
83 HandleSelectionChangedRemoveEvent(aEvent
.OldValue
, aEvent
.NewValue
);
85 case AccessibleEventId::SELECTION_CHANGED_WITHIN
:
86 HandleSelectionChangedWithinEvent(aEvent
.OldValue
, aEvent
.NewValue
);
88 case AccessibleEventId::PAGE_CHANGED
:
89 HandlePageChangedEvent(aEvent
.OldValue
, aEvent
.NewValue
);
91 case AccessibleEventId::SECTION_CHANGED
:
92 HandleSectionChangedEvent(aEvent
.OldValue
, aEvent
.NewValue
);
94 case AccessibleEventId::COLUMN_CHANGED
:
95 HandleColumnChangedEvent(aEvent
.OldValue
, aEvent
.NewValue
);
98 AccEventListener::notifyEvent(aEvent
);
103 void AccContainerEventListener::HandleStateChangedEvent(Any oldValue
, Any newValue
)
106 if( newValue
>>= State
)
108 SetComponentState(State
, true);
110 else if (oldValue
>>= State
)
112 SetComponentState(State
, false);
118 * handle the CHILD event
119 * @param oldValue the child to be deleted
120 * @param newValue the child to be added
122 void AccContainerEventListener::HandleChildChangedEvent(Any oldValue
, Any newValue
)
124 Reference
< XAccessible
> xChild
;
125 if( newValue
>>= xChild
)
130 XAccessible
* pAcc
= xChild
.get();
133 if (pAgent
->InsertAccObj(pAcc
, m_xAccessible
.get()))
135 //add all oldValue's existing children
136 pAgent
->InsertChildrenAccObj(pAcc
);
137 pAgent
->NotifyAccEvent(UM_EVENT_CHILD_ADDED
, pAcc
);
143 else if (oldValue
>>= xChild
)
145 //delete a existing child
148 XAccessible
* pAcc
= xChild
.get();
149 pAgent
->NotifyAccEvent(UM_EVENT_CHILD_REMOVED
, pAcc
);
150 //delete all oldValue's existing children
151 pAgent
->DeleteChildrenAccObj( pAcc
);
153 pAgent
->DeleteAccObj( pAcc
);
163 * handle the SELECTION_CHANGED event
164 * @param oldValue the old value of the source of event
165 * @param newValue the new value of the source of event
167 void AccContainerEventListener::HandleSelectionChangedEvent(const Any
& /*oldValue*/, const Any
& newValue
)
169 if(NotifyChildEvent(UM_EVENT_SELECTION_CHANGED
,newValue
))
174 //menu bar does not process selection change event,just same as word behavior
175 if (GetRole()!=AccessibleRole::MENU_BAR
)
176 pAgent
->NotifyAccEvent(UM_EVENT_SELECTION_CHANGED
, m_xAccessible
.get());
180 * handle the INVALIDATE_ALL_CHILDREN event
182 void AccContainerEventListener::HandleAllChildrenChangedEvent()
184 //TODO: update all the children
185 if (m_xAccessible
.is())
187 //delete all oldValue's existing children
188 pAgent
->DeleteChildrenAccObj(m_xAccessible
.get());
189 //add all oldValue's existing children
190 pAgent
->InsertChildrenAccObj(m_xAccessible
.get());
191 pAgent
->NotifyAccEvent(UM_EVENT_OBJECT_REORDER
, m_xAccessible
.get());
196 * handle the TEXT_CHANGED event
198 void AccContainerEventListener::HandleTextChangedEvent(Any oldValue
, Any newValue
)
200 pAgent
->UpdateValue(m_xAccessible
.get(), newValue
);
201 pAgent
->NotifyAccEvent(UM_EVENT_OBJECT_TEXTCHANGE
, m_xAccessible
.get());
205 * set the new state and fire the MSAA event
206 * @param state new state id
207 * @param enable true if state is set, false if state is unset
209 void AccContainerEventListener::SetComponentState(short state
, bool enable
)
211 // only the following state can be fired state event.
215 case AccessibleStateType::SELECTED
:
216 case AccessibleStateType::BUSY
:
217 case AccessibleStateType::INDETERMINATE
:
218 case AccessibleStateType::OFFSCREEN
:
219 case AccessibleStateType::FOCUSABLE
:
220 case AccessibleStateType::SHOWING
:
221 case AccessibleStateType::VISIBLE
:
222 FireStatePropertyChange(state
, enable
);
224 case AccessibleStateType::FOCUSED
:
225 FireStateFocusedChange(enable
);
227 case AccessibleStateType::ENABLED
:
230 pAgent
->DecreaseState(m_xAccessible
.get(), AccessibleStateType::DEFUNC
);
231 pAgent
->IncreaseState(m_xAccessible
.get(), AccessibleStateType::FOCUSABLE
);
232 pAgent
->UpdateState(m_xAccessible
.get());
234 UpdateAllChildrenState(m_xAccessible
.get());
238 pAgent
->IncreaseState(m_xAccessible
.get(), AccessibleStateType::DEFUNC
);
239 pAgent
->DecreaseState(m_xAccessible
.get(), AccessibleStateType::FOCUSABLE
);
240 pAgent
->UpdateState(m_xAccessible
.get());
242 UpdateAllChildrenState(m_xAccessible
.get());
245 case AccessibleStateType::ACTIVE
:
246 // Only frames should be active
247 // no msaa state mapping
248 //for PAGE_TAB_LIST, there will be ACTIVE state, then it should be converted to FOCUSED event.
249 if (GetRole() == AccessibleRole::PAGE_TAB_LIST
)
251 if (!enable
) /* get the active state */
253 pAgent
->IncreaseState(m_xAccessible
.get(), AccessibleStateType::FOCUSED
);
256 else /* lose the active state */
258 pAgent
->DecreaseState(m_xAccessible
.get(), AccessibleStateType::FOCUSED
);
263 case AccessibleStateType::EXPANDED
:
264 case AccessibleStateType::COLLAPSE
:
265 case AccessibleStateType::CHECKED
:
267 pAgent
->UpdateState(m_xAccessible
.get());
268 pAgent
->NotifyAccEvent(UM_EVENT_STATE_BUSY
, m_xAccessible
.get());
278 * fire the MSAA state changed event
279 * @param state the state id
280 * @param set true if state is set, false if state is unset
282 void AccContainerEventListener::FireStatePropertyChange(short state
, bool set
)
289 case AccessibleStateType::SELECTED
:
290 pAgent
->IncreaseState(m_xAccessible
.get(), state
);
292 case AccessibleStateType::INDETERMINATE
:
293 case AccessibleStateType::BUSY
:
294 case AccessibleStateType::FOCUSABLE
:
295 case AccessibleStateType::OFFSCREEN
:
296 pAgent
->IncreaseState(m_xAccessible
.get(), state
);
297 pAgent
->NotifyAccEvent(UM_EVENT_STATE_BUSY
, m_xAccessible
.get());
299 case AccessibleStateType::SHOWING
:
300 // UNO !SHOWING == MSAA OFFSCREEN
301 pAgent
->IncreaseState(m_xAccessible
.get(), AccessibleStateType::SHOWING
);
303 case AccessibleStateType::VISIBLE
:
304 // UNO !VISIBLE == MSAA INVISIBLE
305 pAgent
->IncreaseState(m_xAccessible
.get(), AccessibleStateType::VISIBLE
);
316 case AccessibleStateType::SELECTED
:
317 pAgent
->DecreaseState(m_xAccessible
.get(), state
);
319 case AccessibleStateType::BUSY
:
320 case AccessibleStateType::INDETERMINATE
:
321 case AccessibleStateType::FOCUSABLE
:
322 case AccessibleStateType::OFFSCREEN
:
323 pAgent
->DecreaseState(m_xAccessible
.get(), state
);
324 pAgent
->NotifyAccEvent(UM_EVENT_STATE_BUSY
, m_xAccessible
.get());
326 case AccessibleStateType::SHOWING
:
327 // UNO !SHOWING == MSAA OFFSCREEN
328 pAgent
->DecreaseState(m_xAccessible
.get(), AccessibleStateType::SHOWING
);
330 case AccessibleStateType::VISIBLE
:
331 // UNO !VISIBLE == MSAA INVISIBLE
332 pAgent
->DecreaseState(m_xAccessible
.get(), AccessibleStateType::VISIBLE
);
341 * handle the focused event
342 * @param enable true if get focus, false if lose focus
344 void AccContainerEventListener::FireStateFocusedChange(bool enable
)
348 pAgent
->IncreaseState(m_xAccessible
.get(), AccessibleStateType::FOCUSED
);
349 //if the acc role is MENU_BAR, MSAA UM_EVENT_MENU_START event should be sent
350 //if the acc role is POPUP_MENU, MSAA UM_EVENT_MENUPOPUPSTART event should be sent
351 short role
= GetRole();
352 if(role
== AccessibleRole::MENU_BAR
)
354 pAgent
->NotifyAccEvent(UM_EVENT_MENU_START
, m_xAccessible
.get());
356 else if (role
== AccessibleRole::POPUP_MENU
)
357 pAgent
->NotifyAccEvent(UM_EVENT_MENUPOPUPSTART
, m_xAccessible
.get());
358 //Disable the focused event on option_pane and Panel.
359 //only disable option_pane for toolbar has panel to get focus
360 else if (role
== AccessibleRole::PANEL
|| role
== AccessibleRole::OPTION_PANE
)
362 //don't send focused event on PANEL & OPTION_PANE if the parent is not toolbar
363 short parentRole
= GetParentRole();
364 if (parentRole
== AccessibleRole::TOOL_BAR
365 || parentRole
== AccessibleRole::SCROLL_PANE
// sidebar
366 || parentRole
== AccessibleRole::PANEL
) // sidebar
367 pAgent
->NotifyAccEvent(UM_EVENT_STATE_FOCUSED
, m_xAccessible
.get());
369 //to update ComboBox's description
370 else if (role
== AccessibleRole::COMBO_BOX
)
372 pAgent
->UpdateDescription(m_xAccessible
.get());
373 //for editable combobox, send focus event on only edit control,
374 bool bSendFocusOnCombobox
= true;
375 //send focused event to the first text child
376 Reference
<XAccessibleContext
> mxContext(m_xAccessible
.get()->getAccessibleContext(), UNO_QUERY
);
379 Reference
<XAccessible
> mxChild
= mxContext
->getAccessibleChild(0);
382 Reference
<XAccessibleContext
> mxChildContext(mxChild
->getAccessibleContext(),UNO_QUERY
);
383 short childrole
= mxChildContext
->getAccessibleRole();
384 if (childrole
== AccessibleRole::TEXT
)
386 if (IsEditable(mxChildContext
))
388 pAgent
->DecreaseState(m_xAccessible
.get(), AccessibleStateType::FOCUSED
);
389 pAgent
->IncreaseState( mxChild
.get(), AccessibleStateType::FOCUSED
);
390 pAgent
->NotifyAccEvent(UM_EVENT_STATE_FOCUSED
, mxChild
.get());
391 bSendFocusOnCombobox
= false;
396 if (bSendFocusOnCombobox
)
397 pAgent
->NotifyAccEvent(UM_EVENT_STATE_FOCUSED
, m_xAccessible
.get());
400 pAgent
->NotifyAccEvent(UM_EVENT_STATE_FOCUSED
, m_xAccessible
.get());
404 pAgent
->DecreaseState(m_xAccessible
.get(), AccessibleStateType::FOCUSED
);
405 //if the acc role is MENU_BAR, MSAA UM_EVENT_MENU_END event should be sent
406 //if the acc role is POPUP_MENU, MSAA UM_EVENT_MENUPOPUPEND event should be sent
407 if (GetRole() == AccessibleRole::MENU_BAR
)
409 pAgent
->NotifyAccEvent(UM_EVENT_MENU_END
, m_xAccessible
.get());
411 else if (GetRole() == AccessibleRole::POPUP_MENU
)
413 pAgent
->NotifyAccEvent(UM_EVENT_MENUPOPUPEND
, m_xAccessible
.get());
419 * handle the VALUE_CHANGED event
421 * @param oldValue the old value of the source of event
422 * @param newValue the new value of the source of event
424 void AccContainerEventListener::HandleValueChangedEvent(Any oldValue
, Any newValue
)
426 pAgent
->UpdateValue(m_xAccessible
.get());
427 pAgent
->NotifyAccEvent(UM_EVENT_OBJECT_VALUECHANGE
, m_xAccessible
.get());
430 bool AccContainerEventListener::IsEditable(Reference
<XAccessibleContext
> xContext
)
433 Reference
< XAccessibleStateSet
> pRState
= xContext
->getAccessibleStateSet();
437 Sequence
<short> pStates
= pRState
->getStates();
438 int count
= pStates
.getLength();
439 for( int iIndex
= 0;iIndex
< count
;iIndex
++ )
441 if(pStates
[iIndex
] == AccessibleStateType::EDITABLE
)
447 bool AccContainerEventListener::NotifyChildEvent(short nWinEvent
,const Any
&Value
)
449 Reference
< XAccessible
> xChild
;
450 if(Value
>>= xChild
)
454 XAccessible
* pAcc
= xChild
.get();
455 pAgent
->NotifyAccEvent(nWinEvent
, pAcc
);
462 void AccContainerEventListener::HandleSelectionChangedAddEvent(const Any
& /*oldValue*/, const Any
& newValue
)
464 if(NotifyChildEvent(UM_EVENT_SELECTION_CHANGED_ADD
,newValue
))
468 pAgent
->NotifyAccEvent(UM_EVENT_SELECTION_CHANGED_ADD
, m_xAccessible
.get());
471 void AccContainerEventListener::HandleSelectionChangedRemoveEvent(const Any
& /*oldValue*/, const Any
& newValue
)
473 if(NotifyChildEvent(UM_EVENT_SELECTION_CHANGED_REMOVE
,newValue
))
477 pAgent
->NotifyAccEvent(UM_EVENT_SELECTION_CHANGED_REMOVE
, m_xAccessible
.get());
480 void AccContainerEventListener::HandleSelectionChangedWithinEvent(const Any
& /*oldValue*/, const Any
& newValue
)
482 if(NotifyChildEvent(UM_EVENT_SELECTION_CHANGED_WITHIN
,newValue
))
486 pAgent
->NotifyAccEvent(UM_EVENT_SELECTION_CHANGED_WITHIN
, m_xAccessible
.get());
489 void AccContainerEventListener::UpdateAllChildrenState(XAccessible
* pXAccessible
)
491 Reference
<com::sun::star::accessibility::XAccessibleContext
> xContext(pXAccessible
->getAccessibleContext(),UNO_QUERY
);
496 com::sun::star::accessibility::XAccessibleContext
* pAccessibleContext
= xContext
.get();
497 if(pAccessibleContext
== NULL
)
502 if (pAgent
&& pAgent
->IsStateManageDescendant(pXAccessible
))
507 int count
= pAccessibleContext
->getAccessibleChildCount();
508 for (int i
=0;i
<count
;i
++)
510 Reference
<com::sun::star::accessibility::XAccessible
> mxAccessible
511 = pAccessibleContext
->getAccessibleChild(i
);
513 com::sun::star::accessibility::XAccessible
* mpAccessible
= mxAccessible
.get();
514 if(mpAccessible
!= NULL
)
516 pAgent
->UpdateState(mpAccessible
);
517 UpdateAllChildrenState(mpAccessible
);
522 void AccContainerEventListener::HandlePageChangedEvent(const Any
& /*oldValue*/, const Any
& /*newValue*/)
524 pAgent
->NotifyAccEvent(UM_EVENT_OBJECT_PAGECHANGED
, m_xAccessible
.get());
527 void AccContainerEventListener::HandleSectionChangedEvent(const Any
& /*oldValue*/, const Any
& /*newValue*/ )
529 pAgent
->NotifyAccEvent(UM_EVENT_SECTION_CHANGED
, m_xAccessible
.get());
532 void AccContainerEventListener::HandleColumnChangedEvent(const Any
& /*oldValue*/, const Any
& /*newValue*/)
534 pAgent
->NotifyAccEvent(UM_EVENT_COLUMN_CHANGED
, m_xAccessible
.get());
537 void AccContainerEventListener::HandleNameChangedEvent( Any name
)
539 if (GetRole() == AccessibleRole::COMBO_BOX
)
541 Reference
<XAccessibleContext
> mxContext(m_xAccessible
->getAccessibleContext());
544 Reference
<XAccessible
> mxChild
= mxContext
->getAccessibleChild(0);
547 Reference
<XAccessibleContext
> mxChildContext(mxChild
->getAccessibleContext(),UNO_QUERY
);
548 short childrole
= mxChildContext
->getAccessibleRole();
549 if (childrole
== AccessibleRole::TEXT
)
551 pAgent
->UpdateAccName(mxChild
.get(), name
);
556 AccEventListener::HandleNameChangedEvent(name
);
559 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */