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