xref: /AOO41X/main/sc/source/ui/Accessibility/AccessibleContextBase.cxx (revision b3f79822e811ac3493b185030a72c3c5a51f32d8)
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 wich 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     throw (uno::RuntimeException)
129 {
130     uno::Any aAny (ScAccessibleContextBaseWeakImpl::queryInterface(rType));
131     return aAny.hasValue() ? aAny : ScAccessibleContextBaseImplEvent::queryInterface(rType);
132 }
133 
acquire()134 void SAL_CALL ScAccessibleContextBase::acquire()
135     throw ()
136 {
137     ScAccessibleContextBaseWeakImpl::acquire();
138 }
139 
release()140 void SAL_CALL ScAccessibleContextBase::release()
141     throw ()
142 {
143     ScAccessibleContextBaseWeakImpl::release();
144 }
145 
146 //=====  SfxListener  =====================================================
147 
Notify(SfxBroadcaster &,const SfxHint & rHint)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
getAccessibleContext(void)164     ScAccessibleContextBase::getAccessibleContext(void)
165     throw (uno::RuntimeException)
166 {
167     return this;
168 }
169 
170 //=====  XAccessibleComponent  ================================================
171 
containsPoint(const awt::Point & rPoint)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 
getAccessibleAtPoint(const awt::Point &)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 
getBounds()188 awt::Rectangle SAL_CALL ScAccessibleContextBase::getBounds(  )
189         throw (uno::RuntimeException)
190 {
191     ScUnoGuard aGuard;
192     IsObjectValid();
193     return AWTRectangle(GetBoundingBox());
194 }
195 
getLocation()196 awt::Point SAL_CALL ScAccessibleContextBase::getLocation(  )
197         throw (uno::RuntimeException)
198 {
199     ScUnoGuard aGuard;
200     IsObjectValid();
201     return AWTPoint(GetBoundingBox().TopLeft());
202 }
203 
getLocationOnScreen()204 awt::Point SAL_CALL ScAccessibleContextBase::getLocationOnScreen(  )
205         throw (uno::RuntimeException)
206 {
207     ScUnoGuard aGuard;
208     IsObjectValid();
209     return AWTPoint(GetBoundingBoxOnScreen().TopLeft());
210 }
211 
getSize()212 awt::Size SAL_CALL ScAccessibleContextBase::getSize(  )
213         throw (uno::RuntimeException)
214 {
215     ScUnoGuard aGuard;
216     IsObjectValid();
217     return AWTSize(GetBoundingBox().GetSize());
218 }
219 
isShowing()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 
isVisible()239 sal_Bool SAL_CALL ScAccessibleContextBase::isVisible(  )
240         throw (uno::RuntimeException)
241 {
242     return sal_True;
243 }
244 
grabFocus()245 void SAL_CALL ScAccessibleContextBase::grabFocus(  )
246         throw (uno::RuntimeException)
247 {
248     DBG_ERROR("not implemented");
249 }
250 
getForeground()251 sal_Int32 SAL_CALL ScAccessibleContextBase::getForeground(  )
252         throw (uno::RuntimeException)
253 {
254     return COL_BLACK;
255 }
256 
getBackground()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
getAccessibleChildCount(void)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
getAccessibleChild(sal_Int32)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
getAccessibleParent(void)282     ScAccessibleContextBase::getAccessibleParent(void)
283     throw (uno::RuntimeException)
284 {
285     return mxParent;
286 }
287 
288 sal_Int32 SAL_CALL
getAccessibleIndexInParent(void)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
getAccessibleRole(void)323     ScAccessibleContextBase::getAccessibleRole(void)
324     throw (uno::RuntimeException)
325 {
326     return maRole;
327 }
328 
329 ::rtl::OUString SAL_CALL
getAccessibleDescription(void)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
getAccessibleName(void)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
getAccessibleRelationSet(void)384     ScAccessibleContextBase::getAccessibleRelationSet(void)
385     throw (uno::RuntimeException)
386 {
387     return new utl::AccessibleRelationSetHelper();
388 }
389 
390 uno::Reference<XAccessibleStateSet> SAL_CALL
getAccessibleStateSet(void)391         ScAccessibleContextBase::getAccessibleStateSet(void)
392     throw (uno::RuntimeException)
393 {
394     return uno::Reference<XAccessibleStateSet>();
395 }
396 
397 lang::Locale SAL_CALL
getLocale(void)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
addEventListener(const uno::Reference<XAccessibleEventListener> & xListener)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
removeEventListener(const uno::Reference<XAccessibleEventListener> & xListener)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 
disposing(const lang::EventObject & rSource)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 
notifyEvent(const AccessibleEventObject &)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
getImplementationName(void)481     ScAccessibleContextBase::getImplementationName(void)
482     throw (uno::RuntimeException)
483 {
484     return OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessibleContextBase"));
485 }
486 
487 sal_Bool SAL_CALL
supportsService(const OUString & sServiceName)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
getSupportedServiceNames(void)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 
getTypes()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
getImplementationId(void)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
createAccessibleDescription(void)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
createAccessibleName(void)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 
CommitChange(const AccessibleEventObject & rEvent) const559 void ScAccessibleContextBase::CommitChange(const AccessibleEventObject& rEvent) const
560 {
561     if (mnClientId)
562         comphelper::AccessibleEventNotifier::addEvent( mnClientId, rEvent );
563 }
564 
ChangeName()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 
CommitFocusGained() const580 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 
CommitFocusLost() const592 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 
GetBoundingBoxOnScreen(void) const604 Rectangle ScAccessibleContextBase::GetBoundingBoxOnScreen(void) const
605         throw (uno::RuntimeException)
606 {
607     DBG_ERROR("not implemented");
608     return Rectangle();
609 }
610 
GetBoundingBox(void) const611 Rectangle ScAccessibleContextBase::GetBoundingBox(void) const
612         throw (uno::RuntimeException)
613 {
614     DBG_ERROR("not implemented");
615     return Rectangle();
616 }
617 
IsObjectValid() const618 void ScAccessibleContextBase::IsObjectValid() const
619         throw (lang::DisposedException)
620 {
621     if (rBHelper.bDisposed || rBHelper.bInDispose)
622         throw lang::DisposedException();
623 }
624 
625