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 #include <extended/accessibletablistboxtable.hxx>
21 #include <extended/AccessibleBrowseBoxTableCell.hxx>
22 #include <extended/AccessibleBrowseBoxCheckBoxCell.hxx>
23 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
24 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
25 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
26 #include <vcl/toolkit/svtabbx.hxx>
27 
28 namespace accessibility
29 {
30 
31 
32     // class AccessibleTabListBoxTable ---------------------------------------------
33 
34     using namespace ::com::sun::star::accessibility;
35     using namespace ::com::sun::star::uno;
36     using namespace ::com::sun::star::lang;
37     using namespace ::com::sun::star;
38 
39 
40     // Ctor() and Dtor()
41 
AccessibleTabListBoxTable(const Reference<XAccessible> & rxParent,SvHeaderTabListBox & rBox)42     AccessibleTabListBoxTable::AccessibleTabListBoxTable( const Reference< XAccessible >& rxParent, SvHeaderTabListBox& rBox ) :
43 
44         AccessibleBrowseBoxTable( rxParent, rBox ),
45 
46         m_pTabListBox   ( &rBox )
47 
48     {
49         m_pTabListBox->AddEventListener( LINK( this, AccessibleTabListBoxTable, WindowEventListener ) );
50     }
51 
~AccessibleTabListBoxTable()52     AccessibleTabListBoxTable::~AccessibleTabListBoxTable()
53     {
54         if ( isAlive() )
55         {
56             m_pTabListBox = nullptr;
57 
58             // increment ref count to prevent double call of Dtor
59             osl_atomic_increment( &m_refCount );
60             dispose();
61         }
62     }
63 
ProcessWindowEvent(const VclWindowEvent & rVclWindowEvent)64     void AccessibleTabListBoxTable::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
65     {
66         if ( !isAlive() )
67             return;
68 
69         switch ( VclEventId nEventId = rVclWindowEvent.GetId(); nEventId )
70         {
71             case  VclEventId::ObjectDying :
72             {
73                 m_pTabListBox->RemoveEventListener( LINK( this, AccessibleTabListBoxTable, WindowEventListener ) );
74                 m_pTabListBox = nullptr;
75                 break;
76             }
77 
78             case VclEventId::ControlGetFocus :
79             case VclEventId::ControlLoseFocus :
80             {
81                 uno::Any aOldValue, aNewValue;
82                 if ( nEventId == VclEventId::ControlGetFocus )
83                     aNewValue <<= AccessibleStateType::FOCUSED;
84                 else
85                     aOldValue <<= AccessibleStateType::FOCUSED;
86                 commitEvent( AccessibleEventId::STATE_CHANGED, aNewValue, aOldValue );
87                 break;
88             }
89 
90             case VclEventId::ListboxSelect :
91             {
92                 // First send an event that tells the listeners of a
93                 // modified selection.  The active descendant event is
94                 // send after that so that the receiving AT has time to
95                 // read the text or name of the active child.
96                 commitEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() );
97                 if ( m_pTabListBox && m_pTabListBox->HasFocus() )
98                 {
99                     SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
100                     if ( pEntry )
101                     {
102                         sal_Int32 nRow = m_pTabListBox->GetEntryPos( pEntry );
103                         sal_uInt16 nCol = m_pTabListBox->GetCurrColumn();
104                         Reference< XAccessible > xChild =
105                             m_pTabListBox->CreateAccessibleCell( nRow, nCol );
106                         uno::Any aOldValue, aNewValue;
107                         aNewValue <<= xChild;
108                         commitEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aNewValue, aOldValue );
109                     }
110                 }
111                 break;
112             }
113             case VclEventId::WindowGetFocus :
114             {
115                 uno::Any aOldValue, aNewValue;
116                 aNewValue <<= AccessibleStateType::FOCUSED;
117                 commitEvent( AccessibleEventId::STATE_CHANGED, aNewValue, aOldValue );
118                 break;
119 
120             }
121             case VclEventId::WindowLoseFocus :
122             {
123                 uno::Any aOldValue, aNewValue;
124                 aOldValue <<= AccessibleStateType::FOCUSED;
125                 commitEvent( AccessibleEventId::STATE_CHANGED, aNewValue, aOldValue );
126                 break;
127             }
128             case VclEventId::ListboxTreeSelect:
129                 {
130                     SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
131                     if (pEntry)
132                     {
133                         sal_Int32 nRow = m_pTabListBox->GetEntryPos( pEntry );
134                         Reference< XAccessible > xChild = m_pTabListBox->CreateAccessibleCell( nRow, m_pTabListBox->GetCurrColumn() );
135                         TriState eState = TRISTATE_INDET;
136                         if ( m_pTabListBox->IsCellCheckBox( nRow, m_pTabListBox->GetCurrColumn(), eState ) )
137                         {
138                             AccessibleCheckBoxCell* pCell = static_cast< AccessibleCheckBoxCell* >( xChild.get() );
139                             pCell->commitEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() );
140                         }
141                         else
142                         {
143                             AccessibleBrowseBoxTableCell* pCell = static_cast< AccessibleBrowseBoxTableCell* >( xChild.get() );
144                             pCell->commitEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() );
145                         }
146                     }
147                 }
148                 break;
149             case VclEventId::ListboxTreeFocus:
150                 {
151                     if ( m_pTabListBox && m_pTabListBox->HasFocus() )
152                     {
153                         uno::Any aOldValue, aNewValue;
154                         SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
155                         if ( pEntry )
156                         {
157                             sal_Int32 nRow = m_pTabListBox->GetEntryPos( pEntry );
158                             m_xCurChild = m_pTabListBox->CreateAccessibleCell( nRow, m_pTabListBox->GetCurrColumn() );
159                             aNewValue <<= m_xCurChild;
160                             commitEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aNewValue ,aOldValue);
161                         }
162                         else
163                         {
164                             aNewValue <<= AccessibleStateType::FOCUSED;
165                             commitEvent( AccessibleEventId::STATE_CHANGED, aNewValue ,aOldValue);
166                         }
167                     }
168                 }
169                 break;
170 
171             case VclEventId::CheckboxToggle :
172             {
173                 if ( m_pTabListBox && m_pTabListBox->HasFocus() )
174                 {
175                     SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
176                     if ( pEntry )
177                     {
178                         sal_Int32 nRow = m_pTabListBox->GetEntryPos( pEntry );
179                         sal_uInt16 nCol = m_pTabListBox->GetCurrColumn();
180                         TriState eState = TRISTATE_INDET;
181                         if ( m_pTabListBox->IsCellCheckBox( nRow, nCol, eState ) )
182                         {
183                             Reference< XAccessible > xChild =
184                                 m_pTabListBox->CreateAccessibleCell( nRow, nCol );
185                             AccessibleCheckBoxCell* pCell =
186                                 static_cast< AccessibleCheckBoxCell* >( xChild.get() );
187                             pCell->SetChecked( SvHeaderTabListBox::IsItemChecked( pEntry, nCol ) );
188                         }
189                     }
190                 }
191                 break;
192             }
193 
194             default: break;
195         }
196     }
197 
IMPL_LINK(AccessibleTabListBoxTable,WindowEventListener,VclWindowEvent &,rEvent,void)198     IMPL_LINK( AccessibleTabListBoxTable, WindowEventListener, VclWindowEvent&, rEvent, void )
199     {
200         OSL_ENSURE( rEvent.GetWindow() && m_pTabListBox, "no event window" );
201         ProcessWindowEvent( rEvent );
202     }
203     // helpers --------------------------------------------------------------------
204 
ensureValidIndex(sal_Int32 _nIndex) const205     void AccessibleTabListBoxTable::ensureValidIndex( sal_Int32 _nIndex ) const
206     {
207         if ( ( _nIndex < 0 ) || ( _nIndex >= (implGetRowCount() * implGetColumnCount()) ) )
208             throw IndexOutOfBoundsException();
209     }
210 
implSelectRow(sal_Int32 _nRow,bool _bSelect)211     void AccessibleTabListBoxTable::implSelectRow( sal_Int32 _nRow, bool _bSelect )
212     {
213         if ( m_pTabListBox )
214             m_pTabListBox->Select( m_pTabListBox->GetEntry( _nRow ), _bSelect );
215     }
216 
implGetRowCount() const217     sal_Int32 AccessibleTabListBoxTable::implGetRowCount() const
218     {
219         return m_pTabListBox ? m_pTabListBox->GetEntryCount() : 0;
220     }
221 
implGetColumnCount() const222     sal_Int32 AccessibleTabListBoxTable::implGetColumnCount() const
223     {
224         return m_pTabListBox ? m_pTabListBox->GetColumnCount() : 0;
225     }
226 
implGetSelRowCount() const227     sal_Int32 AccessibleTabListBoxTable::implGetSelRowCount() const
228     {
229         return m_pTabListBox ? m_pTabListBox->GetSelectionCount() : 0;
230     }
231 
implGetSelRow(sal_Int32 nSelRow) const232     sal_Int32 AccessibleTabListBoxTable::implGetSelRow( sal_Int32 nSelRow ) const
233     {
234         if ( m_pTabListBox )
235         {
236             sal_Int32 nRow = 0;
237             SvTreeListEntry* pEntry = m_pTabListBox->FirstSelected();
238             while ( pEntry )
239             {
240                 ++nRow;
241                 if ( nRow == nSelRow )
242                     return m_pTabListBox->GetEntryPos( pEntry );
243                 pEntry = m_pTabListBox->NextSelected( pEntry );
244             }
245         }
246 
247         return 0;
248     }
249 
250     // XInterface & XTypeProvider
251 
IMPLEMENT_FORWARD_XINTERFACE2(AccessibleTabListBoxTable,AccessibleBrowseBoxTable,AccessibleTabListBoxTableImplHelper)252     IMPLEMENT_FORWARD_XINTERFACE2(AccessibleTabListBoxTable, AccessibleBrowseBoxTable, AccessibleTabListBoxTableImplHelper)
253     IMPLEMENT_FORWARD_XTYPEPROVIDER2(AccessibleTabListBoxTable, AccessibleBrowseBoxTable, AccessibleTabListBoxTableImplHelper)
254 
255     // XServiceInfo
256 
257     OUString AccessibleTabListBoxTable::getImplementationName()
258     {
259         return "com.sun.star.comp.svtools.AccessibleTabListBoxTable";
260     }
261 
262     // XAccessibleSelection
263 
selectAccessibleChild(sal_Int32 nChildIndex)264     void SAL_CALL AccessibleTabListBoxTable::selectAccessibleChild( sal_Int32 nChildIndex )
265     {
266         SolarMutexGuard aSolarGuard;
267         ::osl::MutexGuard aGuard( getMutex() );
268 
269         ensureIsAlive();
270         ensureValidIndex( nChildIndex );
271 
272         implSelectRow( implGetRow( nChildIndex ), true );
273     }
274 
isAccessibleChildSelected(sal_Int32 nChildIndex)275     sal_Bool SAL_CALL AccessibleTabListBoxTable::isAccessibleChildSelected( sal_Int32 nChildIndex )
276     {
277         SolarMutexGuard aSolarGuard;
278         ::osl::MutexGuard aGuard( getMutex() );
279 
280         ensureIsAlive();
281         ensureValidIndex( nChildIndex );
282 
283         return m_pTabListBox && m_pTabListBox->IsSelected( m_pTabListBox->GetEntry( implGetRow( nChildIndex ) ) );
284     }
285 
clearAccessibleSelection()286     void SAL_CALL AccessibleTabListBoxTable::clearAccessibleSelection(  )
287     {
288         SolarMutexGuard aSolarGuard;
289         ::osl::MutexGuard aGuard( getMutex() );
290 
291         ensureIsAlive();
292 
293         m_pTabListBox->SetNoSelection();
294     }
295 
selectAllAccessibleChildren()296     void SAL_CALL AccessibleTabListBoxTable::selectAllAccessibleChildren(  )
297     {
298         SolarMutexGuard aSolarGuard;
299         ::osl::MutexGuard aGuard( getMutex() );
300 
301         ensureIsAlive();
302 
303         m_pTabListBox->SelectAll();
304     }
305 
getSelectedAccessibleChildCount()306     sal_Int32 SAL_CALL AccessibleTabListBoxTable::getSelectedAccessibleChildCount(  )
307     {
308         SolarMutexGuard aSolarGuard;
309         ::osl::MutexGuard aGuard( getMutex() );
310 
311         ensureIsAlive();
312 
313         return implGetColumnCount() * implGetSelRowCount();
314     }
315 
getSelectedAccessibleChild(sal_Int32 nSelectedChildIndex)316     Reference< XAccessible > SAL_CALL AccessibleTabListBoxTable::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex )
317     {
318         SolarMutexGuard aSolarGuard;
319         ::osl::MutexGuard aGuard( getMutex() );
320 
321         ensureIsAlive();
322 
323         sal_Int32 nRows = implGetSelRowCount();
324         if ( nRows == 0 )
325             throw IndexOutOfBoundsException();
326 
327         sal_Int32 nRow = implGetSelRow( nSelectedChildIndex % nRows );
328         sal_Int32 nColumn = nSelectedChildIndex / nRows;
329         return getAccessibleCellAt( nRow, nColumn );
330     }
331 
deselectAccessibleChild(sal_Int32 nSelectedChildIndex)332     void SAL_CALL AccessibleTabListBoxTable::deselectAccessibleChild( sal_Int32 nSelectedChildIndex )
333     {
334         SolarMutexGuard aSolarGuard;
335         ::osl::MutexGuard aGuard( getMutex() );
336 
337         ensureIsAlive();
338         ensureValidIndex( nSelectedChildIndex );
339 
340         implSelectRow( implGetRow( nSelectedChildIndex ), false );
341     }
342 
343 
344 }// namespace accessibility
345 
346 
347 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
348