merged tag LIBREOFFICE_3_2_99_3
[LibreOffice.git] / sd / source / ui / accessibility / AccessibleTreeNode.cxx
blob449b3d2235e634dcec7b9bcb1e036ac5b2da4c1d
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,
63 sal_Int16 eRole)
64 : AccessibleTreeNodeBase(MutexOwner::maMutex),
65 mxParent(NULL),
66 mrTreeNode(rNode),
67 mrStateSet(new ::utl::AccessibleStateSetHelper()),
68 msName(rsName),
69 msDescription(rsDescription),
70 meRole(eRole),
71 mnClientId(0)
73 ::Window* pWindow = mrTreeNode.GetWindow();
74 if (pWindow != NULL)
76 ::Window* pParentWindow = pWindow->GetAccessibleParentWindow();
77 if (pParentWindow != NULL && pParentWindow != pWindow)
78 mxParent = pParentWindow->GetAccessible();
80 CommonConstructor();
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),
93 mxParent(rxParent),
94 mrTreeNode(rNode),
95 mrStateSet(new ::utl::AccessibleStateSetHelper()),
96 msName(rsName),
97 msDescription(rsDescription),
98 meRole(eRole),
99 mnClientId(0)
101 CommonConstructor();
107 void AccessibleTreeNode::CommonConstructor (void)
109 UpdateStateSet();
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 (
133 short nEventId,
134 const uno::Any& rOldValue,
135 const uno::Any& rNewValue )
137 if (mnClientId != 0)
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
157 // unregister.
159 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( mnClientId, *this );
160 mnClientId = 0;
166 //===== XAccessible =========================================================
168 Reference<XAccessibleContext > SAL_CALL
169 AccessibleTreeNode::getAccessibleContext (void)
170 throw (uno::RuntimeException)
172 ThrowIfDisposed ();
173 return this;
179 //===== XAccessibleContext ==================================================
181 sal_Int32 SAL_CALL AccessibleTreeNode::getAccessibleChildCount (void)
182 throw (RuntimeException)
184 ThrowIfDisposed();
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)
196 ThrowIfDisposed();
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);
205 if (pNode != NULL)
206 xChild = pNode->GetAccessibleObject();
208 return xChild;
214 Reference<XAccessible > SAL_CALL AccessibleTreeNode::getAccessibleParent (void)
215 throw (uno::RuntimeException)
217 ThrowIfDisposed();
218 const SolarMutexGuard aSolarGuard;
219 return mxParent;
225 sal_Int32 SAL_CALL AccessibleTreeNode::getAccessibleIndexInParent (void)
226 throw (uno::RuntimeException)
228 OSL_ASSERT(getAccessibleParent().is());
229 ThrowIfDisposed();
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))
242 nIndexInParent = i;
243 break;
247 return nIndexInParent;
253 sal_Int16 SAL_CALL AccessibleTreeNode::getAccessibleRole (void)
254 throw (uno::RuntimeException)
256 ThrowIfDisposed();
257 return meRole;
263 ::rtl::OUString SAL_CALL AccessibleTreeNode::getAccessibleDescription (void)
264 throw (uno::RuntimeException)
266 ThrowIfDisposed();
267 return msDescription;
273 ::rtl::OUString SAL_CALL AccessibleTreeNode::getAccessibleName (void)
274 throw (uno::RuntimeException)
276 ThrowIfDisposed();
277 return msName;
283 Reference<XAccessibleRelationSet> SAL_CALL
284 AccessibleTreeNode::getAccessibleRelationSet (void)
285 throw (uno::RuntimeException)
287 ThrowIfDisposed();
288 return Reference<XAccessibleRelationSet>();
294 Reference<XAccessibleStateSet > SAL_CALL
295 AccessibleTreeNode::getAccessibleStateSet (void)
296 throw (uno::RuntimeException)
298 ThrowIfDisposed();
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();
317 if (pWindow != NULL)
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(
330 sal_Int16 aState,
331 bool bValue)
333 if ((mrStateSet->contains(aState)!=sal_False) != bValue)
335 if (bValue)
337 mrStateSet->AddState(aState);
338 FireAccessibleEvent(AccessibleEventId::STATE_CHANGED, Any(),Any(aState));
340 else
342 mrStateSet->RemoveState(aState);
343 FireAccessibleEvent(AccessibleEventId::STATE_CHANGED, Any(aState),Any());
351 lang::Locale SAL_CALL AccessibleTreeNode::getLocale (void)
352 throw (IllegalAccessibleComponentStateException,
353 RuntimeException)
355 ThrowIfDisposed ();
356 Reference<XAccessibleContext> xParentContext;
357 Reference<XAccessible> xParent (getAccessibleParent());
358 if (xParent.is())
359 xParentContext = xParent->getAccessibleContext();
361 if (xParentContext.is())
362 return xParentContext->getLocale();
363 else
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)
375 if (rxListener.is())
377 const osl::MutexGuard aGuard(maMutex);
379 if (IsDisposed())
381 uno::Reference<uno::XInterface> x ((lang::XComponent *)this, uno::UNO_QUERY);
382 rxListener->disposing (lang::EventObject (x));
384 else
386 if ( ! mnClientId)
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)
400 ThrowIfDisposed();
401 if (rxListener.is())
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 );
413 mnClientId = 0;
421 //===== XAccessibleComponent ==================================================
423 sal_Bool SAL_CALL AccessibleTreeNode::containsPoint (const awt::Point& aPoint)
424 throw (RuntimeException)
426 ThrowIfDisposed();
427 const awt::Rectangle aBBox (getBounds());
428 return (aPoint.X >= 0)
429 && (aPoint.X < aBBox.Width)
430 && (aPoint.Y >= 0)
431 && (aPoint.Y < aBBox.Height);
437 Reference<XAccessible> SAL_CALL
438 AccessibleTreeNode::getAccessibleAtPoint (const awt::Point& aPoint)
439 throw (RuntimeException)
441 ThrowIfDisposed();
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);
459 break;
464 return xChildAtPoint;
470 awt::Rectangle SAL_CALL AccessibleTreeNode::getBounds (void)
471 throw (RuntimeException)
473 ThrowIfDisposed ();
475 awt::Rectangle aBBox;
477 ::Window* pWindow = mrTreeNode.GetWindow();
478 if (pWindow != NULL)
480 Point aPosition;
481 if (mxParent.is())
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;
493 else
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();
503 return aBBox;
509 awt::Point SAL_CALL AccessibleTreeNode::getLocation (void)
510 throw (uno::RuntimeException)
512 ThrowIfDisposed();
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)
526 ThrowIfDisposed();
527 const SolarMutexGuard aSolarGuard;
528 awt::Point aLocationOnScreen;
530 ::Window* pWindow = mrTreeNode.GetWindow();
531 if (pWindow != NULL)
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)
547 ThrowIfDisposed();
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)
558 ThrowIfDisposed();
559 const SolarMutexGuard aSolarGuard;
561 if (mrTreeNode.GetWindow() != NULL)
562 mrTreeNode.GetWindow()->GrabFocus();
568 sal_Int32 SAL_CALL AccessibleTreeNode::getForeground (void)
569 throw (RuntimeException)
571 ThrowIfDisposed();
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)
583 ThrowIfDisposed();
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"));
603 sal_Bool SAL_CALL
604 AccessibleTreeNode::supportsService (const OUString& sServiceName)
605 throw (::com::sun::star::uno::RuntimeException)
607 ThrowIfDisposed ();
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])
615 return sal_True;
616 return sal_False;
622 uno::Sequence< ::rtl::OUString> SAL_CALL
623 AccessibleTreeNode::getSupportedServiceNames (void)
624 throw (::com::sun::star::uno::RuntimeException)
626 ThrowIfDisposed ();
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,
671 Any(),
672 Any(pEvent->mpChild->GetAccessibleObject()));
673 else
674 FireAccessibleEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN,Any(),Any());
675 break;
677 case EID_ALL_CHILDREN_REMOVED:
678 FireAccessibleEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN,Any(),Any());
679 break;
681 case EID_EXPANSION_STATE_CHANGED:
682 case EID_FOCUSED_STATE_CHANGED:
683 case EID_SHOWING_STATE_CHANGED:
684 UpdateStateSet();
685 break;
687 return 1;
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);
703 break;
705 case VCLEVENT_WINDOW_SHOW:
706 case VCLEVENT_WINDOW_DATACHANGED:
707 UpdateStateSet();
708 break;
710 case VCLEVENT_WINDOW_MOVE:
711 case VCLEVENT_WINDOW_RESIZE:
712 FireAccessibleEvent(AccessibleEventId::BOUNDRECT_CHANGED,Any(),Any());
713 break;
715 case VCLEVENT_WINDOW_GETFOCUS:
716 case VCLEVENT_WINDOW_LOSEFOCUS:
717 UpdateStateSet();
718 break;
720 return 1;
723 } // end of namespace ::accessibility
725 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */