tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / Accessibility / AccessibleContextBase.cxx
blobb121893e2f6c76d5abf04594461dfd1b27647ea4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <AccessibleContextBase.hxx>
21 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
22 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
23 #include <com/sun/star/accessibility/IllegalAccessibleComponentStateException.hpp>
24 #include <tools/gen.hxx>
25 #include <tools/color.hxx>
26 #include <toolkit/helper/vclunohelper.hxx>
27 #include <svl/hint.hxx>
28 #include <comphelper/sequence.hxx>
29 #include <cppuhelper/supportsservice.hxx>
30 #include <unotools/accessiblerelationsethelper.hxx>
31 #include <utility>
32 #include <vcl/unohelp.hxx>
33 #include <comphelper/accessibleeventnotifier.hxx>
34 #include <vcl/svapp.hxx>
36 using namespace ::com::sun::star;
37 using namespace ::com::sun::star::accessibility;
39 /**
40 The listener is an internal class to prevent reference-counting cycles and therefore memory leaks.
42 typedef cppu::WeakComponentImplHelper<
43 css::accessibility::XAccessibleEventListener
44 > ScAccessibleContextBaseEventListenerWeakImpl;
45 class ScAccessibleContextBase::ScAccessibleContextBaseEventListener : public cppu::BaseMutex, public ScAccessibleContextBaseEventListenerWeakImpl
47 public:
48 ScAccessibleContextBaseEventListener(ScAccessibleContextBase& rBase)
49 : ScAccessibleContextBaseEventListenerWeakImpl(m_aMutex), mrBase(rBase) {}
51 using WeakComponentImplHelperBase::disposing;
53 ///===== XAccessibleEventListener ========================================
55 virtual void SAL_CALL disposing( const lang::EventObject& rSource ) override
57 SolarMutexGuard aGuard;
58 if (rSource.Source == mrBase.mxParent)
59 dispose();
62 virtual void SAL_CALL
63 notifyEvent(
64 const css::accessibility::AccessibleEventObject& /*aEvent*/ ) override {}
65 private:
66 ScAccessibleContextBase& mrBase;
70 ScAccessibleContextBase::ScAccessibleContextBase(
71 uno::Reference<XAccessible> xParent,
72 const sal_Int16 aRole)
74 ScAccessibleContextBaseWeakImpl(m_aMutex),
75 mxParent(std::move(xParent)),
76 mnClientId(0),
77 maRole(aRole)
81 ScAccessibleContextBase::~ScAccessibleContextBase()
83 if (!IsDefunc() && !rBHelper.bInDispose)
85 // increment refcount to prevent double call off dtor
86 osl_atomic_increment( &m_refCount );
87 // call dispose to inform object which have a weak reference to this object
88 dispose();
92 void ScAccessibleContextBase::Init()
94 // hold reference to make sure that the destructor is not called
95 uno::Reference< XAccessibleContext > xKeepAlive(this);
97 if (mxParent.is())
99 uno::Reference< XAccessibleEventBroadcaster > xBroadcaster (mxParent->getAccessibleContext(), uno::UNO_QUERY);
100 if (xBroadcaster.is())
102 if (!mxEventListener)
103 mxEventListener = new ScAccessibleContextBaseEventListener(*this);
104 xBroadcaster->addAccessibleEventListener(mxEventListener);
107 msName = createAccessibleName();
108 msDescription = createAccessibleDescription();
111 void SAL_CALL ScAccessibleContextBase::disposing()
113 SolarMutexGuard aGuard;
114 // CommitDefunc(); not necessary and should not be send, because it cost a lot of time
116 // hold reference to make sure that the destructor is not called
117 uno::Reference< XAccessibleContext > xKeepAlive(this);
119 if ( mnClientId )
121 sal_Int32 nTemClientId(mnClientId);
122 mnClientId = 0;
123 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( nTemClientId, *this );
126 if (mxParent.is())
128 uno::Reference< XAccessibleEventBroadcaster > xBroadcaster (mxParent->getAccessibleContext(), uno::UNO_QUERY);
129 if (xBroadcaster && mxEventListener)
130 xBroadcaster->removeAccessibleEventListener(mxEventListener);
131 mxParent = nullptr;
136 //===== SfxListener =====================================================
138 void ScAccessibleContextBase::Notify( SfxBroadcaster&, const SfxHint& rHint )
140 if (rHint.GetId() == SfxHintId::Dying)
142 // it seems the Broadcaster is dying, since the view is dying
143 dispose();
147 //===== XAccessible =========================================================
149 uno::Reference< XAccessibleContext> SAL_CALL
150 ScAccessibleContextBase::getAccessibleContext()
152 return this;
155 //===== XAccessibleComponent ================================================
157 sal_Bool SAL_CALL ScAccessibleContextBase::containsPoint(const awt::Point& rPoint )
159 SolarMutexGuard aGuard;
160 IsObjectValid();
161 return tools::Rectangle(Point(), GetBoundingBox().GetSize())
162 .Contains(vcl::unohelper::ConvertToVCLPoint(rPoint));
165 uno::Reference< XAccessible > SAL_CALL ScAccessibleContextBase::getAccessibleAtPoint(
166 const awt::Point& /* rPoint */ )
168 OSL_FAIL("not implemented");
169 return uno::Reference<XAccessible>();
172 awt::Rectangle SAL_CALL ScAccessibleContextBase::getBounds( )
174 SolarMutexGuard aGuard;
175 IsObjectValid();
176 return vcl::unohelper::ConvertToAWTRect(GetBoundingBox());
179 awt::Point SAL_CALL ScAccessibleContextBase::getLocation( )
181 SolarMutexGuard aGuard;
182 IsObjectValid();
183 return vcl::unohelper::ConvertToAWTPoint(GetBoundingBox().TopLeft());
186 awt::Point SAL_CALL ScAccessibleContextBase::getLocationOnScreen( )
188 SolarMutexGuard aGuard;
189 IsObjectValid();
190 return vcl::unohelper::ConvertToAWTPoint(GetBoundingBoxOnScreen().TopLeft());
193 awt::Size SAL_CALL ScAccessibleContextBase::getSize( )
195 SolarMutexGuard aGuard;
196 IsObjectValid();
197 return vcl::unohelper::ConvertToAWTSize(GetBoundingBox().GetSize());
200 bool ScAccessibleContextBase::isShowing( )
202 SolarMutexGuard aGuard;
203 IsObjectValid();
204 bool bShowing(false);
205 if (mxParent.is())
207 uno::Reference<XAccessibleComponent> xParentComponent (mxParent->getAccessibleContext(), uno::UNO_QUERY);
208 if (xParentComponent.is())
210 tools::Rectangle aParentBounds(
211 vcl::unohelper::ConvertToVCLRect(xParentComponent->getBounds()));
212 tools::Rectangle aBounds(vcl::unohelper::ConvertToVCLRect(getBounds()));
213 bShowing = aBounds.Overlaps(aParentBounds);
216 return bShowing;
219 bool ScAccessibleContextBase::isVisible()
221 return true;
224 void SAL_CALL ScAccessibleContextBase::grabFocus( )
226 OSL_FAIL("not implemented");
229 sal_Int32 SAL_CALL ScAccessibleContextBase::getForeground( )
231 return sal_Int32(COL_BLACK);
234 sal_Int32 SAL_CALL ScAccessibleContextBase::getBackground( )
236 return sal_Int32(COL_WHITE);
239 //===== XAccessibleContext ==================================================
241 sal_Int64 SAL_CALL ScAccessibleContextBase::getAccessibleChildCount()
243 OSL_FAIL("should be implemented in the abrevated class");
244 return 0;
247 uno::Reference<XAccessible> SAL_CALL
248 ScAccessibleContextBase::getAccessibleChild(sal_Int64 /* nIndex */)
250 OSL_FAIL("should be implemented in the abrevated class");
251 return uno::Reference<XAccessible>();
254 uno::Reference<XAccessible> SAL_CALL
255 ScAccessibleContextBase::getAccessibleParent()
257 return mxParent;
260 sal_Int64 SAL_CALL
261 ScAccessibleContextBase::getAccessibleIndexInParent()
263 SolarMutexGuard aGuard;
264 IsObjectValid();
265 // Use a simple but slow solution for now. Optimize later.
266 // Return -1 to indicate that this object's parent does not know about the
267 // object.
268 sal_Int64 nIndex(-1);
270 // Iterate over all the parent's children and search for this object.
271 if (mxParent.is())
273 uno::Reference<XAccessibleContext> xParentContext (
274 mxParent->getAccessibleContext());
275 if (xParentContext.is())
277 sal_Int64 nChildCount = xParentContext->getAccessibleChildCount();
278 for (sal_Int64 i=0; i<nChildCount; ++i)
280 uno::Reference<XAccessible> xChild (xParentContext->getAccessibleChild (i));
281 if (xChild.is() && xChild.get() == this)
282 nIndex = i;
287 return nIndex;
290 sal_Int16 SAL_CALL
291 ScAccessibleContextBase::getAccessibleRole()
293 return maRole;
296 OUString SAL_CALL
297 ScAccessibleContextBase::getAccessibleDescription()
299 SolarMutexGuard aGuard;
300 IsObjectValid();
301 if (msDescription.isEmpty())
303 OUString sDescription(createAccessibleDescription());
305 if (msDescription != sDescription)
307 AccessibleEventObject aEvent;
308 aEvent.EventId = AccessibleEventId::DESCRIPTION_CHANGED;
309 aEvent.Source = uno::Reference< XAccessibleContext >(this);
310 aEvent.OldValue <<= msDescription;
311 aEvent.NewValue <<= sDescription;
313 msDescription = sDescription;
315 CommitChange(aEvent);
318 return msDescription;
321 OUString SAL_CALL
322 ScAccessibleContextBase::getAccessibleName()
324 SolarMutexGuard aGuard;
325 IsObjectValid();
326 if (msName.isEmpty())
328 OUString sName(createAccessibleName());
329 OSL_ENSURE(!sName.isEmpty(), "We should give always a name.");
331 if (msName != sName)
333 AccessibleEventObject aEvent;
334 aEvent.EventId = AccessibleEventId::NAME_CHANGED;
335 aEvent.Source = uno::Reference< XAccessibleContext >(this);
336 aEvent.OldValue <<= msName;
337 aEvent.NewValue <<= sName;
339 msName = sName;
341 CommitChange(aEvent);
344 return msName;
347 uno::Reference<XAccessibleRelationSet> SAL_CALL
348 ScAccessibleContextBase::getAccessibleRelationSet()
350 return new utl::AccessibleRelationSetHelper();
353 sal_Int64 SAL_CALL ScAccessibleContextBase::getAccessibleStateSet()
355 return 0;
358 lang::Locale SAL_CALL
359 ScAccessibleContextBase::getLocale()
361 SolarMutexGuard aGuard;
362 IsObjectValid();
363 if (mxParent.is())
365 uno::Reference<XAccessibleContext> xParentContext (
366 mxParent->getAccessibleContext());
367 if (xParentContext.is())
368 return xParentContext->getLocale ();
371 // No locale and no parent. Therefore throw exception to indicate this
372 // cluelessness.
373 throw IllegalAccessibleComponentStateException ();
376 //===== XAccessibleEventBroadcaster =====================================
378 void SAL_CALL
379 ScAccessibleContextBase::addAccessibleEventListener(
380 const uno::Reference<XAccessibleEventListener>& xListener)
382 if (xListener.is())
384 SolarMutexGuard aGuard;
385 IsObjectValid();
386 if (!IsDefunc())
388 if (!mnClientId)
389 mnClientId = comphelper::AccessibleEventNotifier::registerClient( );
390 comphelper::AccessibleEventNotifier::addEventListener( mnClientId, xListener );
395 void SAL_CALL
396 ScAccessibleContextBase::removeAccessibleEventListener(
397 const uno::Reference<XAccessibleEventListener>& xListener)
399 if (!xListener.is())
400 return;
402 SolarMutexGuard aGuard;
403 if (IsDefunc() || !mnClientId)
404 return;
406 sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( mnClientId, xListener );
407 if ( !nListenerCount )
409 // no listeners anymore
410 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
411 // and at least to us not firing any events anymore, in case somebody calls
412 // NotifyAccessibleEvent, again
413 comphelper::AccessibleEventNotifier::revokeClient( mnClientId );
414 mnClientId = 0;
418 // XServiceInfo
419 OUString SAL_CALL ScAccessibleContextBase::getImplementationName()
421 return u"ScAccessibleContextBase"_ustr;
424 sal_Bool SAL_CALL ScAccessibleContextBase::supportsService(const OUString& sServiceName)
426 return cppu::supportsService(this, sServiceName);
429 uno::Sequence< OUString> SAL_CALL
430 ScAccessibleContextBase::getSupportedServiceNames()
432 return {u"com.sun.star.accessibility.Accessible"_ustr,
433 u"com.sun.star.accessibility.AccessibleContext"_ustr};
436 //===== internal ============================================================
438 OUString
439 ScAccessibleContextBase::createAccessibleDescription()
441 OSL_FAIL("should be implemented in the abrevated class");
442 return OUString();
445 OUString ScAccessibleContextBase::createAccessibleName()
447 OSL_FAIL("should be implemented in the abrevated class");
448 return OUString();
451 void ScAccessibleContextBase::CommitChange(const AccessibleEventObject& rEvent) const
453 if (mnClientId)
454 comphelper::AccessibleEventNotifier::addEvent( mnClientId, rEvent );
457 void ScAccessibleContextBase::CommitFocusGained() const
459 AccessibleEventObject aEvent;
460 aEvent.EventId = AccessibleEventId::STATE_CHANGED;
461 aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this));
462 aEvent.NewValue <<= AccessibleStateType::FOCUSED;
464 CommitChange(aEvent);
467 void ScAccessibleContextBase::CommitFocusLost() const
469 AccessibleEventObject aEvent;
470 aEvent.EventId = AccessibleEventId::STATE_CHANGED;
471 aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this));
472 aEvent.OldValue <<= AccessibleStateType::FOCUSED;
474 CommitChange(aEvent);
477 AbsoluteScreenPixelRectangle ScAccessibleContextBase::GetBoundingBoxOnScreen() const
479 OSL_FAIL("not implemented");
480 return AbsoluteScreenPixelRectangle();
483 tools::Rectangle ScAccessibleContextBase::GetBoundingBox() const
485 OSL_FAIL("not implemented");
486 return tools::Rectangle();
489 void ScAccessibleContextBase::IsObjectValid() const
491 if (rBHelper.bDisposed || rBHelper.bInDispose)
492 throw lang::DisposedException();
495 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */