1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 
21 #include <extended/accessibletablistboxtable.hxx>
22 #include <extended/AccessibleBrowseBoxTableCell.hxx>
23 #include <extended/AccessibleBrowseBoxCheckBoxCell.hxx>
24 #include <vcl/svtabbx.hxx>
25 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
26 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
27 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
28 
29 
30 namespace accessibility
31 {
32 
33 
34     // class AccessibleTabListBoxTable ---------------------------------------------
35 
36     using namespace ::com::sun::star::accessibility;
37     using namespace ::com::sun::star::uno;
38     using namespace ::com::sun::star::lang;
39     using namespace ::com::sun::star;
40 
41 
42     // Ctor() and Dtor()
43 
AccessibleTabListBoxTable(const Reference<XAccessible> & rxParent,SvHeaderTabListBox & rBox)44     AccessibleTabListBoxTable::AccessibleTabListBoxTable( const Reference< XAccessible >& rxParent, SvHeaderTabListBox& rBox ) :
45 
46         AccessibleBrowseBoxTable( rxParent, rBox ),
47 
48         m_pTabListBox   ( &rBox )
49 
50     {
51         m_pTabListBox->AddEventListener( LINK( this, AccessibleTabListBoxTable, WindowEventListener ) );
52     }
53 
~AccessibleTabListBoxTable()54     AccessibleTabListBoxTable::~AccessibleTabListBoxTable()
55     {
56         if ( isAlive() )
57         {
58             m_pTabListBox = nullptr;
59 
60             // increment ref count to prevent double call of Dtor
61             osl_atomic_increment( &m_refCount );
62             dispose();
63         }
64     }
65 
ProcessWindowEvent(const VclWindowEvent & rVclWindowEvent)66     void AccessibleTabListBoxTable::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
67     {
68         if ( isAlive() )
69         {
70             switch ( VclEventId nEventId = rVclWindowEvent.GetId(); nEventId )
71             {
72                 case  VclEventId::ObjectDying :
73                 {
74                     m_pTabListBox->RemoveEventListener( LINK( this, AccessibleTabListBoxTable, WindowEventListener ) );
75                     m_pTabListBox = nullptr;
76                     break;
77                 }
78 
79                 case VclEventId::ControlGetFocus :
80                 case VclEventId::ControlLoseFocus :
81                 {
82                     uno::Any aOldValue, aNewValue;
83                     if ( nEventId == VclEventId::ControlGetFocus )
84                         aNewValue <<= AccessibleStateType::FOCUSED;
85                     else
86                         aOldValue <<= AccessibleStateType::FOCUSED;
87                     commitEvent( AccessibleEventId::STATE_CHANGED, aNewValue, aOldValue );
88                     break;
89                 }
90 
91                 case VclEventId::ListboxSelect :
92                 {
93                     // First send an event that tells the listeners of a
94                     // modified selection.  The active descendant event is
95                     // send after that so that the receiving AT has time to
96                     // read the text or name of the active child.
97                     commitEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() );
98                     if ( m_pTabListBox && m_pTabListBox->HasFocus() )
99                     {
100                         SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
101                         if ( pEntry )
102                         {
103                             sal_Int32 nRow = m_pTabListBox->GetEntryPos( pEntry );
104                             sal_uInt16 nCol = m_pTabListBox->GetCurrColumn();
105                             Reference< XAccessible > xChild =
106                                 m_pTabListBox->CreateAccessibleCell( nRow, nCol );
107                             uno::Any aOldValue, aNewValue;
108 
109                             if ( m_pTabListBox->IsTransientChildrenDisabled() )
110                             {
111                                 aNewValue <<= AccessibleStateType::FOCUSED;
112                                 TriState eState = TRISTATE_INDET;
113                                 if ( m_pTabListBox->IsCellCheckBox( nRow, nCol, eState ) )
114                                 {
115                                     AccessibleCheckBoxCell* pCell =
116                                         static_cast< AccessibleCheckBoxCell* >( xChild.get() );
117                                     pCell->commitEvent( AccessibleEventId::STATE_CHANGED, aNewValue, aOldValue );
118                                 }
119                                 else
120                                 {
121                                     AccessibleBrowseBoxTableCell* pCell =
122                                         static_cast< AccessibleBrowseBoxTableCell* >( xChild.get() );
123                                     pCell->commitEvent( AccessibleEventId::STATE_CHANGED, aNewValue, aOldValue );
124                                 }
125                             }
126                             else
127                             {
128                                 aNewValue <<= xChild;
129                                 commitEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aNewValue, aOldValue );
130                             }
131                         }
132                     }
133                     break;
134                 }
135                 case VclEventId::WindowGetFocus :
136                 {
137                     uno::Any aOldValue, aNewValue;
138                     aNewValue <<= AccessibleStateType::FOCUSED;
139                     commitEvent( AccessibleEventId::STATE_CHANGED, aNewValue, aOldValue );
140                     break;
141 
142                 }
143                 case VclEventId::WindowLoseFocus :
144                 {
145                     uno::Any aOldValue, aNewValue;
146                     aOldValue <<= AccessibleStateType::FOCUSED;
147                     commitEvent( AccessibleEventId::STATE_CHANGED, aNewValue, aOldValue );
148                     break;
149                 }
150                 case VclEventId::ListboxTreeSelect:
151                     {
152                         SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
153                         if (pEntry)
154                         {
155                             sal_Int32 nRow = m_pTabListBox->GetEntryPos( pEntry );
156                             Reference< XAccessible > xChild = m_pTabListBox->CreateAccessibleCell( nRow, m_pTabListBox->GetCurrColumn() );
157                             TriState eState = TRISTATE_INDET;
158                             if ( m_pTabListBox->IsCellCheckBox( nRow, m_pTabListBox->GetCurrColumn(), eState ) )
159                             {
160                                 AccessibleCheckBoxCell* pCell = static_cast< AccessibleCheckBoxCell* >( xChild.get() );
161                                 pCell->commitEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() );
162                             }
163                             else
164                             {
165                                 AccessibleBrowseBoxTableCell* pCell = static_cast< AccessibleBrowseBoxTableCell* >( xChild.get() );
166                                 pCell->commitEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() );
167                             }
168                         }
169                     }
170                     break;
171                 case VclEventId::ListboxTreeFocus:
172                     {
173                         if ( m_pTabListBox && m_pTabListBox->HasFocus() )
174                         {
175                             uno::Any aOldValue, aNewValue;
176                             SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
177                             if ( pEntry )
178                             {
179                                 sal_Int32 nRow = m_pTabListBox->GetEntryPos( pEntry );
180                                 m_xCurChild = m_pTabListBox->CreateAccessibleCell( nRow, m_pTabListBox->GetCurrColumn() );
181                                 aNewValue <<= m_xCurChild;
182                                 commitEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aNewValue ,aOldValue);
183                             }
184                             else
185                             {
186                                 aNewValue <<= AccessibleStateType::FOCUSED;
187                                 commitEvent( AccessibleEventId::STATE_CHANGED, aNewValue ,aOldValue);
188                             }
189                         }
190                     }
191                     break;
192 
193                 case VclEventId::CheckboxToggle :
194                 {
195                     if ( m_pTabListBox && m_pTabListBox->HasFocus() )
196                     {
197                         SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
198                         if ( pEntry )
199                         {
200                             sal_Int32 nRow = m_pTabListBox->GetEntryPos( pEntry );
201                             sal_uInt16 nCol = m_pTabListBox->GetCurrColumn();
202                             TriState eState = TRISTATE_INDET;
203                             if ( m_pTabListBox->IsCellCheckBox( nRow, nCol, eState ) )
204                             {
205                                 Reference< XAccessible > xChild =
206                                     m_pTabListBox->CreateAccessibleCell( nRow, nCol );
207                                 AccessibleCheckBoxCell* pCell =
208                                     static_cast< AccessibleCheckBoxCell* >( xChild.get() );
209                                 pCell->SetChecked( SvHeaderTabListBox::IsItemChecked( pEntry, nCol ) );
210                             }
211                         }
212                     }
213                     break;
214                 }
215 
216                 case VclEventId::TableCellNameChanged :
217                 {
218                     if ( m_pTabListBox->IsTransientChildrenDisabled() )
219                     {
220                         commitEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() );
221                         TabListBoxEventData* pData = static_cast< TabListBoxEventData* >( rVclWindowEvent.GetData() );
222                         SvTreeListEntry* pEntry = pData != nullptr ? pData->m_pEntry : nullptr;
223                         if ( pEntry )
224                         {
225                             sal_Int32 nRow = m_pTabListBox->GetEntryPos( pEntry );
226                             sal_uInt16 nCol = pData->m_nColumn;
227                             Reference< XAccessible > xChild =
228                                 m_pTabListBox->CreateAccessibleCell( nRow, nCol );
229                             uno::Any aOldValue, aNewValue;
230                             aOldValue <<= pData->m_sOldText;
231                             OUString sNewText( m_pTabListBox->GetCellText( nRow, nCol ) );
232                             aNewValue <<= sNewText;
233                             TriState eState = TRISTATE_INDET;
234 
235                             if ( m_pTabListBox->IsCellCheckBox( nRow, nCol, eState ) )
236                             {
237                                 AccessibleCheckBoxCell* pCell =
238                                     static_cast< AccessibleCheckBoxCell* >( xChild.get() );
239                                 pCell->commitEvent( AccessibleEventId::NAME_CHANGED, aNewValue, aOldValue );
240                             }
241                             else
242                             {
243                                 AccessibleBrowseBoxTableCell* pCell =
244                                     static_cast< AccessibleBrowseBoxTableCell* >( xChild.get() );
245                                 pCell->nameChanged( sNewText, pData->m_sOldText );
246                             }
247                         }
248                     }
249                     break;
250                 }
251                 default: break;
252             }
253         }
254     }
255 
IMPL_LINK(AccessibleTabListBoxTable,WindowEventListener,VclWindowEvent &,rEvent,void)256     IMPL_LINK( AccessibleTabListBoxTable, WindowEventListener, VclWindowEvent&, rEvent, void )
257     {
258         OSL_ENSURE( rEvent.GetWindow() && m_pTabListBox, "no event window" );
259         ProcessWindowEvent( rEvent );
260     }
261     // helpers --------------------------------------------------------------------
262 
ensureValidIndex(sal_Int32 _nIndex) const263     void AccessibleTabListBoxTable::ensureValidIndex( sal_Int32 _nIndex ) const
264     {
265         if ( ( _nIndex < 0 ) || ( _nIndex >= (implGetRowCount() * implGetColumnCount()) ) )
266             throw IndexOutOfBoundsException();
267     }
268 
implSelectRow(sal_Int32 _nRow,bool _bSelect)269     void AccessibleTabListBoxTable::implSelectRow( sal_Int32 _nRow, bool _bSelect )
270     {
271         if ( m_pTabListBox )
272             m_pTabListBox->Select( m_pTabListBox->GetEntry( _nRow ), _bSelect );
273     }
274 
implGetRowCount() const275     sal_Int32 AccessibleTabListBoxTable::implGetRowCount() const
276     {
277         return m_pTabListBox ? m_pTabListBox->GetEntryCount() : 0;
278     }
279 
implGetColumnCount() const280     sal_Int32 AccessibleTabListBoxTable::implGetColumnCount() const
281     {
282         return m_pTabListBox ? m_pTabListBox->GetColumnCount() : 0;
283     }
284 
implGetSelRowCount() const285     sal_Int32 AccessibleTabListBoxTable::implGetSelRowCount() const
286     {
287         return m_pTabListBox ? m_pTabListBox->GetSelectionCount() : 0;
288     }
289 
implGetSelRow(sal_Int32 nSelRow) const290     sal_Int32 AccessibleTabListBoxTable::implGetSelRow( sal_Int32 nSelRow ) const
291     {
292         if ( m_pTabListBox )
293         {
294             sal_Int32 nRow = 0;
295             SvTreeListEntry* pEntry = m_pTabListBox->FirstSelected();
296             while ( pEntry )
297             {
298                 ++nRow;
299                 if ( nRow == nSelRow )
300                     return m_pTabListBox->GetEntryPos( pEntry );
301                 pEntry = m_pTabListBox->NextSelected( pEntry );
302             }
303         }
304 
305         return 0;
306     }
307 
308     // XInterface & XTypeProvider
309 
IMPLEMENT_FORWARD_XINTERFACE2(AccessibleTabListBoxTable,AccessibleBrowseBoxTable,AccessibleTabListBoxTableImplHelper)310     IMPLEMENT_FORWARD_XINTERFACE2(AccessibleTabListBoxTable, AccessibleBrowseBoxTable, AccessibleTabListBoxTableImplHelper)
311     IMPLEMENT_FORWARD_XTYPEPROVIDER2(AccessibleTabListBoxTable, AccessibleBrowseBoxTable, AccessibleTabListBoxTableImplHelper)
312 
313     // XServiceInfo
314 
315     OUString AccessibleTabListBoxTable::getImplementationName()
316     {
317         return "com.sun.star.comp.svtools.AccessibleTabListBoxTable";
318     }
319 
320     // XAccessibleSelection
321 
selectAccessibleChild(sal_Int32 nChildIndex)322     void SAL_CALL AccessibleTabListBoxTable::selectAccessibleChild( sal_Int32 nChildIndex )
323     {
324         SolarMutexGuard aSolarGuard;
325         ::osl::MutexGuard aGuard( getMutex() );
326 
327         ensureIsAlive();
328         ensureValidIndex( nChildIndex );
329 
330         implSelectRow( implGetRow( nChildIndex ), true );
331     }
332 
isAccessibleChildSelected(sal_Int32 nChildIndex)333     sal_Bool SAL_CALL AccessibleTabListBoxTable::isAccessibleChildSelected( sal_Int32 nChildIndex )
334     {
335         SolarMutexGuard aSolarGuard;
336         ::osl::MutexGuard aGuard( getMutex() );
337 
338         ensureIsAlive();
339         ensureValidIndex( nChildIndex );
340 
341         return m_pTabListBox && m_pTabListBox->IsSelected( m_pTabListBox->GetEntry( implGetRow( nChildIndex ) ) );
342     }
343 
clearAccessibleSelection()344     void SAL_CALL AccessibleTabListBoxTable::clearAccessibleSelection(  )
345     {
346         SolarMutexGuard aSolarGuard;
347         ::osl::MutexGuard aGuard( getMutex() );
348 
349         ensureIsAlive();
350 
351         m_pTabListBox->SetNoSelection();
352     }
353 
selectAllAccessibleChildren()354     void SAL_CALL AccessibleTabListBoxTable::selectAllAccessibleChildren(  )
355     {
356         SolarMutexGuard aSolarGuard;
357         ::osl::MutexGuard aGuard( getMutex() );
358 
359         ensureIsAlive();
360 
361         m_pTabListBox->SelectAll();
362     }
363 
getSelectedAccessibleChildCount()364     sal_Int32 SAL_CALL AccessibleTabListBoxTable::getSelectedAccessibleChildCount(  )
365     {
366         SolarMutexGuard aSolarGuard;
367         ::osl::MutexGuard aGuard( getMutex() );
368 
369         ensureIsAlive();
370 
371         return implGetColumnCount() * implGetSelRowCount();
372     }
373 
getSelectedAccessibleChild(sal_Int32 nSelectedChildIndex)374     Reference< XAccessible > SAL_CALL AccessibleTabListBoxTable::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex )
375     {
376         SolarMutexGuard aSolarGuard;
377         ::osl::MutexGuard aGuard( getMutex() );
378 
379         ensureIsAlive();
380 
381         sal_Int32 nRows = implGetSelRowCount();
382         if ( nRows == 0 )
383             throw IndexOutOfBoundsException();
384 
385         sal_Int32 nRow = implGetSelRow( nSelectedChildIndex % nRows );
386         sal_Int32 nColumn = nSelectedChildIndex / nRows;
387         return getAccessibleCellAt( nRow, nColumn );
388     }
389 
deselectAccessibleChild(sal_Int32 nSelectedChildIndex)390     void SAL_CALL AccessibleTabListBoxTable::deselectAccessibleChild( sal_Int32 nSelectedChildIndex )
391     {
392         SolarMutexGuard aSolarGuard;
393         ::osl::MutexGuard aGuard( getMutex() );
394 
395         ensureIsAlive();
396         ensureValidIndex( nSelectedChildIndex );
397 
398         implSelectRow( implGetRow( nSelectedChildIndex ), false );
399     }
400 
401 
402 }// namespace accessibility
403 
404 
405 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
406