1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 // MARKER(update_precomp.py): autogen include statement, do not remove
30 #include "precompiled_sd.hxx"
32 #include "AccessibleTreeNode.hxx"
34 #include "taskpane/TaskPaneTreeNode.hxx"
35 #include "taskpane/ControlContainer.hxx"
37 #include "sdresid.hxx"
38 #include "accessibility.hrc"
39 #include <com/sun/star/accessibility/AccessibleRole.hpp>
40 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
41 #include <comphelper/accessibleeventnotifier.hxx>
43 #include <vcl/svapp.hxx>
44 #include <vcl/window.hxx>
45 #include <svtools/colorcfg.hxx>
47 using ::rtl::OUString
;
48 using namespace ::com::sun::star
;
49 using namespace ::com::sun::star::uno
;
50 using namespace ::com::sun::star::accessibility
;
51 using namespace ::sd::toolpanel
;
53 namespace accessibility
{
57 //===== AccessibleTreeNode =============================================
59 AccessibleTreeNode::AccessibleTreeNode(
60 ::sd::toolpanel::TreeNode
& rNode
,
61 const OUString
& rsName
,
62 const OUString
& rsDescription
,
64 : AccessibleTreeNodeBase(MutexOwner::maMutex
),
67 mrStateSet(new ::utl::AccessibleStateSetHelper()),
69 msDescription(rsDescription
),
73 ::Window
* pWindow
= mrTreeNode
.GetWindow();
76 ::Window
* pParentWindow
= pWindow
->GetAccessibleParentWindow();
77 if (pParentWindow
!= NULL
&& pParentWindow
!= pWindow
)
78 mxParent
= pParentWindow
->GetAccessible();
86 AccessibleTreeNode::AccessibleTreeNode(
87 const Reference
<XAccessible
>& rxParent
,
88 ::sd::toolpanel::TreeNode
& rNode
,
89 const OUString
& rsName
,
90 const OUString
& rsDescription
,
91 const sal_Int16 eRole
)
92 : AccessibleTreeNodeBase(MutexOwner::maMutex
),
95 mrStateSet(new ::utl::AccessibleStateSetHelper()),
97 msDescription(rsDescription
),
107 void AccessibleTreeNode::CommonConstructor (void)
111 Link
aStateChangeLink (LINK(this,AccessibleTreeNode
,StateChangeListener
));
112 mrTreeNode
.AddStateChangeListener(aStateChangeLink
);
114 if (mrTreeNode
.GetWindow() != NULL
)
116 Link
aWindowEventLink (LINK(this,AccessibleTreeNode
,WindowEventListener
));
117 mrTreeNode
.GetWindow()->AddEventListener(aWindowEventLink
);
124 AccessibleTreeNode::~AccessibleTreeNode (void)
126 OSL_ASSERT(IsDisposed());
132 void AccessibleTreeNode::FireAccessibleEvent (
134 const uno::Any
& rOldValue
,
135 const uno::Any
& rNewValue
)
139 AccessibleEventObject aEventObject
;
141 aEventObject
.Source
= Reference
<XWeak
>(this);
142 aEventObject
.EventId
= nEventId
;
143 aEventObject
.NewValue
= rNewValue
;
144 aEventObject
.OldValue
= rOldValue
;
146 comphelper::AccessibleEventNotifier::addEvent (mnClientId
, aEventObject
);
153 void SAL_CALL
AccessibleTreeNode::disposing (void)
155 // We are still listening to the tree node and its window. Both
156 // probably are by now more or less dead and we must not call them to
159 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( mnClientId
, *this );
166 //===== XAccessible =========================================================
168 Reference
<XAccessibleContext
> SAL_CALL
169 AccessibleTreeNode::getAccessibleContext (void)
170 throw (uno::RuntimeException
)
179 //===== XAccessibleContext ==================================================
181 sal_Int32 SAL_CALL
AccessibleTreeNode::getAccessibleChildCount (void)
182 throw (RuntimeException
)
185 const SolarMutexGuard aSolarGuard
;
186 return mrTreeNode
.GetControlContainer().GetControlCount();
192 Reference
<XAccessible
> SAL_CALL
193 AccessibleTreeNode::getAccessibleChild (sal_Int32 nIndex
)
194 throw (lang::IndexOutOfBoundsException
, RuntimeException
)
197 const SolarMutexGuard aSolarGuard
;
199 if (nIndex
<0 || (sal_uInt32
)nIndex
>=mrTreeNode
.GetControlContainer().GetControlCount())
200 throw lang::IndexOutOfBoundsException();
202 Reference
<XAccessible
> xChild
;
204 ::sd::toolpanel::TreeNode
* pNode
= mrTreeNode
.GetControlContainer().GetControl(nIndex
);
206 xChild
= pNode
->GetAccessibleObject();
214 Reference
<XAccessible
> SAL_CALL
AccessibleTreeNode::getAccessibleParent (void)
215 throw (uno::RuntimeException
)
218 const SolarMutexGuard aSolarGuard
;
225 sal_Int32 SAL_CALL
AccessibleTreeNode::getAccessibleIndexInParent (void)
226 throw (uno::RuntimeException
)
228 OSL_ASSERT(getAccessibleParent().is());
230 const SolarMutexGuard aSolarGuard
;
231 sal_Int32
nIndexInParent(-1);
234 Reference
<XAccessibleContext
> xParentContext (getAccessibleParent()->getAccessibleContext());
235 if (xParentContext
.is())
237 sal_Int32
nChildCount (xParentContext
->getAccessibleChildCount());
238 for (sal_Int32 i
=0; i
<nChildCount
; ++i
)
239 if (xParentContext
->getAccessibleChild(i
).get()
240 == static_cast<XAccessible
*>(this))
247 return nIndexInParent
;
253 sal_Int16 SAL_CALL
AccessibleTreeNode::getAccessibleRole (void)
254 throw (uno::RuntimeException
)
263 ::rtl::OUString SAL_CALL
AccessibleTreeNode::getAccessibleDescription (void)
264 throw (uno::RuntimeException
)
267 return msDescription
;
273 ::rtl::OUString SAL_CALL
AccessibleTreeNode::getAccessibleName (void)
274 throw (uno::RuntimeException
)
283 Reference
<XAccessibleRelationSet
> SAL_CALL
284 AccessibleTreeNode::getAccessibleRelationSet (void)
285 throw (uno::RuntimeException
)
288 return Reference
<XAccessibleRelationSet
>();
294 Reference
<XAccessibleStateSet
> SAL_CALL
295 AccessibleTreeNode::getAccessibleStateSet (void)
296 throw (uno::RuntimeException
)
299 const SolarMutexGuard aSolarGuard
;
300 return mrStateSet
.get();
306 void AccessibleTreeNode::UpdateStateSet (void)
308 if (mrTreeNode
.IsExpandable())
310 UpdateState(AccessibleStateType::EXPANDABLE
, true);
311 UpdateState(AccessibleStateType::EXPANDED
, mrTreeNode
.IsExpanded());
314 UpdateState(AccessibleStateType::FOCUSABLE
, true);
316 ::Window
* pWindow
= mrTreeNode
.GetWindow();
319 UpdateState(AccessibleStateType::ENABLED
, pWindow
->IsEnabled());
320 UpdateState(AccessibleStateType::FOCUSED
, pWindow
->HasFocus());
321 UpdateState(AccessibleStateType::VISIBLE
, pWindow
->IsVisible());
322 UpdateState(AccessibleStateType::SHOWING
, pWindow
->IsReallyVisible());
329 void AccessibleTreeNode::UpdateState(
333 if ((mrStateSet
->contains(aState
)!=sal_False
) != bValue
)
337 mrStateSet
->AddState(aState
);
338 FireAccessibleEvent(AccessibleEventId::STATE_CHANGED
, Any(),Any(aState
));
342 mrStateSet
->RemoveState(aState
);
343 FireAccessibleEvent(AccessibleEventId::STATE_CHANGED
, Any(aState
),Any());
351 lang::Locale SAL_CALL
AccessibleTreeNode::getLocale (void)
352 throw (IllegalAccessibleComponentStateException
,
356 Reference
<XAccessibleContext
> xParentContext
;
357 Reference
<XAccessible
> xParent (getAccessibleParent());
359 xParentContext
= xParent
->getAccessibleContext();
361 if (xParentContext
.is())
362 return xParentContext
->getLocale();
364 // Strange, no parent! Anyway, return the default locale.
365 return Application::GetSettings().GetLocale();
371 void SAL_CALL
AccessibleTreeNode::addEventListener(
372 const Reference
<XAccessibleEventListener
>& rxListener
)
373 throw (RuntimeException
)
377 const osl::MutexGuard
aGuard(maMutex
);
381 uno::Reference
<uno::XInterface
> x ((lang::XComponent
*)this, uno::UNO_QUERY
);
382 rxListener
->disposing (lang::EventObject (x
));
387 mnClientId
= comphelper::AccessibleEventNotifier::registerClient();
388 comphelper::AccessibleEventNotifier::addEventListener(mnClientId
, rxListener
);
396 void SAL_CALL
AccessibleTreeNode::removeEventListener(
397 const Reference
<XAccessibleEventListener
>& rxListener
)
398 throw (RuntimeException
)
403 const osl::MutexGuard
aGuard(maMutex
);
405 sal_Int32 nListenerCount
= comphelper::AccessibleEventNotifier::removeEventListener( mnClientId
, rxListener
);
406 if ( !nListenerCount
)
408 // no listeners anymore
409 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
410 // and at least to us not firing any events anymore, in case somebody calls
411 // NotifyAccessibleEvent, again
412 comphelper::AccessibleEventNotifier::revokeClient( mnClientId
);
421 //===== XAccessibleComponent ==================================================
423 sal_Bool SAL_CALL
AccessibleTreeNode::containsPoint (const awt::Point
& aPoint
)
424 throw (RuntimeException
)
427 const awt::Rectangle
aBBox (getBounds());
428 return (aPoint
.X
>= 0)
429 && (aPoint
.X
< aBBox
.Width
)
431 && (aPoint
.Y
< aBBox
.Height
);
437 Reference
<XAccessible
> SAL_CALL
438 AccessibleTreeNode::getAccessibleAtPoint (const awt::Point
& aPoint
)
439 throw (RuntimeException
)
442 Reference
<XAccessible
> xChildAtPoint
;
443 const SolarMutexGuard aSolarGuard
;
445 sal_Int32 nChildCount
= getAccessibleChildCount();
446 for (sal_Int32 nIndex
=0; nIndex
<nChildCount
; ++nIndex
)
448 Reference
<XAccessibleComponent
> xChildComponent(
449 getAccessibleChild(nIndex
), UNO_QUERY
);
450 if (xChildComponent
.is())
452 awt::Point
aChildPoint(aPoint
);
453 awt::Point
aChildOrigin(xChildComponent
->getLocation());
454 aChildPoint
.X
-= aChildOrigin
.X
;
455 aChildPoint
.Y
-= aChildOrigin
.Y
;
456 if (xChildComponent
->containsPoint(aChildPoint
))
458 xChildAtPoint
= getAccessibleChild(nIndex
);
464 return xChildAtPoint
;
470 awt::Rectangle SAL_CALL
AccessibleTreeNode::getBounds (void)
471 throw (RuntimeException
)
475 awt::Rectangle aBBox
;
477 ::Window
* pWindow
= mrTreeNode
.GetWindow();
483 aPosition
= pWindow
->OutputToAbsoluteScreenPixel(Point(0,0));
484 Reference
<XAccessibleComponent
> xParentComponent (
485 mxParent
->getAccessibleContext(), UNO_QUERY
);
486 if (xParentComponent
.is())
488 awt::Point
aParentPosition (xParentComponent
->getLocationOnScreen());
489 aPosition
.X() -= aParentPosition
.X
;
490 aPosition
.Y() -= aParentPosition
.Y
;
494 aPosition
= pWindow
->GetPosPixel();
495 aBBox
.X
= aPosition
.X();
496 aBBox
.Y
= aPosition
.Y();
498 Size
aSize (pWindow
->GetSizePixel());
499 aBBox
.Width
= aSize
.Width();
500 aBBox
.Height
= aSize
.Height();
509 awt::Point SAL_CALL
AccessibleTreeNode::getLocation (void)
510 throw (uno::RuntimeException
)
513 const awt::Rectangle
aBBox (getBounds());
514 return awt::Point(aBBox
.X
,aBBox
.Y
);
520 /** Calculate the location on screen from the parent's location on screen
521 and our own relative location.
523 awt::Point SAL_CALL
AccessibleTreeNode::getLocationOnScreen()
524 throw (uno::RuntimeException
)
527 const SolarMutexGuard aSolarGuard
;
528 awt::Point aLocationOnScreen
;
530 ::Window
* pWindow
= mrTreeNode
.GetWindow();
533 Point
aPoint (pWindow
->OutputToAbsoluteScreenPixel(Point(0,0)));
534 aLocationOnScreen
.X
= aPoint
.X();
535 aLocationOnScreen
.Y
= aPoint
.Y();
538 return aLocationOnScreen
;
544 awt::Size SAL_CALL
AccessibleTreeNode::getSize (void)
545 throw (uno::RuntimeException
)
548 const awt::Rectangle
aBBox (getBounds());
549 return awt::Size(aBBox
.Width
,aBBox
.Height
);
555 void SAL_CALL
AccessibleTreeNode::grabFocus (void)
556 throw (uno::RuntimeException
)
559 const SolarMutexGuard aSolarGuard
;
561 if (mrTreeNode
.GetWindow() != NULL
)
562 mrTreeNode
.GetWindow()->GrabFocus();
568 sal_Int32 SAL_CALL
AccessibleTreeNode::getForeground (void)
569 throw (RuntimeException
)
572 svtools::ColorConfig aColorConfig
;
573 UINT32 nColor
= aColorConfig
.GetColorValue( svtools::FONTCOLOR
).nColor
;
574 return static_cast<sal_Int32
>(nColor
);
580 sal_Int32 SAL_CALL
AccessibleTreeNode::getBackground (void)
581 throw (RuntimeException
)
584 UINT32 nColor
= Application::GetSettings().GetStyleSettings().GetWindowColor().GetColor();
585 return static_cast<sal_Int32
>(nColor
);
591 //===== XServiceInfo ========================================================
593 ::rtl::OUString SAL_CALL
594 AccessibleTreeNode::getImplementationName (void)
595 throw (::com::sun::star::uno::RuntimeException
)
597 return OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleTreeNode"));
604 AccessibleTreeNode::supportsService (const OUString
& sServiceName
)
605 throw (::com::sun::star::uno::RuntimeException
)
609 // Iterate over all supported service names and return true if on of them
610 // matches the given name.
611 uno::Sequence
< ::rtl::OUString
> aSupportedServices (
612 getSupportedServiceNames ());
613 for (int i
=0; i
<aSupportedServices
.getLength(); i
++)
614 if (sServiceName
== aSupportedServices
[i
])
622 uno::Sequence
< ::rtl::OUString
> SAL_CALL
623 AccessibleTreeNode::getSupportedServiceNames (void)
624 throw (::com::sun::star::uno::RuntimeException
)
627 static const OUString sServiceNames
[2] = {
628 OUString(RTL_CONSTASCII_USTRINGPARAM(
629 "com.sun.star.accessibility.Accessible")),
630 OUString(RTL_CONSTASCII_USTRINGPARAM(
631 "com.sun.star.accessibility.AccessibleContext")),
633 return uno::Sequence
<OUString
> (sServiceNames
, 2);
639 void AccessibleTreeNode::ThrowIfDisposed (void)
640 throw (lang::DisposedException
)
642 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
644 OSL_TRACE ("Calling disposed object. Throwing exception:");
645 throw lang::DisposedException (
646 OUString(RTL_CONSTASCII_USTRINGPARAM("object has been already disposed")),
647 static_cast<uno::XWeak
*>(this));
653 sal_Bool
AccessibleTreeNode::IsDisposed (void)
655 return (rBHelper
.bDisposed
|| rBHelper
.bInDispose
);
661 IMPL_LINK(AccessibleTreeNode
, StateChangeListener
, TreeNodeStateChangeEvent
*, pEvent
)
663 OSL_ASSERT(pEvent
!=NULL
);
664 OSL_ASSERT(&pEvent
->mrSource
==&mrTreeNode
);
666 switch(pEvent
->meEventId
)
668 case EID_CHILD_ADDED
:
669 if (pEvent
->mpChild
!= NULL
)
670 FireAccessibleEvent(AccessibleEventId::CHILD
,
672 Any(pEvent
->mpChild
->GetAccessibleObject()));
674 FireAccessibleEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN
,Any(),Any());
677 case EID_ALL_CHILDREN_REMOVED
:
678 FireAccessibleEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN
,Any(),Any());
681 case EID_EXPANSION_STATE_CHANGED
:
682 case EID_FOCUSED_STATE_CHANGED
:
683 case EID_SHOWING_STATE_CHANGED
:
693 IMPL_LINK(AccessibleTreeNode
, WindowEventListener
, VclWindowEvent
*, pEvent
)
695 switch (pEvent
->GetId())
697 case VCLEVENT_WINDOW_HIDE
:
698 // This event may be sent while the window is destroyed so do
699 // not call UpdateStateSet() which calls back to the window but
700 // just set the two states VISIBLE and SHOWING to false.
701 UpdateState(AccessibleStateType::VISIBLE
, false);
702 UpdateState(AccessibleStateType::SHOWING
, false);
705 case VCLEVENT_WINDOW_SHOW
:
706 case VCLEVENT_WINDOW_DATACHANGED
:
710 case VCLEVENT_WINDOW_MOVE
:
711 case VCLEVENT_WINDOW_RESIZE
:
712 FireAccessibleEvent(AccessibleEventId::BOUNDRECT_CHANGED
,Any(),Any());
715 case VCLEVENT_WINDOW_GETFOCUS
:
716 case VCLEVENT_WINDOW_LOSEFOCUS
:
723 } // end of namespace ::accessibility
725 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */