merge the formfield patch from ooo-build
[ooovba.git] / sd / source / ui / accessibility / AccessibleTreeNode.cxx
blobcc9681695b9872997a28c03b5c379f89c7e2be71
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: AccessibleTreeNode.cxx,v $
10 * $Revision: 1.7 $
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,
65 sal_Int16 eRole)
66 : AccessibleTreeNodeBase(MutexOwner::maMutex),
67 mxParent(NULL),
68 mrTreeNode(rNode),
69 mrStateSet(new ::utl::AccessibleStateSetHelper()),
70 msName(rsName),
71 msDescription(rsDescription),
72 meRole(eRole),
73 mnClientId(0)
75 ::Window* pWindow = mrTreeNode.GetWindow();
76 if (pWindow != NULL)
78 ::Window* pParentWindow = pWindow->GetAccessibleParentWindow();
79 if (pParentWindow != NULL && pParentWindow != pWindow)
80 mxParent = pParentWindow->GetAccessible();
82 CommonConstructor();
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),
95 mxParent(rxParent),
96 mrTreeNode(rNode),
97 mrStateSet(new ::utl::AccessibleStateSetHelper()),
98 msName(rsName),
99 msDescription(rsDescription),
100 meRole(eRole),
101 mnClientId(0)
103 CommonConstructor();
109 void AccessibleTreeNode::CommonConstructor (void)
111 UpdateStateSet();
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 (
135 short nEventId,
136 const uno::Any& rOldValue,
137 const uno::Any& rNewValue )
139 if (mnClientId != 0)
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
159 // unregister.
161 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( mnClientId, *this );
162 mnClientId = 0;
168 //===== XAccessible =========================================================
170 Reference<XAccessibleContext > SAL_CALL
171 AccessibleTreeNode::getAccessibleContext (void)
172 throw (uno::RuntimeException)
174 ThrowIfDisposed ();
175 return this;
181 //===== XAccessibleContext ==================================================
183 sal_Int32 SAL_CALL AccessibleTreeNode::getAccessibleChildCount (void)
184 throw (RuntimeException)
186 ThrowIfDisposed();
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)
198 ThrowIfDisposed();
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);
207 if (pNode != NULL)
208 xChild = pNode->GetAccessibleObject();
210 return xChild;
216 Reference<XAccessible > SAL_CALL AccessibleTreeNode::getAccessibleParent (void)
217 throw (uno::RuntimeException)
219 ThrowIfDisposed();
220 const vos::OGuard aSolarGuard (Application::GetSolarMutex());
221 return mxParent;
227 sal_Int32 SAL_CALL AccessibleTreeNode::getAccessibleIndexInParent (void)
228 throw (uno::RuntimeException)
230 OSL_ASSERT(getAccessibleParent().is());
231 ThrowIfDisposed();
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))
244 nIndexInParent = i;
245 break;
249 return nIndexInParent;
255 sal_Int16 SAL_CALL AccessibleTreeNode::getAccessibleRole (void)
256 throw (uno::RuntimeException)
258 ThrowIfDisposed();
259 return meRole;
265 ::rtl::OUString SAL_CALL AccessibleTreeNode::getAccessibleDescription (void)
266 throw (uno::RuntimeException)
268 ThrowIfDisposed();
269 return msDescription;
275 ::rtl::OUString SAL_CALL AccessibleTreeNode::getAccessibleName (void)
276 throw (uno::RuntimeException)
278 ThrowIfDisposed();
279 return msName;
285 Reference<XAccessibleRelationSet> SAL_CALL
286 AccessibleTreeNode::getAccessibleRelationSet (void)
287 throw (uno::RuntimeException)
289 ThrowIfDisposed();
290 return Reference<XAccessibleRelationSet>();
296 Reference<XAccessibleStateSet > SAL_CALL
297 AccessibleTreeNode::getAccessibleStateSet (void)
298 throw (uno::RuntimeException)
300 ThrowIfDisposed();
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();
319 if (pWindow != NULL)
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(
332 sal_Int16 aState,
333 bool bValue)
335 if ((mrStateSet->contains(aState)!=sal_False) != bValue)
337 if (bValue)
339 mrStateSet->AddState(aState);
340 FireAccessibleEvent(AccessibleEventId::STATE_CHANGED, Any(),Any(aState));
342 else
344 mrStateSet->RemoveState(aState);
345 FireAccessibleEvent(AccessibleEventId::STATE_CHANGED, Any(aState),Any());
353 lang::Locale SAL_CALL AccessibleTreeNode::getLocale (void)
354 throw (IllegalAccessibleComponentStateException,
355 RuntimeException)
357 ThrowIfDisposed ();
358 Reference<XAccessibleContext> xParentContext;
359 Reference<XAccessible> xParent (getAccessibleParent());
360 if (xParent.is())
361 xParentContext = xParent->getAccessibleContext();
363 if (xParentContext.is())
364 return xParentContext->getLocale();
365 else
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)
377 if (rxListener.is())
379 const osl::MutexGuard aGuard(maMutex);
381 if (IsDisposed())
383 uno::Reference<uno::XInterface> x ((lang::XComponent *)this, uno::UNO_QUERY);
384 rxListener->disposing (lang::EventObject (x));
386 else
388 if ( ! mnClientId)
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)
402 ThrowIfDisposed();
403 if (rxListener.is())
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 );
415 mnClientId = 0;
423 //===== XAccessibleComponent ==================================================
425 sal_Bool SAL_CALL AccessibleTreeNode::containsPoint (const awt::Point& aPoint)
426 throw (RuntimeException)
428 ThrowIfDisposed();
429 const awt::Rectangle aBBox (getBounds());
430 return (aPoint.X >= 0)
431 && (aPoint.X < aBBox.Width)
432 && (aPoint.Y >= 0)
433 && (aPoint.Y < aBBox.Height);
439 Reference<XAccessible> SAL_CALL
440 AccessibleTreeNode::getAccessibleAtPoint (const awt::Point& aPoint)
441 throw (RuntimeException)
443 ThrowIfDisposed();
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);
461 break;
466 return xChildAtPoint;
472 awt::Rectangle SAL_CALL AccessibleTreeNode::getBounds (void)
473 throw (RuntimeException)
475 ThrowIfDisposed ();
477 awt::Rectangle aBBox;
479 ::Window* pWindow = mrTreeNode.GetWindow();
480 if (pWindow != NULL)
482 Point aPosition;
483 if (mxParent.is())
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;
495 else
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();
505 return aBBox;
511 awt::Point SAL_CALL AccessibleTreeNode::getLocation (void)
512 throw (uno::RuntimeException)
514 ThrowIfDisposed();
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)
528 ThrowIfDisposed();
529 const vos::OGuard aSolarGuard( Application::GetSolarMutex() );
530 awt::Point aLocationOnScreen;
532 ::Window* pWindow = mrTreeNode.GetWindow();
533 if (pWindow != NULL)
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)
549 ThrowIfDisposed();
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)
560 ThrowIfDisposed();
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)
573 ThrowIfDisposed();
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)
585 ThrowIfDisposed();
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"));
605 sal_Bool SAL_CALL
606 AccessibleTreeNode::supportsService (const OUString& sServiceName)
607 throw (::com::sun::star::uno::RuntimeException)
609 ThrowIfDisposed ();
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])
617 return sal_True;
618 return sal_False;
624 uno::Sequence< ::rtl::OUString> SAL_CALL
625 AccessibleTreeNode::getSupportedServiceNames (void)
626 throw (::com::sun::star::uno::RuntimeException)
628 ThrowIfDisposed ();
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,
673 Any(),
674 Any(pEvent->mpChild->GetAccessibleObject()));
675 else
676 FireAccessibleEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN,Any(),Any());
677 break;
679 case EID_ALL_CHILDREN_REMOVED:
680 FireAccessibleEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN,Any(),Any());
681 break;
683 case EID_EXPANSION_STATE_CHANGED:
684 case EID_FOCUSED_STATE_CHANGED:
685 case EID_SHOWING_STATE_CHANGED:
686 UpdateStateSet();
687 break;
689 return 1;
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);
705 break;
707 case VCLEVENT_WINDOW_SHOW:
708 case VCLEVENT_WINDOW_DATACHANGED:
709 UpdateStateSet();
710 break;
712 case VCLEVENT_WINDOW_MOVE:
713 case VCLEVENT_WINDOW_RESIZE:
714 FireAccessibleEvent(AccessibleEventId::BOUNDRECT_CHANGED,Any(),Any());
715 break;
717 case VCLEVENT_WINDOW_GETFOCUS:
718 case VCLEVENT_WINDOW_LOSEFOCUS:
719 UpdateStateSet();
721 return 1;
724 } // end of namespace ::accessibility