diff options
Diffstat (limited to 'old/libqtslave/qtestslave.cpp')
-rw-r--r-- | old/libqtslave/qtestslave.cpp | 1797 |
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); +} |