Bump version to 6.4-15
[LibreOffice.git] / starmath / source / AccessibleSmElementsControl.cxx
blob3e9c2d84e792a6c1050d7eead57be04b9d27f068
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 <AccessibleSmElementsControl.hxx>
21 #include <AccessibleSmElement.hxx>
22 #include <ElementsDockingWindow.hxx>
23 #include <smmod.hxx>
25 #include <comphelper/accessiblewrapper.hxx>
26 #include <comphelper/processfactory.hxx>
27 #include <comphelper/types.hxx>
28 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
29 #include <com/sun/star/accessibility/AccessibleRole.hpp>
30 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
31 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
32 #include <cppuhelper/supportsservice.hxx>
33 #include <cppuhelper/typeprovider.hxx>
34 #include <toolkit/helper/convert.hxx>
35 #include <unotools/accessiblerelationsethelper.hxx>
36 #include <unotools/accessiblestatesethelper.hxx>
37 #include <vcl/svapp.hxx>
38 #include <vcl/vclevent.hxx>
40 using namespace ::com::sun::star;
41 using namespace ::com::sun::star::accessibility;
42 using OContextEntryGuard = ::comphelper::OContextEntryGuard;
43 using OExternalLockGuard = ::comphelper::OExternalLockGuard;
45 // AccessibleSmElementsControl
47 AccessibleSmElementsControl::AccessibleSmElementsControl(SmElementsControl& rControl)
48 : m_pControl(&rControl)
52 AccessibleSmElementsControl::~AccessibleSmElementsControl() {}
54 void AccessibleSmElementsControl::UpdateFocus(sal_uInt16 nPos)
56 const bool bSetFocus = (nPos == SAL_MAX_UINT16);
58 // submit events only if the widget has the focus to avoid sending events due to mouse move
59 if (!m_pControl || (bSetFocus && !m_pControl->HasFocus()))
60 return;
62 if (bSetFocus)
63 nPos = m_pControl->itemHighlighted() - m_pControl->itemOffset();
65 if (nPos < m_aAccessibleChildren.size())
67 const auto& rxChild = m_aAccessibleChildren[nPos];
68 if (rxChild.is())
69 rxChild->SetFocus(bSetFocus);
73 void AccessibleSmElementsControl::ReleaseAllItems()
75 if (m_aAccessibleChildren.empty())
76 return;
78 m_aAccessibleChildren.clear();
80 // The original toolbox accessibility code uses individual NAME_CHANGED
81 // events in a loop. We can't do this, because on each remove event the
82 // list of known children is rebuild. But since we rely on the child
83 // count of the SmElementsControl, we'll always have no or all items.
84 // In the latter case this would automatically recreate all items!
85 assert(m_pControl && m_pControl->itemCount() == 0);
86 NotifyAccessibleEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN, uno::Any(), uno::Any());
89 void AccessibleSmElementsControl::AddAllItems()
91 assert(m_pControl);
92 if (!m_pControl)
93 return;
95 uno::Any aNewName(getAccessibleName());
96 NotifyAccessibleEvent(AccessibleEventId::NAME_CHANGED, uno::Any(), aNewName);
98 // register the new items
99 sal_uInt16 nCount = getAccessibleChildCount();
100 for (sal_uInt16 i = 0; i < nCount; ++i)
102 uno::Any aNewValue;
103 aNewValue <<= getAccessibleChild(static_cast<sal_Int32>(i));
104 NotifyAccessibleEvent(AccessibleEventId::CHILD, uno::Any(), aNewValue);
108 IMPLEMENT_FORWARD_XINTERFACE2(AccessibleSmElementsControl, comphelper::OAccessibleComponentHelper,
109 AccessibleSmElementsControl_BASE)
111 IMPLEMENT_FORWARD_XTYPEPROVIDER2(AccessibleSmElementsControl,
112 comphelper::OAccessibleComponentHelper,
113 AccessibleSmElementsControl_BASE)
115 // XAccessible
116 uno::Reference<XAccessibleContext> AccessibleSmElementsControl::getAccessibleContext()
118 return this;
121 // XComponent
122 void AccessibleSmElementsControl::disposing()
124 comphelper::OAccessibleComponentHelper::disposing();
125 m_aAccessibleChildren.clear();
128 void AccessibleSmElementsControl::grabFocus()
130 SolarMutexGuard aGuard;
131 if (!m_pControl)
132 throw uno::RuntimeException();
134 m_pControl->GrabFocus();
137 sal_Int32 AccessibleSmElementsControl::getForeground()
139 SolarMutexGuard aGuard;
141 if (!m_pControl)
142 throw uno::RuntimeException();
143 return static_cast<sal_Int32>(m_pControl->GetTextColor());
146 sal_Int32 AccessibleSmElementsControl::getBackground()
148 SolarMutexGuard aGuard;
150 if (!m_pControl)
151 throw uno::RuntimeException();
152 Color nCol = m_pControl->GetControlBackground();
153 return static_cast<sal_Int32>(nCol);
156 // XServiceInfo
157 OUString AccessibleSmElementsControl::getImplementationName()
159 return "com.sun.star.comp.toolkit.AccessibleSmElementsControl";
162 sal_Bool AccessibleSmElementsControl::supportsService(const OUString& rServiceName)
164 return cppu::supportsService(this, rServiceName);
167 uno::Sequence<OUString> AccessibleSmElementsControl::getSupportedServiceNames()
169 return { "com.sun.star.accessibility.AccessibleContext",
170 "com.sun.star.accessibility.AccessibleComponent",
171 "com.sun.star.accessibility.AccessibleSelection",
172 "com.sun.star.accessibility.AccessibleSmElementsControl" };
175 // XAccessibleContext
176 sal_Int32 AccessibleSmElementsControl::getAccessibleChildCount()
178 comphelper::OExternalLockGuard aGuard(this);
179 sal_Int32 nCount = 0;
180 if (m_pControl)
182 nCount = m_pControl->itemCount();
183 if (m_aAccessibleChildren.size() != sal_uInt16(nCount))
184 m_aAccessibleChildren.resize(nCount);
185 if (m_pControl->scrollbarAccessible().is())
186 nCount++;
188 return nCount;
191 uno::Reference<XAccessible> AccessibleSmElementsControl::getAccessibleChild(sal_Int32 i)
193 comphelper::OExternalLockGuard aGuard(this);
195 if (i < 0 || i >= getAccessibleChildCount())
196 throw lang::IndexOutOfBoundsException();
198 // first child may be the scrollbar
199 sal_uInt16 c(i);
200 uno::Reference<XAccessible> xScrollbar = m_pControl->scrollbarAccessible();
201 if (xScrollbar.is())
203 if (c == 0)
204 return xScrollbar;
205 c--;
208 assert(c < m_aAccessibleChildren.size());
209 rtl::Reference<AccessibleSmElement> xChild = m_aAccessibleChildren[c];
210 const sal_uInt16 nItemId = m_pControl->itemOffset() + c;
211 if (xChild.is() && xChild->itemId() != nItemId)
212 xChild.clear();
213 if (!xChild.is())
215 sal_uInt16 nHighlightItemId = m_pControl->itemHighlighted();
216 AccessibleSmElement* pChild = new AccessibleSmElement(m_pControl, nItemId, i);
217 if (pChild->itemId() == nHighlightItemId)
218 pChild->SetFocus(true);
219 m_aAccessibleChildren[c] = pChild;
220 xChild = pChild;
222 return xChild.get();
225 uno::Reference<XAccessible> AccessibleSmElementsControl::getAccessibleParent()
227 SolarMutexGuard aGuard;
228 if (!m_pControl)
229 throw uno::RuntimeException();
231 vcl::Window* pAccParent = m_pControl->GetAccessibleParentWindow();
232 assert(pAccParent);
233 return pAccParent ? pAccParent->GetAccessible() : uno::Reference<XAccessible>();
236 uno::Reference<XAccessible>
237 AccessibleSmElementsControl::getAccessibleAtPoint(const awt::Point& rPoint)
239 comphelper::OExternalLockGuard aGuard(this);
241 uno::Reference<XAccessible> xAccessible;
242 if (m_pControl)
244 sal_uInt16 nPos = m_pControl->itemAtPos(VCLPoint(rPoint));
245 nPos -= m_pControl->itemOffset();
246 if (nPos <= m_aAccessibleChildren.size())
247 xAccessible = getAccessibleChild(nPos);
249 return xAccessible;
252 sal_Int16 AccessibleSmElementsControl::getAccessibleRole() { return AccessibleRole::SCROLL_PANE; }
254 OUString AccessibleSmElementsControl::getAccessibleDescription() { return OUString(); }
256 OUString AccessibleSmElementsControl::getAccessibleName()
258 SolarMutexGuard aGuard;
259 OUString aName;
260 if (m_pControl)
261 aName = SmResId(m_pControl->elementSetId().getStr());
262 return aName;
265 // XAccessibleSelection
266 void AccessibleSmElementsControl::selectAccessibleChild(sal_Int32 nChildIndex)
268 OExternalLockGuard aGuard(this);
270 if ((!m_pControl) || nChildIndex < 0
271 || static_cast<size_t>(nChildIndex) >= m_aAccessibleChildren.size())
272 throw lang::IndexOutOfBoundsException();
274 m_pControl->setItemHighlighted(nChildIndex);
277 sal_Bool AccessibleSmElementsControl::isAccessibleChildSelected(sal_Int32 nChildIndex)
279 OExternalLockGuard aGuard(this);
280 if ((!m_pControl) || nChildIndex < 0
281 || static_cast<size_t>(nChildIndex) >= m_aAccessibleChildren.size())
282 throw lang::IndexOutOfBoundsException();
284 return (m_pControl->itemHighlighted() == nChildIndex);
287 void AccessibleSmElementsControl::clearAccessibleSelection()
289 OExternalLockGuard aGuard(this);
290 if (m_pControl)
291 m_pControl->setItemHighlighted(SAL_MAX_UINT16);
294 void AccessibleSmElementsControl::selectAllAccessibleChildren()
296 // intentionally empty
299 sal_Int32 AccessibleSmElementsControl::getSelectedAccessibleChildCount()
301 OExternalLockGuard aGuard(this);
303 sal_Int32 nRet = 0;
304 if (m_pControl
305 && (m_pControl->itemHighlighted() - m_pControl->itemOffset()) < getAccessibleChildCount())
306 nRet = 1;
307 return nRet;
310 uno::Reference<XAccessible>
311 AccessibleSmElementsControl::getSelectedAccessibleChild(sal_Int32 nSelectedChildIndex)
313 OExternalLockGuard aGuard(this);
314 if (nSelectedChildIndex != 0 || !m_pControl)
315 throw lang::IndexOutOfBoundsException();
316 return getAccessibleChild(m_pControl->itemHighlighted() - m_pControl->itemOffset());
319 void AccessibleSmElementsControl::deselectAccessibleChild(sal_Int32 nChildIndex)
321 OExternalLockGuard aGuard(this);
322 if (nChildIndex != 0 || nChildIndex >= getAccessibleChildCount())
323 throw lang::IndexOutOfBoundsException();
324 clearAccessibleSelection(); // there can be just one selected child
327 // XAccessibleComponent
328 static awt::Point lcl_GetLocationOnScreen(vcl::Window const* m_pControl)
330 awt::Point aPos;
331 if (m_pControl)
333 tools::Rectangle aRect = m_pControl->GetWindowExtentsRelative(nullptr);
334 aPos.X = aRect.Left();
335 aPos.Y = aRect.Top();
337 return aPos;
340 static awt::Rectangle lcl_GetBounds(vcl::Window const* m_pControl)
342 // !! see VCLXAccessibleComponent::implGetBounds()
344 //! the coordinates returned are relative to the parent window !
345 //! Thus the top-left point may be different from (0, 0) !
347 awt::Rectangle aBounds;
348 if (m_pControl)
350 tools::Rectangle aRect = m_pControl->GetWindowExtentsRelative(nullptr);
351 aBounds.X = aRect.Left();
352 aBounds.Y = aRect.Top();
353 aBounds.Width = aRect.GetWidth();
354 aBounds.Height = aRect.GetHeight();
356 vcl::Window* pParent = m_pControl->GetAccessibleParentWindow();
357 if (pParent)
359 tools::Rectangle aParentRect = pParent->GetWindowExtentsRelative(nullptr);
360 awt::Point aParentScreenLoc(aParentRect.Left(), aParentRect.Top());
361 aBounds.X -= aParentScreenLoc.X;
362 aBounds.Y -= aParentScreenLoc.Y;
365 return aBounds;
368 void AccessibleSmElementsControl::TestControl()
370 if (!m_pControl)
371 throw uno::RuntimeException();
372 assert(m_pControl->GetParent()->GetAccessible() == getAccessibleParent());
375 awt::Rectangle AccessibleSmElementsControl::implGetBounds()
377 SolarMutexGuard aGuard;
378 TestControl();
379 return lcl_GetBounds(m_pControl);
382 awt::Rectangle AccessibleSmElementsControl::getBounds() { return implGetBounds(); }
384 sal_Bool AccessibleSmElementsControl::containsPoint(const awt::Point& aPoint)
386 SolarMutexGuard aGuard;
387 TestControl();
388 Size aSz(m_pControl->GetSizePixel());
389 return aPoint.X >= 0 && aPoint.Y >= 0 && aPoint.X < aSz.Width() && aPoint.Y < aSz.Height();
392 awt::Point AccessibleSmElementsControl::getLocation()
394 SolarMutexGuard aGuard;
395 TestControl();
396 awt::Rectangle aRect(lcl_GetBounds(m_pControl));
397 return awt::Point(aRect.X, aRect.Y);
400 awt::Point AccessibleSmElementsControl::getLocationOnScreen()
402 SolarMutexGuard aGuard;
403 TestControl();
404 return lcl_GetLocationOnScreen(m_pControl);
407 awt::Size AccessibleSmElementsControl::getSize()
409 SolarMutexGuard aGuard;
410 TestControl();
412 Size aSz(m_pControl->GetSizePixel());
413 #if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
414 awt::Rectangle aRect(lcl_GetBounds(m_pControl));
415 Size aSz2(aRect.Width, aRect.Height);
416 assert(aSz == aSz2 && "mismatch in width");
417 #endif
418 return awt::Size(aSz.Width(), aSz.Height());
421 uno::Reference<XAccessibleRelationSet> AccessibleSmElementsControl::getAccessibleRelationSet()
423 uno::Reference<XAccessibleRelationSet> xRelSet = new utl::AccessibleRelationSetHelper();
424 return xRelSet; // empty relation set
427 uno::Reference<XAccessibleStateSet> AccessibleSmElementsControl::getAccessibleStateSet()
429 SolarMutexGuard aGuard;
430 ::utl::AccessibleStateSetHelper* pStateSet = new ::utl::AccessibleStateSetHelper;
432 uno::Reference<XAccessibleStateSet> xStateSet(pStateSet);
434 if (!m_pControl)
435 pStateSet->AddState(AccessibleStateType::DEFUNC);
436 else
438 pStateSet->AddState(AccessibleStateType::ENABLED);
439 pStateSet->AddState(AccessibleStateType::FOCUSABLE);
440 if (m_pControl->HasFocus())
441 pStateSet->AddState(AccessibleStateType::FOCUSED);
442 if (m_pControl->IsActive())
443 pStateSet->AddState(AccessibleStateType::ACTIVE);
444 if (m_pControl->IsVisible())
445 pStateSet->AddState(AccessibleStateType::SHOWING);
446 if (m_pControl->IsReallyVisible())
447 pStateSet->AddState(AccessibleStateType::VISIBLE);
448 if (COL_TRANSPARENT != m_pControl->GetBackground().GetColor())
449 pStateSet->AddState(AccessibleStateType::OPAQUE);
452 return xStateSet;
455 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */