bump product version to 6.4.0.3
[LibreOffice.git] / vcl / source / window / accessibility.cxx
blobb50c610645f43c1e282b1c96dfb0aaa4e10993a2
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 <vcl/layout.hxx>
21 #include <vcl/fixed.hxx>
22 #include <vcl/window.hxx>
23 #include <vcl/menu.hxx>
24 #include <vcl/wrkwin.hxx>
25 #include <vcl/popupmenuwindow.hxx>
27 #include <window.h>
28 #include <brdwin.hxx>
30 #include <com/sun/star/accessibility/XAccessible.hpp>
31 #include <com/sun/star/accessibility/AccessibleRole.hpp>
32 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
33 #include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
35 #include <sal/log.hxx>
37 using namespace ::com::sun::star::uno;
38 using namespace ::com::sun::star::lang;
39 using namespace ::com::sun::star::datatransfer::clipboard;
40 using namespace ::com::sun::star::datatransfer::dnd;
41 using namespace ::com::sun::star;
44 ImplAccessibleInfos::ImplAccessibleInfos()
46 nAccessibleRole = 0xFFFF;
47 pLabeledByWindow = nullptr;
48 pLabelForWindow = nullptr;
49 pMemberOfWindow = nullptr;
52 ImplAccessibleInfos::~ImplAccessibleInfos()
56 namespace vcl {
58 css::uno::Reference< css::accessibility::XAccessible > Window::GetAccessible( bool bCreate )
60 // do not optimize hierarchy for the top level border win (ie, when there is no parent)
61 /* // do not optimize accessible hierarchy at all to better reflect real VCL hierarchy
62 if ( GetParent() && ( GetType() == WindowType::BORDERWINDOW ) && ( GetChildCount() == 1 ) )
63 //if( !ImplIsAccessibleCandidate() )
65 vcl::Window* pChild = GetAccessibleChildWindow( 0 );
66 if ( pChild )
67 return pChild->GetAccessible();
70 if ( !mpWindowImpl )
71 return css::uno::Reference< css::accessibility::XAccessible >();
72 if ( !mpWindowImpl->mxAccessible.is() && bCreate )
73 mpWindowImpl->mxAccessible = CreateAccessible();
75 return mpWindowImpl->mxAccessible;
78 css::uno::Reference< css::accessibility::XAccessible > Window::CreateAccessible()
80 css::uno::Reference< css::accessibility::XAccessible > xAcc( GetComponentInterface(), css::uno::UNO_QUERY );
81 return xAcc;
84 void Window::SetAccessible( const css::uno::Reference< css::accessibility::XAccessible >& x )
86 if (!mpWindowImpl)
87 return;
89 mpWindowImpl->mxAccessible = x;
92 // skip all border windows that are not top level frames
93 bool Window::ImplIsAccessibleCandidate() const
95 if( !mpWindowImpl->mbBorderWin )
96 return true;
97 else
98 // #101741 do not check for WB_CLOSEABLE because undecorated floaters (like menus!) are closeable
99 if( mpWindowImpl->mbFrame && mpWindowImpl->mnStyle & (WB_MOVEABLE | WB_SIZEABLE) )
100 return true;
101 else
102 return false;
105 bool Window::ImplIsAccessibleNativeFrame() const
107 if( mpWindowImpl->mbFrame )
108 // #101741 do not check for WB_CLOSEABLE because undecorated floaters (like menus!) are closeable
109 if( mpWindowImpl->mnStyle & (WB_MOVEABLE | WB_SIZEABLE) )
110 return true;
111 else
112 return false;
113 else
114 return false;
117 vcl::Window* Window::GetAccessibleParentWindow() const
119 if (!mpWindowImpl || ImplIsAccessibleNativeFrame())
120 return nullptr;
122 vcl::Window* pParent = mpWindowImpl->mpParent;
123 if( GetType() == WindowType::MENUBARWINDOW )
125 // report the menubar as a child of THE workwindow
126 vcl::Window *pWorkWin = GetParent()->mpWindowImpl->mpFirstChild;
127 while( pWorkWin && (pWorkWin == this) )
128 pWorkWin = pWorkWin->mpWindowImpl->mpNext;
129 pParent = pWorkWin;
131 // If this is a floating window which has a native border window, then that border should be reported as
132 // the accessible parent, unless the floating window is a PopupMenuFloatingWindow
134 // The logic here has to match that of AccessibleFactory::createAccessibleContext in
135 // accessibility/source/helper/acc_factory.cxx to avoid PopupMenuFloatingWindow
136 // becoming a11y parents of themselves
137 else if( GetType() == WindowType::FLOATINGWINDOW &&
138 mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame &&
139 !PopupMenuFloatingWindow::isPopupMenu(this))
141 pParent = mpWindowImpl->mpBorderWindow;
143 else if( pParent && !pParent->ImplIsAccessibleCandidate() )
145 pParent = pParent->mpWindowImpl->mpParent;
147 return pParent;
150 sal_uInt16 Window::GetAccessibleChildWindowCount()
152 if (!mpWindowImpl)
153 return 0;
155 sal_uInt16 nChildren = 0;
156 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
157 while( pChild )
159 if( pChild->IsVisible() )
160 nChildren++;
161 pChild = pChild->mpWindowImpl->mpNext;
164 // report the menubarwindow as a child of THE workwindow
165 if( GetType() == WindowType::BORDERWINDOW )
167 ImplBorderWindow *pBorderWindow = static_cast<ImplBorderWindow*>(this);
168 if( pBorderWindow->mpMenuBarWindow &&
169 pBorderWindow->mpMenuBarWindow->IsVisible()
171 --nChildren;
173 else if( GetType() == WindowType::WORKWINDOW )
175 WorkWindow *pWorkWindow = static_cast<WorkWindow*>(this);
176 if( pWorkWindow->GetMenuBar() &&
177 pWorkWindow->GetMenuBar()->GetWindow() &&
178 pWorkWindow->GetMenuBar()->GetWindow()->IsVisible()
180 ++nChildren;
183 return nChildren;
186 vcl::Window* Window::GetAccessibleChildWindow( sal_uInt16 n )
188 // report the menubarwindow as the first child of THE workwindow
189 if( GetType() == WindowType::WORKWINDOW && static_cast<WorkWindow *>(this)->GetMenuBar() )
191 if( n == 0 )
193 MenuBar *pMenuBar = static_cast<WorkWindow *>(this)->GetMenuBar();
194 if( pMenuBar->GetWindow() && pMenuBar->GetWindow()->IsVisible() )
195 return pMenuBar->GetWindow();
197 else
198 --n;
201 // transform n to child number including invisible children
202 sal_uInt16 nChildren = n;
203 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
204 while( pChild )
206 if( pChild->IsVisible() )
208 if( ! nChildren )
209 break;
210 nChildren--;
212 pChild = pChild->mpWindowImpl->mpNext;
215 if( GetType() == WindowType::BORDERWINDOW && pChild && pChild->GetType() == WindowType::MENUBARWINDOW )
217 do pChild = pChild->mpWindowImpl->mpNext; while( pChild && ! pChild->IsVisible() );
218 SAL_WARN_IF( !pChild, "vcl", "GetAccessibleChildWindow(): wrong index in border window");
221 if ( pChild && ( pChild->GetType() == WindowType::BORDERWINDOW ) && ( pChild->GetChildCount() == 1 ) )
223 pChild = pChild->GetChild( 0 );
225 return pChild;
228 void Window::SetAccessibleRole( sal_uInt16 nRole )
230 if ( !mpWindowImpl->mpAccessibleInfos )
231 mpWindowImpl->mpAccessibleInfos.reset( new ImplAccessibleInfos );
233 SAL_WARN_IF( mpWindowImpl->mpAccessibleInfos->nAccessibleRole != 0xFFFF, "vcl", "AccessibleRole already set!" );
234 mpWindowImpl->mpAccessibleInfos->nAccessibleRole = nRole;
237 sal_uInt16 Window::getDefaultAccessibleRole() const
239 sal_uInt16 nRole = 0xFFFF;
240 switch ( GetType() )
242 case WindowType::MESSBOX: // MT: Would be nice to have special roles!
243 case WindowType::INFOBOX:
244 case WindowType::WARNINGBOX:
245 case WindowType::ERRORBOX:
246 case WindowType::QUERYBOX: nRole = accessibility::AccessibleRole::ALERT; break;
248 case WindowType::MODELESSDIALOG:
249 case WindowType::MODALDIALOG:
250 case WindowType::TABDIALOG:
251 case WindowType::BUTTONDIALOG:
252 case WindowType::DIALOG: nRole = accessibility::AccessibleRole::DIALOG; break;
254 case WindowType::PUSHBUTTON:
255 case WindowType::OKBUTTON:
256 case WindowType::CANCELBUTTON:
257 case WindowType::HELPBUTTON:
258 case WindowType::IMAGEBUTTON:
259 case WindowType::MOREBUTTON:
260 case WindowType::SPINBUTTON: nRole = accessibility::AccessibleRole::PUSH_BUTTON; break;
261 case WindowType::MENUBUTTON: nRole = accessibility::AccessibleRole::BUTTON_MENU; break;
263 case WindowType::RADIOBUTTON: nRole = accessibility::AccessibleRole::RADIO_BUTTON; break;
264 case WindowType::TRISTATEBOX:
265 case WindowType::CHECKBOX: nRole = accessibility::AccessibleRole::CHECK_BOX; break;
267 case WindowType::MULTILINEEDIT: nRole = accessibility::AccessibleRole::SCROLL_PANE; break;
269 case WindowType::PATTERNFIELD:
270 case WindowType::EDIT: nRole = static_cast<Edit const *>(this)->IsPassword() ? accessibility::AccessibleRole::PASSWORD_TEXT : accessibility::AccessibleRole::TEXT; break;
272 case WindowType::CALCINPUTLINE: nRole = accessibility::AccessibleRole::TEXT; break;
274 case WindowType::PATTERNBOX:
275 case WindowType::NUMERICBOX:
276 case WindowType::METRICBOX:
277 case WindowType::CURRENCYBOX:
278 case WindowType::LONGCURRENCYBOX:
279 case WindowType::COMBOBOX: nRole = accessibility::AccessibleRole::COMBO_BOX; break;
281 case WindowType::LISTBOX:
282 case WindowType::MULTILISTBOX: nRole = accessibility::AccessibleRole::LIST; break;
284 case WindowType::TREELISTBOX: nRole = accessibility::AccessibleRole::TREE; break;
286 case WindowType::FIXEDTEXT: nRole = accessibility::AccessibleRole::LABEL; break;
287 case WindowType::FIXEDLINE:
288 if( !GetText().isEmpty() )
289 nRole = accessibility::AccessibleRole::LABEL;
290 else
291 nRole = accessibility::AccessibleRole::SEPARATOR;
292 break;
294 case WindowType::FIXEDBITMAP:
295 case WindowType::FIXEDIMAGE: nRole = accessibility::AccessibleRole::ICON; break;
296 case WindowType::GROUPBOX: nRole = accessibility::AccessibleRole::GROUP_BOX; break;
297 case WindowType::SCROLLBAR: nRole = accessibility::AccessibleRole::SCROLL_BAR; break;
299 case WindowType::SLIDER:
300 case WindowType::SPLITTER:
301 case WindowType::SPLITWINDOW: nRole = accessibility::AccessibleRole::SPLIT_PANE; break;
303 case WindowType::DATEBOX:
304 case WindowType::TIMEBOX:
305 case WindowType::DATEFIELD:
306 case WindowType::TIMEFIELD: nRole = accessibility::AccessibleRole::DATE_EDITOR; break;
308 case WindowType::NUMERICFIELD:
309 case WindowType::METRICFIELD:
310 case WindowType::CURRENCYFIELD:
311 case WindowType::LONGCURRENCYFIELD:
312 case WindowType::SPINFIELD: nRole = accessibility::AccessibleRole::SPIN_BOX; break;
314 case WindowType::TOOLBOX: nRole = accessibility::AccessibleRole::TOOL_BAR; break;
315 case WindowType::STATUSBAR: nRole = accessibility::AccessibleRole::STATUS_BAR; break;
317 case WindowType::TABPAGE: nRole = accessibility::AccessibleRole::PANEL; break;
318 case WindowType::TABCONTROL: nRole = accessibility::AccessibleRole::PAGE_TAB_LIST; break;
320 case WindowType::DOCKINGWINDOW: nRole = (mpWindowImpl->mbFrame) ? accessibility::AccessibleRole::FRAME :
321 accessibility::AccessibleRole::PANEL; break;
323 case WindowType::FLOATINGWINDOW: nRole = ( mpWindowImpl->mbFrame ||
324 (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame) ||
325 (GetStyle() & WB_OWNERDRAWDECORATION) ) ? accessibility::AccessibleRole::FRAME :
326 accessibility::AccessibleRole::WINDOW; break;
328 case WindowType::WORKWINDOW: nRole = accessibility::AccessibleRole::ROOT_PANE; break;
330 case WindowType::SCROLLBARBOX: nRole = accessibility::AccessibleRole::FILLER; break;
332 case WindowType::HELPTEXTWINDOW: nRole = accessibility::AccessibleRole::TOOL_TIP; break;
334 case WindowType::RULER: nRole = accessibility::AccessibleRole::RULER; break;
336 case WindowType::SCROLLWINDOW: nRole = accessibility::AccessibleRole::SCROLL_PANE; break;
338 case WindowType::WINDOW:
339 case WindowType::CONTROL:
340 case WindowType::BORDERWINDOW:
341 case WindowType::SYSTEMCHILDWINDOW:
342 default:
343 if (ImplIsAccessibleNativeFrame() )
344 nRole = accessibility::AccessibleRole::FRAME;
345 else if( IsScrollable() )
346 nRole = accessibility::AccessibleRole::SCROLL_PANE;
347 else if( this->ImplGetWindow()->IsMenuFloatingWindow() )
348 nRole = accessibility::AccessibleRole::WINDOW; // #106002#, contextmenus are windows (i.e. toplevel)
349 else
350 // #104051# WINDOW seems to be a bad default role, use LAYEREDPANE instead
351 // a WINDOW is interpreted as a top-level window, which is typically not the case
352 //nRole = accessibility::AccessibleRole::WINDOW;
353 nRole = accessibility::AccessibleRole::PANEL;
355 return nRole;
358 sal_uInt16 Window::GetAccessibleRole() const
360 if (!mpWindowImpl)
361 return 0;
363 sal_uInt16 nRole = mpWindowImpl->mpAccessibleInfos ? mpWindowImpl->mpAccessibleInfos->nAccessibleRole : 0xFFFF;
364 if ( nRole == 0xFFFF )
365 nRole = getDefaultAccessibleRole();
366 return nRole;
369 void Window::SetAccessibleName( const OUString& rName )
371 if ( !mpWindowImpl->mpAccessibleInfos )
372 mpWindowImpl->mpAccessibleInfos.reset( new ImplAccessibleInfos );
374 OUString oldName = GetAccessibleName();
376 mpWindowImpl->mpAccessibleInfos->pAccessibleName = rName;
378 CallEventListeners( VclEventId::WindowFrameTitleChanged, &oldName );
381 OUString Window::GetAccessibleName() const
383 if (!mpWindowImpl)
384 return OUString();
386 if (mpWindowImpl->mpAccessibleInfos && mpWindowImpl->mpAccessibleInfos->pAccessibleName)
387 return *mpWindowImpl->mpAccessibleInfos->pAccessibleName;
388 return getDefaultAccessibleName();
391 OUString Window::getDefaultAccessibleName() const
393 OUString aAccessibleName;
394 switch ( GetType() )
396 case WindowType::MULTILINEEDIT:
397 case WindowType::PATTERNFIELD:
398 case WindowType::NUMERICFIELD:
399 case WindowType::METRICFIELD:
400 case WindowType::CURRENCYFIELD:
401 case WindowType::LONGCURRENCYFIELD:
402 case WindowType::CALCINPUTLINE:
403 case WindowType::EDIT:
405 case WindowType::DATEBOX:
406 case WindowType::TIMEBOX:
407 case WindowType::CURRENCYBOX:
408 case WindowType::LONGCURRENCYBOX:
409 case WindowType::DATEFIELD:
410 case WindowType::TIMEFIELD:
411 case WindowType::SPINFIELD:
413 case WindowType::COMBOBOX:
414 case WindowType::LISTBOX:
415 case WindowType::MULTILISTBOX:
416 case WindowType::TREELISTBOX:
417 case WindowType::METRICBOX:
419 vcl::Window *pLabel = GetAccessibleRelationLabeledBy();
420 if ( pLabel && pLabel != this )
421 aAccessibleName = pLabel->GetText();
422 if (aAccessibleName.isEmpty())
423 aAccessibleName = GetQuickHelpText();
425 break;
427 case WindowType::IMAGEBUTTON:
428 case WindowType::PUSHBUTTON:
429 aAccessibleName = GetText();
430 if (aAccessibleName.isEmpty())
432 aAccessibleName = GetQuickHelpText();
433 if (aAccessibleName.isEmpty())
434 aAccessibleName = GetHelpText();
436 break;
438 case WindowType::TOOLBOX:
439 aAccessibleName = GetText();
440 break;
442 case WindowType::MOREBUTTON:
443 aAccessibleName = mpWindowImpl->maText;
444 break;
446 default:
447 aAccessibleName = GetText();
448 break;
451 return GetNonMnemonicString( aAccessibleName );
454 void Window::SetAccessibleDescription( const OUString& rDescription )
456 if ( ! mpWindowImpl->mpAccessibleInfos )
457 mpWindowImpl->mpAccessibleInfos.reset( new ImplAccessibleInfos );
459 SAL_WARN_IF( mpWindowImpl->mpAccessibleInfos->pAccessibleDescription, "vcl", "AccessibleDescription already set!" );
460 mpWindowImpl->mpAccessibleInfos->pAccessibleDescription = rDescription;
463 OUString Window::GetAccessibleDescription() const
465 if (!mpWindowImpl)
466 return OUString();
468 OUString aAccessibleDescription;
469 if ( mpWindowImpl->mpAccessibleInfos && mpWindowImpl->mpAccessibleInfos->pAccessibleDescription )
471 aAccessibleDescription = *mpWindowImpl->mpAccessibleInfos->pAccessibleDescription;
473 else
475 // Special code for help text windows. ZT asks the border window for the
476 // description so we have to forward this request to our inner window.
477 const vcl::Window* pWin = this->ImplGetWindow();
478 if ( pWin->GetType() == WindowType::HELPTEXTWINDOW )
479 aAccessibleDescription = pWin->GetHelpText();
480 else
481 aAccessibleDescription = GetHelpText();
484 return aAccessibleDescription;
487 void Window::SetAccessibleRelationLabeledBy( vcl::Window* pLabeledBy )
489 if ( !mpWindowImpl->mpAccessibleInfos )
490 mpWindowImpl->mpAccessibleInfos.reset( new ImplAccessibleInfos );
491 mpWindowImpl->mpAccessibleInfos->pLabeledByWindow = pLabeledBy;
494 void Window::SetAccessibleRelationLabelFor( vcl::Window* pLabelFor )
496 if ( !mpWindowImpl->mpAccessibleInfos )
497 mpWindowImpl->mpAccessibleInfos.reset( new ImplAccessibleInfos );
498 mpWindowImpl->mpAccessibleInfos->pLabelForWindow = pLabelFor;
501 void Window::SetAccessibleRelationMemberOf( vcl::Window* pMemberOfWin )
503 if ( !mpWindowImpl->mpAccessibleInfos )
504 mpWindowImpl->mpAccessibleInfos.reset( new ImplAccessibleInfos );
505 mpWindowImpl->mpAccessibleInfos->pMemberOfWindow = pMemberOfWin;
508 vcl::Window* Window::GetAccessibleRelationMemberOf() const
510 if (mpWindowImpl->mpAccessibleInfos && mpWindowImpl->mpAccessibleInfos->pMemberOfWindow)
511 return mpWindowImpl->mpAccessibleInfos->pMemberOfWindow;
513 if (!isContainerWindow(this) && !isContainerWindow(GetParent()))
514 return getLegacyNonLayoutAccessibleRelationMemberOf();
516 return nullptr;
519 vcl::Window* Window::getAccessibleRelationLabelFor() const
521 if (mpWindowImpl->mpAccessibleInfos && mpWindowImpl->mpAccessibleInfos->pLabelForWindow)
522 return mpWindowImpl->mpAccessibleInfos->pLabelForWindow;
524 return nullptr;
527 vcl::Window* Window::GetAccessibleRelationLabelFor() const
529 vcl::Window* pWindow = getAccessibleRelationLabelFor();
531 if (pWindow)
532 return pWindow;
534 if (!isContainerWindow(this) && !isContainerWindow(GetParent()))
535 return getLegacyNonLayoutAccessibleRelationLabelFor();
537 return nullptr;
540 vcl::Window* Window::GetAccessibleRelationLabeledBy() const
542 if (mpWindowImpl->mpAccessibleInfos && mpWindowImpl->mpAccessibleInfos->pLabeledByWindow)
543 return mpWindowImpl->mpAccessibleInfos->pLabeledByWindow;
545 std::vector<VclPtr<FixedText> > aMnemonicLabels(list_mnemonic_labels());
546 if (!aMnemonicLabels.empty())
548 //if we have multiple labels, then prefer the first that is visible
549 for (auto const & rCandidate : aMnemonicLabels)
551 if (rCandidate->IsVisible())
552 return rCandidate;
554 return aMnemonicLabels[0];
557 if (!isContainerWindow(this) && !isContainerWindow(GetParent()))
558 return getLegacyNonLayoutAccessibleRelationLabeledBy();
560 return nullptr;
563 bool Window::IsAccessibilityEventsSuppressed( bool bTraverseParentPath )
565 if( !bTraverseParentPath )
566 return mpWindowImpl->mbSuppressAccessibilityEvents;
567 else
569 vcl::Window *pParent = this;
570 while ( pParent && pParent->mpWindowImpl)
572 if( pParent->mpWindowImpl->mbSuppressAccessibilityEvents )
573 return true;
574 else
575 pParent = pParent->mpWindowImpl->mpParent; // do not use GetParent() to find borderwindows that are frames
577 return false;
581 void Window::SetAccessibilityEventsSuppressed(bool bSuppressed)
583 mpWindowImpl->mbSuppressAccessibilityEvents = bSuppressed;
586 } /* namespace vcl */
588 uno::Reference<accessibility::XAccessibleEditableText>
589 FindFocusedEditableText(uno::Reference<accessibility::XAccessibleContext> const& xContext)
591 if (!xContext.is())
592 return uno::Reference<accessibility::XAccessibleEditableText>();
594 uno::Reference<accessibility::XAccessibleStateSet> xState = xContext->getAccessibleStateSet();
595 if (xState.is())
597 if (xState->contains(accessibility::AccessibleStateType::FOCUSED))
599 uno::Reference<accessibility::XAccessibleEditableText> xText(xContext, uno::UNO_QUERY);
600 if (xText.is())
601 return xText;
602 if (xState->contains(accessibility::AccessibleStateType::MANAGES_DESCENDANTS))
603 return uno::Reference<accessibility::XAccessibleEditableText>();
607 bool bSafeToIterate = true;
608 sal_Int32 nCount = xContext->getAccessibleChildCount();
609 if (nCount < 0 || nCount > SAL_MAX_UINT16 /* slow enough for anyone */)
610 bSafeToIterate = false;
611 if (!bSafeToIterate)
612 return uno::Reference<accessibility::XAccessibleEditableText>();
614 for (sal_Int32 i = 0; i < xContext->getAccessibleChildCount(); ++i)
616 uno::Reference<accessibility::XAccessible> xChild = xContext->getAccessibleChild(i);
617 if (!xChild.is())
618 continue;
619 uno::Reference<accessibility::XAccessibleContext> xChildContext
620 = xChild->getAccessibleContext();
621 if (!xChildContext.is())
622 continue;
623 uno::Reference<accessibility::XAccessibleEditableText> xText
624 = FindFocusedEditableText(xChildContext);
625 if (xText.is())
626 return xText;
628 return uno::Reference<accessibility::XAccessibleEditableText>();
631 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */