summaryrefslogtreecommitdiffstats
path: root/old/libqtslave/qtestslave.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'old/libqtslave/qtestslave.cpp')
-rw-r--r--old/libqtslave/qtestslave.cpp1797
1 files changed, 1797 insertions, 0 deletions
diff --git a/old/libqtslave/qtestslave.cpp b/old/libqtslave/qtestslave.cpp
new file mode 100644
index 0000000..a4ac20a
--- /dev/null
+++ b/old/libqtslave/qtestslave.cpp
@@ -0,0 +1,1797 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of QtUiTest.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qtestslave.h>
+#include <qtestslaveglobal.h>
+#include <qtestwidgets.h>
+#include <qtuitestnamespace.h>
+#include <qtuitestrecorder.h>
+
+#include <QWidget>
+#include <QPixmap>
+#include <QApplication>
+#include <QDir>
+#include <QVariant>
+#include <QMetaProperty>
+#include <QMetaObject>
+#include <QMetaType>
+#include <QPoint>
+#include <QProcess>
+#include <QSettings>
+#include <QLocale>
+#include <QDebug>
+#include <QPainter>
+#include <QSound>
+
+#ifndef QT_NO_CLIPBOARD
+# include <QClipboard>
+#endif
+
+#define qLog(A) if(1); else qDebug() << #A
+
+#ifdef Q_OS_UNIX
+# include <sys/time.h>
+#endif
+
+#include <qalternatestack_p.h>
+
+using namespace QtUiTest;
+
+template <typename T>
+T* findTestWidget(QTestMessage const& message)
+{
+ using namespace QtUiTest;
+ T* ret = 0;
+ QTestMessage reply;
+ QString error;
+ QString qp = message["queryPath"].toString();
+ QObject *o;
+ if (!QActiveTestWidget::instance()->findWidget( qp, o, error)) {
+ setErrorString(error);
+ return ret;
+ }
+
+ ret = qtuitest_cast<T*>(o);
+ if (!ret) {
+ setErrorString(QString("Error: %1 is not of type %2").arg(qp).arg(static_cast<T*>(0)->_q_interfaceName()));
+ } else {
+ setErrorString(QString());
+ }
+
+ return ret;
+}
+
+/* Handler for test messages */
+class QTestSlavePrivate : public QObject
+{
+Q_OBJECT
+public:
+ QTestSlavePrivate(QTestSlave *parent)
+ : eventRecordingEnabled(false),
+ p(parent),
+ recorder(this),
+ targetId(QLatin1String("default"))
+ {
+ // Play a sound as a audible confirmation that an app is started with QtUITest plugin loaded
+ QString fname = QDir::homePath() + QDir::separator() + "qtuitest.wav";
+ if (QFile::exists(fname)) QSound::play(fname);
+ }
+
+ bool event(QEvent *e);
+ bool waitForIdle(int timeout = 10000);
+ QString recursiveDelete(QString const&) const;
+ void startWaitForIdle(int);
+ static void processMessage(QAlternateStack*,QVariant const&);
+ QPoint mousePointForMessage(QTestMessage const&,QTestMessage&,bool&);
+
+ bool eventRecordingEnabled;
+ QTestSlave *p;
+ QTime lastFocusWarn;
+ QtUiTestRecorder recorder;
+ QVariant targetId;
+
+public slots:
+ void record_entered(QObject*, QVariant const&);
+ void record_selected(QObject*, QString const&);
+ void record_activated(QObject*);
+ void record_stateChanged(QObject*, int);
+ void record_gotFocus(QObject*);
+
+ QTestMessage widget (QTestMessage const&);
+
+ QTestMessage currentTitle (QTestMessage const&);
+ QTestMessage getWindowTitles (QTestMessage const&);
+ QTestMessage activateWindow (QTestMessage const&);
+ QTestMessage appName (QTestMessage const&);
+ QTestMessage isVisible (QTestMessage const&);
+
+ QTestMessage startEventRecording(QTestMessage const&);
+ QTestMessage stopEventRecording (QTestMessage const&);
+
+ QTestMessage activeWindow (QTestMessage const&);
+ QTestMessage focusWidget (QTestMessage const&);
+ QTestMessage hasFocus (QTestMessage const&);
+
+ QTestMessage grabPixmap (QTestMessage const&);
+ QTestMessage getSelectedText (QTestMessage const&);
+ QTestMessage getText (QTestMessage const&);
+ QTestMessage getSelectedValue (QTestMessage const&);
+ QTestMessage getValue (QTestMessage const&);
+ QTestMessage getCenter (QTestMessage const&);
+ QTestMessage getList (QTestMessage const&);
+ QTestMessage getLabels (QTestMessage const&);
+
+ QTestMessage isChecked (QTestMessage const&);
+ QTestMessage setChecked (QTestMessage const&);
+ QTestMessage checkState (QTestMessage const&);
+ QTestMessage setCheckState (QTestMessage const&);
+
+ QTestMessage enter (QTestMessage const&);
+ QTestMessage select (QTestMessage const&);
+ QTestMessage selectIndex (QTestMessage const&);
+ QTestMessage getSelectedIndex (QTestMessage const&);
+ QTestMessage activate (QTestMessage const&);
+ QTestMessage ensureVisible (QTestMessage const&);
+
+ QTestMessage activeWidgetInfo (QTestMessage const&);
+
+ QTestMessage invokeMethod (QTestMessage const&);
+ QTestMessage setProperty (QTestMessage const&);
+ QTestMessage getProperty (QTestMessage const&);
+ QTestMessage findByProperty (QTestMessage const&);
+ QTestMessage findByProperties (QTestMessage const&);
+
+ QTestMessage getSetting (QTestMessage const&);
+ QTestMessage setSetting (QTestMessage const&);
+
+ QTestMessage getClipboardText (QTestMessage const&);
+ QTestMessage setClipboardText (QTestMessage const&);
+
+ QTestMessage mousePreferred (QTestMessage const&);
+ QTestMessage setMousePreferred (QTestMessage const&);
+ QTestMessage labelOrientation (QTestMessage const&);
+ QTestMessage setLabelOrientation(QTestMessage const&);
+
+ QTestMessage putFile (QTestMessage const&);
+ QTestMessage getFile (QTestMessage const&);
+ QTestMessage deletePath (QTestMessage const&);
+ QTestMessage getDirectoryEntries(QTestMessage const&);
+
+ QTestMessage getImageSize (QTestMessage const&);
+ QTestMessage getGeometry (QTestMessage const&);
+ QTestMessage setSystemTime (QTestMessage const&);
+ QTestMessage systemTime (QTestMessage const&);
+
+ QTestMessage waitForIdle (QTestMessage const&);
+
+ QTestMessage keyPress (QTestMessage const&);
+ QTestMessage keyRelease (QTestMessage const&);
+ QTestMessage keyClick (QTestMessage const&);
+
+ QTestMessage mousePress (QTestMessage const&);
+ QTestMessage mouseRelease (QTestMessage const&);
+ QTestMessage mouseClick (QTestMessage const&);
+
+ QTestMessage translate (QTestMessage const&);
+ QTestMessage getLocale (QTestMessage const&);
+ QTestMessage getenv (QTestMessage const&);
+ QTestMessage checkOS (QTestMessage const&);
+ QTestMessage targetIdentifier (QTestMessage const&);
+ QTestMessage setTargetIdentifier(QTestMessage const&);
+
+ void sendBecameIdleMessage();
+
+signals:
+ void applicationBecameIdle();
+};
+
+class IdleEvent : public QEvent
+{
+public:
+ enum EventType { Type = QEvent::User + 10 };
+ IdleEvent(QTime itime, int itimeout)
+ : QEvent( (QEvent::Type)Type ), time(itime), timeout(itimeout) {}
+
+ QTime time;
+ int timeout;
+};
+
+#include "qtestslave.moc"
+
+#define RET(message, str) (\
+ message["status"] = str,\
+ message["location"] = QString("%1:%2%3").arg(__FILE__).arg(__LINE__).arg(!message["location"].toString().isEmpty() ? "\n" + message["location"].toString() : ""),\
+ message)
+
+QTestSlave::QTestSlave()
+ : QTestProtocol()
+ , d(new QTestSlavePrivate(this))
+{
+ // Stop text cursors from flashing so that we can take reproducible screen shots
+ QApplication::setCursorFlashTime(0);
+ QtUiTest::testInputOption(QtUiTest::NoOptions);
+}
+
+QTestSlave::~QTestSlave()
+{
+ delete d;
+ disconnect();
+}
+
+void QTestSlave::onConnected()
+{
+ QTestProtocol::onConnected();
+ QTestMessage msg("APP_NAME");
+ msg["appName"] = qApp->applicationName();
+ msg["appVersion"] = qApp->applicationVersion();
+ msg["qtVersion"] = QT_VERSION_STR;
+ postMessage( msg );
+}
+
+void QTestSlave::setRecordingEvents(bool on)
+{
+ d->eventRecordingEnabled = on;
+ if (on) {
+ QObject::connect(&d->recorder, SIGNAL(entered(QObject*,QVariant)),
+ d, SLOT(record_entered(QObject*,QVariant)));
+ QObject::connect(&d->recorder, SIGNAL(selected(QObject*,QString)),
+ d, SLOT(record_selected(QObject*,QString)));
+ QObject::connect(&d->recorder, SIGNAL(gotFocus(QObject*)),
+ d, SLOT(record_gotFocus(QObject*)));
+ QObject::connect(&d->recorder, SIGNAL(activated(QObject*)),
+ d, SLOT(record_activated(QObject*)));
+ QObject::connect(&d->recorder, SIGNAL(stateChanged(QObject*,int)),
+ d, SLOT(record_stateChanged(QObject*,int)));
+ } else {
+ QObject::disconnect(&d->recorder, 0, d, 0);
+ }
+}
+
+bool QTestSlave::recordingEvents() const
+{ return d->eventRecordingEnabled; }
+
+QTestMessage QTestSlavePrivate::currentTitle(QTestMessage const&)
+{
+ QTestMessage reply;
+
+ QObject* focus = qApp->focusWidget();
+ QtUiTest::Widget* w = qtuitest_cast<QtUiTest::Widget*>(focus);
+ while (w && !(w->windowFlags() & Qt::Window) && w->parent()) {
+ w = qtuitest_cast<QtUiTest::Widget*>(w->parent());
+ }
+ if (w) {
+ reply["currentTitle"] = w->windowTitle();
+ reply["status"] = "OK";
+ } else if (!focus) {
+ reply["status"] = "Could not get current window title: could not find currently focused widget!";
+ } else {
+ reply["status"] = "Could not get current window title: could not find a top-level QtUiTest::Widget!";
+ }
+ return reply;
+}
+
+QTestMessage QTestSlavePrivate::getWindowTitles(QTestMessage const&)
+{
+ QTestMessage reply;
+ reply["getWindowTitles"] = QActiveTestWidget::instance()->getWindowTitles();
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::activateWindow(QTestMessage const &message)
+{
+ QTestMessage reply;
+ QWidget *window = QActiveTestWidget::instance()->findWindow(message["window"].toString());
+ if (window) {
+ if (window != qApp->activeWindow()) {
+ window->activateWindow();
+ window->raise();
+ for (int i=0; i<10; ++i) {
+ QtUiTest::wait(50);
+ if (window == qApp->activeWindow()) break;
+ }
+ if (window != qApp->activeWindow()) {
+ return RET(reply, "Could not activate window \"" + message["window"].toString() + "\"");
+ }
+ }
+ } else {
+ return RET(reply, "Could not find window \"" + message["window"].toString() + "\"");
+ }
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::grabPixmap(QTestMessage const &message)
+{
+ QTestMessage reply;
+ QPixmap pix;
+
+ Widget *tw = 0;
+ if (!message["queryPath"].toString().isEmpty()) {
+ tw = findTestWidget<Widget>(message);
+ } else {
+ tw = qtuitest_cast<Widget*>(qApp->activeWindow());
+ }
+
+ if (tw) {
+ tw->grabPixmap(pix);
+
+ if (!message["mask"].toStringList().isEmpty()) {
+ QPainter painter(&pix);
+ painter.setBrush(Qt::black);
+ QString error;
+ foreach (QString maskStr, message["mask"].toStringList()) {
+ QObject *o;
+ if (!QActiveTestWidget::instance()->findWidget( maskStr, o, error)) {
+ setErrorString(error);
+ break;
+ }
+ QtUiTest::Widget *w = qtuitest_cast<Widget*>(o);
+ if (!w) {
+ return RET(reply, "Could not find masked widget \"" + maskStr + "\"");
+ }
+ QRect rect = w->geometry();
+ rect.moveTo( tw->mapFromGlobal(w->mapToGlobal( QPoint(0,0) )) );
+ painter.drawRect(rect);
+ }
+ }
+ } else {
+ if (QtUiTest::errorString().isEmpty())
+ return RET(reply, "Widget not found");
+ }
+
+ reply["grabPixmap"] = pix;
+
+ if (!QtUiTest::errorString().isEmpty())
+ return RET(reply, QtUiTest::errorString());
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::activeWidgetInfo(QTestMessage const &message)
+{
+ Q_UNUSED(message);
+ QTestMessage reply;
+ QString error;
+ if (!QActiveTestWidget::instance()->rescan(error)) {
+ return RET(reply, error);
+ }
+ reply["activeWidgetInfo"] = QActiveTestWidget::instance()->toString();
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::getSelectedText(QTestMessage const &message)
+{
+ QTestMessage reply;
+ TextWidget *tw = findTestWidget<TextWidget>(message);
+ if (tw) {
+ reply["getSelectedText"] = tw->selectedText();
+ }
+
+ if (!QtUiTest::errorString().isEmpty())
+ return RET(reply, QtUiTest::errorString());
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::getText(QTestMessage const &message)
+{
+ QTestMessage reply;
+ TextWidget *tw = findTestWidget<TextWidget>(message);
+ if (tw) {
+ reply["getText"] = tw->text();
+ }
+
+ if (!QtUiTest::errorString().isEmpty())
+ return RET(reply, QtUiTest::errorString());
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::getSelectedValue(QTestMessage const &message)
+{
+ QTestMessage reply;
+ TextWidget *tw = findTestWidget<TextWidget>(message);
+ if (tw) {
+ reply["getSelectedValue"] = tw->selectedValue();
+ }
+
+ if (!QtUiTest::errorString().isEmpty())
+ return RET(reply, QtUiTest::errorString());
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::getValue(QTestMessage const &message)
+{
+ QTestMessage reply;
+ TextWidget *tw = findTestWidget<TextWidget>(message);
+ if (tw) {
+ reply["getValue"] = tw->value();
+ }
+
+ if (!QtUiTest::errorString().isEmpty())
+ return RET(reply, QtUiTest::errorString());
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::getList(QTestMessage const &message)
+{
+ QTestMessage reply;
+ ListWidget *lw = findTestWidget<ListWidget>(message);
+ if (lw) {
+ reply["getList"] = lw->list();
+ }
+
+ if (!QtUiTest::errorString().isEmpty())
+ return RET(reply, QtUiTest::errorString());
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::getLabels(QTestMessage const &/*message*/)
+{
+ QTestMessage reply;
+ QString error;
+ if (!QActiveTestWidget::instance()->rescan(error)) {
+ return RET(reply, error);
+ }
+ reply["getLabels"] = QActiveTestWidget::instance()->allLabels();
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::isVisible(QTestMessage const &message)
+{
+ QTestMessage reply;
+ Widget *w = findTestWidget<Widget>(message);
+ if (w) {
+ reply["isVisible"] = !(w->visibleRegion() | w->childrenVisibleRegion()).isEmpty();
+ } else {
+ reply["isVisible"] = false;
+ }
+
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::widget(QTestMessage const &message)
+{
+ QObject *tw;
+ QTestMessage reply;
+ QString error;
+ int offset = 0;
+ if (!message["offset"].toString().isEmpty()) offset = message["offset"].toInt();
+ if (QActiveTestWidget::instance()->findWidget( message["queryPath"].toString(), tw, error, offset )) {
+ reply["widget"] = QTestWidgets::signature(tw);//tw->signature();
+ return RET(reply, "OK");
+ }
+ return RET(reply, error);
+}
+
+QTestMessage QTestSlavePrivate::isChecked(QTestMessage const &message)
+{
+ QTestMessage reply;
+ if (message["item"].isValid()) {
+ CheckItemWidget *ciw = findTestWidget<CheckItemWidget>(message);
+ if (ciw) {
+ reply["isChecked"] = ciw->isChecked(message["item"].toString());
+ } else {
+ reply["isChecked"] = false;
+ }
+ } else {
+ CheckWidget *cw = findTestWidget<CheckWidget>(message);
+ if (cw) {
+ reply["isChecked"] = (cw->checkState() != Qt::Unchecked);
+ } else {
+ reply["isChecked"] = false;
+ }
+ }
+
+ if (!QtUiTest::errorString().isEmpty())
+ return RET(reply, QtUiTest::errorString());
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::setChecked(QTestMessage const &message)
+{
+ QTestMessage reply;
+ if (message["item"].isValid()) {
+ CheckItemWidget *ciw = findTestWidget<CheckItemWidget>(message);
+ if (ciw) {
+ ciw->setChecked(message["item"].toString(), message["doCheck"].toBool());
+ }
+ } else {
+ CheckWidget *cw = findTestWidget<CheckWidget>(message);
+ if (cw) {
+ Qt::CheckState state = Qt::Unchecked;
+ if (message["doCheck"].toBool())
+ state = Qt::Checked;
+ if (cw->checkState() == state)
+ return RET(reply, "OK");
+ if (!cw->setCheckState(state) && QtUiTest::errorString().isEmpty())
+ QtUiTest::setErrorString("Failed to change check state of widget");
+ }
+ }
+
+ if (!QtUiTest::errorString().isEmpty())
+ return RET(reply, QtUiTest::errorString());
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::checkState(QTestMessage const &message)
+{
+ QTestMessage reply;
+ CheckWidget *cw = findTestWidget<CheckWidget>(message);
+ if (cw) {
+ reply["checkState"] = static_cast<int>(cw->checkState());
+ }
+
+ if (!QtUiTest::errorString().isEmpty())
+ return RET(reply, QtUiTest::errorString());
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::setCheckState(QTestMessage const &message)
+{
+ QTestMessage reply;
+ CheckWidget *cw = findTestWidget<CheckWidget>(message);
+ if (cw) {
+ Qt::CheckState state = static_cast<Qt::CheckState>(message["state"].toInt());
+ if (!cw->setCheckState(state) && QtUiTest::errorString().isEmpty())
+ QtUiTest::setErrorString("Failed to change check state of widget");
+ }
+
+ if (!QtUiTest::errorString().isEmpty())
+ return RET(reply, QtUiTest::errorString());
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::getCenter(QTestMessage const &message)
+{
+ QTestMessage reply;
+ Widget *qw = findTestWidget<Widget>(message);
+ QPoint pos;
+ QRegion visibleRegion = qw->visibleRegion() | qw->childrenVisibleRegion();
+
+ // If we have just gotten focus, the visible region might be empty.
+ // Wait for up to 100ms for screen expose events to propagate correctly.
+ for (int i = 0;
+ i < 100 && visibleRegion.isEmpty();
+ QtUiTest::wait(20), i += 20, visibleRegion = qw->visibleRegion() | qw->childrenVisibleRegion()) {}
+
+ if (message["item"].isValid()) {
+ bool ok = false;
+ ListWidget *lw = findTestWidget<ListWidget>(message);
+ if (lw) {
+ ok = true;
+ pos = qw->mapToGlobal(lw->visualRect(message["item"].toString()).center());
+ }
+
+ if (!ok) {
+ return RET(reply, "ERROR: couldn't get center of item " + message["item"].toString() +
+ " in widget " + message["queryPath"].toString());
+ }
+ }
+
+ if (pos.isNull()) {
+ pos = qw->center();
+ }
+
+ reply["getCenter"] = QVariant::fromValue(pos);
+
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::activeWindow(QTestMessage const &message)
+{
+ Q_UNUSED(message);
+ QTestMessage reply;
+ QObject *w = qApp->activeWindow();
+ if (w) {
+ reply["activeWindow"] = QTestWidgets::signature( w );
+ return RET(reply, "OK");
+ }
+
+ return RET(reply, "ERROR: No active application window");
+}
+
+QTestMessage QTestSlavePrivate::focusWidget(QTestMessage const &message)
+{
+ Q_UNUSED(message);
+ QTestMessage reply;
+ QtUiTestElapsedTimer t;
+ QObject *w = 0;
+ while (t.elapsed() < VISIBLE_RESPONSE_TIME) {
+ QString error;
+ QActiveTestWidget::instance()->rescan(error);
+ w = qApp->focusWidget();
+ if (w) break;
+ QtUiTest::wait(3);
+ }
+ if (!w) w = QTestWidgets::activeWidget();
+ if (w) {
+ reply["focusWidget"] = QTestWidgets::signature( w );
+ return RET(reply, "OK");
+ }
+
+ return RET(reply, QString("ERROR: No focus widget found in application '%1' in %2 ms.").arg(qApp->applicationName()).arg(t.elapsed()));
+}
+
+QTestMessage QTestSlavePrivate::hasFocus( QTestMessage const &message )
+{
+ QTestMessage reply;
+ Widget *w = findTestWidget<Widget>(message);
+
+ if (w) {
+ reply["hasFocus"] = w->hasFocus();
+ }
+
+ if (!QtUiTest::errorString().isEmpty())
+ return RET(reply, QtUiTest::errorString());
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::appName(QTestMessage const &message)
+{
+ Q_UNUSED(message);
+ QTestMessage reply;
+ reply["appName"] = qApp->applicationName();
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::startEventRecording(QTestMessage const &message)
+{
+ Q_UNUSED(message);
+ QTestMessage reply;
+ if (qApp != 0) {
+ p->setRecordingEvents(true);
+ qApp->installEventFilter( this );
+ return RET(reply, "OK");
+ }
+ return RET(reply, "ERROR: No application available to record events. This is unusual.");
+}
+
+QTestMessage QTestSlavePrivate::stopEventRecording(QTestMessage const &message)
+{
+ Q_UNUSED(message);
+ QTestMessage reply;
+ if (qApp != 0) {
+ p->setRecordingEvents(false);
+ qApp->removeEventFilter( this );
+ return RET(reply, "OK");
+ }
+ return RET(reply, "ERROR: No application available to stop event recording. This is unusual.");
+}
+
+void QTestSlave::recordEvent(RecordEvent::Type type, QString const& widget, QString const& focusWidget, QVariant const& data)
+{
+ RecordEvent event;
+ event.type = type;
+ event.widget = widget;
+ event.focusWidget = focusWidget;
+ event.data = data;
+
+ QList<RecordEvent> unpostedEvents;
+ unpostedEvents << event;
+
+ QTestMessage msg("recordedEvents");
+ msg["events"] = QVariant::fromValue(unpostedEvents);
+ postMessage(msg);
+}
+
+QTestMessage QTestSlavePrivate::invokeMethod(QTestMessage const &message)
+{
+ QObject *o;
+ QString error;
+ QTestMessage reply;
+ if (!QActiveTestWidget::instance()->findWidget( message["queryPath"].toString(), o, error))
+ return RET(reply,error);
+
+ QString method = message["method"].toString();
+ bool returns = message["returns"].toBool();
+ Qt::ConnectionType connType = (Qt::ConnectionType)message["conntype"].toInt();
+
+ method = QMetaObject::normalizedSignature(qPrintable(method));
+
+ QVariantList argList = message["args"].toList();
+
+ QMetaObject const *mo = o->metaObject();
+
+ int m = mo->indexOfMethod(QMetaObject::normalizedSignature(qPrintable(method)));
+ if (-1 == m) {
+ return RET(reply, "ERROR_NO_METHOD");
+ }
+ QMetaMethod mm = mo->method(m);
+ if (mm.methodType() == QMetaMethod::Method) {
+ return RET(reply, "ERROR_METHOD_NOT_INVOKABLE");
+ }
+ QList<QByteArray> paramTypes = mm.parameterTypes();
+ if (paramTypes.count() != argList.count()) {
+ (void)RET(reply, "ERROR_WRONG_ARG_COUNT");
+ reply["warning"] = QString("actual args %1, expected args %2").arg(paramTypes.count()).arg(argList.count());
+ return reply;
+ }
+ QString retType = mm.typeName();
+ if (returns && retType.isEmpty()) {
+ return RET(reply, "ERROR_NO_RETURN");
+ }
+
+ QGenericArgument arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9;
+#define LARG(i) do {\
+ if (argList.count() <= i) break;\
+ arg##i = QGenericArgument(paramTypes[i], argList[i].constData());\
+} while(0);
+ LARG(0);LARG(1);LARG(2);LARG(3);LARG(4);LARG(5);LARG(6);
+ LARG(7);LARG(8);LARG(9);
+#undef LARG
+
+ QString methodName = method.left(method.indexOf('('));
+
+ if (!retType.isEmpty()) {
+ /* FIXME! What if the variable is larger than this? */
+ char buf[16384];
+ QGenericReturnArgument rarg(qPrintable(retType), static_cast<void *>(buf));
+ if (!QMetaObject::invokeMethod(o, qPrintable(methodName), connType,
+ rarg, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)) {
+ return RET(reply, "ERROR_IN_INVOKE");
+ }
+ int typeId = QMetaType::type(qPrintable(retType));
+ QVariant var(typeId, static_cast<const void *>(buf));
+ reply["returns"] = var;
+ } else {
+ if (!QMetaObject::invokeMethod(o, qPrintable(methodName), connType,
+ arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)) {
+ return RET(reply, "ERROR_IN_INVOKE");
+ }
+ }
+
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::setProperty(QTestMessage const &message)
+{
+ QTestMessage reply;
+ Widget *w = findTestWidget<Widget>(message);
+ if (w) {
+ QString property = message["property"].toString();
+ QVariant value = message["value"];
+ if (!w->setProperty(property, value) && QtUiTest::errorString().isEmpty()) {
+ return RET(reply, "ERROR_SETTING_PROPERTY");
+ }
+ }
+
+ if (!QtUiTest::errorString().isEmpty())
+ return RET(reply, QtUiTest::errorString());
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::getProperty(QTestMessage const &message)
+{
+ QTestMessage reply;
+ Widget *w = findTestWidget<Widget>(message);
+ if (w) {
+ QString property = message["property"].toString();
+ QVariant value = w->getProperty(property);
+ if (QObject *obj = value.value<QObject*>()) {
+ value = QTestWidgets::signature(obj);
+ }
+ reply["getProperty"] = value;
+ if (!value.isValid()) {
+ QtUiTest::setErrorString("Failed to retrieve property from object");
+ }
+ }
+
+ if (!QtUiTest::errorString().isEmpty())
+ return RET(reply, QtUiTest::errorString());
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::findByProperty(QTestMessage const &message)
+{
+ QTestMessage reply;
+ QString error;
+ if (!QActiveTestWidget::instance()->rescan(error)) {
+ return RET(reply, error);
+ }
+
+ QString property = message["property"].toString();
+ QVariant searchValue = message["searchValue"];
+ if (property.isEmpty() || !searchValue.isValid()) {
+ return RET(reply, "ERROR_MISSING_PARAMETERS");
+ }
+
+ QObjectList ol = QActiveTestWidget::instance()->findObjectsByProperty( property, searchValue );
+
+ // Sort the list by widget position
+ qStableSort(ol.begin(), ol.end(), QTestWidgets::lessThan);
+
+ QStringList ret = QTestWidgets::objectListToSignatures(ol);
+ reply["findByProperty"] = ret;
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::findByProperties(QTestMessage const &message)
+{
+ QTestMessage reply;
+ QString error;
+ if (!QActiveTestWidget::instance()->rescan(error)) {
+ return RET(reply, error);
+ }
+
+ QVariantMap searchValues = message["searchValues"].toMap();
+ if ( searchValues.isEmpty() ) {
+ return RET(reply, "ERROR_MISSING_PARAMETERS");
+ }
+
+ QObjectList ol = QActiveTestWidget::instance()->findObjectsByProperty( searchValues );
+
+ // Sort the list by widget position
+ qStableSort(ol.begin(), ol.end(), QTestWidgets::lessThan);
+
+ QStringList ret = QTestWidgets::objectListToSignatures(ol);
+ reply["findByProperties"] = ret;
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::getSetting(QTestMessage const &message)
+{
+ QTestMessage reply;
+ QString org = message["org"].toString();
+ QString app = message["app"].toString();
+ QString path = message["path"].toString();
+ QString group = message["group"].toString();
+ QString key = message["key"].toString();
+ path = p->processEnvironment(path);
+ if (group.isEmpty() || key.isEmpty()) {
+ return RET(reply, "ERROR_MISSING_PARAMETERS");
+ }
+ if (!path.isEmpty() && (!org.isEmpty() || !app.isEmpty())) {
+ return RET(reply, "ERROR_BAD_PARAMETERS");
+ } else if (path.isEmpty() && org.isEmpty()) {
+ return RET(reply, "ERROR_MISSING_PARAMETERS");
+ }
+
+ QSettings *settings = 0;
+ if (!path.isEmpty()) settings = new QSettings(path, QSettings::NativeFormat);
+ else settings = new QSettings(org, app);
+
+ settings->beginGroup(group);
+ reply["getSetting"] = settings->value(key);
+ delete settings;
+
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::setSetting(QTestMessage const &message)
+{
+ QTestMessage reply;
+ QString org = message["org"].toString();
+ QString app = message["app"].toString();
+ QString path = message["path"].toString();
+ QString group = message["group"].toString();
+ QString key = message["key"].toString();
+ path = p->processEnvironment(path);
+ if (key.isEmpty()) {
+ return RET(reply, "ERROR_MISSING_PARAMETERS");
+ }
+ if (!path.isEmpty() && (!org.isEmpty() || !app.isEmpty())) {
+ return RET(reply, "ERROR_BAD_PARAMETERS");
+ } else if (path.isEmpty() && org.isEmpty()) {
+ return RET(reply, "ERROR_MISSING_PARAMETERS");
+ }
+
+ QSettings *settings = 0;
+ if (!path.isEmpty()) settings = new QSettings(path, QSettings::NativeFormat);
+ else settings = new QSettings(org, app);
+
+ if (!group.isEmpty())
+ settings->beginGroup(group);
+ settings->setValue(key, message["value"]);
+ delete settings;
+
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::getClipboardText(QTestMessage const &message)
+{
+ Q_UNUSED(message);
+ QTestMessage reply;
+
+#ifndef QT_NO_CLIPBOARD
+ QClipboard *cb = QApplication::clipboard();
+ if (cb) {
+ reply["getClipboardText"] = cb->text();
+ return RET(reply, "OK");
+ }
+#endif
+
+ return RET(reply, "ERROR: couldn't get clipboard");
+}
+
+QTestMessage QTestSlavePrivate::setClipboardText(QTestMessage const &message)
+{
+ QTestMessage reply;
+
+#ifndef QT_NO_CLIPBOARD
+ QString value = message["text"].toString();
+ QClipboard *cb = QApplication::clipboard();
+ if (cb) {
+ cb->setText(value);
+ return RET(reply, "OK");
+ }
+#endif
+
+ return RET(reply, "ERROR: couldn't get clipboard");
+}
+
+QTestMessage QTestSlavePrivate::mousePreferred(QTestMessage const &message)
+{
+ Q_UNUSED(message);
+ QTestMessage reply;
+
+ reply["mousePreferred"] = QtUiTest::mousePreferred();
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::setMousePreferred(QTestMessage const &message)
+{
+ QTestMessage reply;
+ bool useMouse = message["useMouse"].toBool();
+
+ QtUiTest::setMousePreferred(useMouse);
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::labelOrientation(QTestMessage const &message)
+{
+ Q_UNUSED(message);
+ QTestMessage reply;
+
+ reply["labelOrientation"] = QtUiTest::labelOrientation();
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::setLabelOrientation(QTestMessage const &message)
+{
+ QTestMessage reply;
+ int orientation = message["orientation"].toInt();
+
+ QtUiTest::setLabelOrientation(static_cast<QtUiTest::LabelOrientation>(orientation));
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::putFile(QTestMessage const &message)
+{
+ QTestMessage reply;
+ QString path = message["path"].toString();
+ path = p->processEnvironment(path);
+ QByteArray data = message["data"].toByteArray();
+
+ if (path.isEmpty())
+ return RET(reply, "ERROR_MISSING_PARAMETERS");
+
+ {
+ QFileInfo info = QFileInfo(path);
+ QDir dir = info.dir();
+ if (info.exists()) {
+ dir.remove(info.fileName());
+ } else if (!dir.exists() && !QDir("/").mkpath(dir.absolutePath())) {
+ return RET(reply, "Could not create path '" + dir.absolutePath() + "'");
+ }
+ }
+
+ QFile f(path);
+ if (f.open(QIODevice::WriteOnly)) {
+ if (message["permissions"].isValid() && !f.setPermissions(static_cast<QFile::Permissions>(message["permissions"].toInt()))) {
+ return RET(reply, "ERROR_FILE_PERMISSIONS");
+ }
+ QDataStream ds(&f);
+ if (data.constData()) {
+ int bytesWritten = ds.writeRawData(data.constData(), data.size());
+ if (bytesWritten == data.size())
+ return RET(reply, "OK");
+ else {
+ reply["warning"] = QString("Wrote %1 byte(s), expected %2").arg(bytesWritten).arg(data.size());
+ return RET(reply, "ERROR_TRUNCATED");
+ }
+ }
+ // It's OK for data to be empty, then we create an empty file.
+ return RET(reply, "OK");
+ }
+
+ return RET(reply, "ERROR_FILE_OPEN");
+}
+
+QTestMessage QTestSlavePrivate::getFile(QTestMessage const &message)
+{
+ QTestMessage reply;
+ QString path = message["path"].toString();
+ path = p->processEnvironment(path);
+
+ if (path.isEmpty())
+ return RET(reply, "ERROR_MISSING_PARAMETERS");
+
+ QFile f(path);
+ if (!f.exists()) return RET(reply, "ERROR_FILE_NOT_EXIST");
+ if (f.open(QIODevice::ReadOnly)) {
+ QByteArray data;
+ QDataStream ds(&f);
+ data.resize(f.size());
+ int bytesRead = ds.readRawData(data.data(), f.size());
+ reply["getFile"] = data;
+ if (bytesRead == f.size())
+ return RET(reply, "OK");
+ else {
+ reply["warning"] = QString("Read %1 byte(s), expected %2").arg(bytesRead).arg(data.size());
+ return RET(reply, "ERROR_TRUNCATED");
+ }
+ }
+ return RET(reply, "ERROR_FILE_OPEN");
+}
+
+QTestMessage QTestSlavePrivate::getImageSize(QTestMessage const &message)
+{
+ QTestMessage reply;
+ QString path = message["path"].toString();
+ path = p->processEnvironment(path);
+
+ if (path.isEmpty())
+ return RET(reply, "Error: Path is Empty.");
+
+ QImage f(path);
+ if (f.isNull())
+ return RET(reply, "Error: No Image Loaded.");
+ QSize imgSize = f.size();
+ reply["getImageSize"] = imgSize;
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::getGeometry(QTestMessage const &message)
+{
+ QTestMessage reply;
+ Widget *w = findTestWidget<Widget>(message);
+ if (w) {
+ QRect ret = w->geometry();
+ ret.moveTo( w->mapToGlobal( QPoint(0,0) ) );
+ reply["getGeometry"] = ret;
+ }
+
+ if (!QtUiTest::errorString().isEmpty())
+ return RET(reply, QtUiTest::errorString());
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::setSystemTime(QTestMessage const &message)
+{
+ QTestMessage reply;
+#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
+ QDateTime dt = message["dateTime"].value<QDateTime>();
+ if (!dt.isValid()) return RET(reply, "ERROR: Invalid date/time specified");
+
+ struct timeval myTv;
+ myTv.tv_sec = dt.toTime_t();
+ myTv.tv_usec = 0;
+
+ if ( myTv.tv_sec != -1 )
+ ::settimeofday( &myTv, 0 );
+
+ return RET(reply, "OK");
+#else
+ Q_UNUSED(message);
+ return RET(reply, "ERROR: setSystemTime is not implemented on this platform!");
+#endif
+}
+
+QTestMessage QTestSlavePrivate::systemTime(QTestMessage const &message)
+{
+ Q_UNUSED(message);
+ QTestMessage reply;
+ reply["systemTime"] = QDateTime::currentDateTime();
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::getDirectoryEntries(QTestMessage const &message)
+{
+ QTestMessage reply;
+ QString path = message["path"].toString();
+ path = p->processEnvironment(path);
+
+ if (path.isEmpty()) {
+ return RET(reply, "ERROR_MISSING_PARAMETERS");
+ }
+
+ QDir d(path);
+ if (!d.exists()) {
+ reply["getDirectoryEntries"] = QStringList();
+ return RET(reply, "OK");
+ }
+
+ QDir::Filters filters;
+ {
+ int filters_int = message["filters"].toInt();
+ filters = QFlag(filters_int);
+ }
+
+ QStringList list = d.entryList(filters);
+ reply["getDirectoryEntries"] = list;
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::deletePath(QTestMessage const &message)
+{
+ QTestMessage reply;
+ QString path = message["path"].toString();
+ path = p->processEnvironment(path);
+ return RET(reply, recursiveDelete(path));
+}
+
+// All messages get processed on their own stack.
+// This function is the entry point into the alternate stacks.
+void QTestSlavePrivate::processMessage(QAlternateStack* stack, QVariant const& data)
+{
+ QVariantList list = data.toList();
+ QTestSlave* slave = qobject_cast<QTestSlave*>(list.at(0).value<QObject*>());
+ QTestMessage msg = list.at(1).value<QTestMessage>();
+
+ QTestMessage reply = slave->constructReplyToMessage(msg);
+
+ if (!reply.isNull()) {
+ // Warn if we couldn't use QAlternateStack.
+ static char mem = 0;
+ while (!mem) {
+ mem = 1;
+ if (stack) break;
+ if (QApplication::type() != QApplication::GuiServer) break;
+ static const char warning[] =
+ "QAlternateStack is not available on this platform.\n"
+ "Modal dialogs, message boxes and nested event loops may cause a hang.";
+ qWarning("QtUitest: %s", warning);
+ reply["warning"] = QString::fromLatin1(warning);
+ }
+ slave->replyMessage(&msg, reply);
+ }
+
+ // The alternate stack is no longer required, so delete it after
+ // we return.
+ if (stack) stack->deleteLater();
+}
+
+Q_DECLARE_METATYPE(QAlternateStackEntryPoint);
+Q_DECLARE_METATYPE(QVariant);
+
+void QTestSlave::processMessage( QTestMessage *msg )
+{
+ // Make sure we don't process within an alternate stack.
+ foreach (QAlternateStack* stack, QAlternateStack::instances()) {
+ if (stack->isCurrentStack())
+ qFatal( "%s received message %s while in an alternate stack! "
+ "This is a programmer error; it means events are being "
+ "processed in an alternate stack. This should never "
+ "happen.",
+ qPrintable(qApp->applicationName()),
+ qPrintable(msg->event()));
+ }
+
+ QVariantList list;
+ list.append( QVariant::fromValue(static_cast<QObject*>(this)) );
+ list.append( QVariant::fromValue(*msg) );
+
+ // If possible, use an alternate stack to handle the messages.
+ // We only want to switch to that stack once we get back to the event loop.
+ if (QAlternateStack::isAvailable()) {
+ QAlternateStack* stack;
+ if (msg->event() == "grabPixmap") {
+ stack = new QAlternateStack(131072, this);
+ } else {
+ stack = new QAlternateStack(65536, this);
+ }
+
+ static const int type1 = qRegisterMetaType<QAlternateStackEntryPoint>();
+ static const int type2 = qRegisterMetaType<QVariant>();
+ Q_UNUSED(type1); Q_UNUSED(type2);
+ QMetaObject::invokeMethod(stack, "start", Qt::QueuedConnection,
+ Q_ARG(QAlternateStackEntryPoint, QTestSlavePrivate::processMessage),
+ Q_ARG(QVariant, qVariantFromValue(list)));
+ }
+ // Some platforms can't use QAlternateStack.
+ // In that case, just process the message as usual. This means bug 194361
+ // can happen.
+ else {
+ QTestSlavePrivate::processMessage(0, list);
+ }
+}
+
+QTestMessage QTestSlave::constructReplyToMessage( QTestMessage const &_msg )
+{
+ QTestMessage reply;
+ QTestMessage msg(_msg);
+ reply["from"] = qApp->applicationName();
+
+// TO HANDLE A NEW SYSTEM TEST EVENT:
+// implement a function with signature:
+// QTestMessage QTestSlavePrivate::eventName(QTestMessage const &message)
+
+ QString qp = msg["queryPath"].toString();
+
+ if (!QMetaObject::invokeMethod(d, msg.event().toLatin1().constData(), Qt::DirectConnection,
+ Q_RETURN_ARG(QTestMessage, reply),
+ Q_ARG(QTestMessage, msg))) {
+ (void)RET(reply, "ERROR: Unhandled event '" + msg.event() + "'");
+ }
+
+ return reply;
+}
+
+QString QTestSlave::processEnvironment( QString const& in ) const
+{
+ struct SystemEnvironment {
+ static QMap<QString,QString> get() {
+ QMap<QString,QString> ret;
+ QStringList env = QProcess::systemEnvironment();
+ foreach (QString str, env) {
+ if (str.contains('=')) {
+ ret[str.left(str.indexOf('=')).toUpper()] = str.mid(str.indexOf('=') + 1);
+ }
+ }
+ return ret;
+ }
+ };
+ static const QMap<QString,QString> environment( SystemEnvironment::get() );
+
+ QString out;
+ static QRegExp re("\\$[{(]?([A-Za-z0-9_]+)[})]?");
+ int offset = 0;
+ while (true) {
+ int index = re.indexIn(in, offset);
+ if (-1 == index) {
+ out += in.mid(offset);
+ break;
+ }
+ out += in.mid(offset, index - offset);
+ out += environment.value(re.cap(1).toUpper());
+ offset += re.matchedLength();
+ }
+
+ return out;
+}
+
+QString QTestSlavePrivate::recursiveDelete( const QString &path ) const
+{
+ if (path.isEmpty()) return "ERROR_CANT_DELETE_EMPTY_PATH";
+
+ QFileInfo i(path);
+ if (!i.exists()) return "OK";
+ if (!i.isDir() || i.isSymLink()) {
+ if (!i.dir().remove(i.fileName())) {
+ return "ERROR_CANT_DELETE_FILE_" + path;
+ } else {
+ return "OK";
+ }
+ }
+
+ QDir dir(path);
+
+ QStringList children = dir.entryList( QDir::AllEntries | QDir::System | QDir::Hidden | QDir::NoDotAndDotDot );
+
+ QString res;
+ foreach (QString child, children) {
+ res = recursiveDelete( dir.absolutePath() + "/" + child );
+ if (res != "OK" ) return res;
+ }
+
+ QString dirName = dir.dirName();
+ dir.cdUp();
+
+ if (!dir.rmdir(dirName)) {
+ return "ERROR_CANT_DELETE_DIRECTORY_" + path;
+ }
+ return "OK";
+}
+
+bool QTestSlavePrivate::waitForIdle(int timeout)
+{
+ connect(this, SIGNAL(applicationBecameIdle()), this, SLOT(sendBecameIdleMessage()));
+ startWaitForIdle(timeout);
+
+ QtUiTest::waitForSignal(this, SIGNAL(applicationBecameIdle()), timeout);
+
+ return true;
+}
+
+QTestMessage QTestSlavePrivate::waitForIdle(QTestMessage const &message)
+{
+ QTestMessage reply;
+ if (waitForIdle(message["timeout"].toInt()))
+ return RET(reply, "OK");
+ return RET(reply, "ERROR_IDLE_TIMEOUT");
+}
+
+QTestMessage QTestSlavePrivate::select( QTestMessage const &message )
+{
+ bool should_rescan = false;
+ QTestMessage reply;
+ int try_count = 5;
+ QString text = message["text"].toString();
+ QString error;
+
+ qLog(QtUitest) << "select" << text << message["queryPath"].toString();
+
+ while (try_count-- > 0) {
+ if (should_rescan) {
+ // Wait a moment to process events and then try again
+ QtUiTest::wait(200);
+ if (!QActiveTestWidget::instance()->rescan(error)) {
+ return RET(reply, error);
+ }
+ reply["warning"] = "Item selection failed ... will try again in 200 ms";
+ should_rescan = false;
+ }
+
+ QString qp = message["queryPath"].toString();
+ QObject *o = 0;
+
+ // See if we should interpret select("Something") as activate("Something").
+ // From a user's point of view, activating a button from a set of buttons
+ // and selecting an action from a list are pretty much the same thing.
+ if (qp.isEmpty() && !text.isEmpty()) {
+ QString error;
+ if (QActiveTestWidget::instance()->findWidget( text, o, error)) {
+ ActivateWidget *aw = qtuitest_cast<ActivateWidget*>(o);
+ if (aw) {
+ aw->activate();
+ if (!QtUiTest::errorString().isEmpty())
+ return RET(reply, QtUiTest::errorString());
+ return RET(reply, "OK");
+ }
+ }
+ }
+
+ if (!QActiveTestWidget::instance()->findWidget(qp, o, error)) {
+ if (try_count > 0) {
+ should_rescan = true;
+ continue;
+ } else {
+ return RET(reply,error);
+ }
+ }
+ if (qp.isEmpty()) qp = QTestWidgets::signature(o);
+
+ QtUiTest::SelectWidget *sw = qtuitest_cast<QtUiTest::SelectWidget*>(o);
+ if (!sw) {
+ QString resolvedQp;
+ QDebug(&resolvedQp) << o;
+ return RET(reply, "ERROR: " + qp + " (" + resolvedQp + ") is not a SelectWidget.");
+ }
+ if (!sw->select(text)) {
+ if (!sw->canSelect(text)) {
+ if (try_count > 0) {
+ should_rescan = true;
+ continue;
+ } else {
+ QString error = "ERROR: item '" + text
+ + "' is not available for selection in " + qp;
+ if (!QtUiTest::errorString().isEmpty()) {
+ error += "\n" + QtUiTest::errorString();
+ }
+ QtUiTest::ListWidget *lw = qtuitest_cast<QtUiTest::ListWidget*> (o);
+ if (lw) {
+ error += "\nAvailable items: " + lw->list().join(",");
+ }
+ return RET(reply, error);
+ }
+ }
+ error = "ERROR: unknown error selecting item '" + text
+ + "' from " + qp;
+ if (!QtUiTest::errorString().isEmpty())
+ error = QtUiTest::errorString();
+ return RET(reply, error);
+ }
+ return RET(reply, "OK");
+ }
+
+ error = "ERROR: unknown error selecting item '" + text + "'";
+ return RET(reply, error);
+}
+
+QTestMessage QTestSlavePrivate::selectIndex( QTestMessage const &message )
+{
+ QTestMessage reply;
+ IndexedWidget *iw = findTestWidget<IndexedWidget>(message);
+ if (iw) {
+ QVariantList index = message["index"].toList();
+ iw->selectIndex(index);
+ }
+
+ if (!QtUiTest::errorString().isEmpty())
+ return RET(reply, QtUiTest::errorString());
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::getSelectedIndex( QTestMessage const &message )
+{
+ QTestMessage reply;
+ IndexedWidget *iw = findTestWidget<IndexedWidget>(message);
+ if (iw) {
+ reply["getSelectedIndex"] = iw->selectedIndex();
+ }
+
+ if (!QtUiTest::errorString().isEmpty())
+ return RET(reply, QtUiTest::errorString());
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::activate( QTestMessage const &message )
+{
+ QTestMessage reply;
+ ActivateWidget *aw = findTestWidget<ActivateWidget>(message);
+ if (aw) {
+ aw->activate();
+ }
+
+ if (!QtUiTest::errorString().isEmpty())
+ return RET(reply, QtUiTest::errorString());
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::ensureVisible( QTestMessage const &message )
+{
+ QTestMessage reply;
+ if (message["item"].isValid()) {
+ ListWidget *lw = findTestWidget<ListWidget>(message);
+ if (lw) {
+ bool ok = lw->ensureVisible(message["item"].toString());
+ if (!ok && QtUiTest::errorString().isEmpty()) {
+ return RET(reply, "ERROR: Failed to make item visible");
+ }
+ }
+ } else {
+ return RET(reply, "ERROR: No item specified");
+ }
+
+ if (!QtUiTest::errorString().isEmpty())
+ return RET(reply, QtUiTest::errorString());
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::enter( QTestMessage const &message )
+{
+ QObject* o;
+ QString error;
+ QString qp = message["queryPath"].toString();
+ QVariant value = message["value"];
+ bool mode = message["mode"] == "NoCommit";
+
+ QTestMessage reply;
+ if (!QActiveTestWidget::instance()->findWidget(qp, o, error))
+ return RET(reply,error);
+
+ QPointer<QObject> safeTw = o;
+
+ QtUiTest::InputWidget *iw
+ = qtuitest_cast<QtUiTest::InputWidget*>(o);
+
+ QString sig = QTestWidgets::signature(o);
+
+ if (!iw) {
+ return RET(reply, "ERROR: " + qp + " is not an InputWidget. Signature: " + sig);
+ }
+
+ if (!iw->enter(value, mode)) {
+ QString error;
+ if (!safeTw) {
+ error = "ERROR: " + qp + " was destroyed while entering text into it.";
+ } else if (!iw->canEnter(value) && QtUiTest::errorString().isEmpty()) {
+ QString resolvedQp;
+ QDebug(&resolvedQp) << o;
+ return RET(reply, "ERROR: '" + value.toString()
+ + "' is not valid input for " + qp + " (" + resolvedQp + "; " + sig + ")");
+ } else {
+ error = "ERROR: unknown error entering '" + value.toString()
+ + "' into " + qp + ". Signature: " + sig;
+ if (!QtUiTest::errorString().isEmpty())
+ error = QtUiTest::errorString();
+ }
+ return RET(reply, error);
+ }
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::keyPress(QTestMessage const &message)
+{
+ QTestMessage reply;
+ if (!message["key"].isValid()) {
+ return RET(reply, "ERROR_MISSING_KEY");
+ }
+
+ Qt::Key key = (Qt::Key)(message["key"].toInt());
+ if (!key) return RET(reply, "ERROR_ZERO_KEY");
+
+ QtUiTest::keyPress(key);
+
+ if (message["duration"].isValid()) {
+ int duration = message["duration"].toInt();
+ if (duration >= 500) {
+ QtUiTest::wait(500);
+ duration -= 500;
+ bool keyRepeat=QtUiTest::testInputOption(QtUiTest::KeyRepeat);
+ QtUiTest::setInputOption(QtUiTest::KeyRepeat, true);
+ QtUiTest::keyPress(key);
+ while (duration > 0) {
+ QtUiTest::wait(150);
+ duration -= 150;
+ QtUiTest::keyPress(key);
+ }
+ QtUiTest::setInputOption(QtUiTest::KeyRepeat, keyRepeat);
+ } else {
+ QtUiTest::wait(duration);
+ }
+ }
+
+ return RET(reply, "OK" );
+}
+
+QTestMessage QTestSlavePrivate::keyRelease(QTestMessage const &message)
+{
+ QTestMessage reply;
+ if (!message["key"].isValid()) {
+ return RET(reply, "ERROR_MISSING_KEY");
+ }
+ Qt::Key key = (Qt::Key)(message["key"].toInt());
+ if (!key) return RET(reply, "ERROR_ZERO_KEY");
+ QtUiTest::keyRelease(key);
+ return RET(reply, "OK" );
+}
+
+QTestMessage QTestSlavePrivate::keyClick(QTestMessage const &message)
+{
+ QTestMessage reply;
+ if (!message["key"].isValid()) {
+ return RET(reply, "ERROR_MISSING_KEY");
+ }
+
+ Qt::Key key = (Qt::Key)(message["key"].toInt());
+ if (!key) return RET(reply, "ERROR_ZERO_KEY");
+ QtUiTest::keyClick(key);
+ return RET(reply, "OK" );
+}
+
+QTestMessage QTestSlavePrivate::mousePress(QTestMessage const &message)
+{
+ QTestMessage reply;
+ bool ok;
+ Qt::MouseButtons buttons = (Qt::MouseButtons)(message["buttons"].toInt(&ok));
+ if (!ok) buttons = Qt::LeftButton;
+
+ QPoint pos(mousePointForMessage(message, reply, ok));
+ if (ok) QtUiTest::mousePress(pos, buttons);
+ else return reply;
+ return RET(reply, "OK" );
+}
+
+QTestMessage QTestSlavePrivate::mouseRelease(QTestMessage const &message)
+{
+ QTestMessage reply;
+ bool ok;
+ Qt::MouseButtons buttons = (Qt::MouseButtons)(message["buttons"].toInt(&ok));
+ if (!ok) buttons = Qt::LeftButton;
+
+ QPoint pos(mousePointForMessage(message, reply, ok));
+ if (ok) QtUiTest::mouseRelease(pos, buttons);
+ else return reply;
+ return RET(reply, "OK" );
+}
+
+QTestMessage QTestSlavePrivate::mouseClick(QTestMessage const &message)
+{
+ QTestMessage reply;
+ bool ok;
+ Qt::MouseButtons buttons = (Qt::MouseButtons)(message["buttons"].toInt(&ok));
+ if (!ok) buttons = Qt::LeftButton;
+
+ if (message["pos"].isValid()) {
+ QtUiTest::mouseClick(message["pos"].value<QPoint>(), buttons);
+ } else {
+ Widget *w = findTestWidget<Widget>(message);
+ if (w) {
+ QPoint pos(w->rect().center());
+ if (w->visibleRegion().boundingRect().contains(pos) ||
+ w->ensureVisiblePoint(pos)) {
+ QtUiTest::mouseClick(w->mapToGlobal(pos), buttons);
+ } else {
+ //can't make visible
+ return RET(reply, "ERROR: couldn't make widget visible");
+ }
+ }
+ }
+
+ return RET(reply, "OK");
+}
+
+QPoint QTestSlavePrivate::mousePointForMessage(QTestMessage const &message, QTestMessage &reply, bool &ok)
+{
+ ok = true;
+ if (message["pos"].isValid())
+ return message["pos"].value<QPoint>();
+ reply = getCenter( message );
+ return reply["getCenter"].value<QPoint>();
+}
+
+QTestMessage QTestSlavePrivate::translate( QTestMessage const &message )
+{
+ QTestMessage reply;
+ QByteArray context = message["context"].toString().toLatin1();
+ QByteArray text = message["text"].toString().toLatin1();
+ QByteArray comment = message["comment"].toString().toLatin1();
+ int n = message["number"].toInt();
+ reply["translate"] = QCoreApplication::translate(context, text, comment, QCoreApplication::CodecForTr, n);
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::getLocale( QTestMessage const &message )
+{
+ Q_UNUSED(message);
+ QTestMessage reply;
+ reply["getLocale"] = QLocale::system();
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::getenv( QTestMessage const &message )
+{
+ QTestMessage reply;
+ reply["getenv"] = QVariant::fromValue(qgetenv(message["key"].toString().toLatin1()));
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::checkOS( QTestMessage const &message )
+{
+ QTestMessage reply;
+ QString os = message["os"].toString().toUpper();
+
+ bool result = false;
+
+#ifdef Q_OS_UNIX
+ if (os == "UNIX") result = true;
+#endif
+#ifdef Q_OS_LINUX
+ if (os == "LINUX") result = true;
+#endif
+#ifdef Q_OS_MAEMO
+ if (os == "MAEMO") result = true;
+#endif
+#ifdef Q_OS_MAC
+ if (os == "MAC") result = true;
+#endif
+#ifdef Q_OS_WIN32
+ if (os == "WIN32") result = true;
+#endif
+#ifdef Q_OS_WINCE
+ if (os == "WINCE") result = true;
+#endif
+#ifdef Q_OS_SYMBIAN
+ if (os == "SYMBIAN") result = true;
+#endif
+
+ reply["checkOS"] = result;
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::targetIdentifier(QTestMessage const&message)
+{
+ QTestMessage reply;
+ reply["targetIdentifier"] = targetId;
+ return RET(reply, "OK");
+}
+
+QTestMessage QTestSlavePrivate::setTargetIdentifier(QTestMessage const&message)
+{
+ QTestMessage reply;
+ targetId = message["targetIdentifier"];
+ return RET(reply, "OK");
+}
+
+bool QTestSlavePrivate::event(QEvent *e)
+{
+ if ((int)IdleEvent::Type != (int)e->type()) return false;
+ e->accept();
+
+ extern uint qGlobalPostedEventsCount();
+
+ static uint lastCount = 0;
+ static uint times = 0;
+
+ IdleEvent *i = static_cast<IdleEvent*>(e);
+ uint count = qGlobalPostedEventsCount();
+ if (count == lastCount) {
+ ++times;
+ } else {
+ lastCount = count;
+ times = 0;
+ }
+ if (times < 50 && count > 1) {
+ if (i->timeout == -1 || i->time.elapsed() < i->timeout) {
+ IdleEvent *new_i = new IdleEvent(*i);
+ QCoreApplication::postEvent(this, new_i, -2000);
+ }
+ } else {
+ emit applicationBecameIdle();
+ }
+
+ return true;
+}
+
+void QTestSlavePrivate::startWaitForIdle(int timeout)
+{
+ QTime now;
+ now.start();
+ IdleEvent *i = new IdleEvent(now, timeout);
+ QCoreApplication::postEvent(this, i, -2000);
+}
+
+void QTestSlavePrivate::sendBecameIdleMessage()
+{
+ QTestMessage msg("appBecameIdle");
+ msg["appName"] = QCoreApplication::applicationName();
+ p->postMessage(msg);
+}
+
+// ***********************************************************************
+
+void QTestSlavePrivate::record_entered(QObject* object, QVariant const& item)
+{
+ p->recordEvent(RecordEvent::Entered, QActiveTestWidget::instance()->friendlyName(object),
+ QActiveTestWidget::instance()->friendlyName(QTestWidgets::focusWidget()), item);
+}
+
+void QTestSlavePrivate::record_gotFocus(QObject* object)
+{
+ p->recordEvent(RecordEvent::GotFocus, QActiveTestWidget::instance()->friendlyName(object),
+ QActiveTestWidget::instance()->friendlyName(QTestWidgets::focusWidget()));
+}
+
+void QTestSlavePrivate::record_activated(QObject* object)
+{
+ p->recordEvent(RecordEvent::Activated, QActiveTestWidget::instance()->friendlyName(object),
+ QActiveTestWidget::instance()->friendlyName(QTestWidgets::focusWidget()));
+}
+
+void QTestSlavePrivate::record_selected(QObject* object, QString const& item)
+{
+ p->recordEvent(RecordEvent::Selected, QActiveTestWidget::instance()->friendlyName(object),
+ QActiveTestWidget::instance()->friendlyName(QTestWidgets::focusWidget()), item);
+}
+
+void QTestSlavePrivate::record_stateChanged(QObject* object, int state)
+{
+ p->recordEvent(RecordEvent::CheckStateChanged, QActiveTestWidget::instance()->friendlyName(object),
+ QActiveTestWidget::instance()->friendlyName(QTestWidgets::focusWidget()), state);
+}