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_editeng.hxx"
30 
31 
32 #include <editeng/AccessibleContextBase.hxx>
33 
34 #include <com/sun/star/accessibility/AccessibleRole.hpp>
35 #include <com/sun/star/beans/PropertyChangeEvent.hpp>
36 #include <com/sun/star/accessibility/XAccessibleEventListener.hpp>
37 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
38 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
39 
40 #include <unotools/accessiblestatesethelper.hxx>
41 #include <unotools/accessiblerelationsethelper.hxx>
42 #include <comphelper/accessibleeventnotifier.hxx>
43 #include <rtl/uuid.h>
44 #include <vos/mutex.hxx>
45 //#include <vcl/svapp.hxx>
46 
47 #include <utility>
48 
49 using namespace	::rtl;
50 using namespace	::com::sun::star;
51 using namespace	::com::sun::star::accessibility;
52 using ::com::sun::star::uno::Reference;
53 
54 namespace accessibility {
55 
56 //=====  internal  ============================================================
57 
58 // Define a shortcut for the somewhot longish base class name.
59 typedef ::cppu::WeakComponentImplHelper4<
60     ::com::sun::star::accessibility::XAccessible,
61     ::com::sun::star::accessibility::XAccessibleContext,
62     ::com::sun::star::accessibility::XAccessibleEventBroadcaster,
63     ::com::sun::star::lang::XServiceInfo> BaseClass;
64 
65 AccessibleContextBase::AccessibleContextBase (
66         const uno::Reference<XAccessible>& rxParent,
67 		const sal_Int16 aRole)
68 	:   BaseClass (MutexOwner::maMutex),
69         mxStateSet (NULL),
70         mxRelationSet (NULL),
71         mxParent(rxParent),
72         msDescription(),
73         meDescriptionOrigin(NotSet),
74         msName(),
75         meNameOrigin(NotSet),
76         mnClientId(0),
77         maRole(aRole)
78 {
79     // Create the state set.
80     ::utl::AccessibleStateSetHelper* pStateSet  = new ::utl::AccessibleStateSetHelper ();
81     mxStateSet = pStateSet;
82 
83     // Set some states.  Don't use the SetState method because no events
84     // shall be broadcastet (that is not yet initialized anyway).
85     if (pStateSet != NULL)
86     {
87         pStateSet->AddState (AccessibleStateType::ENABLED);
88         pStateSet->AddState (AccessibleStateType::SENSITIVE);
89         pStateSet->AddState (AccessibleStateType::SHOWING);
90         pStateSet->AddState (AccessibleStateType::VISIBLE);
91         pStateSet->AddState (AccessibleStateType::FOCUSABLE);
92         pStateSet->AddState (AccessibleStateType::SELECTABLE);
93     }
94 
95     // Create the relation set.
96     ::utl::AccessibleRelationSetHelper* pRelationSet = new ::utl::AccessibleRelationSetHelper ();
97     mxRelationSet = pRelationSet;
98 }
99 
100 
101 
102 
103 AccessibleContextBase::~AccessibleContextBase(void)
104 {
105 }
106 
107 
108 
109 
110 sal_Bool AccessibleContextBase::SetState (sal_Int16 aState)
111 {
112     ::osl::ClearableMutexGuard aGuard (maMutex);
113     ::utl::AccessibleStateSetHelper* pStateSet =
114         static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
115     if ((pStateSet != NULL) && !pStateSet->contains(aState))
116     {
117         pStateSet->AddState (aState);
118         // Clear the mutex guard so that it is not locked during calls to
119         // listeners.
120         aGuard.clear();
121 
122         // Send event for all states except the DEFUNC state.
123         if (aState != AccessibleStateType::DEFUNC)
124         {
125             uno::Any aNewValue;
126             aNewValue <<= aState;
127             CommitChange(
128                 AccessibleEventId::STATE_CHANGED,
129                 aNewValue,
130                 uno::Any());
131         }
132         return sal_True;
133     }
134     else
135         return sal_False;
136 }
137 
138 
139 
140 
141 sal_Bool AccessibleContextBase::ResetState (sal_Int16 aState)
142 {
143     ::osl::ClearableMutexGuard aGuard (maMutex);
144     ::utl::AccessibleStateSetHelper* pStateSet =
145         static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
146     if ((pStateSet != NULL) && pStateSet->contains(aState))
147     {
148         pStateSet->RemoveState (aState);
149         // Clear the mutex guard so that it is not locked during calls to listeners.
150         aGuard.clear();
151 
152         uno::Any aOldValue;
153         aOldValue <<= aState;
154         CommitChange(
155             AccessibleEventId::STATE_CHANGED,
156             uno::Any(),
157             aOldValue);
158         return sal_True;
159     }
160     else
161         return sal_False;
162 }
163 
164 
165 
166 
167 sal_Bool AccessibleContextBase::GetState (sal_Int16 aState)
168 {
169     ::osl::MutexGuard aGuard (maMutex);
170     ::utl::AccessibleStateSetHelper* pStateSet =
171         static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
172     if (pStateSet != NULL)
173         return pStateSet->contains(aState);
174     else
175         // If there is no state set then return false as a default value.
176         return sal_False;
177 }
178 
179 
180 
181 
182 void AccessibleContextBase::SetRelationSet (
183     const uno::Reference<XAccessibleRelationSet>& rxNewRelationSet)
184     throw (::com::sun::star::uno::RuntimeException)
185 {
186     OSL_TRACE ("setting relation set");
187 
188     // Try to emit some meaningfull events indicating differing relations in
189     // both sets.
190     typedef std::pair<short int,short int> RD;
191     const RD aRelationDescriptors[] = {
192         RD(AccessibleRelationType::CONTROLLED_BY, AccessibleEventId::CONTROLLED_BY_RELATION_CHANGED),
193         RD(AccessibleRelationType::CONTROLLER_FOR, AccessibleEventId::CONTROLLER_FOR_RELATION_CHANGED),
194         RD(AccessibleRelationType::LABELED_BY, AccessibleEventId::LABELED_BY_RELATION_CHANGED),
195         RD(AccessibleRelationType::LABEL_FOR, AccessibleEventId::LABEL_FOR_RELATION_CHANGED),
196         RD(AccessibleRelationType::MEMBER_OF, AccessibleEventId::MEMBER_OF_RELATION_CHANGED),
197         RD(AccessibleRelationType::INVALID, -1),
198     };
199     for (int i=0; aRelationDescriptors[i].first!=AccessibleRelationType::INVALID; i++)
200         if (mxRelationSet->containsRelation(aRelationDescriptors[i].first)
201         != rxNewRelationSet->containsRelation(aRelationDescriptors[i].first))
202         CommitChange (aRelationDescriptors[i].second, uno::Any(), uno::Any());
203 
204     mxRelationSet = rxNewRelationSet;
205 }
206 
207 
208 
209 
210 //=====  XAccessible  =========================================================
211 
212 uno::Reference< XAccessibleContext> SAL_CALL
213     AccessibleContextBase::getAccessibleContext (void)
214     throw (uno::RuntimeException)
215 {
216     ThrowIfDisposed ();
217 	return this;
218 }
219 
220 
221 
222 
223 //=====  XAccessibleContext  ==================================================
224 
225 /** No children.
226 */
227 sal_Int32 SAL_CALL
228    	AccessibleContextBase::getAccessibleChildCount (void)
229     throw (uno::RuntimeException)
230 {
231     ThrowIfDisposed ();
232     return 0;
233 }
234 
235 
236 
237 
238 /** Forward the request to the shape.  Return the requested shape or throw
239     an exception for a wrong index.
240 */
241 uno::Reference<XAccessible> SAL_CALL
242     AccessibleContextBase::getAccessibleChild (sal_Int32 nIndex)
243     throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException)
244 {
245     ThrowIfDisposed ();
246     throw lang::IndexOutOfBoundsException (
247         ::rtl::OUString::createFromAscii ("no child with index " + nIndex),
248 		NULL);
249 }
250 
251 
252 
253 
254 uno::Reference<XAccessible> SAL_CALL
255    	AccessibleContextBase::getAccessibleParent (void)
256     throw (::com::sun::star::uno::RuntimeException)
257 {
258     ThrowIfDisposed ();
259 	return mxParent;
260 }
261 
262 
263 
264 
265 sal_Int32 SAL_CALL
266    	AccessibleContextBase::getAccessibleIndexInParent (void)
267     throw (::com::sun::star::uno::RuntimeException)
268 {
269     ThrowIfDisposed ();
270 	//	Use a simple but slow solution for now.  Optimize later.
271 
272     //	Iterate over all the parent's children and search for this object.
273     if (mxParent.is())
274     {
275     	uno::Reference<XAccessibleContext> xParentContext (
276         	mxParent->getAccessibleContext());
277         if (xParentContext.is())
278         {
279         	sal_Int32 nChildCount = xParentContext->getAccessibleChildCount();
280             for (sal_Int32 i=0; i<nChildCount; i++)
281             {
282             	uno::Reference<XAccessible> xChild (xParentContext->getAccessibleChild (i));
283                 if (xChild.is())
284                 {
285                 	uno::Reference<XAccessibleContext> xChildContext = xChild->getAccessibleContext();
286 	            	if (xChildContext == (XAccessibleContext*)this)
287                     	return i;
288                 }
289             }
290         }
291    }
292 
293    //	Return -1 to indicate that this object's parent does not know about the
294    //	object.
295    return -1;
296 }
297 
298 
299 
300 
301 sal_Int16 SAL_CALL
302 	AccessibleContextBase::getAccessibleRole (void)
303     throw (::com::sun::star::uno::RuntimeException)
304 {
305     ThrowIfDisposed ();
306 	return maRole;
307 }
308 
309 
310 
311 
312 ::rtl::OUString SAL_CALL
313    	AccessibleContextBase::getAccessibleDescription (void)
314     throw (::com::sun::star::uno::RuntimeException)
315 {
316     ThrowIfDisposed ();
317 
318     return msDescription;
319 }
320 
321 
322 
323 
324 OUString SAL_CALL
325    	AccessibleContextBase::getAccessibleName (void)
326     throw (::com::sun::star::uno::RuntimeException)
327 {
328     ThrowIfDisposed ();
329 
330     if (meNameOrigin == NotSet)
331     {
332         // Do not send an event because this is the first time it has been
333         // requested.
334         msName = CreateAccessibleName();
335         meNameOrigin = AutomaticallyCreated;
336     }
337 
338     return msName;
339 }
340 
341 
342 
343 
344 /**	Return a copy of the relation set.
345 */
346 uno::Reference<XAccessibleRelationSet> SAL_CALL
347    	AccessibleContextBase::getAccessibleRelationSet (void)
348     throw (::com::sun::star::uno::RuntimeException)
349 {
350     ThrowIfDisposed ();
351 
352     // Create a copy of the relation set and return it.
353     ::utl::AccessibleRelationSetHelper* pRelationSet =
354         static_cast< ::utl::AccessibleRelationSetHelper*>(mxRelationSet.get());
355     if (pRelationSet != NULL)
356     {
357         return uno::Reference<XAccessibleRelationSet> (
358             new ::utl::AccessibleRelationSetHelper (*pRelationSet));
359     }
360     else
361         return uno::Reference<XAccessibleRelationSet>(NULL);
362 }
363 
364 
365 
366 
367 /**	Return a copy of the state set.
368     Possible states are:
369 		ENABLED
370 		SHOWING
371 		VISIBLE
372 */
373 uno::Reference<XAccessibleStateSet> SAL_CALL
374     AccessibleContextBase::getAccessibleStateSet (void)
375     throw (::com::sun::star::uno::RuntimeException)
376 {
377     ::utl::AccessibleStateSetHelper* pStateSet = NULL;
378 
379 	if (rBHelper.bDisposed)
380     {
381         // We are already disposed!
382         // Create a new state set that has only set the DEFUNC state.
383         pStateSet = new ::utl::AccessibleStateSetHelper ();
384         if (pStateSet != NULL)
385             pStateSet->AddState (AccessibleStateType::DEFUNC);
386     }
387     else
388     {
389         // Create a copy of the state set and return it.
390         pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
391 
392         // Merge current focused state from edit engine.
393 #if 0
394         if (aState == AccessibleStateType::FOCUSED
395             && pStateSet != NULL
396             && mpText != NULL)
397         {
398             if (mpText->GetFocusedState ())
399                 pStateSet->AddState (aState);
400             else
401                 pStateSet->RemoveState (aState);
402         }
403 #endif
404         if (pStateSet != NULL)
405             pStateSet = new ::utl::AccessibleStateSetHelper (*pStateSet);
406     }
407 
408     return uno::Reference<XAccessibleStateSet>(pStateSet);
409 }
410 
411 
412 
413 
414 lang::Locale SAL_CALL
415    	AccessibleContextBase::getLocale (void)
416 	throw (IllegalAccessibleComponentStateException,
417         ::com::sun::star::uno::RuntimeException)
418 {
419     ThrowIfDisposed ();
420     // Delegate request to parent.
421 	if (mxParent.is())
422     {
423     	uno::Reference<XAccessibleContext> xParentContext (
424         	mxParent->getAccessibleContext());
425         if (xParentContext.is())
426 	    	return xParentContext->getLocale ();
427     }
428 
429     //	No locale and no parent.  Therefore throw exception to indicate this
430     //	cluelessness.
431     throw IllegalAccessibleComponentStateException ();
432 }
433 
434 
435 
436 
437 //=====  XAccessibleEventListener  ============================================
438 
439 void SAL_CALL
440     AccessibleContextBase::addEventListener (
441         const uno::Reference<XAccessibleEventListener >& rxListener)
442     throw (uno::RuntimeException)
443 {
444 	if (rxListener.is())
445     {
446 	    if (rBHelper.bDisposed || rBHelper.bInDispose)
447 	    {
448             uno::Reference<uno::XInterface> x ((lang::XComponent *)this, uno::UNO_QUERY);
449 		    rxListener->disposing (lang::EventObject (x));
450 	    }
451 	    else
452 	    {
453 		    if (!mnClientId)
454                 mnClientId = comphelper::AccessibleEventNotifier::registerClient( );
455 		    comphelper::AccessibleEventNotifier::addEventListener( mnClientId, rxListener );
456 	    }
457     }
458 }
459 
460 
461 
462 
463 void SAL_CALL
464     AccessibleContextBase::removeEventListener (
465         const uno::Reference<XAccessibleEventListener >& rxListener )
466     throw (uno::RuntimeException)
467 {
468     ThrowIfDisposed ();
469 	if (rxListener.is())
470 	{
471         sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( mnClientId, rxListener );
472 		if ( !nListenerCount )
473 		{
474 			// no listeners anymore
475 			// -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
476 			// and at least to us not firing any events anymore, in case somebody calls
477 			// NotifyAccessibleEvent, again
478 			comphelper::AccessibleEventNotifier::revokeClient( mnClientId );
479 			mnClientId = 0;
480 		}
481 	}
482 }
483 
484 
485 
486 
487 //=====  XServiceInfo  ========================================================
488 
489 ::rtl::OUString SAL_CALL
490    	AccessibleContextBase::getImplementationName (void)
491     throw (::com::sun::star::uno::RuntimeException)
492 {
493     ThrowIfDisposed ();
494 	return OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleContextBase"));
495 }
496 
497 
498 
499 
500 sal_Bool SAL_CALL
501  	AccessibleContextBase::supportsService (const OUString& sServiceName)
502     throw (::com::sun::star::uno::RuntimeException)
503 {
504     ThrowIfDisposed ();
505     //  Iterate over all supported service names and return true if on of them
506     //  matches the given name.
507     uno::Sequence< ::rtl::OUString> aSupportedServices (
508         getSupportedServiceNames ());
509     for (int i=0; i<aSupportedServices.getLength(); i++)
510         if (sServiceName == aSupportedServices[i])
511             return sal_True;
512     return sal_False;
513 }
514 
515 
516 
517 
518 uno::Sequence< ::rtl::OUString> SAL_CALL
519    	AccessibleContextBase::getSupportedServiceNames (void)
520     throw (::com::sun::star::uno::RuntimeException)
521 {
522     ThrowIfDisposed ();
523 	static const OUString sServiceNames[2] = {
524         OUString(RTL_CONSTASCII_USTRINGPARAM(
525             "com.sun.star.accessibility.Accessible")),
526         OUString(RTL_CONSTASCII_USTRINGPARAM(
527             "com.sun.star.accessibility.AccessibleContext"))
528     };
529 	return uno::Sequence<OUString> (sServiceNames, 2);
530 }
531 
532 
533 
534 
535 //=====  XTypeProvider  =======================================================
536 
537 uno::Sequence< ::com::sun::star::uno::Type>
538 	AccessibleContextBase::getTypes (void)
539     throw (::com::sun::star::uno::RuntimeException)
540 {
541     ThrowIfDisposed ();
542 
543     // This class supports no interfaces on its own.  Just return those
544     // supported by the base class.
545 	return BaseClass::getTypes();
546 }
547 
548 
549 
550 
551 uno::Sequence<sal_Int8> SAL_CALL
552 	AccessibleContextBase::getImplementationId (void)
553     throw (::com::sun::star::uno::RuntimeException)
554 {
555     ThrowIfDisposed ();
556 	static uno::Sequence<sal_Int8> aId;
557 	if (aId.getLength() == 0)
558 	{
559         ::osl::MutexGuard aGuard (maMutex);
560 		aId.realloc (16);
561 		rtl_createUuid ((sal_uInt8 *)aId.getArray(), 0, sal_True);
562 	}
563 	return aId;
564 }
565 
566 
567 
568 
569 //=====  internal  ============================================================
570 
571 void SAL_CALL AccessibleContextBase::disposing (void)
572 {
573     SetState (AccessibleStateType::DEFUNC);
574 
575     ::osl::MutexGuard aGuard (maMutex);
576 
577     // Send a disposing to all listeners.
578 	if ( mnClientId )
579 	{
580         comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( mnClientId, *this );
581 		mnClientId =  0;
582 	}
583 }
584 
585 
586 
587 
588 void AccessibleContextBase::SetAccessibleDescription (
589     const ::rtl::OUString& rDescription,
590     StringOrigin eDescriptionOrigin)
591     throw (uno::RuntimeException)
592 {
593     if (eDescriptionOrigin < meDescriptionOrigin
594         || (eDescriptionOrigin == meDescriptionOrigin && msDescription != rDescription))
595 	{
596 		uno::Any aOldValue, aNewValue;
597 		aOldValue <<= msDescription;
598 		aNewValue <<= rDescription;
599 
600 		msDescription = rDescription;
601         meDescriptionOrigin = eDescriptionOrigin;
602 
603         CommitChange(
604             AccessibleEventId::DESCRIPTION_CHANGED,
605             aNewValue,
606             aOldValue);
607 	}
608 }
609 
610 
611 
612 
613 void AccessibleContextBase::SetAccessibleName (
614     const ::rtl::OUString& rName,
615     StringOrigin eNameOrigin)
616     throw (uno::RuntimeException)
617 {
618     if (eNameOrigin < meNameOrigin
619         || (eNameOrigin == meNameOrigin && msName != rName))
620 	{
621 		uno::Any aOldValue, aNewValue;
622 		aOldValue <<= msName;
623 		aNewValue <<= rName;
624 
625 		msName = rName;
626         meNameOrigin = eNameOrigin;
627 
628         CommitChange(
629             AccessibleEventId::NAME_CHANGED,
630             aNewValue,
631             aOldValue);
632 	}
633 }
634 
635 
636 
637 
638 ::rtl::OUString AccessibleContextBase::CreateAccessibleDescription (void)
639     throw (::com::sun::star::uno::RuntimeException)
640 {
641     return ::rtl::OUString::createFromAscii ("Empty Description");
642 }
643 
644 
645 
646 
647 ::rtl::OUString AccessibleContextBase::CreateAccessibleName (void)
648     throw (::com::sun::star::uno::RuntimeException)
649 {
650     return ::rtl::OUString::createFromAscii ("Empty Name");
651 }
652 
653 
654 
655 
656 void AccessibleContextBase::CommitChange (
657     sal_Int16 nEventId,
658     const uno::Any& rNewValue,
659     const uno::Any& rOldValue)
660 {
661     // Do not call FireEvent and do not even create the event object when no
662     // listener has been registered yet.  Creating the event object can
663     // otherwise lead to a crash.  See issue 93419 for details.
664 	if (mnClientId != 0)
665     {
666         AccessibleEventObject aEvent (
667             static_cast<XAccessibleContext*>(this),
668             nEventId,
669             rNewValue,
670             rOldValue);
671 
672         FireEvent (aEvent);
673     }
674 }
675 
676 
677 
678 
679 void AccessibleContextBase::FireEvent (const AccessibleEventObject& aEvent)
680 {
681 	if (mnClientId)
682 		comphelper::AccessibleEventNotifier::addEvent( mnClientId, aEvent );
683 }
684 
685 
686 
687 
688 void AccessibleContextBase::ThrowIfDisposed (void)
689     throw (::com::sun::star::lang::DisposedException)
690 {
691 	if (rBHelper.bDisposed || rBHelper.bInDispose)
692 	{
693         OSL_TRACE ("Calling disposed object. Throwing exception:");
694         throw lang::DisposedException (
695             OUString(RTL_CONSTASCII_USTRINGPARAM("object has been already disposed")),
696             static_cast<uno::XWeak*>(this));
697     }
698 }
699 
700 
701 
702 sal_Bool AccessibleContextBase::IsDisposed (void)
703 {
704 	return (rBHelper.bDisposed || rBHelper.bInDispose);
705 }
706 
707 
708 
709 void AccessibleContextBase::SetAccessibleRole( sal_Int16 _nRole )
710 {
711 	maRole = _nRole;
712 }
713 
714 
715 } // end of namespace accessibility
716