/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
void test::AccessibleTestBase::load(const rtl::OUString& sURL)
{ // make sure there is no open document in case it is called more than once
close();
mxDocument
= mxDesktop->loadComponentFromURL(sURL, u"_blank"_ustr, frame::FrameSearchFlag::AUTO, {});
/* Care has to be taken not to walk sideways as the relation is also used
* with children of nested containers (possibly as the "natural"/"perceived" flow?). */
std::deque<uno::Reference<accessibility::XAccessibleContext>>
test::AccessibleTestBase::getAllChildren( const uno::Reference<accessibility::XAccessibleContext>& xContext)
{ /* first, get all "natural" children */
std::deque<uno::Reference<accessibility::XAccessibleContext>> children; auto childCount = xContext->getAccessibleChildCount();
for (sal_Int64 i = 0; i < childCount && i < AccessibilityTools::MAX_CHILDREN; i++)
{ auto child = xContext->getAccessibleChild(i);
children.push_back(child->getAccessibleContext());
}
if (!children.size()) return children;
/* then, try and find flowing siblings at the same levels that are not included in the list */ /* first, backwards: */ auto child = getPreviousFlowingSibling(children.front()); while (child.is() && children.size() < AccessibilityTools::MAX_CHILDREN)
{ auto childParent = child->getAccessibleParent(); if (childParent.is()
&& AccessibilityTools::equals(xContext, childParent->getAccessibleContext()))
children.push_front(child);
child = getPreviousFlowingSibling(child);
} /* then forward */
child = getNextFlowingSibling(children.back()); while (child.is() && children.size() < AccessibilityTools::MAX_CHILDREN)
{ auto childParent = child->getAccessibleParent(); if (childParent.is()
&& AccessibilityTools::equals(xContext, childParent->getAccessibleContext()))
children.push_back(child);
child = getNextFlowingSibling(child);
}
buffer.append('<');
buffer.append(roleName); for (auto& attr : attrs)
{ if (attr.value.getLength() == 0) continue;
buffer.append(' ');
buffer.append(attr.name);
buffer.append(u"=\"" + attr.value.replaceAll(u"\"", u""") + "\"");
}
buffer.append('>');
} auto openTagLength = buffer.getLength();
uno::Reference<accessibility::XAccessibleText> xText(xContext, uno::UNO_QUERY); if (xText.is())
buffer.append(xText->getText());
for (auto& childContext : getAllChildren(xContext))
collectText(childContext, buffer);
if (!onlyChildren)
{ if (buffer.getLength() != openTagLength)
buffer.append("" + roleName + ">"); else
{ /* there was no content, so make is a short tag for more concise output */
buffer[openTagLength - 1] = '/';
buffer.append('>');
}
}
}
if (relset.is())
{ for (sal_Int32 i = 0; i < relset->getRelationCount(); ++i)
{ constauto rel = relset->getRelation(i); if (rel.RelationType == relationType)
{ for (const uno::Reference<accessibility::XAccessible>& targetAccessible :
rel.TargetSet)
{ if (targetAccessible.is()) return targetAccessible->getAccessibleContext();
}
}
}
}
return nullptr;
}
/** Prints the tree of accessible objects starting at @p xContext to stdout */ void test::AccessibleTestBase::dumpA11YTree( const uno::Reference<accessibility::XAccessibleContext>& xContext, constint depth)
{
Scheduler::ProcessEventsToIdle(); auto xRelSet = xContext->getAccessibleRelationSet();
std::cout << AccessibilityTools::debugString(xContext); /* relation set is not included in AccessibilityTools::debugString(), but might be useful in
* this context, so we compute it here */ if (xRelSet.is())
{ auto relCount = xRelSet->getRelationCount(); if (relCount)
{
std::cout << " rels=["; for (sal_Int32 i = 0; i < relCount; ++i)
{ if (i > 0)
std::cout << ", ";
/** Gets a child by name (usually in a menu) */
uno::Reference<accessibility::XAccessibleContext> test::AccessibleTestBase::getItemFromName( const uno::Reference<accessibility::XAccessibleContext>& xMenuCtx, std::u16string_view name)
{ auto childCount = xMenuCtx->getAccessibleChildCount();
std::cout << "looking up item " << OUString(name) << " in "
<< AccessibilityTools::debugString(xMenuCtx) << std::endl; for (sal_Int64 i = 0; i < childCount && i < AccessibilityTools::MAX_CHILDREN; i++)
{ auto item = xMenuCtx->getAccessibleChild(i)->getAccessibleContext(); if (AccessibilityTools::nameEquals(item, name))
{
std::cout << "-> found " << AccessibilityTools::debugString(item) << std::endl; return item;
}
}
bool test::AccessibleTestBase::activateMenuItem( const uno::Reference<accessibility::XAccessibleAction>& xAction)
{ // assume first action is the right one, there's not description anyway
CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xAction->getAccessibleActionCount()); if (xAction->doAccessibleAction(0))
{
Scheduler::ProcessEventsToIdle(); returntrue;
} returnfalse;
}
#if !defined(MACOSX) /* Dialog handling * * For now this doesn't actually work under macos, so the API is not available there not to create * confusion. The problem there is we don't get notified of new dialogs, so we can't manage them * or interact with them.
*/
std::shared_ptr<test::AccessibleTestBase::DialogWaiter>
test::AccessibleTestBase::awaitDialog(const std::u16string_view name,
std::function<void(Dialog&)> callback, bool bAutoClose)
{ /* Helper class to wait on a dialog to pop up and to close, running user code between the * two. This has to work both for "other window"-style dialogues (non-modal), as well as * for modal dialogues using Dialog::Execute() (which runs a nested main loop, hence * blocking our test flow execution. * The approach here is to wait on the WindowActivate event for the dialog, and run the * test code in there. Then, close the dialog if not already done, resuming normal flow to
* the caller. */ class ListenerHelper : public DialogWaiter
{
DialogCancelMode miPreviousDialogCancelMode;
uno::Reference<awt::XExtendedToolkit> mxToolkit; bool mbWaitingForDialog;
std::exception_ptr mpException;
std::u16string_view msName;
std::function<void(Dialog&)> mCallback; bool mbAutoClose;
Timer maTimeoutTimer;
Idle maIdleHandler;
uno::Reference<awt::XTopWindowListener> mxTopWindowListener;
std::unique_ptr<Dialog> mxDialog;
void timeoutTimerHandler(Timer*)
{
std::cerr << "timeout waiting for dialog '" << OUString(msName) << "' to show up"
<< std::endl;
assert(mbWaitingForDialog);
// This is not very nice, but it should help fail earlier if we never catch the dialog // yet we're in a sub-loop and waitEndDialog() didn't have a chance to run yet. thrownew css::uno::RuntimeException(u"Timeout waiting for dialog"_ustr);
}
class MyTopWindowListener : public ::cppu::WeakImplHelper<awt::XTopWindowListener>
{ private:
ListenerHelper* mpHelper;
/* The popping up dialog ought to be the right one, or something's fishy and * we're bound to failure (e.g. waiting on a dialog that either will never come, or
* that will not run after the current one -- deadlock style) */ if (msName != mxDialog->getWindow()->GetText())
{
mpException = std::make_exception_ptr(css::uno::RuntimeException( "Unexpected dialog '" + mxDialog->getWindow()->GetText()
+ "' opened instead of the expected '" + msName + "'"));
} else
{
std::cout << "found dialog, calling user callback" << std::endl;
// set the real requested auto close now we're just calling the user callback
mxDialog->setAutoClose(mbAutoClose);
public: virtualbool waitEndDialog(sal_uInt64 nTimeoutMs) override
{ /* Usually this loop will actually never run at all because a previous * Scheduler::ProcessEventsToIdle() would have triggered the dialog already, but we
* can't be sure of that or of delays, so be safe and wait with a timeout. */ if (mbWaitingForDialog)
{
Timer aTimer("wait for dialog");
aTimer.SetTimeout(nTimeoutMs);
aTimer.Start(); do
{
Application::Yield();
} while (mbWaitingForDialog && aTimer.IsActive());
}
if (mpException)
std::rethrow_exception(mpException);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.