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 #include "documentfocuslistener.hxx"
25
26 #ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLEEVENTBROADCASTER_HPP_
27 #include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
28 #endif
29
30 #ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLEEVENTID_HPP_
31 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
32 #endif
33
34 #ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLESTATETYPE_HPP_
35 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
36 #endif
37
38 using namespace ::com::sun::star::accessibility;
39 using namespace ::com::sun::star::lang;
40 using namespace ::com::sun::star::uno;
41
42
43 //------------------------------------------------------------------------------
44
DocumentFocusListener(AquaA11yFocusTracker & rTracker)45 DocumentFocusListener::DocumentFocusListener(AquaA11yFocusTracker& rTracker) :
46 m_aFocusTracker(rTracker)
47 {
48 }
49
50 //------------------------------------------------------------------------------
51
52 void SAL_CALL
disposing(const EventObject & aEvent)53 DocumentFocusListener::disposing( const EventObject& aEvent )
54 throw (RuntimeException)
55 {
56 // Unref the object here, but do not remove as listener since the object
57 // might no longer be in a state that safely allows this.
58 if( aEvent.Source.is() )
59 m_aRefList.erase(aEvent.Source);
60 }
61
62 //------------------------------------------------------------------------------
63
64 void SAL_CALL
notifyEvent(const AccessibleEventObject & aEvent)65 DocumentFocusListener::notifyEvent( const AccessibleEventObject& aEvent )
66 throw( RuntimeException )
67 {
68 try {
69 switch( aEvent.EventId )
70 {
71 case AccessibleEventId::STATE_CHANGED:
72 {
73 sal_Int16 nState = AccessibleStateType::INVALID;
74 aEvent.NewValue >>= nState;
75
76 if( AccessibleStateType::FOCUSED == nState )
77 m_aFocusTracker.setFocusedObject( getAccessible(aEvent) );
78 }
79 break;
80
81 case AccessibleEventId::CHILD:
82 {
83 Reference< XAccessible > xChild;
84 if( (aEvent.OldValue >>= xChild) && xChild.is() )
85 detachRecursive(xChild);
86
87 if( (aEvent.NewValue >>= xChild) && xChild.is() )
88 attachRecursive(xChild);
89 }
90 break;
91
92 case AccessibleEventId::INVALIDATE_ALL_CHILDREN:
93 {
94 Reference< XAccessible > xAccessible( getAccessible(aEvent) );
95 detachRecursive(xAccessible);
96 attachRecursive(xAccessible);
97 }
98 OSL_TRACE( "Invalidate all children called\n" );
99 break;
100
101 default:
102 break;
103 }
104 }
105 catch(IndexOutOfBoundsException e)
106 {
107 OSL_TRACE("Focused object has invalid index in parent");
108 }
109 }
110
111 //------------------------------------------------------------------------------
112
getAccessible(const EventObject & aEvent)113 Reference< XAccessible > DocumentFocusListener::getAccessible(const EventObject& aEvent )
114 throw (IndexOutOfBoundsException, RuntimeException)
115 {
116 Reference< XAccessible > xAccessible(aEvent.Source, UNO_QUERY);
117
118 if( xAccessible.is() )
119 return xAccessible;
120
121 Reference< XAccessibleContext > xContext(aEvent.Source, UNO_QUERY);
122
123 if( xContext.is() )
124 {
125 Reference< XAccessible > xParent( xContext->getAccessibleParent() );
126 if( xParent.is() )
127 {
128 Reference< XAccessibleContext > xParentContext( xParent->getAccessibleContext() );
129 if( xParentContext.is() )
130 {
131 return xParentContext->getAccessibleChild( xContext->getAccessibleIndexInParent() );
132 }
133 }
134 }
135
136 return Reference< XAccessible >();
137 }
138
139 //------------------------------------------------------------------------------
140
attachRecursive(const Reference<XAccessible> & xAccessible)141 void DocumentFocusListener::attachRecursive(const Reference< XAccessible >& xAccessible)
142 throw (IndexOutOfBoundsException, RuntimeException)
143 {
144 Reference< XAccessibleContext > xContext = xAccessible->getAccessibleContext();
145
146 if( xContext.is() )
147 attachRecursive(xAccessible, xContext);
148 }
149
150 //------------------------------------------------------------------------------
151
attachRecursive(const Reference<XAccessible> & xAccessible,const Reference<XAccessibleContext> & xContext)152 void DocumentFocusListener::attachRecursive(
153 const Reference< XAccessible >& xAccessible,
154 const Reference< XAccessibleContext >& xContext
155 ) throw (IndexOutOfBoundsException, RuntimeException)
156 {
157 if( xContext.is() )
158 {
159 Reference< XAccessibleStateSet > xStateSet = xContext->getAccessibleStateSet();
160
161 if( xStateSet.is() )
162 attachRecursive(xAccessible, xContext, xStateSet);
163 }
164 }
165
166 //------------------------------------------------------------------------------
167
attachRecursive(const Reference<XAccessible> & xAccessible,const Reference<XAccessibleContext> & xContext,const Reference<XAccessibleStateSet> & xStateSet)168 void DocumentFocusListener::attachRecursive(
169 const Reference< XAccessible >& xAccessible,
170 const Reference< XAccessibleContext >& xContext,
171 const Reference< XAccessibleStateSet >& xStateSet
172 ) throw (IndexOutOfBoundsException,RuntimeException)
173 {
174 if( xStateSet->contains(AccessibleStateType::FOCUSED ) )
175 m_aFocusTracker.setFocusedObject( xAccessible );
176
177 Reference< XAccessibleEventBroadcaster > xBroadcaster =
178 Reference< XAccessibleEventBroadcaster >(xContext, UNO_QUERY);
179
180 // If not already done, add the broadcaster to the list and attach as listener.
181 if( xBroadcaster.is() && m_aRefList.insert(xBroadcaster).second )
182 {
183 xBroadcaster->addEventListener(static_cast< XAccessibleEventListener *>(this));
184
185 if( ! xStateSet->contains(AccessibleStateType::MANAGES_DESCENDANTS ) )
186 {
187 sal_Int32 n, nmax = xContext->getAccessibleChildCount();
188 for( n = 0; n < nmax; n++ )
189 {
190 Reference< XAccessible > xChild( xContext->getAccessibleChild( n ) );
191
192 if( xChild.is() )
193 attachRecursive(xChild);
194 }
195 }
196 }
197 }
198
199 //------------------------------------------------------------------------------
200
detachRecursive(const Reference<XAccessible> & xAccessible)201 void DocumentFocusListener::detachRecursive(const Reference< XAccessible >& xAccessible)
202 throw (IndexOutOfBoundsException, RuntimeException)
203 {
204 Reference< XAccessibleContext > xContext = xAccessible->getAccessibleContext();
205
206 if( xContext.is() )
207 detachRecursive(xAccessible, xContext);
208 }
209
210 //------------------------------------------------------------------------------
211
detachRecursive(const Reference<XAccessible> & xAccessible,const Reference<XAccessibleContext> & xContext)212 void DocumentFocusListener::detachRecursive(
213 const Reference< XAccessible >& xAccessible,
214 const Reference< XAccessibleContext >& xContext
215 ) throw (IndexOutOfBoundsException, RuntimeException)
216 {
217 Reference< XAccessibleStateSet > xStateSet = xContext->getAccessibleStateSet();
218
219 if( xStateSet.is() )
220 detachRecursive(xAccessible, xContext, xStateSet);
221 }
222
223 //------------------------------------------------------------------------------
224
detachRecursive(const Reference<XAccessible> &,const Reference<XAccessibleContext> & xContext,const Reference<XAccessibleStateSet> & xStateSet)225 void DocumentFocusListener::detachRecursive(
226 const Reference< XAccessible >&,
227 const Reference< XAccessibleContext >& xContext,
228 const Reference< XAccessibleStateSet >& xStateSet
229 ) throw (IndexOutOfBoundsException, RuntimeException)
230 {
231 Reference< XAccessibleEventBroadcaster > xBroadcaster =
232 Reference< XAccessibleEventBroadcaster >(xContext, UNO_QUERY);
233
234 if( xBroadcaster.is() && 0 < m_aRefList.erase(xBroadcaster) )
235 {
236 xBroadcaster->removeEventListener(static_cast< XAccessibleEventListener *>(this));
237
238 if( ! xStateSet->contains(AccessibleStateType::MANAGES_DESCENDANTS ) )
239 {
240 sal_Int32 n, nmax = xContext->getAccessibleChildCount();
241 for( n = 0; n < nmax; n++ )
242 {
243 Reference< XAccessible > xChild( xContext->getAccessibleChild( n ) );
244
245 if( xChild.is() )
246 detachRecursive(xChild);
247 }
248 }
249 }
250 }
251