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