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 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_accessibility.hxx"
26 #include <accessibility/extended/accessiblelistbox.hxx>
27 #include <accessibility/extended/accessiblelistboxentry.hxx>
28 #include <svtools/svtreebx.hxx>
29 #include <com/sun/star/awt/Point.hpp>
30 #include <com/sun/star/awt/Rectangle.hpp>
31 #include <com/sun/star/awt/Size.hpp>
32 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
33 #include <com/sun/star/accessibility/AccessibleRole.hpp>
34 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
35 #include <tools/debug.hxx>
36 #include <vcl/svapp.hxx>
37 #include <toolkit/awt/vclxwindow.hxx>
38 #include <toolkit/helper/convert.hxx>
39 #include <unotools/accessiblestatesethelper.hxx>
40 
41 //........................................................................
42 namespace accessibility
43 {
44 //........................................................................
45 
46 	// class AccessibleListBox -----------------------------------------------------
47 
48 	using namespace ::com::sun::star::accessibility;
49 	using namespace ::com::sun::star::uno;
50 	using namespace ::com::sun::star::lang;
51 	using namespace ::com::sun::star;
52 
53 	DBG_NAME(AccessibleListBox)
54 
55 	// -----------------------------------------------------------------------------
56 	// Ctor() and Dtor()
57 	// -----------------------------------------------------------------------------
58 	AccessibleListBox::AccessibleListBox( SvTreeListBox& _rListBox, const Reference< XAccessible >& _xParent ) :
59 
60 		VCLXAccessibleComponent( _rListBox.GetWindowPeer() ),
61 		m_xParent( _xParent )
62 	{
63 		DBG_CTOR( AccessibleListBox, NULL );
64 	}
65 	// -----------------------------------------------------------------------------
66 	AccessibleListBox::~AccessibleListBox()
67 	{
68 		DBG_DTOR( AccessibleListBox, NULL );
69 		if ( isAlive() )
70 		{
71 			// increment ref count to prevent double call of Dtor
72         	osl_incrementInterlockedCount( &m_refCount );
73         	dispose();
74 		}
75 	}
76 	IMPLEMENT_FORWARD_XINTERFACE2(AccessibleListBox, VCLXAccessibleComponent, AccessibleListBox_BASE)
77 	IMPLEMENT_FORWARD_XTYPEPROVIDER2(AccessibleListBox, VCLXAccessibleComponent, AccessibleListBox_BASE)
78 	// -----------------------------------------------------------------------------
79 	SvTreeListBox* AccessibleListBox::getListBox() const
80 	{
81 		return	static_cast< SvTreeListBox* >( const_cast<AccessibleListBox*>(this)->GetWindow() );
82 	}
83 	// -----------------------------------------------------------------------------
84 	void AccessibleListBox::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
85 	{
86     	if ( isAlive() )
87 		{
88 			switch ( rVclWindowEvent.GetId() )
89 			{
90 				case  VCLEVENT_CHECKBOX_TOGGLE :
91 				{
92 					if ( getListBox() && getListBox()->HasFocus() )
93 					{
94 						SvLBoxEntry* pEntry = static_cast< SvLBoxEntry* >( rVclWindowEvent.GetData() );
95 						if ( !pEntry )
96 							pEntry = getListBox()->GetCurEntry();
97 
98 						if ( pEntry )
99 						{
100 							Reference< XAccessible > xChild = new AccessibleListBoxEntry( *getListBox(), pEntry, this );
101 							uno::Any aOldValue, aNewValue;
102 							aNewValue <<= xChild;
103 							NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldValue, aNewValue );
104 						}
105 					}
106 					break;
107 				}
108 
109 				case VCLEVENT_LISTBOX_SELECT :
110 				{
111                     // First send an event that tells the listeners of a
112                     // modified selection.  The active descendant event is
113                     // send after that so that the receiving AT has time to
114                     // read the text or name of the active child.
115                     NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() );
116 					if ( getListBox() && getListBox()->HasFocus() )
117 					{
118 						SvLBoxEntry* pEntry = static_cast< SvLBoxEntry* >( rVclWindowEvent.GetData() );
119 						if ( pEntry )
120 						{
121 							Reference< XAccessible > xChild = new AccessibleListBoxEntry( *getListBox(), pEntry, this );
122 							uno::Any aOldValue, aNewValue;
123 							aNewValue <<= xChild;
124 							NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldValue, aNewValue );
125 						}
126 					}
127 					break;
128 
129                 // --> OD 2009-04-01 #i92103#
130                 case VCLEVENT_ITEM_EXPANDED :
131                 case VCLEVENT_ITEM_COLLAPSED :
132                 {
133                     SvLBoxEntry* pEntry = static_cast< SvLBoxEntry* >( rVclWindowEvent.GetData() );
134                     if ( pEntry )
135                     {
136                         AccessibleListBoxEntry* pAccListBoxEntry =
137                             new AccessibleListBoxEntry( *getListBox(), pEntry, this );
138                         Reference< XAccessible > xChild = pAccListBoxEntry;
139                         const short nAccEvent =
140                                 ( rVclWindowEvent.GetId() == VCLEVENT_ITEM_EXPANDED )
141                                 ? AccessibleEventId::LISTBOX_ENTRY_EXPANDED
142                                 : AccessibleEventId::LISTBOX_ENTRY_COLLAPSED;
143                         uno::Any aListBoxEntry;
144                         aListBoxEntry <<= xChild;
145                         NotifyAccessibleEvent( nAccEvent, Any(), aListBoxEntry );
146                         if ( getListBox() && getListBox()->HasFocus() )
147                         {
148                             NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, Any(), aListBoxEntry );
149                         }
150                     }
151                     break;
152                 }
153                 // <--
154                 }
155 				default:
156 					VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent);
157 			}
158 		}
159 	}
160 	// -----------------------------------------------------------------------------
161     void AccessibleListBox::ProcessWindowChildEvent( const VclWindowEvent& rVclWindowEvent )
162     {
163         switch ( rVclWindowEvent.GetId() )
164         {
165             case VCLEVENT_WINDOW_SHOW:
166             case VCLEVENT_WINDOW_HIDE:
167             {
168             }
169             break;
170             default:
171             {
172                 VCLXAccessibleComponent::ProcessWindowChildEvent( rVclWindowEvent );
173             }
174             break;
175         }
176     }
177 
178 	// -----------------------------------------------------------------------------
179 	// XComponent
180 	// -----------------------------------------------------------------------------
181 	void SAL_CALL AccessibleListBox::disposing()
182 	{
183 		::osl::MutexGuard aGuard( m_aMutex );
184 
185 		VCLXAccessibleComponent::disposing();
186 	    m_xParent = NULL;
187 	}
188 	// -----------------------------------------------------------------------------
189 	// XServiceInfo
190 	// -----------------------------------------------------------------------------
191 	::rtl::OUString SAL_CALL AccessibleListBox::getImplementationName() throw(RuntimeException)
192 	{
193 		return getImplementationName_Static();
194 	}
195 	// -----------------------------------------------------------------------------
196 	Sequence< ::rtl::OUString > SAL_CALL AccessibleListBox::getSupportedServiceNames() throw(RuntimeException)
197 	{
198 		return getSupportedServiceNames_Static();
199 	}
200 	// -----------------------------------------------------------------------------
201 	sal_Bool SAL_CALL AccessibleListBox::supportsService( const ::rtl::OUString& _rServiceName ) throw (RuntimeException)
202 	{
203 		Sequence< ::rtl::OUString > aSupported( getSupportedServiceNames() );
204 		const ::rtl::OUString* pSupported = aSupported.getConstArray();
205 		const ::rtl::OUString* pEnd = pSupported + aSupported.getLength();
206 		for ( ; pSupported != pEnd && !pSupported->equals(_rServiceName); ++pSupported )
207 			;
208 
209 		return pSupported != pEnd;
210 	}
211 	// -----------------------------------------------------------------------------
212 	// XServiceInfo - static methods
213 	// -----------------------------------------------------------------------------
214 	Sequence< ::rtl::OUString > AccessibleListBox::getSupportedServiceNames_Static(void) throw( RuntimeException )
215 	{
216 		Sequence< ::rtl::OUString > aSupported(3);
217 		aSupported[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.accessibility.AccessibleContext") );
218 		aSupported[1] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.accessibility.AccessibleComponent") );
219 		aSupported[2] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.awt.AccessibleTreeListBox") );
220 		return aSupported;
221 	}
222 	// -----------------------------------------------------------------------------
223 	::rtl::OUString AccessibleListBox::getImplementationName_Static(void) throw( RuntimeException )
224 	{
225 		return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.svtools.AccessibleTreeListBox") );
226 	}
227 	// -----------------------------------------------------------------------------
228 	// XAccessible
229 	// -----------------------------------------------------------------------------
230 	Reference< XAccessibleContext > SAL_CALL AccessibleListBox::getAccessibleContext(  ) throw (RuntimeException)
231 	{
232 		ensureAlive();
233 		return this;
234 	}
235 	// -----------------------------------------------------------------------------
236 	// XAccessibleContext
237 	// -----------------------------------------------------------------------------
238 	sal_Int32 SAL_CALL AccessibleListBox::getAccessibleChildCount(  ) throw (RuntimeException)
239 	{
240 		::comphelper::OExternalLockGuard aGuard( this );
241 
242 		ensureAlive();
243 
244         sal_Int32 nCount = 0;
245         SvTreeListBox* pSvTreeListBox = getListBox();
246         if ( pSvTreeListBox )
247             nCount = pSvTreeListBox->GetLevelChildCount( NULL );
248 
249         return nCount;
250 	}
251 	// -----------------------------------------------------------------------------
252 	Reference< XAccessible > SAL_CALL AccessibleListBox::getAccessibleChild( sal_Int32 i ) throw (IndexOutOfBoundsException,RuntimeException)
253 	{
254 		::comphelper::OExternalLockGuard aGuard( this );
255 
256 		ensureAlive();
257 		SvLBoxEntry* pEntry = getListBox()->GetEntry(i);
258 		if ( !pEntry )
259 			throw IndexOutOfBoundsException();
260 
261 		return new AccessibleListBoxEntry( *getListBox(), pEntry, this );
262 	}
263 	// -----------------------------------------------------------------------------
264 	Reference< XAccessible > SAL_CALL AccessibleListBox::getAccessibleParent(  ) throw (RuntimeException)
265 	{
266 		::osl::MutexGuard aGuard( m_aMutex );
267 
268 		ensureAlive();
269 		return m_xParent;
270 	}
271 	// -----------------------------------------------------------------------------
272 	sal_Int16 SAL_CALL AccessibleListBox::getAccessibleRole(  ) throw (RuntimeException)
273 	{
274 		return AccessibleRole::TREE;
275 	}
276 	// -----------------------------------------------------------------------------
277 	::rtl::OUString SAL_CALL AccessibleListBox::getAccessibleDescription(  ) throw (RuntimeException)
278 	{
279 		::comphelper::OExternalLockGuard aGuard( this );
280 
281 		ensureAlive();
282 		return getListBox()->GetAccessibleDescription();
283 	}
284 	// -----------------------------------------------------------------------------
285 	::rtl::OUString SAL_CALL AccessibleListBox::getAccessibleName(  ) throw (RuntimeException)
286 	{
287 		::comphelper::OExternalLockGuard aGuard( this );
288 
289 		ensureAlive();
290 		return getListBox()->GetAccessibleName();
291 	}
292 	// -----------------------------------------------------------------------------
293 	// XAccessibleSelection
294 	// -----------------------------------------------------------------------------
295 	void SAL_CALL AccessibleListBox::selectAccessibleChild( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
296 	{
297     	::comphelper::OExternalLockGuard aGuard( this );
298 
299 		ensureAlive();
300 
301 		SvLBoxEntry* pEntry = getListBox()->GetEntry( nChildIndex );
302 		if ( !pEntry )
303 			throw IndexOutOfBoundsException();
304 
305 		getListBox()->Select( pEntry, sal_True );
306 	}
307 	// -----------------------------------------------------------------------------
308 	sal_Bool SAL_CALL AccessibleListBox::isAccessibleChildSelected( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
309 	{
310     	::comphelper::OExternalLockGuard aGuard( this );
311 
312 		ensureAlive();
313 
314 		SvLBoxEntry* pEntry = getListBox()->GetEntry( nChildIndex );
315 		if ( !pEntry )
316 			throw IndexOutOfBoundsException();
317 
318 		return getListBox()->IsSelected( pEntry );
319 	}
320 	// -----------------------------------------------------------------------------
321 	void SAL_CALL AccessibleListBox::clearAccessibleSelection(  ) throw (RuntimeException)
322 	{
323     	::comphelper::OExternalLockGuard aGuard( this );
324 
325 		ensureAlive();
326 
327     	sal_Int32 i, nCount = 0;
328 		nCount = getListBox()->GetLevelChildCount( NULL );
329 		for ( i = 0; i < nCount; ++i )
330 		{
331 			SvLBoxEntry* pEntry = getListBox()->GetEntry( i );
332 			if ( getListBox()->IsSelected( pEntry ) )
333 				getListBox()->Select( pEntry, sal_False );
334 		}
335 	}
336 	// -----------------------------------------------------------------------------
337 	void SAL_CALL AccessibleListBox::selectAllAccessibleChildren(  ) throw (RuntimeException)
338 	{
339     	::comphelper::OExternalLockGuard aGuard( this );
340 
341 		ensureAlive();
342 
343     	sal_Int32 i, nCount = 0;
344 		nCount = getListBox()->GetLevelChildCount( NULL );
345 		for ( i = 0; i < nCount; ++i )
346 		{
347 			SvLBoxEntry* pEntry = getListBox()->GetEntry( i );
348 			if ( !getListBox()->IsSelected( pEntry ) )
349 				getListBox()->Select( pEntry, sal_True );
350 		}
351 	}
352 	// -----------------------------------------------------------------------------
353 	sal_Int32 SAL_CALL AccessibleListBox::getSelectedAccessibleChildCount(  ) throw (RuntimeException)
354 	{
355     	::comphelper::OExternalLockGuard aGuard( this );
356 
357 		ensureAlive();
358 
359     	sal_Int32 i, nSelCount = 0, nCount = 0;
360 		nCount = getListBox()->GetLevelChildCount( NULL );
361 		for ( i = 0; i < nCount; ++i )
362 		{
363 			SvLBoxEntry* pEntry = getListBox()->GetEntry( i );
364 			if ( getListBox()->IsSelected( pEntry ) )
365 				++nSelCount;
366 		}
367 
368     	return nSelCount;
369 	}
370 	// -----------------------------------------------------------------------------
371 	Reference< XAccessible > SAL_CALL AccessibleListBox::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
372 	{
373     	::comphelper::OExternalLockGuard aGuard( this );
374 
375 		ensureAlive();
376 
377 		if ( nSelectedChildIndex < 0 || nSelectedChildIndex >= getSelectedAccessibleChildCount() )
378 			throw IndexOutOfBoundsException();
379 
380 		Reference< XAccessible > xChild;
381     	sal_Int32 i, nSelCount = 0, nCount = 0;
382 		nCount = getListBox()->GetLevelChildCount( NULL );
383 		for ( i = 0; i < nCount; ++i )
384 		{
385 			SvLBoxEntry* pEntry = getListBox()->GetEntry( i );
386 			if ( getListBox()->IsSelected( pEntry ) )
387 				++nSelCount;
388 
389 			if ( nSelCount == ( nSelectedChildIndex + 1 ) )
390 			{
391 				xChild = new AccessibleListBoxEntry( *getListBox(), pEntry, this );
392 				break;
393 			}
394 		}
395 
396 		return xChild;
397 	}
398 	// -----------------------------------------------------------------------------
399 	void SAL_CALL AccessibleListBox::deselectAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
400 	{
401     	::comphelper::OExternalLockGuard aGuard( this );
402 
403 		ensureAlive();
404 
405 		SvLBoxEntry* pEntry = getListBox()->GetEntry( nSelectedChildIndex );
406 		if ( !pEntry )
407 			throw IndexOutOfBoundsException();
408 
409 		getListBox()->Select( pEntry, sal_False );
410 	}
411 	// -----------------------------------------------------------------------------
412 	void AccessibleListBox::FillAccessibleStateSet( utl::AccessibleStateSetHelper& rStateSet )
413 	{
414 		VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet );
415 		if ( getListBox() && isAlive() )
416 		{
417 			rStateSet.AddState( AccessibleStateType::FOCUSABLE );
418 			rStateSet.AddState( AccessibleStateType::MANAGES_DESCENDANTS );
419 			if ( getListBox()->GetSelectionMode() == MULTIPLE_SELECTION )
420 				rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE );
421 		}
422 	}
423 
424 
425 //........................................................................
426 }// namespace accessibility
427 //........................................................................
428 
429