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 
31 #ifndef ACCESSIBILITY_EXT_ACCESSIBLETABLISTBOXTABLE_HXX_
32 #include "accessibility/extended/accessibletablistboxtable.hxx"
33 #endif
34 #include "accessibility/extended/AccessibleBrowseBoxTableCell.hxx"
35 #include "accessibility/extended/AccessibleBrowseBoxCheckBoxCell.hxx"
36 #include <svtools/svtabbx.hxx>
37 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
38 
39 //........................................................................
40 namespace accessibility
41 {
42 //........................................................................
43 
44 	// class TLBSolarGuard ---------------------------------------------------------
45 
46 	/** Aquire the solar mutex. */
47 	class TLBSolarGuard : public ::vos::OGuard
48 	{
49 	public:
50     	inline TLBSolarGuard() : ::vos::OGuard( Application::GetSolarMutex() ) {}
51 	};
52 
53 	// class AccessibleTabListBoxTable ---------------------------------------------
54 
55 	using namespace ::com::sun::star::accessibility;
56 	using namespace ::com::sun::star::uno;
57 	using namespace ::com::sun::star::lang;
58 	using namespace ::com::sun::star;
59 
60 	DBG_NAME(AccessibleTabListBoxTable)
61 
62 	// -----------------------------------------------------------------------------
63 	// Ctor() and Dtor()
64 	// -----------------------------------------------------------------------------
65 	AccessibleTabListBoxTable::AccessibleTabListBoxTable( const Reference< XAccessible >& rxParent, SvHeaderTabListBox& rBox ) :
66 
67 		AccessibleBrowseBoxTable( rxParent, rBox ),
68 
69 		m_pTabListBox	( &rBox )
70 
71 	{
72 		DBG_CTOR( AccessibleTabListBoxTable, NULL );
73 
74 		m_pTabListBox->AddEventListener( LINK( this, AccessibleTabListBoxTable, WindowEventListener ) );
75 	}
76 	// -----------------------------------------------------------------------------
77 	AccessibleTabListBoxTable::~AccessibleTabListBoxTable()
78 	{
79 		DBG_DTOR( AccessibleTabListBoxTable, NULL );
80 
81 		if ( isAlive() )
82 		{
83 			m_pTabListBox = NULL;
84 
85 			// increment ref count to prevent double call of Dtor
86         	osl_incrementInterlockedCount( &m_refCount );
87         	dispose();
88 		}
89 	}
90 	// -----------------------------------------------------------------------------
91 	void AccessibleTabListBoxTable::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
92 	{
93     	if ( isAlive() )
94 		{
95             sal_uLong nEventId = rVclWindowEvent.GetId();
96             switch ( nEventId )
97             {
98 				case  VCLEVENT_OBJECT_DYING :
99 				{
100 					m_pTabListBox->RemoveEventListener( LINK( this, AccessibleTabListBoxTable, WindowEventListener ) );
101 					m_pTabListBox = NULL;
102 					break;
103 				}
104 
105                 case VCLEVENT_CONTROL_GETFOCUS :
106                 case VCLEVENT_CONTROL_LOSEFOCUS :
107                 {
108                     uno::Any aOldValue, aNewValue;
109                     if ( VCLEVENT_CONTROL_GETFOCUS == nEventId )
110                         aNewValue <<= AccessibleStateType::FOCUSED;
111                     else
112                         aOldValue <<= AccessibleStateType::FOCUSED;
113                     commitEvent( AccessibleEventId::STATE_CHANGED, aNewValue, aOldValue );
114                     break;
115                 }
116 
117                 case VCLEVENT_LISTBOX_SELECT :
118 				{
119                     // First send an event that tells the listeners of a
120                     // modified selection.  The active descendant event is
121                     // send after that so that the receiving AT has time to
122                     // read the text or name of the active child.
123 					commitEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() );
124 					if ( m_pTabListBox && m_pTabListBox->HasFocus() )
125 					{
126                         SvLBoxEntry* pEntry = static_cast< SvLBoxEntry* >( rVclWindowEvent.GetData() );
127 						if ( pEntry )
128 						{
129 							sal_Int32 nRow = m_pTabListBox->GetEntryPos( pEntry );
130                             sal_uInt16 nCol = m_pTabListBox->GetCurrColumn();
131                             Reference< XAccessible > xChild =
132                                 m_pTabListBox->CreateAccessibleCell( nRow, nCol );
133 							uno::Any aOldValue, aNewValue;
134 
135                             if ( m_pTabListBox->IsTransientChildrenDisabled() )
136                             {
137                                 aNewValue <<= AccessibleStateType::FOCUSED;
138                                 TriState eState = STATE_DONTKNOW;
139                                 if ( m_pTabListBox->IsCellCheckBox( nRow, nCol, eState ) )
140                                 {
141                                     AccessibleCheckBoxCell* pCell =
142                                         static_cast< AccessibleCheckBoxCell* >( xChild.get() );
143                                     pCell->commitEvent( AccessibleEventId::STATE_CHANGED, aNewValue, aOldValue );
144                                 }
145                                 else
146                                 {
147                                     AccessibleBrowseBoxTableCell* pCell =
148                                         static_cast< AccessibleBrowseBoxTableCell* >( xChild.get() );
149                                     pCell->commitEvent( AccessibleEventId::STATE_CHANGED, aNewValue, aOldValue );
150                                 }
151                             }
152                             else
153                             {
154                                 aNewValue <<= xChild;
155                                 commitEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aNewValue, aOldValue );
156                             }
157 						}
158 					}
159 					break;
160 				}
161 
162                 case VCLEVENT_CHECKBOX_TOGGLE :
163                 {
164                     if ( m_pTabListBox && m_pTabListBox->HasFocus() )
165                     {
166                         SvLBoxEntry* pEntry = static_cast< SvLBoxEntry* >( rVclWindowEvent.GetData() );
167                         if ( pEntry )
168                         {
169                             sal_Int32 nRow = m_pTabListBox->GetEntryPos( pEntry );
170                             sal_uInt16 nCol = m_pTabListBox->GetCurrColumn();
171                             TriState eState = STATE_DONTKNOW;
172                             if ( m_pTabListBox->IsCellCheckBox( nRow, nCol, eState ) )
173                             {
174                                 Reference< XAccessible > xChild =
175                                     m_pTabListBox->CreateAccessibleCell( nRow, nCol );
176                                 AccessibleCheckBoxCell* pCell =
177                                     static_cast< AccessibleCheckBoxCell* >( xChild.get() );
178                                 pCell->SetChecked( m_pTabListBox->IsItemChecked( pEntry, nCol ) );
179                             }
180                         }
181                     }
182                     break;
183                 }
184 
185                 case VCLEVENT_TABLECELL_NAMECHANGED :
186                 {
187                     if ( m_pTabListBox->IsTransientChildrenDisabled() )
188                     {
189                         commitEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() );
190                         TabListBoxEventData* pData = static_cast< TabListBoxEventData* >( rVclWindowEvent.GetData() );
191                         SvLBoxEntry* pEntry = pData != NULL ? pData->m_pEntry : NULL;
192                         if ( pEntry )
193                         {
194                             sal_Int32 nRow = m_pTabListBox->GetEntryPos( pEntry );
195                             sal_uInt16 nCol = pData->m_nColumn;
196                             Reference< XAccessible > xChild =
197                                 m_pTabListBox->CreateAccessibleCell( nRow, nCol );
198                             uno::Any aOldValue, aNewValue;
199                             aOldValue <<= ::rtl::OUString( pData->m_sOldText );
200                             ::rtl::OUString sNewText( m_pTabListBox->GetCellText( nRow, nCol ) );
201                             aNewValue <<= sNewText;
202                             TriState eState = STATE_DONTKNOW;
203 
204                             if ( m_pTabListBox->IsCellCheckBox( nRow, nCol, eState ) )
205                             {
206                                 AccessibleCheckBoxCell* pCell =
207                                     static_cast< AccessibleCheckBoxCell* >( xChild.get() );
208                                 pCell->commitEvent( AccessibleEventId::NAME_CHANGED, aOldValue, aNewValue );
209                             }
210                             else
211                             {
212                                 AccessibleBrowseBoxTableCell* pCell =
213                                     static_cast< AccessibleBrowseBoxTableCell* >( xChild.get() );
214                                 pCell->nameChanged( sNewText, pData->m_sOldText );
215                             }
216                         }
217                     }
218                     break;
219                 }
220 			}
221 		}
222 	}
223 	// -----------------------------------------------------------------------------
224 	IMPL_LINK( AccessibleTabListBoxTable, WindowEventListener, VclSimpleEvent*, pEvent )
225 	{
226     	DBG_ASSERT( pEvent && pEvent->ISA( VclWindowEvent ), "Unknown WindowEvent!" );
227     	if ( pEvent && pEvent->ISA( VclWindowEvent ) )
228     	{
229         	DBG_ASSERT( ( (VclWindowEvent*)pEvent )->GetWindow() && m_pTabListBox, "no event window" );
230         	ProcessWindowEvent( *(VclWindowEvent*)pEvent );
231     	}
232     	return 0;
233 	}
234 	// helpers --------------------------------------------------------------------
235 
236 	void AccessibleTabListBoxTable::ensureValidIndex( sal_Int32 _nIndex ) const
237 	        SAL_THROW( ( IndexOutOfBoundsException ) )
238 	{
239 	    if ( ( _nIndex < 0 ) || ( _nIndex >= implGetCellCount() ) )
240 	        throw IndexOutOfBoundsException();
241 	}
242 
243 	sal_Bool AccessibleTabListBoxTable::implIsRowSelected( sal_Int32 _nRow ) const
244 	{
245 	    return m_pTabListBox ? m_pTabListBox->IsSelected( m_pTabListBox->GetEntry( _nRow ) ) : sal_False;
246 	}
247 
248 	void AccessibleTabListBoxTable::implSelectRow( sal_Int32 _nRow, sal_Bool _bSelect )
249 	{
250 		if ( m_pTabListBox )
251 		    m_pTabListBox->Select( m_pTabListBox->GetEntry( _nRow ), _bSelect );
252 	}
253 
254 	sal_Int32 AccessibleTabListBoxTable::implGetRowCount() const
255 	{
256 	    return m_pTabListBox ? m_pTabListBox->GetEntryCount() : 0;
257 	}
258 
259 	sal_Int32 AccessibleTabListBoxTable::implGetColumnCount() const
260 	{
261 	    return m_pTabListBox ? m_pTabListBox->GetColumnCount() : 0;
262 	}
263 
264 	sal_Int32 AccessibleTabListBoxTable::implGetSelRowCount() const
265 	{
266 	    return m_pTabListBox ? m_pTabListBox->GetSelectionCount() : 0;
267 	}
268 
269 	sal_Int32 AccessibleTabListBoxTable::implGetSelRow( sal_Int32 nSelRow ) const
270 	{
271 		if ( m_pTabListBox )
272 		{
273 		    sal_Int32 nRow = 0;
274 			SvLBoxEntry* pEntry = m_pTabListBox->FirstSelected();
275 			while ( pEntry )
276 			{
277 				++nRow;
278 				if ( nRow == nSelRow )
279 					return m_pTabListBox->GetEntryPos( pEntry );
280 				pEntry = m_pTabListBox->NextSelected( pEntry );
281 			}
282 		}
283 
284 		return 0;
285 	}
286 	// -----------------------------------------------------------------------------
287 	// XInterface & XTypeProvider
288 	// -----------------------------------------------------------------------------
289 	IMPLEMENT_FORWARD_XINTERFACE2(AccessibleTabListBoxTable, AccessibleBrowseBoxTable, AccessibleTabListBoxTableImplHelper)
290 	IMPLEMENT_FORWARD_XTYPEPROVIDER2(AccessibleTabListBoxTable, AccessibleBrowseBoxTable, AccessibleTabListBoxTableImplHelper)
291 	// -----------------------------------------------------------------------------
292 	// XServiceInfo
293 	// -----------------------------------------------------------------------------
294 	::rtl::OUString AccessibleTabListBoxTable::getImplementationName (void) throw (RuntimeException)
295 	{
296 		return ::rtl::OUString::createFromAscii("com.sun.star.comp.svtools.AccessibleTabListBoxTable");
297 	}
298 	// -----------------------------------------------------------------------------
299 	// XAccessibleSelection
300 	// -----------------------------------------------------------------------------
301 	void SAL_CALL AccessibleTabListBoxTable::selectAccessibleChild( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
302 	{
303     	TLBSolarGuard aSolarGuard;
304 		::osl::MutexGuard aGuard( getOslMutex() );
305 
306 		ensureIsAlive();
307 	    ensureValidIndex( nChildIndex );
308 
309 		implSelectRow( implGetRow( nChildIndex ), sal_True );
310 	}
311 	// -----------------------------------------------------------------------------
312 	sal_Bool SAL_CALL AccessibleTabListBoxTable::isAccessibleChildSelected( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
313 	{
314     	TLBSolarGuard aSolarGuard;
315 		::osl::MutexGuard aGuard( getOslMutex() );
316 
317 		ensureIsAlive();
318 	    ensureValidIndex( nChildIndex );
319 
320 	    return implIsRowSelected( implGetRow( nChildIndex ) );
321 	}
322 	// -----------------------------------------------------------------------------
323 	void SAL_CALL AccessibleTabListBoxTable::clearAccessibleSelection(  ) throw (RuntimeException)
324 	{
325     	TLBSolarGuard aSolarGuard;
326 		::osl::MutexGuard aGuard( getOslMutex() );
327 
328 		ensureIsAlive();
329 
330 		m_pTabListBox->SetNoSelection();
331 	}
332 	// -----------------------------------------------------------------------------
333 	void SAL_CALL AccessibleTabListBoxTable::selectAllAccessibleChildren(  ) throw (RuntimeException)
334 	{
335     	TLBSolarGuard aSolarGuard;
336 		::osl::MutexGuard aGuard( getOslMutex() );
337 
338 		ensureIsAlive();
339 
340 		m_pTabListBox->SelectAll();
341 	}
342 	// -----------------------------------------------------------------------------
343 	sal_Int32 SAL_CALL AccessibleTabListBoxTable::getSelectedAccessibleChildCount(  ) throw (RuntimeException)
344 	{
345     	TLBSolarGuard aSolarGuard;
346 		::osl::MutexGuard aGuard( getOslMutex() );
347 
348 		ensureIsAlive();
349 
350 	    return implGetColumnCount() * implGetSelRowCount();
351 	}
352 	// -----------------------------------------------------------------------------
353 	Reference< XAccessible > SAL_CALL AccessibleTabListBoxTable::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
354 	{
355     	TLBSolarGuard aSolarGuard;
356 		::osl::MutexGuard aGuard( getOslMutex() );
357 
358 		ensureIsAlive();
359 
360 	    sal_Int32 nRows = implGetSelRowCount();
361 	    if ( nRows == 0 )
362 	        throw IndexOutOfBoundsException();
363 
364 	    sal_Int32 nRow = implGetSelRow( nSelectedChildIndex % nRows );
365 	    sal_Int32 nColumn = nSelectedChildIndex / nRows;
366 	    return getAccessibleCellAt( nRow, nColumn );
367 	}
368 	// -----------------------------------------------------------------------------
369 	void SAL_CALL AccessibleTabListBoxTable::deselectAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
370 	{
371     	TLBSolarGuard aSolarGuard;
372 		::osl::MutexGuard aGuard( getOslMutex() );
373 
374 		ensureIsAlive();
375 	    ensureValidIndex( nSelectedChildIndex );
376 
377 		implSelectRow( implGetRow( nSelectedChildIndex ), sal_False );
378 	}
379 
380 //........................................................................
381 }// namespace accessibility
382 //........................................................................
383 
384