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/AccessibleGridControlBase.hxx"
31 #include <svtools/accessibletable.hxx>
32 #include <rtl/uuid.h>
33 //
34 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
35 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
36 #include <unotools/accessiblerelationsethelper.hxx>
37 
38 // ============================================================================
39 
40 using ::rtl::OUString;
41 
42 using ::com::sun::star::uno::Reference;
43 using ::com::sun::star::uno::Sequence;
44 using ::com::sun::star::uno::Any;
45 
46 using namespace ::com::sun::star;
47 using namespace ::com::sun::star::accessibility;
48 using namespace ::comphelper;
49 using namespace ::svt;
50 using namespace ::svt::table;
51 
52 
53 // ============================================================================
54 
55 namespace accessibility {
56 
57 using namespace com::sun::star::accessibility::AccessibleStateType;
58 // ============================================================================
59 
60 DBG_NAME( AccessibleGridControlBase )
61 
62 AccessibleGridControlBase::AccessibleGridControlBase(
63         const Reference< XAccessible >& rxParent,
64 		svt::table::IAccessibleTable& rTable,
65         AccessibleTableControlObjType      eObjType ) :
66     AccessibleGridControlImplHelper( m_aMutex ),
67     m_xParent( rxParent ),
68     m_aTable( rTable),
69     m_eObjType( eObjType ),
70     m_aName( rTable.GetAccessibleObjectName( eObjType, 0, 0 ) ),
71     m_aDescription( rTable.GetAccessibleObjectDescription( eObjType ) ),
72     m_aClientId(0)
73 {
74 }
75 
76 AccessibleGridControlBase::~AccessibleGridControlBase()
77 {
78     if( isAlive() )
79     {
80         // increment ref count to prevent double call of Dtor
81         osl_incrementInterlockedCount( &m_refCount );
82         dispose();
83     }
84 }
85 
86 void SAL_CALL AccessibleGridControlBase::disposing()
87 {
88     ::osl::MutexGuard aGuard( getOslMutex() );
89 
90 	if ( getClientId( ) )
91 	{
92 		AccessibleEventNotifier::TClientId nId( getClientId( ) );
93 	    setClientId( 0 );
94 	    AccessibleEventNotifier::revokeClientNotifyDisposing( nId, *this );
95 	}
96 
97     m_xParent = NULL;
98     //m_aTable = NULL;
99 }
100 
101 // XAccessibleContext ---------------------------------------------------------
102 
103 Reference< XAccessible > SAL_CALL AccessibleGridControlBase::getAccessibleParent()
104     throw ( uno::RuntimeException )
105 {
106     ::osl::MutexGuard aGuard( getOslMutex() );
107     ensureIsAlive();
108     return m_xParent;
109 }
110 
111 sal_Int32 SAL_CALL AccessibleGridControlBase::getAccessibleIndexInParent()
112     throw ( uno::RuntimeException )
113 {
114     ::osl::MutexGuard aGuard( getOslMutex() );
115     ensureIsAlive();
116 
117     // -1 for child not found/no parent (according to specification)
118     sal_Int32 nRet = -1;
119 
120     Reference< uno::XInterface > xMeMyselfAndI( static_cast< XAccessibleContext* >( this ), uno::UNO_QUERY );
121 
122     //  iterate over parent's children and search for this object
123     if( m_xParent.is() )
124     {
125         Reference< XAccessibleContext >
126             xParentContext( m_xParent->getAccessibleContext() );
127         if( xParentContext.is() )
128         {
129 	    Reference< uno::XInterface > xChild;
130 
131             sal_Int32 nChildCount = xParentContext->getAccessibleChildCount();
132             for( sal_Int32 nChild = 0; nChild < nChildCount; ++nChild )
133             {
134 		    xChild = xChild.query( xParentContext->getAccessibleChild( nChild ) );
135 		    if ( xMeMyselfAndI.get() == xChild.get() )
136 		    {
137 			    nRet = nChild;
138 			    break;
139 		    }
140 	    }
141         }
142    }
143    return nRet;
144 }
145 
146 OUString SAL_CALL AccessibleGridControlBase::getAccessibleDescription()
147     throw ( uno::RuntimeException )
148 {
149     ::osl::MutexGuard aGuard( getOslMutex() );
150     ensureIsAlive();
151     return m_aDescription;
152 }
153 
154 OUString SAL_CALL AccessibleGridControlBase::getAccessibleName()
155     throw ( uno::RuntimeException )
156 {
157     ::osl::MutexGuard aGuard( getOslMutex() );
158     ensureIsAlive();
159     return m_aName;
160 }
161 
162 Reference< XAccessibleRelationSet > SAL_CALL
163 AccessibleGridControlBase::getAccessibleRelationSet()
164     throw ( uno::RuntimeException )
165 {
166    ensureIsAlive();
167    // GridControl does not have relations.
168    return new utl::AccessibleRelationSetHelper;
169 }
170 
171 Reference< XAccessibleStateSet > SAL_CALL
172 AccessibleGridControlBase::getAccessibleStateSet()
173     throw ( uno::RuntimeException )
174 {
175     TCSolarGuard aSolarGuard;
176     ::osl::MutexGuard aGuard( getOslMutex() );
177     // don't check whether alive -> StateSet may contain DEFUNC
178     return implCreateStateSetHelper();
179 }
180 
181 lang::Locale SAL_CALL AccessibleGridControlBase::getLocale()
182     throw ( IllegalAccessibleComponentStateException, uno::RuntimeException )
183 {
184     ::osl::MutexGuard aGuard( getOslMutex() );
185     ensureIsAlive();
186     if( m_xParent.is() )
187     {
188         Reference< XAccessibleContext >
189             xParentContext( m_xParent->getAccessibleContext() );
190         if( xParentContext.is() )
191 		return xParentContext->getLocale();
192     }
193     throw IllegalAccessibleComponentStateException();
194 }
195 
196 // XAccessibleComponent -------------------------------------------------------
197 
198 sal_Bool SAL_CALL AccessibleGridControlBase::containsPoint( const awt::Point& rPoint )
199     throw ( uno::RuntimeException )
200 {
201    return Rectangle( Point(), getBoundingBox().GetSize() ).IsInside( VCLPoint( rPoint ) );
202 }
203 
204 awt::Rectangle SAL_CALL AccessibleGridControlBase::getBounds()
205     throw ( uno::RuntimeException )
206 {
207    return AWTRectangle( getBoundingBox() );
208 }
209 
210 awt::Point SAL_CALL AccessibleGridControlBase::getLocation()
211     throw ( uno::RuntimeException )
212 {
213     return AWTPoint( getBoundingBox().TopLeft() );
214 }
215 
216 awt::Point SAL_CALL AccessibleGridControlBase::getLocationOnScreen()
217     throw ( uno::RuntimeException )
218 {
219     return AWTPoint( getBoundingBoxOnScreen().TopLeft() );
220 }
221 
222 awt::Size SAL_CALL AccessibleGridControlBase::getSize()
223     throw ( uno::RuntimeException )
224 {
225     return AWTSize( getBoundingBox().GetSize() );
226 }
227 
228 sal_Bool SAL_CALL AccessibleGridControlBase::isShowing()
229     throw ( uno::RuntimeException )
230 {
231     TCSolarGuard aSolarGuard;
232     ::osl::MutexGuard aGuard( getOslMutex() );
233     ensureIsAlive();
234     return implIsShowing();
235 }
236 
237 sal_Bool SAL_CALL AccessibleGridControlBase::isVisible()
238     throw ( uno::RuntimeException )
239 {
240     Reference< XAccessibleStateSet > xStateSet = getAccessibleStateSet();
241     return xStateSet.is() ?
242         xStateSet->contains( AccessibleStateType::VISIBLE ) : sal_False;
243 }
244 
245 sal_Bool SAL_CALL AccessibleGridControlBase::isFocusTraversable()
246     throw ( uno::RuntimeException )
247 {
248     Reference< XAccessibleStateSet > xStateSet = getAccessibleStateSet();
249     return xStateSet.is() ?
250         xStateSet->contains( AccessibleStateType::FOCUSABLE ) : sal_False;
251 }
252 // XAccessibleEventBroadcaster ------------------------------------------------
253 
254 void SAL_CALL AccessibleGridControlBase::addEventListener(
255         const Reference< XAccessibleEventListener>& _rxListener )
256     throw ( uno::RuntimeException )
257 {
258 	if ( _rxListener.is() )
259 	{
260 		::osl::MutexGuard aGuard( getOslMutex() );
261 		if ( !getClientId( ) )
262 			setClientId( AccessibleEventNotifier::registerClient( ) );
263 
264 		AccessibleEventNotifier::addEventListener( getClientId( ), _rxListener );
265 	}
266 }
267 
268 void SAL_CALL AccessibleGridControlBase::removeEventListener(
269         const Reference< XAccessibleEventListener>& _rxListener )
270     throw ( uno::RuntimeException )
271 {
272     if( _rxListener.is() && getClientId( ) )
273     {
274 	::osl::MutexGuard aGuard( getOslMutex() );
275         sal_Int32 nListenerCount = AccessibleEventNotifier::removeEventListener( getClientId( ), _rxListener );
276 	if ( !nListenerCount )
277 	{
278 		// no listeners anymore
279 		// -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
280 		// and at least to us not firing any events anymore, in case somebody calls
281 		// NotifyAccessibleEvent, again
282 		AccessibleEventNotifier::TClientId nId( getClientId( ) );
283 		setClientId( 0 );
284 		AccessibleEventNotifier::revokeClient( nId );
285 	}
286     }
287 }
288 
289 // XTypeProvider --------------------------------------------------------------
290 
291 Sequence< sal_Int8 > SAL_CALL AccessibleGridControlBase::getImplementationId()
292     throw ( uno::RuntimeException )
293 {
294     ::osl::MutexGuard aGuard( getOslGlobalMutex() );
295     static Sequence< sal_Int8 > aId;
296     implCreateUuid( aId );
297     return aId;
298 }
299 
300 // XServiceInfo ---------------------------------------------------------------
301 
302 sal_Bool SAL_CALL AccessibleGridControlBase::supportsService(
303         const OUString& rServiceName )
304     throw ( uno::RuntimeException )
305 {
306     ::osl::MutexGuard aGuard( getOslMutex() );
307 
308     Sequence< OUString > aSupportedServices( getSupportedServiceNames() );
309     const OUString* pArrBegin = aSupportedServices.getConstArray();
310     const OUString* pArrEnd = pArrBegin + aSupportedServices.getLength();
311     const OUString* pString = pArrBegin;
312 
313     for( ; ( pString != pArrEnd ) && ( rServiceName != *pString ); ++pString )
314 		;
315     return pString != pArrEnd;
316 }
317 
318 Sequence< OUString > SAL_CALL AccessibleGridControlBase::getSupportedServiceNames()
319     throw ( uno::RuntimeException )
320 {
321     const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.accessibility.AccessibleContext" ) );
322     return Sequence< OUString >( &aServiceName, 1 );
323 }
324 // internal virtual methods ---------------------------------------------------
325 
326 sal_Bool AccessibleGridControlBase::implIsShowing()
327 {
328     sal_Bool bShowing = sal_False;
329     if( m_xParent.is() )
330     {
331         Reference< XAccessibleComponent >
332             xParentComp( m_xParent->getAccessibleContext(), uno::UNO_QUERY );
333         if( xParentComp.is() )
334             bShowing = implGetBoundingBox().IsOver(
335                 VCLRectangle( xParentComp->getBounds() ) );
336     }
337     return bShowing;
338 }
339 
340 ::utl::AccessibleStateSetHelper* AccessibleGridControlBase::implCreateStateSetHelper()
341 {
342     ::utl::AccessibleStateSetHelper*
343         pStateSetHelper = new ::utl::AccessibleStateSetHelper;
344 
345     if( isAlive() )
346     {
347 	    // SHOWING done with m_xParent
348 	    if( implIsShowing() )
349 		    pStateSetHelper->AddState( AccessibleStateType::SHOWING );
350 	    // GridControl fills StateSet with states depending on object type
351 	    m_aTable.FillAccessibleStateSet( *pStateSetHelper, getType() );
352     }
353     else
354 	    pStateSetHelper->AddState( AccessibleStateType::DEFUNC );
355     return pStateSetHelper;
356 }
357 
358 // internal helper methods ----------------------------------------------------
359 
360 sal_Bool AccessibleGridControlBase::isAlive() const
361 {
362     return !rBHelper.bDisposed && !rBHelper.bInDispose && &m_aTable;
363 }
364 
365 void AccessibleGridControlBase::ensureIsAlive() const
366     throw ( lang::DisposedException )
367 {
368     if( !isAlive() )
369         throw lang::DisposedException();
370 }
371 
372 Rectangle AccessibleGridControlBase::getBoundingBox()
373     throw ( lang::DisposedException )
374 {
375     TCSolarGuard aSolarGuard;
376     ::osl::MutexGuard aGuard( getOslMutex() );
377     ensureIsAlive();
378     Rectangle aRect = implGetBoundingBox();
379     if ( 0 == aRect.Left() && 0 == aRect.Top() && 0 == aRect.Right() && 0 == aRect.Bottom() )
380     {
381 	    DBG_ERRORFILE( "rectangle doesn't exist" );
382     }
383     return aRect;
384 }
385 
386 Rectangle AccessibleGridControlBase::getBoundingBoxOnScreen()
387     throw ( lang::DisposedException )
388 {
389     TCSolarGuard aSolarGuard;
390     ::osl::MutexGuard aGuard( getOslMutex() );
391     ensureIsAlive();
392     Rectangle aRect = implGetBoundingBoxOnScreen();
393     if ( 0 == aRect.Left() && 0 == aRect.Top() && 0 == aRect.Right() && 0 == aRect.Bottom() )
394     {
395 	    DBG_ERRORFILE( "rectangle doesn't exist" );
396     }
397     return aRect;
398 }
399 
400 void AccessibleGridControlBase::commitEvent(
401         sal_Int16 _nEventId, const Any& _rNewValue, const Any& _rOldValue )
402 {
403     ::osl::ClearableMutexGuard aGuard( getOslMutex() );
404 	if ( !getClientId( ) )
405 	        // if we don't have a client id for the notifier, then we don't have listeners, then
406 	        // we don't need to notify anything
407 	        return;
408 
409 	// build an event object
410 	AccessibleEventObject aEvent;
411 	aEvent.Source = *this;
412 	aEvent.EventId = _nEventId;
413 	aEvent.OldValue = _rOldValue;
414 	aEvent.NewValue = _rNewValue;
415 
416 	// let the notifier handle this event
417 
418 	AccessibleEventNotifier::addEvent( getClientId( ), aEvent );
419 }
420 // -----------------------------------------------------------------------------
421 
422 void AccessibleGridControlBase::implCreateUuid( Sequence< sal_Int8 >& rId )
423 {
424     if( !rId.hasElements() )
425     {
426         rId.realloc( 16 );
427         rtl_createUuid( reinterpret_cast< sal_uInt8* >( rId.getArray() ), 0, sal_True );
428     }
429 }
430 // -----------------------------------------------------------------------------
431 sal_Int16 SAL_CALL AccessibleGridControlBase::getAccessibleRole()
432     throw ( uno::RuntimeException )
433 {
434     ensureIsAlive();
435 	sal_Int16 nRole = AccessibleRole::UNKNOWN;
436 	switch ( m_eObjType )
437 	{
438         case TCTYPE_ROWHEADERCELL:
439 		nRole = AccessibleRole::ROW_HEADER;
440 		break;
441 	case TCTYPE_COLUMNHEADERCELL:
442 		nRole = AccessibleRole::COLUMN_HEADER;
443 		break;
444 	case TCTYPE_COLUMNHEADERBAR:
445 	case TCTYPE_ROWHEADERBAR:
446 	case TCTYPE_TABLE:
447 		nRole = AccessibleRole::TABLE;
448 		break;
449 	case TCTYPE_TABLECELL:
450 		nRole = AccessibleRole::TABLE_CELL;
451 		break;
452 	case TCTYPE_GRIDCONTROL:
453 		nRole = AccessibleRole::PANEL;
454 		break;
455 	}
456     return nRole;
457 }
458 // -----------------------------------------------------------------------------
459 Any SAL_CALL AccessibleGridControlBase::getAccessibleKeyBinding()
460         throw ( uno::RuntimeException )
461 {
462 	return Any();
463 }
464 // -----------------------------------------------------------------------------
465 Reference<XAccessible > SAL_CALL AccessibleGridControlBase::getAccessibleAtPoint( const ::com::sun::star::awt::Point& )
466         throw ( uno::RuntimeException )
467 {
468 	return NULL;
469 }
470 //// -----------------------------------------------------------------------------
471 sal_Int32 SAL_CALL AccessibleGridControlBase::getForeground(  ) throw (::com::sun::star::uno::RuntimeException)
472 {
473     TCSolarGuard aSolarGuard;
474     ::osl::MutexGuard aGuard( getOslMutex() );
475     ensureIsAlive();
476 
477     sal_Int32 nColor = 0;
478     Window* pInst = m_aTable.GetWindowInstance();
479     if ( pInst )
480     {
481         if ( pInst->IsControlForeground() )
482             nColor = pInst->GetControlForeground().GetColor();
483 	else
484 	{
485 		Font aFont;
486 		if ( pInst->IsControlFont() )
487 			aFont = pInst->GetControlFont();
488 		else
489 			aFont = pInst->GetFont();
490 		nColor = aFont.GetColor().GetColor();
491 	}
492     }
493     return nColor;
494 }
495 // -----------------------------------------------------------------------------
496 sal_Int32 SAL_CALL AccessibleGridControlBase::getBackground(  ) throw (::com::sun::star::uno::RuntimeException)
497 {
498     TCSolarGuard aSolarGuard;
499     ::osl::MutexGuard aGuard( getOslMutex() );
500     ensureIsAlive();
501     sal_Int32 nColor = 0;
502     Window* pInst = m_aTable.GetWindowInstance();
503     if ( pInst )
504     {
505         if ( pInst->IsControlBackground() )
506             nColor = pInst->GetControlBackground().GetColor();
507 	else
508             nColor = pInst->GetBackground().GetColor().GetColor();
509     }
510     return nColor;
511 }
512 
513 //// ============================================================================
514 GridControlAccessibleElement::GridControlAccessibleElement( const Reference< XAccessible >& rxParent,
515 						IAccessibleTable& rTable,
516 						AccessibleTableControlObjType  eObjType )
517 	:AccessibleGridControlBase( rxParent, rTable, eObjType )
518 {
519 }
520 
521 // XInterface -----------------------------------------------------------------
522 IMPLEMENT_FORWARD_XINTERFACE2( GridControlAccessibleElement, AccessibleGridControlBase, GridControlAccessibleElement_Base)
523 
524 // XTypeProvider --------------------------------------------------------------
525 IMPLEMENT_FORWARD_XTYPEPROVIDER2( GridControlAccessibleElement, AccessibleGridControlBase, GridControlAccessibleElement_Base )
526 
527 // XAccessible ----------------------------------------------------------------
528 
529 Reference< XAccessibleContext > SAL_CALL GridControlAccessibleElement::getAccessibleContext() throw ( uno::RuntimeException )
530 {
531     ensureIsAlive();
532     return this;
533 }
534 // ----------------------------------------------------------------------------
535 GridControlAccessibleElement::~GridControlAccessibleElement( )
536 {
537 }
538 
539 // ============================================================================
540 
541 } // namespace accessibility
542 
543 // ============================================================================
544 
545