1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "AccessibleTreeNode.hxx"
23 #include "taskpane/TaskPaneTreeNode.hxx"
24 #include "taskpane/ControlContainer.hxx"
26 #include "sdresid.hxx"
27 #include "accessibility.hrc"
28 #include <com/sun/star/accessibility/AccessibleRole.hpp>
29 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
30 #include <comphelper/accessibleeventnotifier.hxx>
32 #include <vcl/svapp.hxx>
33 #include <vcl/window.hxx>
34 #include <svtools/colorcfg.hxx>
36 using namespace ::com::sun::star
;
37 using namespace ::com::sun::star::uno
;
38 using namespace ::com::sun::star::accessibility
;
39 using namespace ::sd::toolpanel
;
41 namespace accessibility
{
45 //===== AccessibleTreeNode =============================================
47 AccessibleTreeNode::AccessibleTreeNode(
48 ::sd::toolpanel::TreeNode
& rNode
,
49 const OUString
& rsName
,
50 const OUString
& rsDescription
,
52 : AccessibleTreeNodeBase(MutexOwner::maMutex
),
55 mrStateSet(new ::utl::AccessibleStateSetHelper()),
57 msDescription(rsDescription
),
61 ::Window
* pWindow
= mrTreeNode
.GetWindow();
64 ::Window
* pParentWindow
= pWindow
->GetAccessibleParentWindow();
65 if (pParentWindow
!= NULL
&& pParentWindow
!= pWindow
)
66 mxParent
= pParentWindow
->GetAccessible();
74 void AccessibleTreeNode::CommonConstructor (void)
78 Link
aStateChangeLink (LINK(this,AccessibleTreeNode
,StateChangeListener
));
79 mrTreeNode
.AddStateChangeListener(aStateChangeLink
);
81 if (mrTreeNode
.GetWindow() != NULL
)
83 Link
aWindowEventLink (LINK(this,AccessibleTreeNode
,WindowEventListener
));
84 mrTreeNode
.GetWindow()->AddEventListener(aWindowEventLink
);
91 AccessibleTreeNode::~AccessibleTreeNode (void)
93 OSL_ASSERT(IsDisposed());
99 void AccessibleTreeNode::FireAccessibleEvent (
101 const uno::Any
& rOldValue
,
102 const uno::Any
& rNewValue
)
106 AccessibleEventObject aEventObject
;
108 aEventObject
.Source
= Reference
<XWeak
>(this);
109 aEventObject
.EventId
= nEventId
;
110 aEventObject
.NewValue
= rNewValue
;
111 aEventObject
.OldValue
= rOldValue
;
113 comphelper::AccessibleEventNotifier::addEvent (mnClientId
, aEventObject
);
120 void SAL_CALL
AccessibleTreeNode::disposing (void)
122 // We are still listening to the tree node and its window. Both
123 // probably are by now more or less dead and we must not call them to
128 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( mnClientId
, *this );
136 //===== XAccessible =========================================================
138 Reference
<XAccessibleContext
> SAL_CALL
139 AccessibleTreeNode::getAccessibleContext (void)
140 throw (uno::RuntimeException
)
149 //===== XAccessibleContext ==================================================
151 sal_Int32 SAL_CALL
AccessibleTreeNode::getAccessibleChildCount (void)
152 throw (RuntimeException
)
155 const SolarMutexGuard aSolarGuard
;
156 return mrTreeNode
.GetControlContainer().GetControlCount();
162 Reference
<XAccessible
> SAL_CALL
163 AccessibleTreeNode::getAccessibleChild (sal_Int32 nIndex
)
164 throw (lang::IndexOutOfBoundsException
, RuntimeException
)
167 const SolarMutexGuard aSolarGuard
;
169 if (nIndex
<0 || (sal_uInt32
)nIndex
>=mrTreeNode
.GetControlContainer().GetControlCount())
170 throw lang::IndexOutOfBoundsException();
172 Reference
<XAccessible
> xChild
;
174 ::sd::toolpanel::TreeNode
* pNode
= mrTreeNode
.GetControlContainer().GetControl(nIndex
);
176 xChild
= pNode
->GetAccessibleObject();
184 Reference
<XAccessible
> SAL_CALL
AccessibleTreeNode::getAccessibleParent (void)
185 throw (uno::RuntimeException
)
188 const SolarMutexGuard aSolarGuard
;
195 sal_Int32 SAL_CALL
AccessibleTreeNode::getAccessibleIndexInParent (void)
196 throw (uno::RuntimeException
)
198 OSL_ASSERT(getAccessibleParent().is());
200 const SolarMutexGuard aSolarGuard
;
201 sal_Int32
nIndexInParent(-1);
204 Reference
<XAccessibleContext
> xParentContext (getAccessibleParent()->getAccessibleContext());
205 if (xParentContext
.is())
207 sal_Int32
nChildCount (xParentContext
->getAccessibleChildCount());
208 for (sal_Int32 i
=0; i
<nChildCount
; ++i
)
209 if (xParentContext
->getAccessibleChild(i
).get()
210 == static_cast<XAccessible
*>(this))
217 return nIndexInParent
;
223 sal_Int16 SAL_CALL
AccessibleTreeNode::getAccessibleRole (void)
224 throw (uno::RuntimeException
)
233 OUString SAL_CALL
AccessibleTreeNode::getAccessibleDescription (void)
234 throw (uno::RuntimeException
)
237 return msDescription
;
243 OUString SAL_CALL
AccessibleTreeNode::getAccessibleName (void)
244 throw (uno::RuntimeException
)
253 Reference
<XAccessibleRelationSet
> SAL_CALL
254 AccessibleTreeNode::getAccessibleRelationSet (void)
255 throw (uno::RuntimeException
)
258 return Reference
<XAccessibleRelationSet
>();
264 Reference
<XAccessibleStateSet
> SAL_CALL
265 AccessibleTreeNode::getAccessibleStateSet (void)
266 throw (uno::RuntimeException
)
269 const SolarMutexGuard aSolarGuard
;
270 return mrStateSet
.get();
276 void AccessibleTreeNode::UpdateStateSet (void)
278 if (mrTreeNode
.IsExpandable())
280 UpdateState(AccessibleStateType::EXPANDABLE
, true);
281 UpdateState(AccessibleStateType::EXPANDED
, mrTreeNode
.IsExpanded());
284 UpdateState(AccessibleStateType::FOCUSABLE
, true);
286 ::Window
* pWindow
= mrTreeNode
.GetWindow();
289 UpdateState(AccessibleStateType::ENABLED
, pWindow
->IsEnabled());
290 UpdateState(AccessibleStateType::FOCUSED
, pWindow
->HasFocus());
291 UpdateState(AccessibleStateType::VISIBLE
, pWindow
->IsVisible());
292 UpdateState(AccessibleStateType::SHOWING
, pWindow
->IsReallyVisible());
299 void AccessibleTreeNode::UpdateState(
303 if ((mrStateSet
->contains(aState
)!=sal_False
) != bValue
)
307 mrStateSet
->AddState(aState
);
308 FireAccessibleEvent(AccessibleEventId::STATE_CHANGED
, Any(),Any(aState
));
312 mrStateSet
->RemoveState(aState
);
313 FireAccessibleEvent(AccessibleEventId::STATE_CHANGED
, Any(aState
),Any());
321 lang::Locale SAL_CALL
AccessibleTreeNode::getLocale (void)
322 throw (IllegalAccessibleComponentStateException
,
326 Reference
<XAccessibleContext
> xParentContext
;
327 Reference
<XAccessible
> xParent (getAccessibleParent());
329 xParentContext
= xParent
->getAccessibleContext();
331 if (xParentContext
.is())
332 return xParentContext
->getLocale();
334 // Strange, no parent! Anyway, return the default locale.
335 return Application::GetSettings().GetLanguageTag().getLocale();
341 void SAL_CALL
AccessibleTreeNode::addAccessibleEventListener(
342 const Reference
<XAccessibleEventListener
>& rxListener
)
343 throw (RuntimeException
)
347 const osl::MutexGuard
aGuard(maMutex
);
351 uno::Reference
<uno::XInterface
> x ((lang::XComponent
*)this, uno::UNO_QUERY
);
352 rxListener
->disposing (lang::EventObject (x
));
357 mnClientId
= comphelper::AccessibleEventNotifier::registerClient();
359 comphelper::AccessibleEventNotifier::addEventListener(mnClientId
, rxListener
);
367 void SAL_CALL
AccessibleTreeNode::removeAccessibleEventListener(
368 const Reference
<XAccessibleEventListener
>& rxListener
)
369 throw (RuntimeException
)
374 const osl::MutexGuard
aGuard(maMutex
);
376 sal_Int32 nListenerCount
= comphelper::AccessibleEventNotifier::removeEventListener( mnClientId
, rxListener
);
377 if ( !nListenerCount
)
379 // no listeners anymore
380 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
381 // and at least to us not firing any events anymore, in case somebody calls
382 // NotifyAccessibleEvent, again
385 comphelper::AccessibleEventNotifier::revokeClient( mnClientId
);
395 //===== XAccessibleComponent ==================================================
397 sal_Bool SAL_CALL
AccessibleTreeNode::containsPoint (const awt::Point
& aPoint
)
398 throw (RuntimeException
)
401 const awt::Rectangle
aBBox (getBounds());
402 return (aPoint
.X
>= 0)
403 && (aPoint
.X
< aBBox
.Width
)
405 && (aPoint
.Y
< aBBox
.Height
);
411 Reference
<XAccessible
> SAL_CALL
412 AccessibleTreeNode::getAccessibleAtPoint (const awt::Point
& aPoint
)
413 throw (RuntimeException
)
416 Reference
<XAccessible
> xChildAtPoint
;
417 const SolarMutexGuard aSolarGuard
;
419 sal_Int32 nChildCount
= getAccessibleChildCount();
420 for (sal_Int32 nIndex
=0; nIndex
<nChildCount
; ++nIndex
)
422 Reference
<XAccessibleComponent
> xChildComponent(
423 getAccessibleChild(nIndex
), UNO_QUERY
);
424 if (xChildComponent
.is())
426 awt::Point
aChildPoint(aPoint
);
427 awt::Point
aChildOrigin(xChildComponent
->getLocation());
428 aChildPoint
.X
-= aChildOrigin
.X
;
429 aChildPoint
.Y
-= aChildOrigin
.Y
;
430 if (xChildComponent
->containsPoint(aChildPoint
))
432 xChildAtPoint
= getAccessibleChild(nIndex
);
438 return xChildAtPoint
;
444 awt::Rectangle SAL_CALL
AccessibleTreeNode::getBounds (void)
445 throw (RuntimeException
)
449 awt::Rectangle aBBox
;
451 ::Window
* pWindow
= mrTreeNode
.GetWindow();
457 aPosition
= pWindow
->OutputToAbsoluteScreenPixel(Point(0,0));
458 Reference
<XAccessibleComponent
> xParentComponent (
459 mxParent
->getAccessibleContext(), UNO_QUERY
);
460 if (xParentComponent
.is())
462 awt::Point
aParentPosition (xParentComponent
->getLocationOnScreen());
463 aPosition
.X() -= aParentPosition
.X
;
464 aPosition
.Y() -= aParentPosition
.Y
;
468 aPosition
= pWindow
->GetPosPixel();
469 aBBox
.X
= aPosition
.X();
470 aBBox
.Y
= aPosition
.Y();
472 Size
aSize (pWindow
->GetSizePixel());
473 aBBox
.Width
= aSize
.Width();
474 aBBox
.Height
= aSize
.Height();
483 awt::Point SAL_CALL
AccessibleTreeNode::getLocation (void)
484 throw (uno::RuntimeException
)
487 const awt::Rectangle
aBBox (getBounds());
488 return awt::Point(aBBox
.X
,aBBox
.Y
);
494 /** Calculate the location on screen from the parent's location on screen
495 and our own relative location.
497 awt::Point SAL_CALL
AccessibleTreeNode::getLocationOnScreen()
498 throw (uno::RuntimeException
)
501 const SolarMutexGuard aSolarGuard
;
502 awt::Point aLocationOnScreen
;
504 ::Window
* pWindow
= mrTreeNode
.GetWindow();
507 Point
aPoint (pWindow
->OutputToAbsoluteScreenPixel(Point(0,0)));
508 aLocationOnScreen
.X
= aPoint
.X();
509 aLocationOnScreen
.Y
= aPoint
.Y();
512 return aLocationOnScreen
;
518 awt::Size SAL_CALL
AccessibleTreeNode::getSize (void)
519 throw (uno::RuntimeException
)
522 const awt::Rectangle
aBBox (getBounds());
523 return awt::Size(aBBox
.Width
,aBBox
.Height
);
529 void SAL_CALL
AccessibleTreeNode::grabFocus (void)
530 throw (uno::RuntimeException
)
533 const SolarMutexGuard aSolarGuard
;
535 if (mrTreeNode
.GetWindow() != NULL
)
536 mrTreeNode
.GetWindow()->GrabFocus();
542 sal_Int32 SAL_CALL
AccessibleTreeNode::getForeground (void)
543 throw (RuntimeException
)
546 svtools::ColorConfig aColorConfig
;
547 sal_uInt32 nColor
= aColorConfig
.GetColorValue( svtools::FONTCOLOR
).nColor
;
548 return static_cast<sal_Int32
>(nColor
);
554 sal_Int32 SAL_CALL
AccessibleTreeNode::getBackground (void)
555 throw (RuntimeException
)
558 sal_uInt32 nColor
= Application::GetSettings().GetStyleSettings().GetWindowColor().GetColor();
559 return static_cast<sal_Int32
>(nColor
);
565 //===== XServiceInfo ========================================================
568 AccessibleTreeNode::getImplementationName (void)
569 throw (::com::sun::star::uno::RuntimeException
)
571 return OUString("AccessibleTreeNode");
578 AccessibleTreeNode::supportsService (const OUString
& sServiceName
)
579 throw (::com::sun::star::uno::RuntimeException
)
583 // Iterate over all supported service names and return true if on of them
584 // matches the given name.
585 uno::Sequence
< OUString
> aSupportedServices (
586 getSupportedServiceNames ());
587 for (int i
=0; i
<aSupportedServices
.getLength(); i
++)
588 if (sServiceName
== aSupportedServices
[i
])
596 uno::Sequence
< OUString
> SAL_CALL
597 AccessibleTreeNode::getSupportedServiceNames (void)
598 throw (::com::sun::star::uno::RuntimeException
)
601 static const OUString sServiceNames
[2] = {
602 OUString("com.sun.star.accessibility.Accessible"),
603 OUString("com.sun.star.accessibility.AccessibleContext"),
605 return uno::Sequence
<OUString
> (sServiceNames
, 2);
611 void AccessibleTreeNode::ThrowIfDisposed (void)
612 throw (lang::DisposedException
)
614 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
616 OSL_TRACE ("Calling disposed object. Throwing exception:");
617 throw lang::DisposedException ("object has been already disposed",
618 static_cast<uno::XWeak
*>(this));
624 sal_Bool
AccessibleTreeNode::IsDisposed (void)
626 return (rBHelper
.bDisposed
|| rBHelper
.bInDispose
);
632 IMPL_LINK(AccessibleTreeNode
, StateChangeListener
, TreeNodeStateChangeEvent
*, pEvent
)
634 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
635 return 1; // mrTreeNode is probably dead
637 OSL_ASSERT(pEvent
!=NULL
);
638 OSL_ASSERT(&pEvent
->mrSource
==&mrTreeNode
);
640 switch(pEvent
->meEventId
)
642 case EID_CHILD_ADDED
:
643 if (pEvent
->mpChild
!= NULL
)
644 FireAccessibleEvent(AccessibleEventId::CHILD
,
646 Any(pEvent
->mpChild
->GetAccessibleObject()));
648 FireAccessibleEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN
,Any(),Any());
651 case EID_ALL_CHILDREN_REMOVED
:
652 FireAccessibleEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN
,Any(),Any());
655 case EID_EXPANSION_STATE_CHANGED
:
656 case EID_FOCUSED_STATE_CHANGED
:
657 case EID_SHOWING_STATE_CHANGED
:
667 IMPL_LINK(AccessibleTreeNode
, WindowEventListener
, VclWindowEvent
*, pEvent
)
669 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
670 return 1; // mrTreeNode is probably dead
672 switch (pEvent
->GetId())
674 case VCLEVENT_WINDOW_HIDE
:
675 // This event may be sent while the window is destroyed so do
676 // not call UpdateStateSet() which calls back to the window but
677 // just set the two states VISIBLE and SHOWING to false.
678 UpdateState(AccessibleStateType::VISIBLE
, false);
679 UpdateState(AccessibleStateType::SHOWING
, false);
682 case VCLEVENT_WINDOW_SHOW
:
683 case VCLEVENT_WINDOW_DATACHANGED
:
687 case VCLEVENT_WINDOW_MOVE
:
688 case VCLEVENT_WINDOW_RESIZE
:
689 FireAccessibleEvent(AccessibleEventId::BOUNDRECT_CHANGED
,Any(),Any());
692 case VCLEVENT_WINDOW_GETFOCUS
:
693 case VCLEVENT_WINDOW_LOSEFOCUS
:
700 } // end of namespace ::accessibility
702 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */