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_sc.hxx"
30 
31 
32 #include "AccessibleContextBase.hxx"
33 #include "unoguard.hxx"
34 #include <com/sun/star/accessibility/AccessibleRole.hpp>
35 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
36 #ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLESTATETYPE_HPP_
37 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
38 #endif
39 #include <com/sun/star/beans/PropertyChangeEvent.hpp>
40 #include <rtl/uuid.h>
41 #include <tools/debug.hxx>
42 #include <tools/gen.hxx>
43 #ifndef _UTL_ACCESSIBLESTATESETHELPER_HXX
44 #include <unotools/accessiblestatesethelper.hxx>
45 #endif
46 #include <toolkit/helper/convert.hxx>
47 #include <svl/smplhint.hxx>
48 #include <comphelper/sequence.hxx>
49 #include <unotools/accessiblerelationsethelper.hxx>
50 #include <vcl/unohelp.hxx>
51 #include <tools/color.hxx>
52 #include <comphelper/accessibleeventnotifier.hxx>
53 
54 using namespace	::rtl;
55 using namespace	::com::sun::star;
56 using namespace	::com::sun::star::accessibility;
57 
58 //=====  internal  ============================================================
59 
60 DBG_NAME(ScAccessibleContextBase)
61 
62 ScAccessibleContextBase::ScAccessibleContextBase(
63 												 const uno::Reference<XAccessible>& rxParent,
64 												 const sal_Int16 aRole)
65 												 :
66 	ScAccessibleContextBaseWeakImpl(m_aMutex),
67 	mxParent(rxParent),
68 	mnClientId(0),
69 	maRole(aRole)
70 {
71 	DBG_CTOR(ScAccessibleContextBase, NULL);
72 }
73 
74 
75 ScAccessibleContextBase::~ScAccessibleContextBase(void)
76 {
77 	DBG_DTOR(ScAccessibleContextBase, NULL);
78 
79 	if (!IsDefunc() && !rBHelper.bInDispose)
80 	{
81 		// increment refcount to prevent double call off dtor
82 		osl_incrementInterlockedCount( &m_refCount );
83 		// call dispose to inform object wich have a weak reference to this object
84 		dispose();
85 	}
86 }
87 
88 void ScAccessibleContextBase::Init()
89 {
90 	// hold reference to make sure that the destructor is not called
91 	uno::Reference< XAccessibleContext > xOwnContext(this);
92 
93 	if (mxParent.is())
94 	{
95 		uno::Reference< XAccessibleEventBroadcaster > xBroadcaster (mxParent->getAccessibleContext(), uno::UNO_QUERY);
96 		if (xBroadcaster.is())
97 			xBroadcaster->addEventListener(this);
98 	}
99 	msName = createAccessibleName();
100 	msDescription = createAccessibleDescription();
101 }
102 
103 void SAL_CALL ScAccessibleContextBase::disposing()
104 {
105     ScUnoGuard aGuard;
106 //	CommitDefunc(); not necessary and should not be send, because it cost a lot of time
107 
108 	// hold reference to make sure that the destructor is not called
109 	uno::Reference< XAccessibleContext > xOwnContext(this);
110 
111 	if ( mnClientId )
112 	{
113 	    sal_Int32 nTemClientId(mnClientId);
114 		mnClientId =  0;
115         comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( nTemClientId, *this );
116 	}
117 
118     if (mxParent.is())
119 	{
120 		uno::Reference< XAccessibleEventBroadcaster > xBroadcaster (mxParent->getAccessibleContext(), uno::UNO_QUERY);
121 		if (xBroadcaster.is())
122 			xBroadcaster->removeEventListener(this);
123 		mxParent = NULL;
124 	}
125 
126 	ScAccessibleContextBaseWeakImpl::disposing();
127 }
128 
129 //=====  XInterface  =====================================================
130 
131 uno::Any SAL_CALL ScAccessibleContextBase::queryInterface( uno::Type const & rType )
132 	throw (uno::RuntimeException)
133 {
134 	uno::Any aAny (ScAccessibleContextBaseWeakImpl::queryInterface(rType));
135 	return aAny.hasValue() ? aAny : ScAccessibleContextBaseImplEvent::queryInterface(rType);
136 }
137 
138 void SAL_CALL ScAccessibleContextBase::acquire()
139 	throw ()
140 {
141 	ScAccessibleContextBaseWeakImpl::acquire();
142 }
143 
144 void SAL_CALL ScAccessibleContextBase::release()
145 	throw ()
146 {
147 	ScAccessibleContextBaseWeakImpl::release();
148 }
149 
150 //=====  SfxListener  =====================================================
151 
152 void ScAccessibleContextBase::Notify( SfxBroadcaster&, const SfxHint& rHint )
153 {
154 	if (rHint.ISA( SfxSimpleHint ) )
155 	{
156 		const SfxSimpleHint& rRef = (const SfxSimpleHint&)rHint;
157 		if (rRef.GetId() == SFX_HINT_DYING)
158 		{
159 			// it seems the Broadcaster is dying, since the view is dying
160 			dispose();
161 		}
162 	}
163 }
164 
165 //=====  XAccessible  =========================================================
166 
167 uno::Reference< XAccessibleContext> SAL_CALL
168     ScAccessibleContextBase::getAccessibleContext(void)
169     throw (uno::RuntimeException)
170 {
171 	return this;
172 }
173 
174 //=====  XAccessibleComponent  ================================================
175 
176 sal_Bool SAL_CALL ScAccessibleContextBase::containsPoint(const awt::Point& rPoint )
177 		throw (uno::RuntimeException)
178 {
179 	ScUnoGuard aGuard;
180     IsObjectValid();
181 	return Rectangle (Point(), GetBoundingBox().GetSize()).IsInside(VCLPoint(rPoint));
182 }
183 
184 uno::Reference< XAccessible > SAL_CALL ScAccessibleContextBase::getAccessibleAtPoint(
185         const awt::Point& /* rPoint */ )
186 		throw (uno::RuntimeException)
187 {
188 	DBG_ERROR("not implemented");
189 	return uno::Reference<XAccessible>();
190 }
191 
192 awt::Rectangle SAL_CALL ScAccessibleContextBase::getBounds(  )
193 		throw (uno::RuntimeException)
194 {
195 	ScUnoGuard aGuard;
196     IsObjectValid();
197 	return AWTRectangle(GetBoundingBox());
198 }
199 
200 awt::Point SAL_CALL ScAccessibleContextBase::getLocation(  )
201 		throw (uno::RuntimeException)
202 {
203 	ScUnoGuard aGuard;
204     IsObjectValid();
205 	return AWTPoint(GetBoundingBox().TopLeft());
206 }
207 
208 awt::Point SAL_CALL ScAccessibleContextBase::getLocationOnScreen(  )
209 		throw (uno::RuntimeException)
210 {
211 	ScUnoGuard aGuard;
212     IsObjectValid();
213 	return AWTPoint(GetBoundingBoxOnScreen().TopLeft());
214 }
215 
216 awt::Size SAL_CALL ScAccessibleContextBase::getSize(  )
217 		throw (uno::RuntimeException)
218 {
219 	ScUnoGuard aGuard;
220     IsObjectValid();
221 	return AWTSize(GetBoundingBox().GetSize());
222 }
223 
224 sal_Bool SAL_CALL ScAccessibleContextBase::isShowing(  )
225 		throw (uno::RuntimeException)
226 {
227 	ScUnoGuard aGuard;
228     IsObjectValid();
229 	sal_Bool bShowing(sal_False);
230     if (mxParent.is())
231     {
232 	    uno::Reference<XAccessibleComponent> xParentComponent (mxParent->getAccessibleContext(), uno::UNO_QUERY);
233 	    if (xParentComponent.is())
234 	    {
235 		    Rectangle aParentBounds(VCLRectangle(xParentComponent->getBounds()));
236 		    Rectangle aBounds(VCLRectangle(getBounds()));
237 		    bShowing = aBounds.IsOver(aParentBounds);
238 	    }
239     }
240 	return bShowing;
241 }
242 
243 sal_Bool SAL_CALL ScAccessibleContextBase::isVisible(  )
244 		throw (uno::RuntimeException)
245 {
246 	return sal_True;
247 }
248 
249 void SAL_CALL ScAccessibleContextBase::grabFocus(  )
250 		throw (uno::RuntimeException)
251 {
252 	DBG_ERROR("not implemented");
253 }
254 
255 sal_Int32 SAL_CALL ScAccessibleContextBase::getForeground(  )
256         throw (uno::RuntimeException)
257 {
258     return COL_BLACK;
259 }
260 
261 sal_Int32 SAL_CALL ScAccessibleContextBase::getBackground(  )
262         throw (uno::RuntimeException)
263 {
264     return COL_WHITE;
265 }
266 
267 //=====  XAccessibleContext  ==================================================
268 
269 sal_Int32 SAL_CALL
270    	ScAccessibleContextBase::getAccessibleChildCount(void)
271     throw (uno::RuntimeException)
272 {
273 	DBG_ERROR("should be implemented in the abrevated class");
274 	return 0;
275 }
276 
277 uno::Reference<XAccessible> SAL_CALL
278     ScAccessibleContextBase::getAccessibleChild(sal_Int32 /* nIndex */)
279         throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
280 {
281 	DBG_ERROR("should be implemented in the abrevated class");
282     return uno::Reference<XAccessible>();
283 }
284 
285 uno::Reference<XAccessible> SAL_CALL
286    	ScAccessibleContextBase::getAccessibleParent(void)
287     throw (uno::RuntimeException)
288 {
289 	return mxParent;
290 }
291 
292 sal_Int32 SAL_CALL
293    	ScAccessibleContextBase::getAccessibleIndexInParent(void)
294     throw (uno::RuntimeException)
295 {
296 	ScUnoGuard aGuard;
297     IsObjectValid();
298 	//	Use a simple but slow solution for now.  Optimize later.
299    //	Return -1 to indicate that this object's parent does not know about the
300    //	object.
301 	sal_Int32 nIndex(-1);
302 
303     //	Iterate over all the parent's children and search for this object.
304     if (mxParent.is())
305     {
306     	uno::Reference<XAccessibleContext> xParentContext (
307         	mxParent->getAccessibleContext());
308         if (xParentContext.is())
309         {
310         	sal_Int32 nChildCount = xParentContext->getAccessibleChildCount();
311             for (sal_Int32 i=0; i<nChildCount; ++i)
312             {
313             	uno::Reference<XAccessible> xChild (xParentContext->getAccessibleChild (i));
314                 if (xChild.is())
315                 {
316 	            	if (xChild.get() == this)
317                     	nIndex = i;
318                 }
319             }
320         }
321    }
322 
323    return nIndex;
324 }
325 
326 sal_Int16 SAL_CALL
327 	ScAccessibleContextBase::getAccessibleRole(void)
328     throw (uno::RuntimeException)
329 {
330 	return maRole;
331 }
332 
333 ::rtl::OUString SAL_CALL
334    	ScAccessibleContextBase::getAccessibleDescription(void)
335     throw (uno::RuntimeException)
336 {
337 	ScUnoGuard aGuard;
338     IsObjectValid();
339 	if (!msDescription.getLength())
340 	{
341 		OUString sDescription(createAccessibleDescription());
342 //		DBG_ASSERT(sDescription.getLength(), "We should give always a descripition.");
343 
344         if (msDescription != sDescription)
345         {
346 		    AccessibleEventObject aEvent;
347 		    aEvent.EventId = AccessibleEventId::DESCRIPTION_CHANGED;
348 		    aEvent.Source = uno::Reference< XAccessibleContext >(this);
349 		    aEvent.OldValue <<= msDescription;
350 		    aEvent.NewValue <<= sDescription;
351 
352 		    msDescription = sDescription;
353 
354 		    CommitChange(aEvent);
355         }
356 	}
357 	return msDescription;
358 }
359 
360 OUString SAL_CALL
361    	ScAccessibleContextBase::getAccessibleName(void)
362     throw (uno::RuntimeException)
363 {
364 	ScUnoGuard aGuard;
365     IsObjectValid();
366 	if (!msName.getLength())
367 	{
368 		OUString sName(createAccessibleName());
369 		DBG_ASSERT(sName.getLength(), "We should give always a name.");
370 
371         if (msName != sName)
372         {
373 		    AccessibleEventObject aEvent;
374 		    aEvent.EventId = AccessibleEventId::NAME_CHANGED;
375 		    aEvent.Source = uno::Reference< XAccessibleContext >(this);
376 		    aEvent.OldValue <<= msName;
377 		    aEvent.NewValue <<= sName;
378 
379 		    msName = sName;
380 
381 		    CommitChange(aEvent);
382         }
383 	}
384 	return msName;
385 }
386 
387 uno::Reference<XAccessibleRelationSet> SAL_CALL
388    	ScAccessibleContextBase::getAccessibleRelationSet(void)
389     throw (uno::RuntimeException)
390 {
391 	return new utl::AccessibleRelationSetHelper();
392 }
393 
394 uno::Reference<XAccessibleStateSet> SAL_CALL
395     	ScAccessibleContextBase::getAccessibleStateSet(void)
396     throw (uno::RuntimeException)
397 {
398 	return uno::Reference<XAccessibleStateSet>();
399 }
400 
401 lang::Locale SAL_CALL
402    	ScAccessibleContextBase::getLocale(void)
403 	throw (IllegalAccessibleComponentStateException,
404 		uno::RuntimeException)
405 {
406 	ScUnoGuard aGuard;
407     IsObjectValid();
408 	if (mxParent.is())
409     {
410     	uno::Reference<XAccessibleContext> xParentContext (
411         	mxParent->getAccessibleContext());
412         if (xParentContext.is())
413 	    	return xParentContext->getLocale ();
414     }
415 
416     //	No locale and no parent.  Therefore throw exception to indicate this
417     //	cluelessness.
418     throw IllegalAccessibleComponentStateException ();
419 }
420 
421 	//=====  XAccessibleEventBroadcaster  =====================================
422 
423 void SAL_CALL
424    	ScAccessibleContextBase::addEventListener(
425        	const uno::Reference<XAccessibleEventListener>& xListener)
426     throw (uno::RuntimeException)
427 {
428 	if (xListener.is())
429     {
430 		ScUnoGuard aGuard;
431         IsObjectValid();
432 		if (!IsDefunc())
433 		{
434 			if (!mnClientId)
435                 mnClientId = comphelper::AccessibleEventNotifier::registerClient( );
436 			comphelper::AccessibleEventNotifier::addEventListener( mnClientId, xListener );
437 		}
438     }
439 }
440 
441 void SAL_CALL
442    	ScAccessibleContextBase::removeEventListener(
443 		const uno::Reference<XAccessibleEventListener>& xListener)
444     throw (uno::RuntimeException)
445 {
446 	if (xListener.is())
447 	{
448 		ScUnoGuard aGuard;
449 		if (!IsDefunc() && mnClientId)
450         {
451 		    sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( mnClientId, xListener );
452 		    if ( !nListenerCount )
453 		    {
454 			    // no listeners anymore
455 			    // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
456 			    // and at least to us not firing any events anymore, in case somebody calls
457 			    // NotifyAccessibleEvent, again
458 			    comphelper::AccessibleEventNotifier::revokeClient( mnClientId );
459 			    mnClientId = 0;
460 		    }
461         }
462 	}
463 }
464 
465 	//=====  XAccessibleEventListener  ========================================
466 
467 void SAL_CALL ScAccessibleContextBase::disposing(
468 	const lang::EventObject& rSource )
469 		throw (uno::RuntimeException)
470 {
471     ScUnoGuard aGuard;
472 	if (rSource.Source == mxParent)
473 		dispose();
474 }
475 
476 void SAL_CALL ScAccessibleContextBase::notifyEvent(
477         const AccessibleEventObject& /* aEvent */ )
478 		throw (uno::RuntimeException)
479 {
480 }
481 
482 //=====  XServiceInfo  ========================================================
483 
484 ::rtl::OUString SAL_CALL
485    	ScAccessibleContextBase::getImplementationName(void)
486     throw (uno::RuntimeException)
487 {
488 	return OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessibleContextBase"));
489 }
490 
491 sal_Bool SAL_CALL
492  	ScAccessibleContextBase::supportsService(const OUString& sServiceName)
493     throw (uno::RuntimeException)
494 {
495     //  Iterate over all supported service names and return true if on of them
496     //  matches the given name.
497     uno::Sequence< ::rtl::OUString> aSupportedServices (
498         getSupportedServiceNames ());
499 	sal_Int32 nLength(aSupportedServices.getLength());
500 	const OUString* pServiceNames = aSupportedServices.getConstArray();
501     for (int i=0; i<nLength; ++i, ++pServiceNames)
502         if (sServiceName == *pServiceNames)
503             return sal_True;
504     return sal_False;
505 }
506 
507 uno::Sequence< ::rtl::OUString> SAL_CALL
508    	ScAccessibleContextBase::getSupportedServiceNames(void)
509     throw (uno::RuntimeException)
510 {
511 	uno::Sequence<OUString> aServiceNames(2);
512 	OUString* pServiceNames = aServiceNames.getArray();
513 	if (pServiceNames)
514 	{
515 		pServiceNames[0] = OUString(RTL_CONSTASCII_USTRINGPARAM ("com.sun.star.accessibility.Accessible"));
516 		pServiceNames[1] = OUString(RTL_CONSTASCII_USTRINGPARAM ("com.sun.star.accessibility.AccessibleContext"));
517 	}
518 
519 	return aServiceNames;
520 }
521 
522 //=====  XTypeProvider  =======================================================
523 
524 uno::Sequence< uno::Type > SAL_CALL ScAccessibleContextBase::getTypes()
525 		throw (uno::RuntimeException)
526 {
527 	return comphelper::concatSequences(ScAccessibleContextBaseWeakImpl::getTypes(), ScAccessibleContextBaseImplEvent::getTypes());
528 }
529 
530 uno::Sequence<sal_Int8> SAL_CALL
531 	ScAccessibleContextBase::getImplementationId(void)
532     throw (uno::RuntimeException)
533 {
534     ScUnoGuard aGuard;
535     IsObjectValid();
536 	static uno::Sequence<sal_Int8> aId;
537 	if (aId.getLength() == 0)
538 	{
539 		aId.realloc (16);
540 		rtl_createUuid (reinterpret_cast<sal_uInt8 *>(aId.getArray()), 0, sal_True);
541 	}
542 	return aId;
543 }
544 
545 //=====  internal  ============================================================
546 
547 ::rtl::OUString SAL_CALL
548     ScAccessibleContextBase::createAccessibleDescription(void)
549     throw (uno::RuntimeException)
550 {
551 	DBG_ERROR("should be implemented in the abrevated class");
552 	return rtl::OUString();
553 }
554 
555 ::rtl::OUString SAL_CALL
556     ScAccessibleContextBase::createAccessibleName(void)
557     throw (uno::RuntimeException)
558 {
559 	DBG_ERROR("should be implemented in the abrevated class");
560 	return rtl::OUString();
561 }
562 
563 void ScAccessibleContextBase::CommitChange(const AccessibleEventObject& rEvent) const
564 {
565 	if (mnClientId)
566 		comphelper::AccessibleEventNotifier::addEvent( mnClientId, rEvent );
567 }
568 
569 void ScAccessibleContextBase::ChangeName()
570 {
571 	AccessibleEventObject aEvent;
572 	aEvent.EventId = AccessibleEventId::NAME_CHANGED;
573 	aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this));
574     aEvent.OldValue <<= msName;
575 
576     msName = rtl::OUString(); // reset the name so it will be hold again
577     getAccessibleName(); // create the new name
578 
579 	aEvent.NewValue <<= msName;
580 
581 	CommitChange(aEvent);
582 }
583 
584 void ScAccessibleContextBase::CommitFocusGained() const
585 {
586 	AccessibleEventObject aEvent;
587 	aEvent.EventId = AccessibleEventId::STATE_CHANGED;
588 	aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this));
589 	aEvent.NewValue <<= AccessibleStateType::FOCUSED;
590 
591 	CommitChange(aEvent);
592 
593     ::vcl::unohelper::NotifyAccessibleStateEventGlobally(aEvent);
594 }
595 
596 void ScAccessibleContextBase::CommitFocusLost() const
597 {
598 	AccessibleEventObject aEvent;
599 	aEvent.EventId = AccessibleEventId::STATE_CHANGED;
600 	aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this));
601 	aEvent.OldValue <<= AccessibleStateType::FOCUSED;
602 
603 	CommitChange(aEvent);
604 
605     vcl::unohelper::NotifyAccessibleStateEventGlobally(aEvent);
606 }
607 
608 Rectangle ScAccessibleContextBase::GetBoundingBoxOnScreen(void) const
609 		throw (uno::RuntimeException)
610 {
611 	DBG_ERROR("not implemented");
612 	return Rectangle();
613 }
614 
615 Rectangle ScAccessibleContextBase::GetBoundingBox(void) const
616 		throw (uno::RuntimeException)
617 {
618 	DBG_ERROR("not implemented");
619 	return Rectangle();
620 }
621 
622 void ScAccessibleContextBase::IsObjectValid() const
623         throw (lang::DisposedException)
624 {
625     if (rBHelper.bDisposed || rBHelper.bInDispose)
626         throw lang::DisposedException();
627 }
628 
629