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: AccessibleTreeNode.cxx,v $
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_sd.hxx"
34 #include "AccessibleTreeNode.hxx"
36 #include "taskpane/TaskPaneTreeNode.hxx"
37 #include "taskpane/ControlContainer.hxx"
39 #include "sdresid.hxx"
40 #include "accessibility.hrc"
41 #include <com/sun/star/accessibility/AccessibleRole.hpp>
42 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
43 #include <comphelper/accessibleeventnotifier.hxx>
45 #include <vcl/svapp.hxx>
46 #include <vcl/window.hxx>
47 #include <svtools/colorcfg.hxx>
49 using ::rtl::OUString
;
50 using namespace ::com::sun::star
;
51 using namespace ::com::sun::star::uno
;
52 using namespace ::com::sun::star::accessibility
;
53 using namespace ::sd::toolpanel
;
55 namespace accessibility
{
59 //===== AccessibleTreeNode =============================================
61 AccessibleTreeNode::AccessibleTreeNode(
62 ::sd::toolpanel::TreeNode
& rNode
,
63 const OUString
& rsName
,
64 const OUString
& rsDescription
,
66 : AccessibleTreeNodeBase(MutexOwner::maMutex
),
69 mrStateSet(new ::utl::AccessibleStateSetHelper()),
71 msDescription(rsDescription
),
75 ::Window
* pWindow
= mrTreeNode
.GetWindow();
78 ::Window
* pParentWindow
= pWindow
->GetAccessibleParentWindow();
79 if (pParentWindow
!= NULL
&& pParentWindow
!= pWindow
)
80 mxParent
= pParentWindow
->GetAccessible();
88 AccessibleTreeNode::AccessibleTreeNode(
89 const Reference
<XAccessible
>& rxParent
,
90 ::sd::toolpanel::TreeNode
& rNode
,
91 const OUString
& rsName
,
92 const OUString
& rsDescription
,
93 const sal_Int16 eRole
)
94 : AccessibleTreeNodeBase(MutexOwner::maMutex
),
97 mrStateSet(new ::utl::AccessibleStateSetHelper()),
99 msDescription(rsDescription
),
109 void AccessibleTreeNode::CommonConstructor (void)
113 Link
aStateChangeLink (LINK(this,AccessibleTreeNode
,StateChangeListener
));
114 mrTreeNode
.AddStateChangeListener(aStateChangeLink
);
116 if (mrTreeNode
.GetWindow() != NULL
)
118 Link
aWindowEventLink (LINK(this,AccessibleTreeNode
,WindowEventListener
));
119 mrTreeNode
.GetWindow()->AddEventListener(aWindowEventLink
);
126 AccessibleTreeNode::~AccessibleTreeNode (void)
128 OSL_ASSERT(IsDisposed());
134 void AccessibleTreeNode::FireAccessibleEvent (
136 const uno::Any
& rOldValue
,
137 const uno::Any
& rNewValue
)
141 AccessibleEventObject aEventObject
;
143 aEventObject
.Source
= Reference
<XWeak
>(this);
144 aEventObject
.EventId
= nEventId
;
145 aEventObject
.NewValue
= rNewValue
;
146 aEventObject
.OldValue
= rOldValue
;
148 comphelper::AccessibleEventNotifier::addEvent (mnClientId
, aEventObject
);
155 void SAL_CALL
AccessibleTreeNode::disposing (void)
157 // We are still listening to the tree node and its window. Both
158 // probably are by now more or less dead and we must not call them to
161 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( mnClientId
, *this );
168 //===== XAccessible =========================================================
170 Reference
<XAccessibleContext
> SAL_CALL
171 AccessibleTreeNode::getAccessibleContext (void)
172 throw (uno::RuntimeException
)
181 //===== XAccessibleContext ==================================================
183 sal_Int32 SAL_CALL
AccessibleTreeNode::getAccessibleChildCount (void)
184 throw (RuntimeException
)
187 const vos::OGuard
aSolarGuard (Application::GetSolarMutex());
188 return mrTreeNode
.GetControlContainer().GetControlCount();
194 Reference
<XAccessible
> SAL_CALL
195 AccessibleTreeNode::getAccessibleChild (sal_Int32 nIndex
)
196 throw (lang::IndexOutOfBoundsException
, RuntimeException
)
199 const vos::OGuard
aSolarGuard (Application::GetSolarMutex());
201 if (nIndex
<0 || (sal_uInt32
)nIndex
>=mrTreeNode
.GetControlContainer().GetControlCount())
202 throw lang::IndexOutOfBoundsException();
204 Reference
<XAccessible
> xChild
;
206 ::sd::toolpanel::TreeNode
* pNode
= mrTreeNode
.GetControlContainer().GetControl(nIndex
);
208 xChild
= pNode
->GetAccessibleObject();
216 Reference
<XAccessible
> SAL_CALL
AccessibleTreeNode::getAccessibleParent (void)
217 throw (uno::RuntimeException
)
220 const vos::OGuard
aSolarGuard (Application::GetSolarMutex());
227 sal_Int32 SAL_CALL
AccessibleTreeNode::getAccessibleIndexInParent (void)
228 throw (uno::RuntimeException
)
230 OSL_ASSERT(getAccessibleParent().is());
232 const vos::OGuard
aSolarGuard (Application::GetSolarMutex());
233 sal_Int32
nIndexInParent(-1);
236 Reference
<XAccessibleContext
> xParentContext (getAccessibleParent()->getAccessibleContext());
237 if (xParentContext
.is())
239 sal_Int32
nChildCount (xParentContext
->getAccessibleChildCount());
240 for (sal_Int32 i
=0; i
<nChildCount
; ++i
)
241 if (xParentContext
->getAccessibleChild(i
).get()
242 == static_cast<XAccessible
*>(this))
249 return nIndexInParent
;
255 sal_Int16 SAL_CALL
AccessibleTreeNode::getAccessibleRole (void)
256 throw (uno::RuntimeException
)
265 ::rtl::OUString SAL_CALL
AccessibleTreeNode::getAccessibleDescription (void)
266 throw (uno::RuntimeException
)
269 return msDescription
;
275 ::rtl::OUString SAL_CALL
AccessibleTreeNode::getAccessibleName (void)
276 throw (uno::RuntimeException
)
285 Reference
<XAccessibleRelationSet
> SAL_CALL
286 AccessibleTreeNode::getAccessibleRelationSet (void)
287 throw (uno::RuntimeException
)
290 return Reference
<XAccessibleRelationSet
>();
296 Reference
<XAccessibleStateSet
> SAL_CALL
297 AccessibleTreeNode::getAccessibleStateSet (void)
298 throw (uno::RuntimeException
)
301 const vos::OGuard
aSolarGuard (Application::GetSolarMutex());
302 return mrStateSet
.get();
308 void AccessibleTreeNode::UpdateStateSet (void)
310 if (mrTreeNode
.IsExpandable())
312 UpdateState(AccessibleStateType::EXPANDABLE
, true);
313 UpdateState(AccessibleStateType::EXPANDED
, mrTreeNode
.IsExpanded());
316 UpdateState(AccessibleStateType::FOCUSABLE
, true);
318 ::Window
* pWindow
= mrTreeNode
.GetWindow();
321 UpdateState(AccessibleStateType::ENABLED
, pWindow
->IsEnabled());
322 UpdateState(AccessibleStateType::FOCUSED
, pWindow
->HasFocus());
323 UpdateState(AccessibleStateType::VISIBLE
, pWindow
->IsVisible());
324 UpdateState(AccessibleStateType::SHOWING
, pWindow
->IsReallyVisible());
331 void AccessibleTreeNode::UpdateState(
335 if ((mrStateSet
->contains(aState
)!=sal_False
) != bValue
)
339 mrStateSet
->AddState(aState
);
340 FireAccessibleEvent(AccessibleEventId::STATE_CHANGED
, Any(),Any(aState
));
344 mrStateSet
->RemoveState(aState
);
345 FireAccessibleEvent(AccessibleEventId::STATE_CHANGED
, Any(aState
),Any());
353 lang::Locale SAL_CALL
AccessibleTreeNode::getLocale (void)
354 throw (IllegalAccessibleComponentStateException
,
358 Reference
<XAccessibleContext
> xParentContext
;
359 Reference
<XAccessible
> xParent (getAccessibleParent());
361 xParentContext
= xParent
->getAccessibleContext();
363 if (xParentContext
.is())
364 return xParentContext
->getLocale();
366 // Strange, no parent! Anyway, return the default locale.
367 return Application::GetSettings().GetLocale();
373 void SAL_CALL
AccessibleTreeNode::addEventListener(
374 const Reference
<XAccessibleEventListener
>& rxListener
)
375 throw (RuntimeException
)
379 const osl::MutexGuard
aGuard(maMutex
);
383 uno::Reference
<uno::XInterface
> x ((lang::XComponent
*)this, uno::UNO_QUERY
);
384 rxListener
->disposing (lang::EventObject (x
));
389 mnClientId
= comphelper::AccessibleEventNotifier::registerClient();
390 comphelper::AccessibleEventNotifier::addEventListener(mnClientId
, rxListener
);
398 void SAL_CALL
AccessibleTreeNode::removeEventListener(
399 const Reference
<XAccessibleEventListener
>& rxListener
)
400 throw (RuntimeException
)
405 const osl::MutexGuard
aGuard(maMutex
);
407 sal_Int32 nListenerCount
= comphelper::AccessibleEventNotifier::removeEventListener( mnClientId
, rxListener
);
408 if ( !nListenerCount
)
410 // no listeners anymore
411 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
412 // and at least to us not firing any events anymore, in case somebody calls
413 // NotifyAccessibleEvent, again
414 comphelper::AccessibleEventNotifier::revokeClient( mnClientId
);
423 //===== XAccessibleComponent ==================================================
425 sal_Bool SAL_CALL
AccessibleTreeNode::containsPoint (const awt::Point
& aPoint
)
426 throw (RuntimeException
)
429 const awt::Rectangle
aBBox (getBounds());
430 return (aPoint
.X
>= 0)
431 && (aPoint
.X
< aBBox
.Width
)
433 && (aPoint
.Y
< aBBox
.Height
);
439 Reference
<XAccessible
> SAL_CALL
440 AccessibleTreeNode::getAccessibleAtPoint (const awt::Point
& aPoint
)
441 throw (RuntimeException
)
444 Reference
<XAccessible
> xChildAtPoint
;
445 const vos::OGuard
aSolarGuard (Application::GetSolarMutex());
447 sal_Int32 nChildCount
= getAccessibleChildCount();
448 for (sal_Int32 nIndex
=0; nIndex
<nChildCount
; ++nIndex
)
450 Reference
<XAccessibleComponent
> xChildComponent(
451 getAccessibleChild(nIndex
), UNO_QUERY
);
452 if (xChildComponent
.is())
454 awt::Point
aChildPoint(aPoint
);
455 awt::Point
aChildOrigin(xChildComponent
->getLocation());
456 aChildPoint
.X
-= aChildOrigin
.X
;
457 aChildPoint
.Y
-= aChildOrigin
.Y
;
458 if (xChildComponent
->containsPoint(aChildPoint
))
460 xChildAtPoint
= getAccessibleChild(nIndex
);
466 return xChildAtPoint
;
472 awt::Rectangle SAL_CALL
AccessibleTreeNode::getBounds (void)
473 throw (RuntimeException
)
477 awt::Rectangle aBBox
;
479 ::Window
* pWindow
= mrTreeNode
.GetWindow();
485 aPosition
= pWindow
->OutputToAbsoluteScreenPixel(Point(0,0));
486 Reference
<XAccessibleComponent
> xParentComponent (
487 mxParent
->getAccessibleContext(), UNO_QUERY
);
488 if (xParentComponent
.is())
490 awt::Point
aParentPosition (xParentComponent
->getLocationOnScreen());
491 aPosition
.X() -= aParentPosition
.X
;
492 aPosition
.Y() -= aParentPosition
.Y
;
496 aPosition
= pWindow
->GetPosPixel();
497 aBBox
.X
= aPosition
.X();
498 aBBox
.Y
= aPosition
.Y();
500 Size
aSize (pWindow
->GetSizePixel());
501 aBBox
.Width
= aSize
.Width();
502 aBBox
.Height
= aSize
.Height();
511 awt::Point SAL_CALL
AccessibleTreeNode::getLocation (void)
512 throw (uno::RuntimeException
)
515 const awt::Rectangle
aBBox (getBounds());
516 return awt::Point(aBBox
.X
,aBBox
.Y
);
522 /** Calculate the location on screen from the parent's location on screen
523 and our own relative location.
525 awt::Point SAL_CALL
AccessibleTreeNode::getLocationOnScreen()
526 throw (uno::RuntimeException
)
529 const vos::OGuard
aSolarGuard( Application::GetSolarMutex() );
530 awt::Point aLocationOnScreen
;
532 ::Window
* pWindow
= mrTreeNode
.GetWindow();
535 Point
aPoint (pWindow
->OutputToAbsoluteScreenPixel(Point(0,0)));
536 aLocationOnScreen
.X
= aPoint
.X();
537 aLocationOnScreen
.Y
= aPoint
.Y();
540 return aLocationOnScreen
;
546 awt::Size SAL_CALL
AccessibleTreeNode::getSize (void)
547 throw (uno::RuntimeException
)
550 const awt::Rectangle
aBBox (getBounds());
551 return awt::Size(aBBox
.Width
,aBBox
.Height
);
557 void SAL_CALL
AccessibleTreeNode::grabFocus (void)
558 throw (uno::RuntimeException
)
561 const vos::OGuard
aSolarGuard (Application::GetSolarMutex());
563 if (mrTreeNode
.GetWindow() != NULL
)
564 mrTreeNode
.GetWindow()->GrabFocus();
570 sal_Int32 SAL_CALL
AccessibleTreeNode::getForeground (void)
571 throw (RuntimeException
)
574 svtools::ColorConfig aColorConfig
;
575 UINT32 nColor
= aColorConfig
.GetColorValue( svtools::FONTCOLOR
).nColor
;
576 return static_cast<sal_Int32
>(nColor
);
582 sal_Int32 SAL_CALL
AccessibleTreeNode::getBackground (void)
583 throw (RuntimeException
)
586 UINT32 nColor
= Application::GetSettings().GetStyleSettings().GetWindowColor().GetColor();
587 return static_cast<sal_Int32
>(nColor
);
593 //===== XServiceInfo ========================================================
595 ::rtl::OUString SAL_CALL
596 AccessibleTreeNode::getImplementationName (void)
597 throw (::com::sun::star::uno::RuntimeException
)
599 return OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleTreeNode"));
606 AccessibleTreeNode::supportsService (const OUString
& sServiceName
)
607 throw (::com::sun::star::uno::RuntimeException
)
611 // Iterate over all supported service names and return true if on of them
612 // matches the given name.
613 uno::Sequence
< ::rtl::OUString
> aSupportedServices (
614 getSupportedServiceNames ());
615 for (int i
=0; i
<aSupportedServices
.getLength(); i
++)
616 if (sServiceName
== aSupportedServices
[i
])
624 uno::Sequence
< ::rtl::OUString
> SAL_CALL
625 AccessibleTreeNode::getSupportedServiceNames (void)
626 throw (::com::sun::star::uno::RuntimeException
)
629 static const OUString sServiceNames
[2] = {
630 OUString(RTL_CONSTASCII_USTRINGPARAM(
631 "com.sun.star.accessibility.Accessible")),
632 OUString(RTL_CONSTASCII_USTRINGPARAM(
633 "com.sun.star.accessibility.AccessibleContext")),
635 return uno::Sequence
<OUString
> (sServiceNames
, 2);
641 void AccessibleTreeNode::ThrowIfDisposed (void)
642 throw (lang::DisposedException
)
644 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
646 OSL_TRACE ("Calling disposed object. Throwing exception:");
647 throw lang::DisposedException (
648 OUString(RTL_CONSTASCII_USTRINGPARAM("object has been already disposed")),
649 static_cast<uno::XWeak
*>(this));
655 sal_Bool
AccessibleTreeNode::IsDisposed (void)
657 return (rBHelper
.bDisposed
|| rBHelper
.bInDispose
);
663 IMPL_LINK(AccessibleTreeNode
, StateChangeListener
, TreeNodeStateChangeEvent
*, pEvent
)
665 OSL_ASSERT(pEvent
!=NULL
);
666 OSL_ASSERT(&pEvent
->mrSource
==&mrTreeNode
);
668 switch(pEvent
->meEventId
)
670 case EID_CHILD_ADDED
:
671 if (pEvent
->mpChild
!= NULL
)
672 FireAccessibleEvent(AccessibleEventId::CHILD
,
674 Any(pEvent
->mpChild
->GetAccessibleObject()));
676 FireAccessibleEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN
,Any(),Any());
679 case EID_ALL_CHILDREN_REMOVED
:
680 FireAccessibleEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN
,Any(),Any());
683 case EID_EXPANSION_STATE_CHANGED
:
684 case EID_FOCUSED_STATE_CHANGED
:
685 case EID_SHOWING_STATE_CHANGED
:
695 IMPL_LINK(AccessibleTreeNode
, WindowEventListener
, VclWindowEvent
*, pEvent
)
697 switch (pEvent
->GetId())
699 case VCLEVENT_WINDOW_HIDE
:
700 // This event may be sent while the window is destroyed so do
701 // not call UpdateStateSet() which calls back to the window but
702 // just set the two states VISIBLE and SHOWING to false.
703 UpdateState(AccessibleStateType::VISIBLE
, false);
704 UpdateState(AccessibleStateType::SHOWING
, false);
707 case VCLEVENT_WINDOW_SHOW
:
708 case VCLEVENT_WINDOW_DATACHANGED
:
712 case VCLEVENT_WINDOW_MOVE
:
713 case VCLEVENT_WINDOW_RESIZE
:
714 FireAccessibleEvent(AccessibleEventId::BOUNDRECT_CHANGED
,Any(),Any());
717 case VCLEVENT_WINDOW_GETFOCUS
:
718 case VCLEVENT_WINDOW_LOSEFOCUS
:
724 } // end of namespace ::accessibility