1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: AccessibleContextBase.cxx,v $
10 * $Revision: 1.33.32.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
35 #include "AccessibleContextBase.hxx"
36 #include "unoguard.hxx"
37 #include <com/sun/star/accessibility/AccessibleRole.hpp>
38 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
39 #ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLESTATETYPE_HPP_
40 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
42 #include <com/sun/star/beans/PropertyChangeEvent.hpp>
44 #include <tools/debug.hxx>
45 #include <tools/gen.hxx>
46 #ifndef _UTL_ACCESSIBLESTATESETHELPER_HXX
47 #include <unotools/accessiblestatesethelper.hxx>
49 #include <toolkit/helper/convert.hxx>
50 #include <svtools/smplhint.hxx>
51 #include <comphelper/sequence.hxx>
52 #include <unotools/accessiblerelationsethelper.hxx>
53 #include <vcl/unohelp.hxx>
54 #include <tools/color.hxx>
55 #include <comphelper/accessibleeventnotifier.hxx>
57 using namespace ::rtl
;
58 using namespace ::com::sun::star
;
59 using namespace ::com::sun::star::accessibility
;
61 //===== internal ============================================================
63 DBG_NAME(ScAccessibleContextBase
)
65 ScAccessibleContextBase::ScAccessibleContextBase(
66 const uno::Reference
<XAccessible
>& rxParent
,
67 const sal_Int16 aRole
)
69 ScAccessibleContextBaseWeakImpl(m_aMutex
),
74 DBG_CTOR(ScAccessibleContextBase
, NULL
);
78 ScAccessibleContextBase::~ScAccessibleContextBase(void)
80 DBG_DTOR(ScAccessibleContextBase
, NULL
);
82 if (!IsDefunc() && !rBHelper
.bInDispose
)
84 // increment refcount to prevent double call off dtor
85 osl_incrementInterlockedCount( &m_refCount
);
86 // call dispose to inform object wich have a weak reference to this object
91 void ScAccessibleContextBase::Init()
93 // hold reference to make sure that the destructor is not called
94 uno::Reference
< XAccessibleContext
> xOwnContext(this);
98 uno::Reference
< XAccessibleEventBroadcaster
> xBroadcaster (mxParent
->getAccessibleContext(), uno::UNO_QUERY
);
99 if (xBroadcaster
.is())
100 xBroadcaster
->addEventListener(this);
102 msName
= createAccessibleName();
103 msDescription
= createAccessibleDescription();
106 void SAL_CALL
ScAccessibleContextBase::disposing()
109 // CommitDefunc(); not necessary and should not be send, because it cost a lot of time
111 // hold reference to make sure that the destructor is not called
112 uno::Reference
< XAccessibleContext
> xOwnContext(this);
116 sal_Int32
nTemClientId(mnClientId
);
118 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( nTemClientId
, *this );
123 uno::Reference
< XAccessibleEventBroadcaster
> xBroadcaster (mxParent
->getAccessibleContext(), uno::UNO_QUERY
);
124 if (xBroadcaster
.is())
125 xBroadcaster
->removeEventListener(this);
129 ScAccessibleContextBaseWeakImpl::disposing();
132 //===== XInterface =====================================================
134 uno::Any SAL_CALL
ScAccessibleContextBase::queryInterface( uno::Type
const & rType
)
135 throw (uno::RuntimeException
)
137 uno::Any
aAny (ScAccessibleContextBaseWeakImpl::queryInterface(rType
));
138 return aAny
.hasValue() ? aAny
: ScAccessibleContextBaseImplEvent::queryInterface(rType
);
141 void SAL_CALL
ScAccessibleContextBase::acquire()
144 ScAccessibleContextBaseWeakImpl::acquire();
147 void SAL_CALL
ScAccessibleContextBase::release()
150 ScAccessibleContextBaseWeakImpl::release();
153 //===== SfxListener =====================================================
155 void ScAccessibleContextBase::Notify( SfxBroadcaster
&, const SfxHint
& rHint
)
157 if (rHint
.ISA( SfxSimpleHint
) )
159 const SfxSimpleHint
& rRef
= (const SfxSimpleHint
&)rHint
;
160 if (rRef
.GetId() == SFX_HINT_DYING
)
162 // it seems the Broadcaster is dying, since the view is dying
168 //===== XAccessible =========================================================
170 uno::Reference
< XAccessibleContext
> SAL_CALL
171 ScAccessibleContextBase::getAccessibleContext(void)
172 throw (uno::RuntimeException
)
177 //===== XAccessibleComponent ================================================
179 sal_Bool SAL_CALL
ScAccessibleContextBase::containsPoint(const awt::Point
& rPoint
)
180 throw (uno::RuntimeException
)
184 return Rectangle (Point(), GetBoundingBox().GetSize()).IsInside(VCLPoint(rPoint
));
187 uno::Reference
< XAccessible
> SAL_CALL
ScAccessibleContextBase::getAccessibleAtPoint(
188 const awt::Point
& /* rPoint */ )
189 throw (uno::RuntimeException
)
191 DBG_ERROR("not implemented");
192 return uno::Reference
<XAccessible
>();
195 awt::Rectangle SAL_CALL
ScAccessibleContextBase::getBounds( )
196 throw (uno::RuntimeException
)
200 return AWTRectangle(GetBoundingBox());
203 awt::Point SAL_CALL
ScAccessibleContextBase::getLocation( )
204 throw (uno::RuntimeException
)
208 return AWTPoint(GetBoundingBox().TopLeft());
211 awt::Point SAL_CALL
ScAccessibleContextBase::getLocationOnScreen( )
212 throw (uno::RuntimeException
)
216 return AWTPoint(GetBoundingBoxOnScreen().TopLeft());
219 awt::Size SAL_CALL
ScAccessibleContextBase::getSize( )
220 throw (uno::RuntimeException
)
224 return AWTSize(GetBoundingBox().GetSize());
227 sal_Bool SAL_CALL
ScAccessibleContextBase::isShowing( )
228 throw (uno::RuntimeException
)
232 sal_Bool
bShowing(sal_False
);
235 uno::Reference
<XAccessibleComponent
> xParentComponent (mxParent
->getAccessibleContext(), uno::UNO_QUERY
);
236 if (xParentComponent
.is())
238 Rectangle
aParentBounds(VCLRectangle(xParentComponent
->getBounds()));
239 Rectangle
aBounds(VCLRectangle(getBounds()));
240 bShowing
= aBounds
.IsOver(aParentBounds
);
246 sal_Bool SAL_CALL
ScAccessibleContextBase::isVisible( )
247 throw (uno::RuntimeException
)
252 void SAL_CALL
ScAccessibleContextBase::grabFocus( )
253 throw (uno::RuntimeException
)
255 DBG_ERROR("not implemented");
258 sal_Int32 SAL_CALL
ScAccessibleContextBase::getForeground( )
259 throw (uno::RuntimeException
)
264 sal_Int32 SAL_CALL
ScAccessibleContextBase::getBackground( )
265 throw (uno::RuntimeException
)
270 //===== XAccessibleContext ==================================================
273 ScAccessibleContextBase::getAccessibleChildCount(void)
274 throw (uno::RuntimeException
)
276 DBG_ERROR("should be implemented in the abrevated class");
280 uno::Reference
<XAccessible
> SAL_CALL
281 ScAccessibleContextBase::getAccessibleChild(sal_Int32
/* nIndex */)
282 throw (lang::IndexOutOfBoundsException
, uno::RuntimeException
)
284 DBG_ERROR("should be implemented in the abrevated class");
285 return uno::Reference
<XAccessible
>();
288 uno::Reference
<XAccessible
> SAL_CALL
289 ScAccessibleContextBase::getAccessibleParent(void)
290 throw (uno::RuntimeException
)
296 ScAccessibleContextBase::getAccessibleIndexInParent(void)
297 throw (uno::RuntimeException
)
301 // Use a simple but slow solution for now. Optimize later.
302 // Return -1 to indicate that this object's parent does not know about the
304 sal_Int32
nIndex(-1);
306 // Iterate over all the parent's children and search for this object.
309 uno::Reference
<XAccessibleContext
> xParentContext (
310 mxParent
->getAccessibleContext());
311 if (xParentContext
.is())
313 sal_Int32 nChildCount
= xParentContext
->getAccessibleChildCount();
314 for (sal_Int32 i
=0; i
<nChildCount
; ++i
)
316 uno::Reference
<XAccessible
> xChild (xParentContext
->getAccessibleChild (i
));
319 if (xChild
.get() == this)
330 ScAccessibleContextBase::getAccessibleRole(void)
331 throw (uno::RuntimeException
)
336 ::rtl::OUString SAL_CALL
337 ScAccessibleContextBase::getAccessibleDescription(void)
338 throw (uno::RuntimeException
)
342 if (!msDescription
.getLength())
344 OUString
sDescription(createAccessibleDescription());
345 // DBG_ASSERT(sDescription.getLength(), "We should give always a descripition.");
347 if (msDescription
!= sDescription
)
349 AccessibleEventObject aEvent
;
350 aEvent
.EventId
= AccessibleEventId::DESCRIPTION_CHANGED
;
351 aEvent
.Source
= uno::Reference
< XAccessibleContext
>(this);
352 aEvent
.OldValue
<<= msDescription
;
353 aEvent
.NewValue
<<= sDescription
;
355 msDescription
= sDescription
;
357 CommitChange(aEvent
);
360 return msDescription
;
364 ScAccessibleContextBase::getAccessibleName(void)
365 throw (uno::RuntimeException
)
369 if (!msName
.getLength())
371 OUString
sName(createAccessibleName());
372 DBG_ASSERT(sName
.getLength(), "We should give always a name.");
376 AccessibleEventObject aEvent
;
377 aEvent
.EventId
= AccessibleEventId::NAME_CHANGED
;
378 aEvent
.Source
= uno::Reference
< XAccessibleContext
>(this);
379 aEvent
.OldValue
<<= msName
;
380 aEvent
.NewValue
<<= sName
;
384 CommitChange(aEvent
);
390 uno::Reference
<XAccessibleRelationSet
> SAL_CALL
391 ScAccessibleContextBase::getAccessibleRelationSet(void)
392 throw (uno::RuntimeException
)
394 return new utl::AccessibleRelationSetHelper();
397 uno::Reference
<XAccessibleStateSet
> SAL_CALL
398 ScAccessibleContextBase::getAccessibleStateSet(void)
399 throw (uno::RuntimeException
)
401 return uno::Reference
<XAccessibleStateSet
>();
404 lang::Locale SAL_CALL
405 ScAccessibleContextBase::getLocale(void)
406 throw (IllegalAccessibleComponentStateException
,
407 uno::RuntimeException
)
413 uno::Reference
<XAccessibleContext
> xParentContext (
414 mxParent
->getAccessibleContext());
415 if (xParentContext
.is())
416 return xParentContext
->getLocale ();
419 // No locale and no parent. Therefore throw exception to indicate this
421 throw IllegalAccessibleComponentStateException ();
424 //===== XAccessibleEventBroadcaster =====================================
427 ScAccessibleContextBase::addEventListener(
428 const uno::Reference
<XAccessibleEventListener
>& xListener
)
429 throw (uno::RuntimeException
)
438 mnClientId
= comphelper::AccessibleEventNotifier::registerClient( );
439 comphelper::AccessibleEventNotifier::addEventListener( mnClientId
, xListener
);
445 ScAccessibleContextBase::removeEventListener(
446 const uno::Reference
<XAccessibleEventListener
>& xListener
)
447 throw (uno::RuntimeException
)
452 if (!IsDefunc() && mnClientId
)
454 sal_Int32 nListenerCount
= comphelper::AccessibleEventNotifier::removeEventListener( mnClientId
, xListener
);
455 if ( !nListenerCount
)
457 // no listeners anymore
458 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
459 // and at least to us not firing any events anymore, in case somebody calls
460 // NotifyAccessibleEvent, again
461 comphelper::AccessibleEventNotifier::revokeClient( mnClientId
);
468 //===== XAccessibleEventListener ========================================
470 void SAL_CALL
ScAccessibleContextBase::disposing(
471 const lang::EventObject
& rSource
)
472 throw (uno::RuntimeException
)
475 if (rSource
.Source
== mxParent
)
479 void SAL_CALL
ScAccessibleContextBase::notifyEvent(
480 const AccessibleEventObject
& /* aEvent */ )
481 throw (uno::RuntimeException
)
485 //===== XServiceInfo ========================================================
487 ::rtl::OUString SAL_CALL
488 ScAccessibleContextBase::getImplementationName(void)
489 throw (uno::RuntimeException
)
491 return OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessibleContextBase"));
495 ScAccessibleContextBase::supportsService(const OUString
& sServiceName
)
496 throw (uno::RuntimeException
)
498 // Iterate over all supported service names and return true if on of them
499 // matches the given name.
500 uno::Sequence
< ::rtl::OUString
> aSupportedServices (
501 getSupportedServiceNames ());
502 sal_Int32
nLength(aSupportedServices
.getLength());
503 const OUString
* pServiceNames
= aSupportedServices
.getConstArray();
504 for (int i
=0; i
<nLength
; ++i
, ++pServiceNames
)
505 if (sServiceName
== *pServiceNames
)
510 uno::Sequence
< ::rtl::OUString
> SAL_CALL
511 ScAccessibleContextBase::getSupportedServiceNames(void)
512 throw (uno::RuntimeException
)
514 uno::Sequence
<OUString
> aServiceNames(2);
515 OUString
* pServiceNames
= aServiceNames
.getArray();
518 pServiceNames
[0] = OUString(RTL_CONSTASCII_USTRINGPARAM ("com.sun.star.accessibility.Accessible"));
519 pServiceNames
[1] = OUString(RTL_CONSTASCII_USTRINGPARAM ("com.sun.star.accessibility.AccessibleContext"));
522 return aServiceNames
;
525 //===== XTypeProvider =======================================================
527 uno::Sequence
< uno::Type
> SAL_CALL
ScAccessibleContextBase::getTypes()
528 throw (uno::RuntimeException
)
530 return comphelper::concatSequences(ScAccessibleContextBaseWeakImpl::getTypes(), ScAccessibleContextBaseImplEvent::getTypes());
533 uno::Sequence
<sal_Int8
> SAL_CALL
534 ScAccessibleContextBase::getImplementationId(void)
535 throw (uno::RuntimeException
)
539 static uno::Sequence
<sal_Int8
> aId
;
540 if (aId
.getLength() == 0)
543 rtl_createUuid (reinterpret_cast<sal_uInt8
*>(aId
.getArray()), 0, sal_True
);
548 //===== internal ============================================================
550 ::rtl::OUString SAL_CALL
551 ScAccessibleContextBase::createAccessibleDescription(void)
552 throw (uno::RuntimeException
)
554 DBG_ERROR("should be implemented in the abrevated class");
555 return rtl::OUString();
558 ::rtl::OUString SAL_CALL
559 ScAccessibleContextBase::createAccessibleName(void)
560 throw (uno::RuntimeException
)
562 DBG_ERROR("should be implemented in the abrevated class");
563 return rtl::OUString();
566 void ScAccessibleContextBase::CommitChange(const AccessibleEventObject
& rEvent
) const
569 comphelper::AccessibleEventNotifier::addEvent( mnClientId
, rEvent
);
572 void ScAccessibleContextBase::ChangeName()
574 AccessibleEventObject aEvent
;
575 aEvent
.EventId
= AccessibleEventId::NAME_CHANGED
;
576 aEvent
.Source
= uno::Reference
< XAccessibleContext
>(const_cast<ScAccessibleContextBase
*>(this));
577 aEvent
.OldValue
<<= msName
;
579 msName
= rtl::OUString(); // reset the name so it will be hold again
580 getAccessibleName(); // create the new name
582 aEvent
.NewValue
<<= msName
;
584 CommitChange(aEvent
);
587 void ScAccessibleContextBase::CommitFocusGained() const
589 AccessibleEventObject aEvent
;
590 aEvent
.EventId
= AccessibleEventId::STATE_CHANGED
;
591 aEvent
.Source
= uno::Reference
< XAccessibleContext
>(const_cast<ScAccessibleContextBase
*>(this));
592 aEvent
.NewValue
<<= AccessibleStateType::FOCUSED
;
594 CommitChange(aEvent
);
596 ::vcl::unohelper::NotifyAccessibleStateEventGlobally(aEvent
);
599 void ScAccessibleContextBase::CommitFocusLost() const
601 AccessibleEventObject aEvent
;
602 aEvent
.EventId
= AccessibleEventId::STATE_CHANGED
;
603 aEvent
.Source
= uno::Reference
< XAccessibleContext
>(const_cast<ScAccessibleContextBase
*>(this));
604 aEvent
.OldValue
<<= AccessibleStateType::FOCUSED
;
606 CommitChange(aEvent
);
608 vcl::unohelper::NotifyAccessibleStateEventGlobally(aEvent
);
611 Rectangle
ScAccessibleContextBase::GetBoundingBoxOnScreen(void) const
612 throw (uno::RuntimeException
)
614 DBG_ERROR("not implemented");
618 Rectangle
ScAccessibleContextBase::GetBoundingBox(void) const
619 throw (uno::RuntimeException
)
621 DBG_ERROR("not implemented");
625 void ScAccessibleContextBase::IsObjectValid() const
626 throw (lang::DisposedException
)
628 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
629 throw lang::DisposedException();
632 void ScAccessibleContextBase::SetRole(sal_Int16 nRole
)