xref: /trunk/main/sc/source/ui/Accessibility/AccessibleContextBase.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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 
DBG_NAME(ScAccessibleContextBase)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 
~ScAccessibleContextBase(void)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 which have a weak reference to this object
80         dispose();
81     }
82 }
83 
Init()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 
disposing()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 
queryInterface(uno::Type const & rType)127 uno::Any SAL_CALL ScAccessibleContextBase::queryInterface( uno::Type const & rType )
128 {
129     uno::Any aAny (ScAccessibleContextBaseWeakImpl::queryInterface(rType));
130     return aAny.hasValue() ? aAny : ScAccessibleContextBaseImplEvent::queryInterface(rType);
131 }
132 
acquire()133 void SAL_CALL ScAccessibleContextBase::acquire()
134     throw ()
135 {
136     ScAccessibleContextBaseWeakImpl::acquire();
137 }
138 
release()139 void SAL_CALL ScAccessibleContextBase::release()
140     throw ()
141 {
142     ScAccessibleContextBaseWeakImpl::release();
143 }
144 
145 //=====  SfxListener  =====================================================
146 
Notify(SfxBroadcaster &,const SfxHint & rHint)147 void ScAccessibleContextBase::Notify( SfxBroadcaster&, const SfxHint& rHint )
148 {
149     if (rHint.ISA( SfxSimpleHint ) )
150     {
151         const SfxSimpleHint& rRef = (const SfxSimpleHint&)rHint;
152         if (rRef.GetId() == SFX_HINT_DYING)
153         {
154             // it seems the Broadcaster is dying, since the view is dying
155             dispose();
156         }
157     }
158 }
159 
160 //=====  XAccessible  =========================================================
161 
162 uno::Reference< XAccessibleContext> SAL_CALL
getAccessibleContext(void)163     ScAccessibleContextBase::getAccessibleContext(void)
164 {
165     return this;
166 }
167 
168 //=====  XAccessibleComponent  ================================================
169 
containsPoint(const awt::Point & rPoint)170 sal_Bool SAL_CALL ScAccessibleContextBase::containsPoint(const awt::Point& rPoint )
171 {
172     ScUnoGuard aGuard;
173     IsObjectValid();
174     return Rectangle (Point(), GetBoundingBox().GetSize()).IsInside(VCLPoint(rPoint));
175 }
176 
getAccessibleAtPoint(const awt::Point &)177 uno::Reference< XAccessible > SAL_CALL ScAccessibleContextBase::getAccessibleAtPoint(
178         const awt::Point& /* rPoint */ )
179 {
180     DBG_ERROR("not implemented");
181     return uno::Reference<XAccessible>();
182 }
183 
getBounds()184 awt::Rectangle SAL_CALL ScAccessibleContextBase::getBounds(  )
185 {
186     ScUnoGuard aGuard;
187     IsObjectValid();
188     return AWTRectangle(GetBoundingBox());
189 }
190 
getLocation()191 awt::Point SAL_CALL ScAccessibleContextBase::getLocation(  )
192 {
193     ScUnoGuard aGuard;
194     IsObjectValid();
195     return AWTPoint(GetBoundingBox().TopLeft());
196 }
197 
getLocationOnScreen()198 awt::Point SAL_CALL ScAccessibleContextBase::getLocationOnScreen(  )
199 {
200     ScUnoGuard aGuard;
201     IsObjectValid();
202     return AWTPoint(GetBoundingBoxOnScreen().TopLeft());
203 }
204 
getSize()205 awt::Size SAL_CALL ScAccessibleContextBase::getSize(  )
206 {
207     ScUnoGuard aGuard;
208     IsObjectValid();
209     return AWTSize(GetBoundingBox().GetSize());
210 }
211 
isShowing()212 sal_Bool SAL_CALL ScAccessibleContextBase::isShowing(  )
213 {
214     ScUnoGuard aGuard;
215     IsObjectValid();
216     sal_Bool bShowing(sal_False);
217     if (mxParent.is())
218     {
219         uno::Reference<XAccessibleComponent> xParentComponent (mxParent->getAccessibleContext(), uno::UNO_QUERY);
220         if (xParentComponent.is())
221         {
222             Rectangle aParentBounds(VCLRectangle(xParentComponent->getBounds()));
223             Rectangle aBounds(VCLRectangle(getBounds()));
224             bShowing = aBounds.IsOver(aParentBounds);
225         }
226     }
227     return bShowing;
228 }
229 
isVisible()230 sal_Bool SAL_CALL ScAccessibleContextBase::isVisible(  )
231 {
232     return sal_True;
233 }
234 
grabFocus()235 void SAL_CALL ScAccessibleContextBase::grabFocus(  )
236 {
237     DBG_ERROR("not implemented");
238 }
239 
getForeground()240 sal_Int32 SAL_CALL ScAccessibleContextBase::getForeground(  )
241 {
242     return COL_BLACK;
243 }
244 
getBackground()245 sal_Int32 SAL_CALL ScAccessibleContextBase::getBackground(  )
246 {
247     return COL_WHITE;
248 }
249 
250 //=====  XAccessibleContext  ==================================================
251 
252 sal_Int32 SAL_CALL
getAccessibleChildCount(void)253     ScAccessibleContextBase::getAccessibleChildCount(void)
254 {
255     DBG_ERROR("should be implemented in the abrevated class");
256     return 0;
257 }
258 
259 uno::Reference<XAccessible> SAL_CALL
getAccessibleChild(sal_Int32)260     ScAccessibleContextBase::getAccessibleChild(sal_Int32 /* nIndex */)
261 {
262     DBG_ERROR("should be implemented in the abrevated class");
263     return uno::Reference<XAccessible>();
264 }
265 
266 uno::Reference<XAccessible> SAL_CALL
getAccessibleParent(void)267     ScAccessibleContextBase::getAccessibleParent(void)
268 {
269     return mxParent;
270 }
271 
272 sal_Int32 SAL_CALL
getAccessibleIndexInParent(void)273     ScAccessibleContextBase::getAccessibleIndexInParent(void)
274 {
275     ScUnoGuard aGuard;
276     IsObjectValid();
277     //  Use a simple but slow solution for now.  Optimize later.
278    //   Return -1 to indicate that this object's parent does not know about the
279    //   object.
280     sal_Int32 nIndex(-1);
281 
282     //  Iterate over all the parent's children and search for this object.
283     if (mxParent.is())
284     {
285         uno::Reference<XAccessibleContext> xParentContext (
286             mxParent->getAccessibleContext());
287         if (xParentContext.is())
288         {
289             sal_Int32 nChildCount = xParentContext->getAccessibleChildCount();
290             for (sal_Int32 i=0; i<nChildCount; ++i)
291             {
292                 uno::Reference<XAccessible> xChild (xParentContext->getAccessibleChild (i));
293                 if (xChild.is())
294                 {
295                     if (xChild.get() == this)
296                         nIndex = i;
297                 }
298             }
299         }
300    }
301 
302    return nIndex;
303 }
304 
305 sal_Int16 SAL_CALL
getAccessibleRole(void)306     ScAccessibleContextBase::getAccessibleRole(void)
307 {
308     return maRole;
309 }
310 
311 ::rtl::OUString SAL_CALL
getAccessibleDescription(void)312     ScAccessibleContextBase::getAccessibleDescription(void)
313 {
314     ScUnoGuard aGuard;
315     IsObjectValid();
316     if (!msDescription.getLength())
317     {
318         OUString sDescription(createAccessibleDescription());
319 //      DBG_ASSERT(sDescription.getLength(), "We should give always a description.");
320 
321         if (msDescription != sDescription)
322         {
323             AccessibleEventObject aEvent;
324             aEvent.EventId = AccessibleEventId::DESCRIPTION_CHANGED;
325             aEvent.Source = uno::Reference< XAccessibleContext >(this);
326             aEvent.OldValue <<= msDescription;
327             aEvent.NewValue <<= sDescription;
328 
329             msDescription = sDescription;
330 
331             CommitChange(aEvent);
332         }
333     }
334     return msDescription;
335 }
336 
337 OUString SAL_CALL
getAccessibleName(void)338     ScAccessibleContextBase::getAccessibleName(void)
339 {
340     ScUnoGuard aGuard;
341     IsObjectValid();
342     if (!msName.getLength())
343     {
344         OUString sName(createAccessibleName());
345         DBG_ASSERT(sName.getLength(), "We should give always a name.");
346 
347         if (msName != sName)
348         {
349             AccessibleEventObject aEvent;
350             aEvent.EventId = AccessibleEventId::NAME_CHANGED;
351             aEvent.Source = uno::Reference< XAccessibleContext >(this);
352             aEvent.OldValue <<= msName;
353             aEvent.NewValue <<= sName;
354 
355             msName = sName;
356 
357             CommitChange(aEvent);
358         }
359     }
360     return msName;
361 }
362 
363 uno::Reference<XAccessibleRelationSet> SAL_CALL
getAccessibleRelationSet(void)364     ScAccessibleContextBase::getAccessibleRelationSet(void)
365 {
366     return new utl::AccessibleRelationSetHelper();
367 }
368 
369 uno::Reference<XAccessibleStateSet> SAL_CALL
getAccessibleStateSet(void)370         ScAccessibleContextBase::getAccessibleStateSet(void)
371 {
372     return uno::Reference<XAccessibleStateSet>();
373 }
374 
375 lang::Locale SAL_CALL
getLocale(void)376     ScAccessibleContextBase::getLocale(void)
377 {
378     ScUnoGuard aGuard;
379     IsObjectValid();
380     if (mxParent.is())
381     {
382         uno::Reference<XAccessibleContext> xParentContext (
383             mxParent->getAccessibleContext());
384         if (xParentContext.is())
385             return xParentContext->getLocale ();
386     }
387 
388     //  No locale and no parent.  Therefore throw exception to indicate this
389     //  cluelessness.
390     throw IllegalAccessibleComponentStateException ();
391 }
392 
393     //=====  XAccessibleEventBroadcaster  =====================================
394 
395 void SAL_CALL
addEventListener(const uno::Reference<XAccessibleEventListener> & xListener)396     ScAccessibleContextBase::addEventListener(
397         const uno::Reference<XAccessibleEventListener>& xListener)
398 {
399     if (xListener.is())
400     {
401         ScUnoGuard aGuard;
402         IsObjectValid();
403         if (!IsDefunc())
404         {
405             if (!mnClientId)
406                 mnClientId = comphelper::AccessibleEventNotifier::registerClient( );
407             comphelper::AccessibleEventNotifier::addEventListener( mnClientId, xListener );
408         }
409     }
410 }
411 
412 void SAL_CALL
removeEventListener(const uno::Reference<XAccessibleEventListener> & xListener)413     ScAccessibleContextBase::removeEventListener(
414         const uno::Reference<XAccessibleEventListener>& xListener)
415 {
416     if (xListener.is())
417     {
418         ScUnoGuard aGuard;
419         if (!IsDefunc() && mnClientId)
420         {
421             sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( mnClientId, xListener );
422             if ( !nListenerCount )
423             {
424                 // no listeners anymore
425                 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
426                 // and at least to us not firing any events anymore, in case somebody calls
427                 // NotifyAccessibleEvent, again
428                 comphelper::AccessibleEventNotifier::revokeClient( mnClientId );
429                 mnClientId = 0;
430             }
431         }
432     }
433 }
434 
435     //=====  XAccessibleEventListener  ========================================
436 
disposing(const lang::EventObject & rSource)437 void SAL_CALL ScAccessibleContextBase::disposing(
438     const lang::EventObject& rSource )
439 {
440     ScUnoGuard aGuard;
441     if (rSource.Source == mxParent)
442         dispose();
443 }
444 
notifyEvent(const AccessibleEventObject &)445 void SAL_CALL ScAccessibleContextBase::notifyEvent(
446         const AccessibleEventObject& /* aEvent */ )
447 {
448 }
449 
450 //=====  XServiceInfo  ========================================================
451 
452 ::rtl::OUString SAL_CALL
getImplementationName(void)453     ScAccessibleContextBase::getImplementationName(void)
454 {
455     return OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessibleContextBase"));
456 }
457 
458 sal_Bool SAL_CALL
supportsService(const OUString & sServiceName)459     ScAccessibleContextBase::supportsService(const OUString& sServiceName)
460 {
461     //  Iterate over all supported service names and return true if on of them
462     //  matches the given name.
463     uno::Sequence< ::rtl::OUString> aSupportedServices (
464         getSupportedServiceNames ());
465     sal_Int32 nLength(aSupportedServices.getLength());
466     const OUString* pServiceNames = aSupportedServices.getConstArray();
467     for (int i=0; i<nLength; ++i, ++pServiceNames)
468         if (sServiceName == *pServiceNames)
469             return sal_True;
470     return sal_False;
471 }
472 
473 uno::Sequence< ::rtl::OUString> SAL_CALL
getSupportedServiceNames(void)474     ScAccessibleContextBase::getSupportedServiceNames(void)
475 {
476     uno::Sequence<OUString> aServiceNames(2);
477     OUString* pServiceNames = aServiceNames.getArray();
478     if (pServiceNames)
479     {
480         pServiceNames[0] = OUString(RTL_CONSTASCII_USTRINGPARAM ("com.sun.star.accessibility.Accessible"));
481         pServiceNames[1] = OUString(RTL_CONSTASCII_USTRINGPARAM ("com.sun.star.accessibility.AccessibleContext"));
482     }
483 
484     return aServiceNames;
485 }
486 
487 //=====  XTypeProvider  =======================================================
488 
getTypes()489 uno::Sequence< uno::Type > SAL_CALL ScAccessibleContextBase::getTypes()
490 {
491     return comphelper::concatSequences(ScAccessibleContextBaseWeakImpl::getTypes(), ScAccessibleContextBaseImplEvent::getTypes());
492 }
493 
494 uno::Sequence<sal_Int8> SAL_CALL
getImplementationId(void)495     ScAccessibleContextBase::getImplementationId(void)
496 {
497     ScUnoGuard aGuard;
498     IsObjectValid();
499     static uno::Sequence<sal_Int8> aId;
500     if (aId.getLength() == 0)
501     {
502         aId.realloc (16);
503         rtl_createUuid (reinterpret_cast<sal_uInt8 *>(aId.getArray()), 0, sal_True);
504     }
505     return aId;
506 }
507 
508 //=====  internal  ============================================================
509 
510 ::rtl::OUString SAL_CALL
createAccessibleDescription(void)511     ScAccessibleContextBase::createAccessibleDescription(void)
512 {
513     DBG_ERROR("should be implemented in the abrevated class");
514     return rtl::OUString();
515 }
516 
517 ::rtl::OUString SAL_CALL
createAccessibleName(void)518     ScAccessibleContextBase::createAccessibleName(void)
519 {
520     DBG_ERROR("should be implemented in the abrevated class");
521     return rtl::OUString();
522 }
523 
CommitChange(const AccessibleEventObject & rEvent) const524 void ScAccessibleContextBase::CommitChange(const AccessibleEventObject& rEvent) const
525 {
526     if (mnClientId)
527         comphelper::AccessibleEventNotifier::addEvent( mnClientId, rEvent );
528 }
529 
ChangeName()530 void ScAccessibleContextBase::ChangeName()
531 {
532     AccessibleEventObject aEvent;
533     aEvent.EventId = AccessibleEventId::NAME_CHANGED;
534     aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this));
535     aEvent.OldValue <<= msName;
536 
537     msName = rtl::OUString(); // reset the name so it will be hold again
538     getAccessibleName(); // create the new name
539 
540     aEvent.NewValue <<= msName;
541 
542     CommitChange(aEvent);
543 }
544 
CommitFocusGained() const545 void ScAccessibleContextBase::CommitFocusGained() const
546 {
547     AccessibleEventObject aEvent;
548     aEvent.EventId = AccessibleEventId::STATE_CHANGED;
549     aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this));
550     aEvent.NewValue <<= AccessibleStateType::FOCUSED;
551 
552     CommitChange(aEvent);
553 
554     ::vcl::unohelper::NotifyAccessibleStateEventGlobally(aEvent);
555 }
556 
CommitFocusLost() const557 void ScAccessibleContextBase::CommitFocusLost() const
558 {
559     AccessibleEventObject aEvent;
560     aEvent.EventId = AccessibleEventId::STATE_CHANGED;
561     aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this));
562     aEvent.OldValue <<= AccessibleStateType::FOCUSED;
563 
564     CommitChange(aEvent);
565 
566     vcl::unohelper::NotifyAccessibleStateEventGlobally(aEvent);
567 }
568 
GetBoundingBoxOnScreen(void) const569 Rectangle ScAccessibleContextBase::GetBoundingBoxOnScreen(void) const
570 {
571     DBG_ERROR("not implemented");
572     return Rectangle();
573 }
574 
GetBoundingBox(void) const575 Rectangle ScAccessibleContextBase::GetBoundingBox(void) const
576 {
577     DBG_ERROR("not implemented");
578     return Rectangle();
579 }
580 
IsObjectValid() const581 void ScAccessibleContextBase::IsObjectValid() const
582 {
583     if (rBHelper.bDisposed || rBHelper.bInDispose)
584         throw lang::DisposedException();
585 }
586