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