summaryrefslogtreecommitdiffstats
path: root/old/libqtuitest
diff options
context:
space:
mode:
Diffstat (limited to 'old/libqtuitest')
-rw-r--r--old/libqtuitest/DESCRIPTION1
-rw-r--r--old/libqtuitest/libqtuitest.pri19
-rw-r--r--old/libqtuitest/libqtuitest.pro89
-rw-r--r--old/libqtuitest/qalternatestack_p.h90
-rw-r--r--old/libqtuitest/qalternatestack_symbian.cpp92
-rw-r--r--old/libqtuitest/qalternatestack_unix.cpp525
-rw-r--r--old/libqtuitest/qalternatestack_win.cpp210
-rw-r--r--old/libqtuitest/qeventwatcher.cpp108
-rw-r--r--old/libqtuitest/qeventwatcher_p.h100
-rw-r--r--old/libqtuitest/qinputgenerator.cpp88
-rw-r--r--old/libqtuitest/qinputgenerator_mac.cpp480
-rw-r--r--old/libqtuitest/qinputgenerator_p.h89
-rw-r--r--old/libqtuitest/qinputgenerator_qws.cpp333
-rw-r--r--old/libqtuitest/qinputgenerator_symbian.cpp425
-rw-r--r--old/libqtuitest/qinputgenerator_win.cpp496
-rw-r--r--old/libqtuitest/qinputgenerator_x11.cpp514
-rw-r--r--old/libqtuitest/qtestprotocol.cpp1162
-rw-r--r--old/libqtuitest/qtestprotocol_p.h228
-rw-r--r--old/libqtuitest/qtuitestconnectionmanager.cpp165
-rw-r--r--old/libqtuitest/qtuitestconnectionmanager_p.h84
-rw-r--r--old/libqtuitest/qtuitestelapsedtimer.cpp103
-rw-r--r--old/libqtuitest/qtuitestelapsedtimer_p.h71
-rw-r--r--old/libqtuitest/qtuitestglobal.h80
-rw-r--r--old/libqtuitest/qtuitestnamespace.cpp1085
-rw-r--r--old/libqtuitest/qtuitestnamespace.h165
-rw-r--r--old/libqtuitest/qtuitestrecorder.cpp367
-rw-r--r--old/libqtuitest/qtuitestrecorder.h83
-rw-r--r--old/libqtuitest/qtuitestwidgetinterface.cpp1102
-rw-r--r--old/libqtuitest/qtuitestwidgetinterface.h263
-rw-r--r--old/libqtuitest/qtuitestwidgets.cpp657
-rw-r--r--old/libqtuitest/qtuitestwidgets_p.h122
-rw-r--r--old/libqtuitest/recordevent_p.h135
-rw-r--r--old/libqtuitest/testwidget.cpp298
-rw-r--r--old/libqtuitest/testwidget.h105
34 files changed, 9934 insertions, 0 deletions
diff --git a/old/libqtuitest/DESCRIPTION b/old/libqtuitest/DESCRIPTION
new file mode 100644
index 0000000..289743a
--- /dev/null
+++ b/old/libqtuitest/DESCRIPTION
@@ -0,0 +1 @@
+Support library for QtUitest plugins.
diff --git a/old/libqtuitest/libqtuitest.pri b/old/libqtuitest/libqtuitest.pri
new file mode 100644
index 0000000..5d52454
--- /dev/null
+++ b/old/libqtuitest/libqtuitest.pri
@@ -0,0 +1,19 @@
+INCLUDEPATH += $$SRCROOT/libqtuitest
+
+symbian {
+ LIBS+=-L$$OUT_PWD/ -lqtuitest
+}
+
+mac {
+ CONFIG(debug,debug|release): LIBS += -L$$BUILDROOT/lib -lqtuitest_debug
+ CONFIG(release,debug|release): LIBS += -L$$BUILDROOT/lib -lqtuitest
+}
+
+win32 {
+ CONFIG(debug,debug|release): LIBS+= -L$$BUILDROOT/libqtuitest -lqtuitestd
+ CONFIG(release,debug|release):LIBS+= -L$$BUILDROOT/libqtuitest -lqtuitest
+}
+
+unix:!symbian {
+ LIBS += -L$$BUILDROOT/lib -lqtuitest
+}
diff --git a/old/libqtuitest/libqtuitest.pro b/old/libqtuitest/libqtuitest.pro
new file mode 100644
index 0000000..3f96f64
--- /dev/null
+++ b/old/libqtuitest/libqtuitest.pro
@@ -0,0 +1,89 @@
+DEFINES+=QTUITEST_TARGET
+
+enable_valgrind:DEFINES+=QTUITEST_HAVE_VALGRIND
+
+PRIVATE_HEADERS += \
+ qeventwatcher_p.h \
+ qinputgenerator_p.h \
+ qtuitestconnectionmanager_p.h \
+ qtuitestwidgets_p.h
+
+SEMI_PRIVATE_HEADERS += \
+ qalternatestack_p.h \
+ qtuitestelapsedtimer_p.h \
+ qtestprotocol_p.h \
+ recordevent_p.h
+
+HEADERS += \
+ qtuitestglobal.h \
+ qtuitestnamespace.h \
+ qtuitestrecorder.h \
+ qtuitestwidgetinterface.h \
+ testwidget.h
+
+SOURCES += \
+ qtuitestelapsedtimer.cpp \
+ qeventwatcher.cpp \
+ qinputgenerator.cpp \
+ qtestprotocol.cpp \
+ qtuitestconnectionmanager.cpp \
+ qtuitestnamespace.cpp \
+ qtuitestrecorder.cpp \
+ qtuitestwidgetinterface.cpp \
+ qtuitestwidgets.cpp \
+ testwidget.cpp
+
+unix:!symbian {
+ SOURCES+=qalternatestack_unix.cpp
+ embedded:SOURCES += qinputgenerator_qws.cpp
+ !embedded:!mac {
+ SOURCES += qinputgenerator_x11.cpp
+ LIBS += -lXtst
+ }
+ MOC_DIR=$$OUT_PWD/.moc
+ OBJECTS_DIR=$$OUT_PWD/.obj
+ DESTDIR=$$BUILDROOT/lib
+ target.path=$$[QT_INSTALL_LIBS]
+ INSTALLS+=target
+}
+
+symbian {
+ TARGET.EPOCALLOWDLLDATA=1
+ TARGET.CAPABILITY += AllFiles ReadDeviceData ReadUserData SwEvent WriteUserData NetworkServices
+ SOURCES += qalternatestack_symbian.cpp qinputgenerator_symbian.cpp
+ LIBS += -lws32
+ LIBS += -leuser -lcone
+}
+
+mac {
+ SOURCES += qinputgenerator_mac.cpp
+ LIBS += -framework ApplicationServices -framework Carbon
+}
+
+win32 {
+ SOURCES += qalternatestack_win.cpp \
+ qinputgenerator_win.cpp
+ LIBS += -luser32
+ target.path=$$[QT_INSTALL_BINS]
+ INSTALLS+=target
+}
+
+symbian {
+ MOC_DIR=$$OUT_PWD/moc
+ OBJECTS_DIR=$$OUT_PWD/obj
+ CONFIG+=staticlib
+}
+
+TEMPLATE=lib
+QT+=network
+HEADERS+=$$SEMI_PRIVATE_HEADERS $$PRIVATE_HEADERS
+VPATH+=$$PWD
+INCLUDEPATH+=$$PWD
+TARGET=qtuitest
+TARGET=$$qtLibraryTarget($$TARGET)
+CONFIG-=debug_and_release_target
+
+maemo5|maemo6 {
+ target.path=$$[QT_INSTALL_LIBS]
+ INSTALLS+=target
+}
diff --git a/old/libqtuitest/qalternatestack_p.h b/old/libqtuitest/qalternatestack_p.h
new file mode 100644
index 0000000..701c797
--- /dev/null
+++ b/old/libqtuitest/qalternatestack_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QALTERNATESTACK_P_H
+#define QALTERNATESTACK_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtUiTest API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QObject>
+#include <QVariant>
+#include <qtuitestglobal.h>
+
+class QAlternateStack;
+typedef void (*QAlternateStackEntryPoint)(QAlternateStack*,QVariant const&);
+
+struct QAlternateStackPrivate;
+
+class QTUITEST_EXPORT QAlternateStack : public QObject
+{
+ Q_OBJECT
+
+public:
+ QAlternateStack(quint32 = 65536, QObject* = 0);
+ virtual ~QAlternateStack();
+
+ bool isActive() const;
+ bool isCurrentStack() const;
+
+ static QList<QAlternateStack*> instances();
+ static bool isAvailable();
+
+public slots:
+ void start(QAlternateStackEntryPoint, const QVariant& = QVariant());
+ void switchTo();
+ void switchFrom();
+
+private:
+ QAlternateStackPrivate* d;
+ friend struct QAlternateStackPrivate;
+};
+
+#endif
+
diff --git a/old/libqtuitest/qalternatestack_symbian.cpp b/old/libqtuitest/qalternatestack_symbian.cpp
new file mode 100644
index 0000000..1fad1db
--- /dev/null
+++ b/old/libqtuitest/qalternatestack_symbian.cpp
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** 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 "qalternatestack_p.h"
+struct QAlternateStackPrivate
+{
+ // All instances of QAlternateStack.
+// static QList<QAlternateStack*> instances;
+};
+
+//QList<QAlternateStack*> QAlternateStackPrivate::instances;
+
+QAlternateStack::QAlternateStack(quint32 size, QObject* parent)
+ : QObject(parent),
+ d(new QAlternateStackPrivate)
+{
+ Q_UNUSED(size);
+ Q_UNUSED(parent);
+ qFatal("QAlternateStack: not available on this platform");
+}
+
+QAlternateStack::~QAlternateStack()
+{
+}
+
+void QAlternateStack::start(QAlternateStackEntryPoint entry, const QVariant& data)
+{
+ Q_UNUSED(entry);
+ Q_UNUSED(data);
+}
+
+void QAlternateStack::switchTo()
+{
+}
+
+void QAlternateStack::switchFrom()
+{
+}
+
+bool QAlternateStack::isActive() const
+{ return false; }
+
+bool QAlternateStack::isCurrentStack() const
+{ return false; }
+
+QList<QAlternateStack*> QAlternateStack::instances()
+{ static QList<QAlternateStack*> l;
+ return l;
+ //QAlternateStackPrivate::instances; }
+}
+
+bool QAlternateStack::isAvailable()
+{ return false; }
+
diff --git a/old/libqtuitest/qalternatestack_unix.cpp b/old/libqtuitest/qalternatestack_unix.cpp
new file mode 100644
index 0000000..016102b
--- /dev/null
+++ b/old/libqtuitest/qalternatestack_unix.cpp
@@ -0,0 +1,525 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+#undef _FORTIFY_SOURCE
+
+#include "qalternatestack_p.h"
+
+#include <errno.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include <QDebug>
+
+#ifdef QTUITEST_HAVE_VALGRIND
+# include <valgrind/valgrind.h>
+/* Make sure we have the right version of valgrind.h */
+# if !defined(VALGRIND_STACK_REGISTER) || !defined(VALGRIND_STACK_DEREGISTER) || !defined(VALGRIND_STACK_CHANGE)
+# warn You have Valgrind but are missing stack annotation macros, disabling Valgrind features.
+# undef QTUITEST_HAVE_VALGRIND
+# endif
+#endif
+
+struct QAlternateStackPrivate
+{
+ QAlternateStack* q;
+
+ // The memory containing the alternate stack.
+ QByteArray stackBuffer;
+ char* stackBegin;
+ int stackSize;
+
+#ifdef QTUITEST_HAVE_VALGRIND
+ int stackValgrindId;
+#endif
+
+ void allocate(int);
+
+ // Alternate and original stack objects.
+ stack_t alternateStack;
+ stack_t originalStack;
+
+ // Sigaction used to jump to new stack, and original sigaction.
+ struct sigaction alternateAction;
+ struct sigaction originalAction;
+
+ // jmp_buf for jumping between stacks.
+ sigjmp_buf alternateJmp;
+ sigjmp_buf originalJmp;
+
+ // Starting point of the new stack.
+ QAlternateStackEntryPoint entryFunction;
+
+ // Argument to be passed to entryFunction.
+ QVariant entryData;
+
+ // All instances of QAlternateStack.
+ static QList<QAlternateStack*> instances;
+};
+QList<QAlternateStack*> QAlternateStackPrivate::instances;
+
+QTUITEST_EXPORT char*& qalternatestack_stackbuf()
+{ static char* ret = 0; return ret; }
+QTUITEST_EXPORT int& qalternatestack_stackbuf_len()
+{ static int ret = 0; return ret; }
+
+#ifndef QT_NO_DEBUG
+QString qobject_to_string(QObject* object)
+{
+ QString ret;
+ {
+ QDebug dbg(&ret);
+ dbg << object;
+ }
+ return ret;
+}
+#endif
+
+void qt_sigaltstack(stack_t const* ss, stack_t* oss)
+{
+ if (0 != sigaltstack(ss, oss)) {
+ qFatal("QAlternateStack: error in sigaltstack: %s", strerror(errno));
+ }
+}
+
+void qt_sigaction(int signum, struct sigaction const* act, struct sigaction* oldact)
+{
+ if (0 != sigaction(signum,act,oldact)) {
+ qFatal("QAlternateStack: error in sigaction: %s", strerror(errno));
+ }
+}
+
+void qt_raise(int signum)
+{
+ if (-1 == raise(signum)) {
+ qFatal("QAlternateStack: error in raise: %s", strerror(errno));
+ }
+}
+
+QAlternateStackPrivate* qt_next_stack;
+
+static const int JMP_SWITCHFROM = 2;
+static const int JMP_SWITCHTO = 3;
+static const int JMP_FINISH = 4;
+static const int QALTERNATESTACK_SIGNAL = SIGUSR2;
+
+/*
+ This wrapper function is called when we first enter an alternate stack,
+ via the raising of QALTERNATESTACK_SIGNAL.
+*/
+void qt_entry_function_wrapper(int)
+{
+ // Establish this context into the alternate jmp_buf.
+ // We cannot have the whole stack run during a signal handler,
+ // so we store our context when we are first called, then return and allow
+ // the original stack to jump back to us.
+
+ int value = sigsetjmp(qt_next_stack->alternateJmp, 0);
+
+ // We might be here for these reasons:
+ //
+ // 1. We are handling the signal and just called setjmp.
+ // value == 0.
+ if (0 == value) {
+ // Return from the signal handler; the original stack will jump back
+ // to us via longjmp.
+ return;
+ }
+ // 2. We are switched to from the original stack.
+ // value == JMP_SWITCHTO.
+ else if (JMP_SWITCHTO == value) {
+ }
+ // Whoops, programmer error.
+ else Q_ASSERT(0);
+
+ QAlternateStackPrivate* stack = qt_next_stack;
+ stack->entryFunction(stack->q, stack->entryData);
+
+ // OK, jump back to the main stack and let it know that we're finished.
+ // We can't just return here; if we did, we'd jump back to the signal
+ // handler frame, but the signal handler is already finished.
+ siglongjmp(stack->originalJmp, JMP_FINISH);
+}
+
+/*!
+ \internal
+ \class QAlternateStack
+ \inpublicgroup QtUiTestModule
+ \brief The QAlternateStack class provides a call stack.
+
+ QAlternateStack can be used to switch between two call stacks without
+ using threads.
+
+ There is one anticipated use for this class, and that is to wait for a
+ specific amount of time, while processing events, without hanging if a
+ nested event loop occurs.
+
+ Example:
+ \code
+ void runsInAlternateStack(QAlternateStack* stack, const QVariant& data)
+ {
+ int foo = data.toInt();
+ // ...
+ // Need to wait for about 1500 milliseconds here, while processing events.
+ // Process events in the main stack to avoid hanging on nested event loops.
+ QTimer::singleShot(1500, stack, SLOT(switchTo()));
+ stack->switchFrom();
+
+ // Execution resumes here in ~1500ms, as long as the main stack is
+ // processing events, even if there was a nested event loop.
+ // ...
+
+ // Don't need the stack any more
+ stack->deleteLater();
+ }
+
+ void runsInMainStack()
+ {
+ QAlternateStack* stack = new QAlternateStack;
+ stack->start(runsInAlternateStack, 123);
+ }
+ \endcode
+
+ Using this class makes code more difficult to understand. Use an
+ alternative where possible.
+*/
+
+/*!
+ \relates QAlternateStack
+ \typedef QAlternateStackEntryPoint
+
+ Typedef for a pointer to a function with the signature
+ \c{void my_function(QAlternateStack*,const QVariant&)}.
+
+ Used as an entry point to a new stack.
+*/
+
+/*!
+ Creates an alternate stack of \a size bytes with the given \a parent.
+
+ Behavior is undefined if the alternate stack exceeds \a size.
+*/
+QAlternateStack::QAlternateStack(quint32 size, QObject* parent)
+ : QObject(parent),
+ d(new QAlternateStackPrivate)
+{
+ Q_ASSERT_X(QAlternateStack::isAvailable(), "QAlternateStack",
+ "QAlternateStack is not available on this platform!");
+
+ d->q = this;
+ d->entryFunction = 0;
+
+ d->allocate(size);
+
+#ifdef QTUITEST_HAVE_VALGRIND
+ d->stackValgrindId = VALGRIND_STACK_REGISTER(d->stackBegin, d->stackBegin+d->stackSize);
+#endif
+
+ QAlternateStackPrivate::instances << this;
+}
+
+void QAlternateStackPrivate::allocate(int size)
+{
+ if (!qalternatestack_stackbuf()) {
+ // Allocate space for the new stack.
+ stackBuffer.resize(size);
+ stackBegin = stackBuffer.data();
+ stackSize = size;
+ return;
+ }
+
+ /*
+ On some systems, it has been found that due to limitations in the kernel and/or threading
+ implementation, setting the stack pointer to point to memory allocated anywhere other than
+ the main stack causes a crash (bug 209341).
+
+ This code works around this bug by using a pool of memory which was earlier allocated on
+ the stack. qalternatestack_stackbuf() and qalternatestack_stackbuf_len() must be
+ explicitly initialized to point to a block of memory and to tell us its length.
+ */
+
+ // Find the first chunk of unused memory.
+ char* begin = qalternatestack_stackbuf();
+ char* end = qalternatestack_stackbuf() + qalternatestack_stackbuf_len();
+ char* found = 0;
+ int total_used = 0;
+
+ for (char* buf = begin; buf <= end - size && !found; buf += size) {
+ char* buf_end = buf + size;
+ // Is this block of memory definitely unused?
+ bool used = false;
+ foreach (QAlternateStack* st, QAlternateStackPrivate::instances) {
+ char* st_buf = st->d->stackBegin;
+ char* st_buf_end = st->d->stackBegin + st->d->stackSize;
+ // If we start after this stack ends, or we end before it finishes, we're OK.
+ if (buf >= st_buf_end || buf_end <= st_buf) {
+ } else {
+ used = true;
+ total_used += (st_buf_end - st_buf);
+ break;
+ }
+ }
+ if (!used) found = buf;
+ }
+
+ if (!found) {
+ qFatal( "QtUiTest: QAlternateStack ran out of memory! There seem to be %d stacks using a "
+ "total of %d bytes (out of %d), and a stack of size %d was requested. "
+ "Please increase the size of qalternatestack_stackbuf!",
+ QAlternateStackPrivate::instances.count(), total_used,
+ qalternatestack_stackbuf_len(), size);
+ }
+ stackBegin = found;
+ stackSize = size;
+}
+
+/*!
+ Destroys the alternate stack.
+
+ Behavior is undefined if the stack is destroyed while currently active.
+*/
+QAlternateStack::~QAlternateStack()
+{
+#ifdef QTUITEST_HAVE_VALGRIND
+ VALGRIND_STACK_DEREGISTER(d->stackValgrindId);
+#endif
+
+ delete d;
+ d = 0;
+ QAlternateStackPrivate::instances.removeAll(this);
+}
+
+/*!
+ Switch from the original stack to the alternate stack, and start
+ executing \a entry in the alternate stack.
+ This stack and \a data will be passed as an argument to \a entry.
+
+ This function should be called when first switching to an alternate
+ stack. When resuming a stack that is already active, use switchTo().
+
+ \sa switchTo(), switchFrom()
+*/
+void QAlternateStack::start(QAlternateStackEntryPoint entry, const QVariant& data)
+{
+ Q_ASSERT_X(!isActive(), "QAlternateStack::start",
+ qPrintable(QString("`start' called while already active. sender(): %1")
+ .arg(qobject_to_string(sender()))));
+
+ // Set up the alternate stack to be jumped to.
+ d->alternateStack.ss_sp = d->stackBegin;
+ d->alternateStack.ss_flags = 0;
+ d->alternateStack.ss_size = d->stackSize;
+ qt_sigaltstack(&d->alternateStack, &d->originalStack);
+
+ // Set up signal handler to jump to entry function wrapper in alternate stack.
+ d->alternateAction.sa_handler = qt_entry_function_wrapper;
+ sigemptyset(&d->alternateAction.sa_mask);
+ d->alternateAction.sa_flags = SA_ONSTACK;
+ qt_sigaction(QALTERNATESTACK_SIGNAL, &d->alternateAction, &d->originalAction);
+
+ // Raise the signal, jumping to the alternate stack.
+ qt_next_stack = d;
+ qt_raise(QALTERNATESTACK_SIGNAL);
+
+ // signal handler returns immediately after storing its context into
+ // alternateJmp. Restore the old signal handler.
+ qt_sigaltstack(&d->originalStack, 0);
+ qt_sigaction(QALTERNATESTACK_SIGNAL, &d->originalAction, 0);
+
+ // OK, now store the entry function and data and jump to the new stack.
+ d->entryFunction = entry;
+ d->entryData = data;
+
+ switchTo();
+}
+
+/*!
+ Switch from the original stack to the alternate stack.
+
+ This function can be called to resume execution in an alternate stack.
+
+ If execution has been suspended in the alternate stack by a call to
+ switchFrom(), switchTo() will resume executing at that point.
+ If the alternate stack has completed execution or hasn't started, this
+ function does nothing and returns immediately.
+
+ It is an error to call this function from the alternate stack.
+*/
+void QAlternateStack::switchTo()
+{
+ // We must not be the currently active stack.
+ Q_ASSERT_X(!isCurrentStack(), "QAlternateStack::switchTo",
+ qPrintable(QString("`switchTo' called in currently active stack. sender(): %1")
+ .arg(qobject_to_string(sender()))));
+
+ // Store where we currently are.
+ int value = sigsetjmp(d->originalJmp, 1);
+
+ // Now it really gets tricky.
+ // At this particular point, we could be here for these reasons:
+ //
+ // 1. switchTo() was actually called from the original stack
+ // and we just returned from setjmp.
+ // value == 0.
+ //
+ // 2. The alternate stack switched to the original stack
+ // by calling switchFrom().
+ // value == JMP_SWITCHFROM.
+ //
+ // 3. The alternate stack finished execution and jumped back to us.
+ // value == JMP_FINISH.
+
+ // Case 1: just returned from setjmp.
+ // Jump to the other stack.
+ if (0 == value) {
+ // If there is no entry function, that means `start' has not been called or we have
+ // finished already. In other words, there's no more to process on this stack, so
+ // just return immediately.
+ if (!d->entryFunction) return;
+
+ // This function never returns; from here we will jump back to
+ // the above call to setjmp() via case 2 or 3.
+ siglongjmp(d->alternateJmp, JMP_SWITCHTO);
+ }
+
+ // Case 2: switchFrom() called in alternate stack.
+ if (value == JMP_SWITCHFROM) {
+ // Don't need to do anything, just return.
+ return;
+ }
+
+ // Case 3: The alternate stack finished execution.
+ // Just need to do a little cleanup.
+ if (value == JMP_FINISH) {
+ d->entryFunction = 0;
+ d->entryData = QVariant();
+ return;
+ }
+
+ // Whoops, bad programmer.
+ Q_ASSERT(0);
+}
+
+/*!
+ Switch from the alternate stack to the original stack.
+
+ Once execution takes place in the alternate stack, there are two ways
+ to return to the original stack.
+
+ The first is simply to return from the entry function passed to the
+ constructor, at which point the switchTo() function in the original
+ stack will return.
+
+ The second is to call switchFrom(). This will cause the switchTo()
+ function to return in the original stack. switchFrom() will not
+ return until switchTo() is called again in the original stack, which
+ is not guaranteed to happen.
+
+ It is an error to call this function from the original stack.
+*/
+void QAlternateStack::switchFrom()
+{
+ // We must be the currently active stack.
+ Q_ASSERT_X(isCurrentStack(), "QAlternateStack::switchFrom",
+ qPrintable(QString("`switchFrom' called from wrong stack. sender(): %1")
+ .arg(qobject_to_string(sender()))));
+
+ int value = sigsetjmp(d->alternateJmp, 1);
+
+ // Two possibilities:
+ //
+ // 1. We just called setjmp and will now jump to main stack.
+ // value == 0
+ if (0 == value) {
+ siglongjmp(d->originalJmp, JMP_SWITCHFROM);
+ }
+ // 2. We just jumped to here from main stack.
+ // value == JMP_SWITCHTO
+ else if (JMP_SWITCHTO == value) {
+ }
+ // Whoops, bad programmer.
+ else Q_ASSERT(0);
+}
+
+/*!
+ Returns true if the stack has started (entry function has been called)
+ and not yet finished (entry function has not returned).
+
+ \sa isCurrentStack()
+*/
+bool QAlternateStack::isActive() const
+{ return d->entryFunction; }
+
+/*!
+ Returns true if the currently used stack is this QAlternateStack.
+
+ \sa isActive()
+*/
+bool QAlternateStack::isCurrentStack() const
+{
+ // Test if a stack-allocated variable resides within the alternate
+ // stack buffer.
+ char dummy = 1;
+ quint32 diff = &dummy - d->stackBegin;
+ return (diff < (quint32)d->stackSize);
+}
+
+/*!
+ Returns all created QAlternateStack objects.
+*/
+QList<QAlternateStack*> QAlternateStack::instances()
+{ return QAlternateStackPrivate::instances; }
+
+/*!
+ Returns true if QAlternateStack is usable on this platform.
+
+ Usage of QAlternateStack when this function returns false will typically
+ result in a fatal error at runtime.
+*/
+bool QAlternateStack::isAvailable()
+{
+#ifdef Q_OS_MAC
+ return false;
+#endif
+ return true;
+}
+
diff --git a/old/libqtuitest/qalternatestack_win.cpp b/old/libqtuitest/qalternatestack_win.cpp
new file mode 100644
index 0000000..e0e600e
--- /dev/null
+++ b/old/libqtuitest/qalternatestack_win.cpp
@@ -0,0 +1,210 @@
+/****************************************************************************
+**
+** 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 "qalternatestack_p.h"
+
+#include <QCoreApplication>
+#include <QThread>
+
+#include <windows.h>
+
+struct QAlternateStackPrivate
+{
+ // All instances of QAlternateStack.
+ static QList<QAlternateStack*> instances;
+
+ // Callback used to start each fiber.
+ static void CALLBACK startFiber(PVOID);
+
+ static LPVOID mainFiber;
+
+ QAlternateStackEntryPoint entryFunction;
+ QVariant entryData;
+ quint32 size;
+
+ LPVOID fiber;
+};
+QList<QAlternateStack*> QAlternateStackPrivate::instances;
+LPVOID QAlternateStackPrivate::mainFiber = 0;
+
+/*
+ Given a Windows error code, return a C string with the corresponding error text.
+ The returned pointer points to static storage, hence this function is not thread safe.
+*/
+const char* qstrwinerror(DWORD errorcode)
+{
+ static char out[256];
+ DWORD ok = FormatMessageA(
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ 0,
+ errorcode,
+ 0,
+ out,
+ sizeof(out)/sizeof(TCHAR),
+ 0
+ );
+ if (!ok) {
+ QByteArray realError = QByteArray::number((int)errorcode);
+ QByteArray nextError = QByteArray::number((int)GetLastError());
+ QByteArray outString = "(error ";
+ outString += realError;
+ outString += "; additionally, error ";
+ outString += nextError;
+ outString += " while looking up error string)";
+ qstrncpy(out, outString.constData(), sizeof(out));
+ }
+ return out;
+}
+
+void CALLBACK QAlternateStackPrivate::startFiber(PVOID _q)
+{
+ QAlternateStack* q = static_cast<QAlternateStack*>(_q);
+ QAlternateStackPrivate* d = q->d;
+
+ d->entryFunction(q, d->entryData);
+
+ /* Setting entryFunction to 0 tells main fiber we are done */
+ d->entryFunction = 0;
+ d->entryData = QVariant();
+
+ q->switchFrom();
+}
+
+QAlternateStack::QAlternateStack(quint32 size, QObject* parent)
+ : QObject(parent),
+ d(new QAlternateStackPrivate)
+{
+ Q_ASSERT_X(QAlternateStack::isAvailable(), "QAlternateStack",
+ "QAlternateStack is not available on this platform!");
+
+ /*
+ Make sure we belong to the main thread to avoid keeping track of whether each thread has
+ been converted to a fiber.
+ */
+ Q_ASSERT_X(QThread::currentThread() == QCoreApplication::instance()->thread(),
+ "QAlternateStack", "Alternate stacks must be created in the main thread!");
+
+ /*
+ The main thread must be a fiber before we can manage any other fibers.
+ Unfortunately, earlier than Windows Vista, it is not possible to test if a thread is
+ a fiber. So it is possible ConvertThreadToFiber will be called more than once for
+ the main thread.
+ */
+ if (!QAlternateStackPrivate::mainFiber) {
+ QAlternateStackPrivate::mainFiber = ConvertThreadToFiber(0);
+ if (!QAlternateStackPrivate::mainFiber) {
+ qFatal("QAlternateStack: failed to convert thread to fiber: %s",
+ qstrwinerror(GetLastError()));
+ }
+ }
+
+ d->entryFunction = 0;
+ d->size = size;
+ d->fiber = 0;
+
+ QAlternateStackPrivate::instances << this;
+}
+
+QAlternateStack::~QAlternateStack()
+{
+ delete d;
+ d = 0;
+ QAlternateStackPrivate::instances.removeAll(this);
+}
+
+void QAlternateStack::start(QAlternateStackEntryPoint entry, const QVariant& data)
+{
+ Q_ASSERT_X(!isActive(), "QAlternateStack::start",
+ qPrintable(QString("`start' called while already active.")));
+
+ d->fiber = CreateFiber(d->size, QAlternateStackPrivate::startFiber, this);
+ if (!d->fiber) {
+ qFatal("QAlternateStack: failed to create fiber: %s", qstrwinerror(GetLastError()));
+ }
+
+ d->entryFunction = entry;
+ d->entryData = data;
+ SwitchToFiber(d->fiber);
+
+ if (!d->entryFunction) {
+ DeleteFiber(d->fiber);
+ d->fiber = 0;
+ }
+}
+
+void QAlternateStack::switchTo()
+{
+ // We must not be the currently active stack.
+ Q_ASSERT_X(!isCurrentStack(), "QAlternateStack::switchTo",
+ qPrintable(QString("`switchTo' called in currently active stack.")));
+
+ // If not active, nothing to do
+ if (!isActive()) return;
+
+ SwitchToFiber(d->fiber);
+
+ if (!d->entryFunction) {
+ DeleteFiber(d->fiber);
+ d->fiber = 0;
+ }
+}
+
+void QAlternateStack::switchFrom()
+{
+ // We must be the currently active stack.
+ Q_ASSERT_X(isCurrentStack(), "QAlternateStack::switchFrom",
+ qPrintable(QString("`switchFrom' called from wrong stack.")));
+
+ SwitchToFiber(QAlternateStackPrivate::mainFiber);
+}
+
+bool QAlternateStack::isActive() const
+{ return d->fiber; }
+
+bool QAlternateStack::isCurrentStack() const
+{ return GetFiberData() == this; }
+
+QList<QAlternateStack*> QAlternateStack::instances()
+{ return QAlternateStackPrivate::instances; }
+
+bool QAlternateStack::isAvailable()
+{ return true; }
+
diff --git a/old/libqtuitest/qeventwatcher.cpp b/old/libqtuitest/qeventwatcher.cpp
new file mode 100644
index 0000000..938c2a4
--- /dev/null
+++ b/old/libqtuitest/qeventwatcher.cpp
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** 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 "qeventwatcher_p.h"
+
+#include <QSet>
+#include <QPointer>
+#include <QCoreApplication>
+
+struct QEventWatcherPrivate
+{
+ QSet<QObject*> objects;
+ QList<QEventWatcherFilter*> filters;
+ int count;
+};
+
+QEventWatcher::QEventWatcher(QObject* parent)
+ : QObject(parent),
+ d(new QEventWatcherPrivate)
+{
+ d->count = 0;
+}
+
+QEventWatcher::~QEventWatcher()
+{
+ qDeleteAll(d->filters);
+ delete d;
+ d = 0;
+}
+
+void QEventWatcher::addObject(QObject* obj)
+{
+ d->objects << obj;
+ qApp->installEventFilter(this);
+}
+
+void QEventWatcher::addFilter(QEventWatcherFilter* filter)
+{ d->filters << filter; }
+
+int QEventWatcher::count() const
+{ return d->count; }
+
+QString QEventWatcher::toString() const
+{
+ QString ret;
+ QString sep;
+ for (int i = d->filters.count()-1; i >= 0; --i) {
+ ret += sep + d->filters.at(i)->toString();
+ sep = ", ";
+ }
+ return ret;
+}
+
+bool QEventWatcher::eventFilter(QObject* obj, QEvent* e)
+{
+ if (!d->objects.contains(obj)) return false;
+
+ bool accept = (d->filters.count() ? false : true);
+ for (int i = d->filters.count()-1; i >= 0 && !accept; --i) {
+ accept = d->filters.at(i)->accept(obj,e);
+ }
+
+ if (accept) {
+ ++d->count;
+ emit event(obj, e->type());
+ }
+
+ return false;
+}
+
diff --git a/old/libqtuitest/qeventwatcher_p.h b/old/libqtuitest/qeventwatcher_p.h
new file mode 100644
index 0000000..96b941b
--- /dev/null
+++ b/old/libqtuitest/qeventwatcher_p.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QEVENTWATCHER_H
+#define QEVENTWATCHER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtUiTest API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QObject>
+#include <QEvent>
+
+struct QEventWatcherPrivate;
+class QEventWatcherFilter;
+
+class QEventWatcher : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit QEventWatcher(QObject* parent =0);
+ virtual ~QEventWatcher();
+
+ void addObject(QObject*);
+ void addFilter(QEventWatcherFilter*);
+
+ int count() const;
+
+ QString toString() const;
+
+signals:
+ void event(QObject*,int);
+
+protected:
+ bool eventFilter(QObject *obj, QEvent *event);
+
+private:
+ QEventWatcherPrivate* d;
+};
+
+class QEventWatcherFilter
+{
+public:
+ virtual ~QEventWatcherFilter() {}
+
+protected:
+ virtual bool accept(QObject*,QEvent*) const =0;
+ virtual QString toString() const =0;
+
+ friend class QEventWatcher;
+};
+
+#endif
+
diff --git a/old/libqtuitest/qinputgenerator.cpp b/old/libqtuitest/qinputgenerator.cpp
new file mode 100644
index 0000000..aa4b091
--- /dev/null
+++ b/old/libqtuitest/qinputgenerator.cpp
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** 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 "qinputgenerator_p.h"
+
+#include <QApplication>
+#include <QPoint>
+#include <QWidget>
+
+#define QINPUTGENERATOR_DEBUG() if (1); else qDebug() << "QInputGenerator:"
+
+Qt::KeyboardModifier const QInputGenerator::AllModifiers[] =
+ { Qt::ShiftModifier, Qt::ControlModifier, Qt::AltModifier, Qt::MetaModifier };
+
+/*
+ Given a co-ordinate relative to the application's currently active window,
+ maps it to this input generator's co-ordinate system.
+*/
+QPoint QInputGenerator::mapFromActiveWindow(QPoint const& pos) const
+{
+ QPoint ret(pos);
+
+ QWidget *w = QApplication::activeWindow();
+ if (!w) w = QApplication::activePopupWidget();
+ if (!w) w = QApplication::activeModalWidget();
+
+ if (w) {
+ ret = w->mapToGlobal(pos);
+ }
+
+ return ret;
+}
+
+Qt::Key QInputGenerator::modifierToKey(Qt::KeyboardModifier mod)
+{
+ switch (mod) {
+ case Qt::ShiftModifier:
+ return Qt::Key_Shift;
+ case Qt::ControlModifier:
+ return Qt::Key_Control;
+ case Qt::AltModifier:
+ return Qt::Key_Alt;
+ case Qt::MetaModifier:
+ return Qt::Key_Meta;
+ default:
+ break;
+ }
+ return Qt::Key(0);
+}
+
diff --git a/old/libqtuitest/qinputgenerator_mac.cpp b/old/libqtuitest/qinputgenerator_mac.cpp
new file mode 100644
index 0000000..a4adaab
--- /dev/null
+++ b/old/libqtuitest/qinputgenerator_mac.cpp
@@ -0,0 +1,480 @@
+/****************************************************************************
+**
+** 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 "qinputgenerator_p.h"
+
+#include <QtCore>
+#include <QtGui>
+
+#include <ApplicationServices/ApplicationServices.h>
+#include <Carbon/Carbon.h>
+
+#include "qtuitestnamespace.h"
+#include "private/qcore_mac_p.h"
+
+#define QINPUTGENERATOR_DEBUG() if (1); else qDebug() << "QInputGenerator:"
+
+QMap<int,QPair<int,Qt::KeyboardModifiers> > qt_key_to_mac_keycode_make()
+{
+ QMap<int,QPair<int,Qt::KeyboardModifiers> > m;
+
+ static UInt32 deadKeyState = 0L;
+ const UCKeyboardLayout *keyLayout = 0;
+
+#if defined(Q_OS_MAC32)
+ KeyboardLayoutRef keyLayoutRef = 0;
+ KLGetCurrentKeyboardLayout(&keyLayoutRef);
+ OSStatus err;
+ if (keyLayoutRef != 0) {
+ err = KLGetKeyboardLayoutProperty(keyLayoutRef, kKLuchrData,
+ (reinterpret_cast<const void **>(&keyLayout)));
+ if (err != noErr) {
+ qWarning("Qt::internal::unable to get keyboardlayout %ld %s:%d",
+ long(err), __FILE__, __LINE__);
+ }
+ }
+#else
+ QCFType<TISInputSourceRef> inputSource = TISCopyCurrentKeyboardInputSource();
+ Q_ASSERT(inputSource != 0);
+ CFDataRef data = static_cast<CFDataRef>(TISGetInputSourceProperty(inputSource,
+ kTISPropertyUnicodeKeyLayoutData));
+ keyLayout = data ? reinterpret_cast<const UCKeyboardLayout *>(CFDataGetBytePtr(data)) : 0;
+#endif
+
+ if (keyLayout) {
+ UniChar string[4];
+ UniCharCount actualLength;
+
+ for (UInt32 keyCode = 0; keyCode < 128; ++keyCode) {
+ if (noErr == UCKeyTranslate(keyLayout, keyCode, kUCKeyActionDisplay, 0, LMGetKbdType(),
+ kUCKeyTranslateNoDeadKeysMask, &deadKeyState, 4, &actualLength, string))
+ m.insert(int(string[0]), qMakePair(int(keyCode), Qt::KeyboardModifiers(Qt::NoModifier)));
+ if (noErr == UCKeyTranslate(keyLayout, keyCode, kUCKeyActionDisplay, ((shiftKey >> 8) & 0xff), LMGetKbdType(),
+ kUCKeyTranslateNoDeadKeysMask, &deadKeyState, 4, &actualLength, string))
+ m.insert(int(string[0]), qMakePair(int(keyCode), Qt::KeyboardModifiers(Qt::ShiftModifier)));
+ }
+ }
+#ifdef Q_OS_MAC32
+ else {
+ const void *keyboard_layout;
+ KeyboardLayoutRef keyLayoutRef = 0;
+ KLGetCurrentKeyboardLayout(&keyLayoutRef);
+ err = KLGetKeyboardLayoutProperty(keyLayoutRef, kKLKCHRData,
+ reinterpret_cast<const void **>(&keyboard_layout));
+
+ for (UInt32 keyCode = 0; keyCode < 128; ++keyCode) {
+ int translatedChar = KeyTranslate(keyboard_layout, keyCode, &deadKeyState);
+ if (translatedChar >= Qt::Key_Space && translatedChar <= Qt::Key_AsciiTilde) {
+ m.insert(translatedChar, qMakePair(int(keyCode), Qt::KeyboardModifiers(Qt::NoModifier)));
+ }
+ translatedChar = KeyTranslate(keyboard_layout, keyCode | shiftKey, &deadKeyState);
+ if (translatedChar >= Qt::Key_Space && translatedChar <= Qt::Key_AsciiTilde) {
+ m.insert(translatedChar, qMakePair(int(keyCode), Qt::KeyboardModifiers(Qt::ShiftModifier)));
+ }
+
+ }
+ }
+#endif
+
+ m.insert( Qt::Key_Escape, qMakePair(53, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_Tab, qMakePair(48, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_Backspace, qMakePair(51, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_Return, qMakePair(36, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_Enter, qMakePair(76, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_Insert, qMakePair(114, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_Delete, qMakePair(117, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_Print, qMakePair(105, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_Space, qMakePair(49, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_PageUp, qMakePair(116, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_PageDown, qMakePair(121, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_End, qMakePair(119, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_Home, qMakePair(115, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_Left, qMakePair(123, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_Up, qMakePair(126, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_Right, qMakePair(124, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_Down, qMakePair(125, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_CapsLock, qMakePair(57, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_NumLock, qMakePair(71, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_F1, qMakePair(122, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_F2, qMakePair(120, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_F3, qMakePair(99, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_F4, qMakePair(118, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_F5, qMakePair(96, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_F6, qMakePair(97, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_F7, qMakePair(98, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_F8, qMakePair(100, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_F9, qMakePair(101, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_F10, qMakePair(109, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_F11, qMakePair(103, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_F12, qMakePair(111, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_F13, qMakePair(105, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_F14, qMakePair(107, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_F15, qMakePair(113, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_Menu, qMakePair(110, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_Help, qMakePair(114, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_division, qMakePair(75, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_multiply, qMakePair(67, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_Minus, qMakePair(78, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_Plus, qMakePair(69, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_Period, qMakePair(65, Qt::KeyboardModifiers(Qt::NoModifier)) );
+
+ // Modifiers
+ m.insert( Qt::ShiftModifier, qMakePair(56, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_Shift, qMakePair(56, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::ControlModifier, qMakePair(55, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_Control, qMakePair(55, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::AltModifier, qMakePair(58, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_Alt, qMakePair(58, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::MetaModifier, qMakePair(59, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_Meta, qMakePair(55, Qt::KeyboardModifiers(Qt::NoModifier)) );
+ m.insert( Qt::Key_CapsLock, qMakePair(57, Qt::KeyboardModifiers(Qt::NoModifier)) );
+
+ return m;
+}
+
+QMap<int,uint> qt_button_to_mac_button_down_make()
+{
+ QMap<int,uint> m;
+
+ m.insert( Qt::LeftButton, kCGEventLeftMouseDown );
+ m.insert( Qt::MidButton, kCGEventOtherMouseDown );
+ m.insert( Qt::RightButton, kCGEventRightMouseDown );
+ return m;
+}
+
+QMap<int,uint> qt_button_to_mac_button_up_make()
+{
+ QMap<int,uint> m;
+
+ m.insert( Qt::LeftButton, kCGEventLeftMouseUp );
+ m.insert( Qt::MidButton, kCGEventOtherMouseUp );
+ m.insert( Qt::RightButton, kCGEventRightMouseUp );
+ return m;
+}
+
+QMap<int,uint> qt_button_to_mac_button_drag_make()
+{
+ QMap<int,uint> m;
+
+ m.insert( Qt::LeftButton, kCGEventLeftMouseDragged );
+ m.insert( Qt::MidButton, kCGEventOtherMouseDragged );
+ m.insert( Qt::RightButton, kCGEventRightMouseDragged );
+ return m;
+}
+
+QMap<int,uint> qt_button_to_mac_button_make()
+{
+ QMap<int,uint> m;
+
+ m.insert( Qt::LeftButton, kCGMouseButtonLeft );
+ m.insert( Qt::MidButton, kCGMouseButtonCenter );
+ m.insert( Qt::RightButton, kCGMouseButtonRight );
+ return m;
+}
+
+class QInputGeneratorPrivate
+{
+public:
+ QInputGeneratorPrivate();
+ QInputGenerator* q;
+
+ void keyEvent(Qt::Key, bool);
+ void mouseEvent(QPoint const&, Qt::MouseButtons);
+
+ void ensureModifiers(Qt::KeyboardModifiers);
+ Qt::KeyboardModifiers currentModifiers() const;
+
+ QMap<int,QPair<int,Qt::KeyboardModifiers> > const keyMap;
+ QMap<int,uint> const buttonMap;
+ QMap<int,uint> const buttonDownMap;
+ QMap<int,uint> const buttonUpMap;
+ QMap<int,uint> const buttonDragMap;
+
+ QPoint currentPos;
+ Qt::MouseButtons currentButtons;
+};
+
+QInputGeneratorPrivate::QInputGeneratorPrivate()
+ : keyMap(qt_key_to_mac_keycode_make()),
+ buttonMap(qt_button_to_mac_button_make()),
+ buttonDownMap(qt_button_to_mac_button_down_make()),
+ buttonUpMap(qt_button_to_mac_button_up_make()),
+ buttonDragMap(qt_button_to_mac_button_drag_make()),
+ currentPos(),
+ currentButtons(0)
+{
+ //Following line is workaround for a bug in Tiger...
+ CFRelease(CGEventCreate(NULL));
+}
+
+QInputGenerator::QInputGenerator(QObject* parent)
+ : QObject(parent),
+ d(new QInputGeneratorPrivate)
+{
+ d->q = this;
+ QINPUTGENERATOR_DEBUG() << "constructor";
+}
+
+QInputGenerator::~QInputGenerator()
+{
+ QINPUTGENERATOR_DEBUG() << "destructor";
+
+ /*
+ Restore all keyboard modifiers to off.
+ If we don't do this, the current modifiers stay activated
+ even when this application is closed.
+ Note that there is no guarantee this code actually gets run.
+ */
+ d->ensureModifiers(0);
+ if (d->currentButtons) {
+ d->mouseEvent(d->currentPos, 0);
+ }
+
+ d->q = 0;
+ delete d;
+ d = 0;
+}
+
+/*
+ Returns the Qt keyboard modifiers which are currently pressed.
+*/
+Qt::KeyboardModifiers QInputGeneratorPrivate::currentModifiers() const
+{
+ quint32 modifiers = GetCurrentKeyModifiers();
+
+ int state = 0;
+ state |= (modifiers & shiftKey ? Qt::ShiftModifier : Qt::NoModifier);
+ state |= (modifiers & controlKey ? Qt::ControlModifier : Qt::NoModifier);
+ state |= (modifiers & optionKey ? Qt::AltModifier : Qt::NoModifier);
+ state |= (modifiers & cmdKey ? Qt::MetaModifier : Qt::NoModifier);
+
+ return Qt::KeyboardModifier(state);
+}
+
+void QInputGeneratorPrivate::ensureModifiers(Qt::KeyboardModifiers desiredMod)
+{
+ Qt::KeyboardModifiers currentMod = currentModifiers();
+
+ // For each modifier..
+ for (unsigned i = 0; i < sizeof(q->AllModifiers)/sizeof(Qt::KeyboardModifier); ++i) {
+ Qt::KeyboardModifier thisMod = q->AllModifiers[i];
+ // If the modifier is currently disabled but we want it enabled, or vice-versa...
+ if ((desiredMod & thisMod) && !(currentMod & thisMod)) {
+ QINPUTGENERATOR_DEBUG() << "Enabling modifier" << (void*)thisMod << "by press";
+ // press to enable
+ keyEvent(q->modifierToKey(thisMod), true);
+ } else if (!(desiredMod & thisMod) && (currentMod & thisMod)) {
+ QINPUTGENERATOR_DEBUG() << "Disabling modifier" << (void*)thisMod << "by release";
+ // release to disable
+ keyEvent(q->modifierToKey(thisMod), false);
+ }
+ }
+
+ if (currentMod != desiredMod) {
+ currentMod = desiredMod;
+ for (int i = 0;
+ i < 1000 && QApplication::keyboardModifiers() & Qt::KeypadModifier != desiredMod & Qt::KeypadModifier;
+ i += 50, QtUiTest::wait(50))
+ {}
+
+ if (QApplication::keyboardModifiers() & Qt::KeypadModifier != desiredMod & Qt::KeypadModifier)
+ qWarning() << "QtUitest: couldn't set all modifiers to desired state! "
+ "Current state:" << (void*)(int)QApplication::keyboardModifiers() <<
+ "Desired:" << (void*)(int)desiredMod;
+ }
+
+}
+
+void QInputGeneratorPrivate::keyEvent(Qt::Key key, bool is_press)
+{
+ int sym = 0;
+ Qt::KeyboardModifiers modifiers = Qt::KeyboardModifiers(Qt::NoModifier);
+ do {
+ QMap<int,QPair<int,Qt::KeyboardModifiers> >::const_iterator found = keyMap.find(key);
+ if (found != keyMap.end()) {
+ sym = (*found).first;
+ if (key < Qt::Key_A || key > Qt::Key_Z)
+ modifiers = (*found).second;
+ break;
+ }
+
+ qWarning() << "QInputGenerator: don't know how to translate Qt key"
+ << (void*)key << "into Mac keycode";
+ return;
+
+ } while(0);
+
+ if (modifiers) {
+ ensureModifiers(modifiers);
+ }
+
+ //TODO: CGPostKeyboardEvent is deprecated in Snow Leopard, however the alternative (using CGEventPost)
+ // does not work as reliably (at least on Tiger/PPC). Further investigation required.
+ CGPostKeyboardEvent(0, (CGKeyCode)sym, is_press);
+
+#if 0
+ CGEventRef event = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)sym, is_press);
+ CGEventPost(kCGHIDEventTap, event);
+ CFRelease(event);
+#endif
+
+ QINPUTGENERATOR_DEBUG() << (is_press ? "press" : "release") << sym;
+}
+
+void QInputGenerator::keyPress(Qt::Key key, Qt::KeyboardModifiers mod, bool autoRepeat)
+{
+ Q_UNUSED(autoRepeat);
+ d->ensureModifiers(mod);
+ d->keyEvent(key, true);
+ QtUiTest::wait(1);
+}
+
+void QInputGenerator::keyRelease(Qt::Key key, Qt::KeyboardModifiers mod)
+{
+ d->ensureModifiers(mod);
+ d->keyEvent(key, false);
+ QtUiTest::wait(1);
+}
+
+void QInputGenerator::keyClick(Qt::Key key, Qt::KeyboardModifiers mod)
+{
+ keyPress(key,mod);
+ QtUiTest::wait(20);
+ keyRelease(key,mod);
+}
+
+void QInputGeneratorPrivate::mouseEvent(QPoint const& pos, Qt::MouseButtons state)
+{
+ CGPoint p;
+ p.x = (float)(pos.x());
+ p.y = (float)(pos.y());
+
+ ProcessSerialNumber psn;
+ GetCurrentProcess(&psn);
+
+ //TODO: CGPostMouseEvent is deprecated in Snow Leopard, however the alternative (using CGEventPost)
+ // does not work as reliably (at least on Tiger/PPC). Further investigation required.
+ CGPostMouseEvent(p, true, 3, Qt::LeftButton & state, Qt::RightButton & state, Qt::MidButton & state);
+
+#if 0
+ if (currentPos != pos) {
+ currentPos = pos;
+ QINPUTGENERATOR_DEBUG() << "Mouse is at: " << QCursor::pos();
+
+ CGEventType eventType = kCGEventMouseMoved;
+ CGEventRef eventRef = CGEventCreateMouseEvent(NULL, eventType, p, kCGMouseButtonLeft);
+ //This shouldn't be necessary, but it is...
+ CGEventSetType(eventRef, eventType);
+ CGEventPostToPSN(&psn, eventRef);
+ CFRelease(eventRef);
+
+ for (int i = 0;
+ i < 1000 && QCursor::pos() != pos;
+ i += 50, QtUiTest::wait(50))
+ {}
+
+ QINPUTGENERATOR_DEBUG() << "Mouse is now at: " << QCursor::pos();
+
+ if (QCursor::pos() != pos)
+ qWarning() << "QtUitest: couldn't move cursor to desired point! "
+ "Current position:" << QCursor::pos() <<
+ "Desired:" << pos;
+ }
+
+ typedef QPair<uint,uint> ButtonEvent;
+ QList<ButtonEvent> buttonEvents;
+
+ foreach (int button, buttonMap.keys()) {
+ bool desired = button & state;
+ bool current = button & currentButtons;
+
+ // Do we need to release?
+ if (!desired && current) {
+ buttonEvents << qMakePair(buttonUpMap[button], buttonMap[button]);
+ QINPUTGENERATOR_DEBUG() << "releasing " << buttonMap[button];
+ }
+
+ // Do we need to press?
+ if (desired && !current) {
+ buttonEvents << qMakePair(buttonDownMap[button], buttonMap[button]);
+ QINPUTGENERATOR_DEBUG() << "pressing " << buttonMap[button];
+ }
+
+ // Do we need to drag? Is this necessary?
+ if (desired && current) {
+ buttonEvents << qMakePair(buttonDragMap[button], buttonMap[button]);
+ QINPUTGENERATOR_DEBUG() << "dragging " << buttonMap[button];
+ }
+ }
+
+ foreach (ButtonEvent const& event, buttonEvents) {
+ CGEventType eventType = event.first;
+ QINPUTGENERATOR_DEBUG() << "posting Quartz event " << eventType << ", " << event.second;
+ CGEventRef eventRef = CGEventCreateMouseEvent(NULL, eventType, p, event.second);
+ CGEventSetType(eventRef, eventType);
+ CGEventPostToPSN(&psn, eventRef);
+ CFRelease(eventRef);
+ }
+#endif
+
+ currentButtons = state;
+}
+
+void QInputGenerator::mousePress(QPoint const& pos, Qt::MouseButtons state)
+{
+ QINPUTGENERATOR_DEBUG() << "Mouse press" << pos << (void*)(int)state;
+ d->mouseEvent(pos, d->currentButtons | state);
+}
+
+void QInputGenerator::mouseRelease(QPoint const& pos, Qt::MouseButtons state)
+{
+ QINPUTGENERATOR_DEBUG() << "Mouse release" << pos << (void*)(int)(d->currentButtons & ~state);
+ d->mouseEvent(pos, d->currentButtons & ~state);
+}
+
+void QInputGenerator::mouseClick(QPoint const& pos, Qt::MouseButtons state)
+{
+ mousePress (pos,state);
+ QtUiTest::wait(1);
+ mouseRelease(pos,state);
+ QtUiTest::wait(1);
+}
+
diff --git a/old/libqtuitest/qinputgenerator_p.h b/old/libqtuitest/qinputgenerator_p.h
new file mode 100644
index 0000000..c18bde6
--- /dev/null
+++ b/old/libqtuitest/qinputgenerator_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QKEYGENERATOR_P_H
+#define QKEYGENERATOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtUiTest API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGlobal>
+#include <QObject>
+#include <qtuitestglobal.h>
+
+class QPoint;
+class QInputGeneratorPrivate;
+
+class QTUITEST_EXPORT QInputGenerator : public QObject
+{
+Q_OBJECT
+public:
+ explicit QInputGenerator(QObject* =0);
+ virtual ~QInputGenerator();
+
+ void keyPress (Qt::Key, Qt::KeyboardModifiers, bool=false);
+ void keyRelease(Qt::Key, Qt::KeyboardModifiers);
+ void keyClick (Qt::Key, Qt::KeyboardModifiers);
+
+ void mousePress (QPoint const&, Qt::MouseButtons);
+ void mouseRelease(QPoint const&, Qt::MouseButtons);
+ void mouseClick (QPoint const&, Qt::MouseButtons);
+
+ QPoint mapFromActiveWindow(QPoint const&) const;
+
+private:
+ QInputGeneratorPrivate* d;
+ friend class QInputGeneratorPrivate;
+
+ static Qt::Key modifierToKey(Qt::KeyboardModifier);
+ static Qt::KeyboardModifier const AllModifiers[4];
+};
+
+#endif
+
diff --git a/old/libqtuitest/qinputgenerator_qws.cpp b/old/libqtuitest/qinputgenerator_qws.cpp
new file mode 100644
index 0000000..657f34e
--- /dev/null
+++ b/old/libqtuitest/qinputgenerator_qws.cpp
@@ -0,0 +1,333 @@
+/****************************************************************************
+**
+** 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 "qinputgenerator_p.h"
+
+#include <QCopChannel>
+#include <QDebug>
+#include <QKeySequence>
+#include <QScreen>
+#include <QWSServer>
+#include <QWidget>
+
+#include "qtuitestnamespace.h"
+
+#ifdef QTOPIA_TARGET
+# include <qtopialog.h>
+# define QINPUTGENERATOR_DEBUG() qLog(QtUitest)
+#else
+# define QINPUTGENERATOR_DEBUG() if (1); else qDebug() << "QInputGenerator:"
+#endif
+
+#define QINPUTGENERATOR_QCOP "QtUiTest/QInputGenerator"
+#define QINPUTGENERATOR_QCOP_KEYEVENT "keyEvent(int,int,int,bool)"
+#define QINPUTGENERATOR_QCOP_VERSION QDataStream::Qt_4_0
+
+struct QInputGeneratorPrivate
+{
+ QInputGeneratorPrivate();
+ QInputGenerator* q;
+
+ enum KeyEventType { KeyPress, KeyRelease, KeyClick };
+ enum MouseEventType { MousePress, MouseRelease, MouseClick };
+
+ void keyEvent (Qt::Key, Qt::KeyboardModifiers, KeyEventType, bool = false);
+ void mouseEvent(QPoint const&, Qt::MouseButtons, MouseEventType);
+
+ void ensureModifiers(Qt::KeyboardModifiers);
+
+ Qt::KeyboardModifiers currentModifiers;
+};
+
+struct QInputGeneratorService : public QCopChannel
+{
+ QInputGeneratorService(QInputGeneratorPrivate*,QObject* =0);
+
+ virtual void receive(QString const&,QByteArray const&);
+
+ QInputGeneratorPrivate* d;
+};
+
+QInputGeneratorService::QInputGeneratorService(QInputGeneratorPrivate* _d, QObject* parent)
+ : QCopChannel(QINPUTGENERATOR_QCOP, parent),
+ d(_d)
+{
+ Q_ASSERT(qApp->type() == qApp->GuiServer);
+}
+
+void QInputGeneratorService::receive(QString const& message, QByteArray const& data)
+{
+ if (message == QLatin1String(QINPUTGENERATOR_QCOP_KEYEVENT)) {
+ int key = 0;
+ int mod = 0;
+ int type = 0;
+ bool autoRepeat = false;
+
+ QByteArray copy(data);
+ QDataStream ds(&copy, QIODevice::ReadOnly);
+ ds.setVersion(QINPUTGENERATOR_QCOP_VERSION);
+ ds >> key >> mod >> type >> autoRepeat;
+
+ if (ds.status() != QDataStream::Ok) {
+ qWarning() << "QtUitest: error deserializing " QINPUTGENERATOR_QCOP_KEYEVENT
+ " message, a key event might be lost.";
+ } else {
+ Qt::KeyboardModifiers qtMod(mod);
+ d->ensureModifiers(qtMod);
+ d->keyEvent(Qt::Key(key), qtMod, static_cast<QInputGeneratorPrivate::KeyEventType>(type), autoRepeat);
+ }
+ } else {
+ qWarning() << "QtUitest: QInputGenerator received unknown message" << message;
+ }
+}
+
+QInputGeneratorPrivate::QInputGeneratorPrivate()
+ : q(0)
+ , currentModifiers(0)
+{}
+
+QInputGenerator::QInputGenerator(QObject* parent)
+ : QObject(parent),
+ d(new QInputGeneratorPrivate)
+{
+ d->q = this;
+ if (qApp->type() == qApp->GuiServer) {
+ new QInputGeneratorService(d, this);
+ }
+}
+
+QInputGenerator::~QInputGenerator()
+{
+ d->ensureModifiers(0);
+ d->q = 0;
+ delete d;
+ d = 0;
+}
+
+void QInputGeneratorPrivate::keyEvent(Qt::Key key, Qt::KeyboardModifiers mod, KeyEventType type, bool autoRepeat)
+{
+ if (qApp->type() != qApp->GuiServer) {
+ QByteArray data;
+ {
+ QDataStream ds(&data,QIODevice::WriteOnly);
+ ds.setVersion(QINPUTGENERATOR_QCOP_VERSION);
+ ds << int(key) << int(mod) << int(type) << autoRepeat;
+ if (ds.status() != QDataStream::Ok) {
+ qWarning() << "QtUitest: error serializing " QINPUTGENERATOR_QCOP_KEYEVENT
+ " message, a key event might be lost.";
+ }
+ }
+ if (!QCopChannel::send(QINPUTGENERATOR_QCOP, QINPUTGENERATOR_QCOP_KEYEVENT, data)) {
+ qWarning() << "QtUitest: error sending " QINPUTGENERATOR_QCOP_KEYEVENT
+ " message, a key event might be lost.";
+ }
+ return;
+ }
+
+ QINPUTGENERATOR_DEBUG() << "about to simulate key"
+ << ((type==KeyPress) ? "press" : ((type==KeyRelease) ? "release" : "click"))
+ << QKeySequence(key|mod).toString() << "autorepeat" << QString("%1").arg(autoRepeat);
+
+ ushort unicode = 0;
+ if (key <= 0xff) {
+ QChar ch(key);
+ // FIXME this should be less of a hack. The case should not implicitly depend on mod.
+ if (mod & Qt::ShiftModifier) ch = ch.toUpper();
+ else ch = ch.toLower();
+ unicode = ch.unicode();
+ }
+
+ /*
+ The screensaver may consume key events.
+ There is no way to query the server to determine if the next key event will be consumed,
+ or even if the screensaver is currently active. All we can do is force the screensaver
+ (if any) to wake up before every key event to ensure none of them are consumed.
+ */
+ if (!QMetaObject::invokeMethod(QWSServer::instance(), "_q_screenSaverWake"))
+ Q_ASSERT(0);
+
+ QWSServer::processKeyEvent(unicode, key, mod, (type != KeyRelease), autoRepeat);
+
+ if (type == KeyClick) {
+ // Key press/release should not occur in same millisecond
+ QtUiTest::wait(10);
+ QWSServer::processKeyEvent(unicode, key, mod, false, autoRepeat);
+ }
+
+ QINPUTGENERATOR_DEBUG() << "simulated key"
+ << ((type==KeyPress) ? "press" : ((type==KeyRelease) ? "release" : "click"))
+ << QKeySequence(key|mod).toString() << "autorepeat" << QString("%1").arg(autoRepeat);
+}
+
+void QInputGenerator::keyPress(Qt::Key key, Qt::KeyboardModifiers mod, bool autoRepeat)
+{
+ if (qApp->type() == qApp->GuiServer) {
+ d->ensureModifiers(mod);
+ }
+ d->keyEvent(key, mod, d->KeyPress, autoRepeat);
+}
+
+void QInputGenerator::keyRelease(Qt::Key key, Qt::KeyboardModifiers mod)
+{
+ if (qApp->type() == qApp->GuiServer) {
+ d->ensureModifiers(mod);
+ }
+ d->keyEvent(key, mod, d->KeyRelease);
+}
+
+void QInputGenerator::keyClick(Qt::Key key, Qt::KeyboardModifiers mod)
+{
+ if (qApp->type() == qApp->GuiServer) {
+ d->ensureModifiers(mod);
+ }
+ d->keyEvent(key, mod, d->KeyClick);
+}
+
+void QInputGeneratorPrivate::mouseEvent(QPoint const& local, Qt::MouseButtons state, MouseEventType type)
+{
+ QPoint pos(q->mapFromActiveWindow(local));
+
+ QINPUTGENERATOR_DEBUG() << "about to simulate mouse"
+ << ((type==MousePress) ? "press" : ((type==MouseRelease) ? "release" : "click"));
+
+ Q_ASSERT(pos.x() >= 0 && pos.x() < QScreen::instance()->width()
+ && pos.y() >= 0 && pos.y() < QScreen::instance()->height());
+
+ // When a mouse click occurs while an input method is currently active,
+ // and the click goes to a non-qpe window, there's a fair chance it will
+ // cause the current IM to change.
+ // We'd better wait for it, because it can cause widgets to be resized
+ // and hence screw up subsequent clicks.
+ struct InputMethods {
+ static QWidget* widget()
+ {
+ static QWidget* inputMethods = 0;
+ if (!inputMethods) {
+ QWidgetList wl(QApplication::topLevelWidgets());
+ foreach (QWidget *w, wl) {
+ inputMethods = w->findChild<QWidget*>("InputMethods");
+ if (inputMethods) break;
+ }
+ }
+ return inputMethods;
+ }
+
+ static QString current()
+ {
+ QString ret;
+ if (InputMethods::widget()) {
+ QMetaObject::invokeMethod(InputMethods::widget(), "currentShown",
+ Qt::DirectConnection, Q_RETURN_ARG(QString, ret));
+ }
+ return ret;
+
+ }
+ };
+
+ QWSWindow *win = QWSServer::instance()->windowAt(pos);
+ QString client_before_click = (win ? win->client()->identity() : QString());
+ QString im_before_click = InputMethods::current();
+
+ QWSServer::sendMouseEvent(pos, (MouseRelease == type) ? Qt::MouseButtons(0) : state, 0);
+
+ if (type == MouseClick) {
+ // This wait is to avoid the mouse press and release occurring in
+ // the same millisecond, which surely won't happen with real
+ // hardware and wouldn't be unlikely to confuse some apps.
+ QtUiTest::wait(10);
+ QWSServer::sendMouseEvent(pos, 0, 0);
+ }
+
+ if (type == MouseClick && client_before_click != "qpe"
+ && !im_before_click.isEmpty()) {
+ for (int i = 0;
+ i < 500 && InputMethods::current() == im_before_click;
+ i += 50, QtUiTest::wait(50)) {}
+ }
+
+ QINPUTGENERATOR_DEBUG() << "simulated mouse"
+ << ((type==MousePress) ? "press" : ((type==MouseRelease) ? "release" : "click"));
+}
+
+void QInputGenerator::mousePress(QPoint const& pos, Qt::MouseButtons state)
+{ d->mouseEvent(pos, state, d->MousePress); }
+
+void QInputGenerator::mouseRelease(QPoint const& pos, Qt::MouseButtons state)
+{ d->mouseEvent(pos, state, d->MouseRelease); }
+
+void QInputGenerator::mouseClick(QPoint const& pos, Qt::MouseButtons state)
+{ d->mouseEvent(pos, state, d->MouseClick); }
+
+void QInputGeneratorPrivate::ensureModifiers(Qt::KeyboardModifiers desiredMod)
+{
+ if (currentModifiers == desiredMod) return;
+
+ Qt::KeyboardModifiers incrementalMod = currentModifiers;
+ // For each modifier..
+ for (unsigned i = 0; i < sizeof(q->AllModifiers)/sizeof(Qt::KeyboardModifier); ++i) {
+ Qt::KeyboardModifier thisMod = q->AllModifiers[i];
+ // If the modifier is currently disabled but we want it enabled, or vice-versa...
+ if ((desiredMod & thisMod) && !(currentModifiers & thisMod)) {
+ QINPUTGENERATOR_DEBUG() << "Enabling modifier" << (void*)thisMod << "by press";
+ incrementalMod |= thisMod;
+ keyEvent(q->modifierToKey(thisMod), incrementalMod, KeyPress, false);
+ } else if (!(desiredMod & thisMod) && (currentModifiers & thisMod)) {
+ QINPUTGENERATOR_DEBUG() << "Disabling modifier" << (void*)thisMod << "by release";
+ incrementalMod &= ~thisMod;
+ keyEvent(q->modifierToKey(thisMod), incrementalMod, KeyRelease, false);
+ }
+ }
+
+ /*
+ On QWS, we cannot check if QApplication::keyboardModifiers() changes to the desired
+ state. That function returns whatever modifiers were set on the last spontaneous
+ input event, and the modifiers set on input events are the modifiers _before_ the
+ event occurred (e.g. the Shift key press event does not have the Shift modifier set,
+ but the next key event does).
+
+ So QApplication::keyboardModifiers() is off-by-one and thus can't be checked until
+ the next event occurs - we're just assuming success.
+ */
+ currentModifiers = desiredMod;
+
+}
+
+
diff --git a/old/libqtuitest/qinputgenerator_symbian.cpp b/old/libqtuitest/qinputgenerator_symbian.cpp
new file mode 100644
index 0000000..2adce33
--- /dev/null
+++ b/old/libqtuitest/qinputgenerator_symbian.cpp
@@ -0,0 +1,425 @@
+/****************************************************************************
+**
+** 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 "qinputgenerator_p.h"
+
+#include <QtCore>
+#include <QtGui>
+
+#include <w32std.h>
+#include <e32event.h>
+#include <e32std.h>
+
+#include <coemain.h>
+
+#include "qtuitestnamespace.h"
+
+#define QINPUTGENERATOR_DEBUG() if (1); else qDebug() << "QInputGenerator:"
+
+QMap<int,int> qt_key_to_symbian_keycode_make()
+{
+ QMap<int,int> m;
+
+ m.insert( Qt::Key_Backspace, EKeyBackspace );
+ m.insert( Qt::Key_Tab, EKeyTab );
+ m.insert( Qt::Key_Enter, EKeyEnter );
+ m.insert( Qt::Key_Escape, EKeyEscape );
+ m.insert( Qt::Key_Space, EKeySpace );
+ m.insert( Qt::Key_Delete, EKeyDelete );
+ m.insert( Qt::Key_SysReq, EKeyPrintScreen );
+ m.insert( Qt::Key_Pause, EKeyPause );
+ m.insert( Qt::Key_Home, EKeyHome );
+ m.insert( Qt::Key_End, EKeyEnd );
+ m.insert( Qt::Key_PageUp, EKeyPageUp );
+ m.insert( Qt::Key_PageDown, EKeyPageDown );
+ m.insert( Qt::Key_Insert, EKeyInsert );
+ m.insert( Qt::Key_Left, EKeyLeftArrow );
+ m.insert( Qt::Key_Right, EKeyRightArrow );
+ m.insert( Qt::Key_Up, EKeyUpArrow );
+ m.insert( Qt::Key_Down, EKeyDownArrow );
+
+ m.insert( Qt::Key_Shift, EKeyLeftShift );
+ m.insert( Qt::Key_Control, EKeyLeftCtrl );
+ m.insert( Qt::Key_Alt, EKeyLeftAlt );
+ m.insert( Qt::Key_AltGr, EKeyRightAlt );
+ m.insert( Qt::Key_Super_L, EKeyLeftFunc );
+ m.insert( Qt::Key_Super_R, EKeyRightFunc );
+ m.insert( Qt::Key_CapsLock, EKeyCapsLock );
+ m.insert( Qt::Key_NumLock, EKeyNumLock );
+ m.insert( Qt::Key_ScrollLock, EKeyScrollLock );
+
+ m.insert( Qt::Key_F1, EKeyF1 );
+ m.insert( Qt::Key_F2, EKeyF2 );
+ m.insert( Qt::Key_F3, EKeyF3 );
+ m.insert( Qt::Key_F4, EKeyF4 );
+ m.insert( Qt::Key_F5, EKeyF5 );
+ m.insert( Qt::Key_F6, EKeyF6 );
+ m.insert( Qt::Key_F7, EKeyF7 );
+ m.insert( Qt::Key_F8, EKeyF8 );
+ m.insert( Qt::Key_F9, EKeyF9 );
+ m.insert( Qt::Key_F10, EKeyF10 );
+ m.insert( Qt::Key_F11, EKeyF11 );
+ m.insert( Qt::Key_F12, EKeyF12 );
+ m.insert( Qt::Key_F13, EKeyF13 );
+ m.insert( Qt::Key_F14, EKeyF14 );
+ m.insert( Qt::Key_F15, EKeyF15 );
+ m.insert( Qt::Key_F16, EKeyF16 );
+ m.insert( Qt::Key_F17, EKeyF17 );
+ m.insert( Qt::Key_F18, EKeyF18 );
+ m.insert( Qt::Key_F19, EKeyF19 );
+ m.insert( Qt::Key_F20, EKeyF20 );
+ m.insert( Qt::Key_F21, EKeyF21 );
+ m.insert( Qt::Key_F22, EKeyF22 );
+ m.insert( Qt::Key_F23, EKeyF23 );
+ m.insert( Qt::Key_F24, EKeyF24 );
+
+ m.insert( Qt::Key_Menu, EKeyMenu );
+ m.insert( Qt::Key_Help, EKeyHelp );
+ m.insert( Qt::Key_Call, EKeyDial );
+
+ m.insert( Qt::Key_Context1, EKeyDevice0 );
+ m.insert( Qt::Key_Context2, EKeyDevice1 );
+ m.insert( Qt::Key_Select, EKeyDevice3 );
+
+ m.insert( Qt::Key_Launch0, EKeyApplication0 );
+ m.insert( Qt::Key_Launch1, EKeyApplication1 );
+ m.insert( Qt::Key_Launch2, EKeyApplication2 );
+ m.insert( Qt::Key_Launch3, EKeyApplication3 );
+ m.insert( Qt::Key_Launch4, EKeyApplication4 );
+ m.insert( Qt::Key_Launch5, EKeyApplication5 );
+ m.insert( Qt::Key_Launch6, EKeyApplication6 );
+ m.insert( Qt::Key_Launch7, EKeyApplication7 );
+ m.insert( Qt::Key_Launch8, EKeyApplication8 );
+ m.insert( Qt::Key_Launch9, EKeyApplication9 );
+ m.insert( Qt::Key_LaunchA, EKeyApplicationA );
+ m.insert( Qt::Key_LaunchB, EKeyApplicationB );
+ m.insert( Qt::Key_LaunchC, EKeyApplicationC );
+ m.insert( Qt::Key_LaunchD, EKeyApplicationD );
+ m.insert( Qt::Key_LaunchE, EKeyApplicationE );
+ m.insert( Qt::Key_LaunchF, EKeyApplicationF );
+
+ m.insert( Qt::Key_Yes, EKeyYes );
+ m.insert( Qt::Key_No, EKeyNo );
+
+ m.insert( Qt::Key_Call, EKeyYes );
+ m.insert( Qt::Key_Hangup, EKeyNo );
+
+ return m;
+}
+
+QMap<int,uint> qt_modifier_to_symbian_modifier_make()
+{
+ QMap<int,uint> m;
+ m.insert( Qt::ShiftModifier, EModifierShift );
+ m.insert( Qt::ControlModifier, EModifierCtrl );
+ m.insert( Qt::AltModifier, EModifierAlt );
+ return m;
+}
+
+QMap<int,uint> qt_button_to_symbian_button_down_make()
+{
+ QMap<int,uint> m;
+
+ m.insert( Qt::LeftButton, TRawEvent::EButton1Down );
+ m.insert( Qt::MidButton, TRawEvent::EButton2Down );
+ m.insert( Qt::RightButton, TRawEvent::EButton3Down );
+ return m;
+}
+
+QMap<int,uint> qt_button_to_symbian_button_up_make()
+{
+ QMap<int,uint> m;
+
+ m.insert( Qt::LeftButton, TRawEvent::EButton1Up );
+ m.insert( Qt::MidButton, TRawEvent::EButton2Up );
+ m.insert( Qt::RightButton, TRawEvent::EButton3Up );
+ return m;
+}
+
+class QInputGeneratorPrivate
+{
+public:
+ QInputGeneratorPrivate();
+ QInputGenerator* q;
+
+ void keyEvent(Qt::Key, bool);
+ void mouseEvent(QPoint const&, Qt::MouseButtons);
+
+ void ensureModifiers(Qt::KeyboardModifiers);
+ Qt::KeyboardModifiers currentModifiers() const;
+
+ QMap<int,int> const keyMap;
+ QMap<int,uint> const buttonDownMap;
+ QMap<int,uint> const buttonUpMap;
+ QMap<int,uint> const buttonDragMap;
+
+ QPoint currentPos;
+ Qt::MouseButtons currentButtons;
+};
+
+QInputGeneratorPrivate::QInputGeneratorPrivate()
+ : keyMap(qt_key_to_symbian_keycode_make()),
+ buttonDownMap(qt_button_to_symbian_button_down_make()),
+ buttonUpMap(qt_button_to_symbian_button_up_make()),
+ currentPos(),
+ currentButtons(0)
+{
+}
+
+QInputGenerator::QInputGenerator(QObject* parent)
+ : QObject(parent),
+ d(new QInputGeneratorPrivate)
+{
+ d->q = this;
+ QINPUTGENERATOR_DEBUG() << "constructor";
+}
+
+QInputGenerator::~QInputGenerator()
+{
+ QINPUTGENERATOR_DEBUG() << "destructor";
+
+ /*
+ Restore all keyboard modifiers to off.
+ If we don't do this, the current modifiers stay activated
+ even when this application is closed.
+ Note that there is no guarantee this code actually gets run.
+ */
+ d->ensureModifiers(0);
+ if (d->currentButtons) {
+ d->mouseEvent(d->currentPos, 0);
+ }
+
+ d->q = 0;
+ delete d;
+ d = 0;
+}
+
+/*
+ Returns the Qt keyboard modifiers which are currently pressed.
+*/
+Qt::KeyboardModifiers QInputGeneratorPrivate::currentModifiers() const
+{
+ quint32 modifiers = 0;//GetCurrentKeyModifiers();
+
+ int state = 0;
+/*
+ state |= (modifiers & shiftKey ? Qt::ShiftModifier : Qt::NoModifier);
+ state |= (modifiers & controlKey ? Qt::ControlModifier : Qt::NoModifier);
+ state |= (modifiers & optionKey ? Qt::AltModifier : Qt::NoModifier);
+ state |= (modifiers & cmdKey ? Qt::MetaModifier : Qt::NoModifier);
+*/
+ return Qt::KeyboardModifier(state);
+}
+
+void QInputGeneratorPrivate::ensureModifiers(Qt::KeyboardModifiers desiredMod)
+{
+ Qt::KeyboardModifiers currentMod = currentModifiers();
+
+ // For each modifier..
+ for (unsigned i = 0; i < sizeof(q->AllModifiers)/sizeof(Qt::KeyboardModifier); ++i) {
+ Qt::KeyboardModifier thisMod = q->AllModifiers[i];
+ // If the modifier is currently disabled but we want it enabled, or vice-versa...
+ if ((desiredMod & thisMod) && !(currentMod & thisMod)) {
+ QINPUTGENERATOR_DEBUG() << "Enabling modifier" << (void*)thisMod << "by press";
+ // press to enable
+ keyEvent(q->modifierToKey(thisMod), true);
+ } else if (!(desiredMod & thisMod) && (currentMod & thisMod)) {
+ QINPUTGENERATOR_DEBUG() << "Disabling modifier" << (void*)thisMod << "by release";
+ // release to disable
+ keyEvent(q->modifierToKey(thisMod), false);
+ }
+ }
+
+ if (currentMod != desiredMod) {
+ currentMod = desiredMod;
+ for (int i = 0;
+ i < 1000 && QApplication::keyboardModifiers() != desiredMod;
+ i += 50, QtUiTest::wait(50))
+ {}
+
+ if (QApplication::keyboardModifiers() != desiredMod)
+ qWarning() << "QtUitest: couldn't set all modifiers to desired state! "
+ "Current state:" << (void*)(int)QApplication::keyboardModifiers() <<
+ "Desired:" << (void*)(int)desiredMod;
+ }
+}
+
+void QInputGeneratorPrivate::keyEvent(Qt::Key key, bool is_press)
+{
+ int sym = 0;
+
+ do {
+ if (key >= Qt::Key_Space && key <= Qt::Key_AsciiTilde) {
+ sym = QChar(key).toUpper().toAscii();
+ break;
+ }
+
+ QMap<int,int>::const_iterator found = keyMap.find(key);
+ if (found != keyMap.end()) {
+ sym = *found;
+ break;
+ }
+
+ qWarning() << "QInputGenerator: don't know how to translate Qt key"
+ << (void*)key << "into Symbian keycode";
+ return;
+
+ } while(0);
+
+ RWsSession wsSession=CCoeEnv::Static()->WsSession();
+ TRawEvent keyEvent;
+ keyEvent.Set(is_press ? TRawEvent::EKeyDown : TRawEvent::EKeyUp, sym);
+ wsSession.SimulateRawEvent(keyEvent);
+ wsSession.Flush();
+
+ QINPUTGENERATOR_DEBUG() << (is_press ? "press" : "release") << sym;
+}
+
+void QInputGenerator::keyPress(Qt::Key key, Qt::KeyboardModifiers mod, bool autoRepeat)
+{
+ Q_UNUSED(autoRepeat);
+ d->ensureModifiers(mod);
+ d->keyEvent(key, true);
+ QtUiTest::wait(1);
+}
+
+void QInputGenerator::keyRelease(Qt::Key key, Qt::KeyboardModifiers mod)
+{
+ d->ensureModifiers(mod);
+ d->keyEvent(key, false);
+ QtUiTest::wait(1);
+}
+
+void QInputGenerator::keyClick(Qt::Key key, Qt::KeyboardModifiers mod)
+{
+ // Using RWsSession::SimulateKeyEvent seems to work more reliably than using
+ // TRawEvent but it only simulates keyclicks (press and release)
+
+ int sym = 0;
+
+ do {
+ if (key >= Qt::Key_Space && key <= Qt::Key_AsciiTilde) {
+ sym = QChar(key).toUpper().toAscii();
+ if (mod == Qt::NoModifier) {
+ sym = sym = QChar(key).toLower().toAscii();
+ }
+ break;
+ }
+
+ QMap<int,int>::const_iterator found = d->keyMap.find(key);
+ if (found != d->keyMap.end()) {
+ sym = *found;
+ break;
+ }
+
+ qWarning() << "QInputGenerator: don't know how to translate Qt key"
+ << (void*)key << "into Symbian keycode";
+ return;
+
+ } while(0);
+
+ RWsSession wsSession=CCoeEnv::Static()->WsSession();
+
+ TKeyEvent keyEvent;
+ keyEvent.iCode = sym;
+ keyEvent.iScanCode = 0; // don't think Qt requires this
+ keyEvent.iModifiers = 0; // should set this
+ keyEvent.iRepeats = 0;
+ wsSession.SimulateKeyEvent(keyEvent);
+ wsSession.Flush();
+ QtUiTest::wait(10);
+}
+
+void QInputGeneratorPrivate::mouseEvent(QPoint const& pos, Qt::MouseButtons state)
+{
+ typedef QPair<uint,uint> ButtonEvent;
+ QList<ButtonEvent> buttonEvents;
+
+ RWsSession wsSession=CCoeEnv::Static()->WsSession();
+
+ // FIXME: This doesn't handle screen orientation yet
+ int x = pos.x();
+ int y = pos.y();
+
+ foreach (int button, buttonDownMap.keys()) {
+ bool desired = button & state;
+ bool current = button & currentButtons;
+
+ // Do we need to release?
+ if (!desired && current) {
+ TRawEvent event;
+ event.Set(TRawEvent::EButton1Up, x, y);
+ wsSession.SimulateRawEvent(event);
+ wsSession.Flush();
+ }
+
+ // Do we need to press?
+ if (desired && !current) {
+ TRawEvent event;
+ event.Set(TRawEvent::EButton1Down, x, y);
+ wsSession.SimulateRawEvent(event);
+ wsSession.Flush();
+ }
+ }
+
+ currentButtons = state;
+}
+
+void QInputGenerator::mousePress(QPoint const& pos, Qt::MouseButtons state)
+{
+ QINPUTGENERATOR_DEBUG() << "Mouse press" << pos << (void*)(int)state;
+ d->mouseEvent(pos, d->currentButtons | state);
+ qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
+}
+
+void QInputGenerator::mouseRelease(QPoint const& pos, Qt::MouseButtons state)
+{
+ QINPUTGENERATOR_DEBUG() << "Mouse release" << pos << (void*)(int)(d->currentButtons & ~state);
+ d->mouseEvent(pos, d->currentButtons & ~state);
+ qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
+}
+
+void QInputGenerator::mouseClick(QPoint const& pos, Qt::MouseButtons state)
+{
+ mousePress (pos,state);
+ QtUiTest::wait(20);
+ mouseRelease(pos,state);
+}
diff --git a/old/libqtuitest/qinputgenerator_win.cpp b/old/libqtuitest/qinputgenerator_win.cpp
new file mode 100644
index 0000000..991755b
--- /dev/null
+++ b/old/libqtuitest/qinputgenerator_win.cpp
@@ -0,0 +1,496 @@
+/****************************************************************************
+**
+** 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 "qinputgenerator_p.h"
+
+#include <QtCore>
+#include <QtGui>
+
+#include <qt_windows.h>
+#include <windows.h>
+#ifdef __GNUC__
+ #include <winable.h>
+#endif
+
+#include "qtuitestnamespace.h"
+
+#define QINPUTGENERATOR_DEBUG() if (1); else qDebug() << "QInputGenerator:"
+
+enum WindowsNativeModifiers {
+ ShiftLeft = 0x00000001,
+ ControlLeft = 0x00000002,
+ AltLeft = 0x00000004,
+ MetaLeft = 0x00000008,
+ ShiftRight = 0x00000010,
+ ControlRight = 0x00000020,
+ AltRight = 0x00000040,
+ MetaRight = 0x00000080,
+ CapsLock = 0x00000100,
+ NumLock = 0x00000200,
+ ScrollLock = 0x00000400,
+ ExtendedKey = 0x01000000,
+
+ // Convenience mappings
+ ShiftAny = 0x00000011,
+ ControlAny = 0x00000022,
+ AltAny = 0x00000044,
+ MetaAny = 0x00000088,
+ LockAny = 0x00000700
+};
+
+QMap<int,int> qt_key_to_win_vk_make()
+{
+ QMap<int,int> m;
+
+ m.insert( Qt::Key_Escape, VK_ESCAPE );
+ m.insert( Qt::Key_Tab, VK_TAB );
+ m.insert( Qt::Key_Backspace, VK_BACK );
+ m.insert( Qt::Key_Return, VK_RETURN );
+ m.insert( Qt::Key_Enter, VK_RETURN );
+ m.insert( Qt::Key_Insert, VK_INSERT );
+ m.insert( Qt::Key_Delete, VK_DELETE );
+ m.insert( Qt::Key_Pause, VK_PAUSE );
+ m.insert( Qt::Key_Print, VK_SNAPSHOT );
+ m.insert( Qt::Key_Mode_switch, VK_MODECHANGE );
+ m.insert( Qt::Key_PageUp, VK_PRIOR );
+ m.insert( Qt::Key_PageDown, VK_NEXT );
+ m.insert( Qt::Key_End, VK_END );
+ m.insert( Qt::Key_Home, VK_HOME );
+ m.insert( Qt::Key_Sleep, VK_SLEEP );
+ m.insert( Qt::Key_Left, VK_LEFT );
+ m.insert( Qt::Key_Up, VK_UP );
+ m.insert( Qt::Key_Right, VK_RIGHT );
+ m.insert( Qt::Key_Down, VK_DOWN );
+ m.insert( Qt::Key_Select, VK_SELECT );
+ m.insert( Qt::Key_Printer, VK_PRINT );
+ m.insert( Qt::Key_Execute, VK_EXECUTE );
+ m.insert( Qt::Key_CapsLock, VK_CAPITAL );
+ m.insert( Qt::Key_NumLock, VK_NUMLOCK );
+ m.insert( Qt::Key_ScrollLock, VK_SCROLL );
+ m.insert( Qt::Key_F1, VK_F1 );
+ m.insert( Qt::Key_F2, VK_F2 );
+ m.insert( Qt::Key_F3, VK_F3 );
+ m.insert( Qt::Key_F4, VK_F4 );
+ m.insert( Qt::Key_F5, VK_F5 );
+ m.insert( Qt::Key_F6, VK_F6 );
+ m.insert( Qt::Key_F7, VK_F7 );
+ m.insert( Qt::Key_F8, VK_F8 );
+ m.insert( Qt::Key_F9, VK_F9 );
+ m.insert( Qt::Key_F10, VK_F10 );
+ m.insert( Qt::Key_F11, VK_F11 );
+ m.insert( Qt::Key_F12, VK_F12 );
+ m.insert( Qt::Key_F13, VK_F13 );
+ m.insert( Qt::Key_F14, VK_F14 );
+ m.insert( Qt::Key_F15, VK_F15 );
+ m.insert( Qt::Key_F16, VK_F16 );
+ m.insert( Qt::Key_F17, VK_F17 );
+ m.insert( Qt::Key_F18, VK_F18 );
+ m.insert( Qt::Key_F19, VK_F19 );
+ m.insert( Qt::Key_F20, VK_F20 );
+ m.insert( Qt::Key_F21, VK_F21 );
+ m.insert( Qt::Key_F22, VK_F22 );
+ m.insert( Qt::Key_F23, VK_F23 );
+ m.insert( Qt::Key_F24, VK_F24 );
+ m.insert( Qt::Key_Menu, VK_APPS );
+ m.insert( Qt::Key_Help, VK_HELP );
+ m.insert( Qt::Key_Cancel, VK_CANCEL );
+ m.insert( Qt::Key_Clear, VK_CLEAR );
+ m.insert( Qt::Key_Play, VK_PLAY );
+ m.insert( Qt::Key_Zoom, VK_ZOOM );
+
+#if (_WIN32_WINNT >= 0x0500)
+#if !defined(VK_OEM_BACKTAB)
+# define VK_OEM_BACKTAB 0xF5
+#endif
+ m.insert( Qt::Key_Backtab, VK_OEM_BACKTAB );
+ m.insert( Qt::Key_Back, VK_BROWSER_BACK );
+ m.insert( Qt::Key_Forward, VK_BROWSER_FORWARD );
+ m.insert( Qt::Key_Refresh, VK_BROWSER_REFRESH );
+ m.insert( Qt::Key_Stop, VK_BROWSER_STOP );
+ m.insert( Qt::Key_Search, VK_BROWSER_SEARCH );
+ m.insert( Qt::Key_Favorites, VK_BROWSER_FAVORITES );
+ m.insert( Qt::Key_HomePage, VK_BROWSER_HOME );
+ m.insert( Qt::Key_VolumeMute, VK_VOLUME_MUTE );
+ m.insert( Qt::Key_VolumeDown, VK_VOLUME_DOWN );
+ m.insert( Qt::Key_VolumeUp, VK_VOLUME_UP );
+ m.insert( Qt::Key_MediaNext, VK_MEDIA_NEXT_TRACK );
+ m.insert( Qt::Key_MediaPrevious, VK_MEDIA_PREV_TRACK );
+ m.insert( Qt::Key_MediaStop, VK_MEDIA_STOP );
+ m.insert( Qt::Key_MediaPlay, VK_MEDIA_PLAY_PAUSE );
+ m.insert( Qt::Key_LaunchMail, VK_LAUNCH_MAIL );
+ m.insert( Qt::Key_LaunchMedia, VK_LAUNCH_MEDIA_SELECT );
+ m.insert( Qt::Key_Launch0, VK_LAUNCH_APP1 );
+ m.insert( Qt::Key_Launch1, VK_LAUNCH_APP2 );
+#endif
+
+
+ // Modifiers
+ m.insert( Qt::ShiftModifier, VK_SHIFT );
+ m.insert( Qt::Key_Shift, VK_SHIFT );
+ m.insert( Qt::ControlModifier, VK_CONTROL );
+ m.insert( Qt::Key_Control, VK_CONTROL );
+ m.insert( Qt::AltModifier, VK_MENU );
+ m.insert( Qt::Key_Alt, VK_MENU );
+ m.insert( Qt::MetaModifier, VK_LWIN );
+ m.insert( Qt::Key_Meta, VK_LWIN );
+
+ return m;
+}
+
+QMap<int,uint> qt_button_to_win_button_down_make()
+{
+ QMap<int,uint> m;
+
+ m.insert( Qt::LeftButton, MOUSEEVENTF_LEFTDOWN );
+ m.insert( Qt::MidButton, MOUSEEVENTF_MIDDLEDOWN );
+ m.insert( Qt::RightButton, MOUSEEVENTF_RIGHTDOWN );
+
+#if (_WIN32_WINNT >= 0x0500)
+ m.insert( Qt::XButton1, MOUSEEVENTF_XDOWN );
+ m.insert( Qt::XButton2, MOUSEEVENTF_XDOWN );
+#endif
+
+ return m;
+}
+
+QMap<int,uint> qt_button_to_win_button_up_make()
+{
+ QMap<int,uint> m;
+
+ m.insert( Qt::LeftButton, MOUSEEVENTF_LEFTUP );
+ m.insert( Qt::MidButton, MOUSEEVENTF_MIDDLEUP );
+ m.insert( Qt::RightButton, MOUSEEVENTF_RIGHTUP );
+
+#if (_WIN32_WINNT >= 0x0500)
+ m.insert( Qt::XButton1, MOUSEEVENTF_XUP );
+ m.insert( Qt::XButton2, MOUSEEVENTF_XUP );
+#endif
+
+ return m;
+}
+
+QMap<int,uint> qt_button_to_win_mousedata_make()
+{
+ QMap<int,uint> m;
+
+#if (_WIN32_WINNT >= 0x0500)
+ m.insert( Qt::XButton1, XBUTTON1 );
+ m.insert( Qt::XButton2, XBUTTON2 );
+#endif
+
+ return m;
+}
+
+class QInputGeneratorPrivate
+{
+public:
+ QInputGeneratorPrivate();
+ QInputGenerator* q;
+
+ void keyEvent(Qt::Key, bool);
+ void mouseEvent(QPoint const&, Qt::MouseButtons);
+
+ void ensureModifiers(Qt::KeyboardModifiers);
+ Qt::KeyboardModifiers currentModifiers() const;
+
+ QMap<int,int> const keyMap;
+ QMap<int,uint> const buttonDownMap;
+ QMap<int,uint> const buttonUpMap;
+ QMap<int,uint> const buttonMouseDataMap;
+
+ QPoint currentPos;
+ Qt::MouseButtons currentButtons;
+};
+
+QInputGeneratorPrivate::QInputGeneratorPrivate()
+ : keyMap(qt_key_to_win_vk_make()),
+ buttonDownMap(qt_button_to_win_button_down_make()),
+ buttonUpMap(qt_button_to_win_button_up_make()),
+ buttonMouseDataMap(qt_button_to_win_mousedata_make()),
+ currentPos(),
+ currentButtons(0)
+{}
+
+QInputGenerator::QInputGenerator(QObject* parent)
+ : QObject(parent),
+ d(new QInputGeneratorPrivate)
+{
+ d->q = this;
+ QINPUTGENERATOR_DEBUG() << "constructor";
+}
+
+QInputGenerator::~QInputGenerator()
+{
+ QINPUTGENERATOR_DEBUG() << "destructor";
+
+ /*
+ Restore all keyboard modifiers to off.
+ Note that there is no guarantee this code actually gets run.
+ */
+ d->ensureModifiers(0);
+ if (d->currentButtons) {
+ d->mouseEvent(d->currentPos, 0);
+ }
+
+ d->q = 0;
+ delete d;
+ d = 0;
+}
+
+/*
+ Returns the Qt keyboard modifiers which are currently pressed.
+*/
+Qt::KeyboardModifiers QInputGeneratorPrivate::currentModifiers() const
+{
+ quint32 nModifiers = 0;
+
+ if (QSysInfo::WindowsVersion < QSysInfo::WV_NT || QSysInfo::WindowsVersion & QSysInfo::WV_CE_based) {
+ nModifiers |= (GetKeyState(VK_SHIFT ) < 0 ? ShiftAny : 0);
+ nModifiers |= (GetKeyState(VK_CONTROL) < 0 ? ControlAny : 0);
+ nModifiers |= (GetKeyState(VK_MENU ) < 0 ? AltAny : 0);
+ nModifiers |= (GetKeyState(VK_LWIN ) < 0 ? MetaLeft : 0);
+ nModifiers |= (GetKeyState(VK_RWIN ) < 0 ? MetaRight : 0);
+ } else {
+ // Map native modifiers to some bit representation
+ nModifiers |= (GetKeyState(VK_LSHIFT ) & 0x80 ? ShiftLeft : 0);
+ nModifiers |= (GetKeyState(VK_RSHIFT ) & 0x80 ? ShiftRight : 0);
+ nModifiers |= (GetKeyState(VK_LCONTROL) & 0x80 ? ControlLeft : 0);
+ nModifiers |= (GetKeyState(VK_RCONTROL) & 0x80 ? ControlRight : 0);
+ nModifiers |= (GetKeyState(VK_LMENU ) & 0x80 ? AltLeft : 0);
+ nModifiers |= (GetKeyState(VK_RMENU ) & 0x80 ? AltRight : 0);
+ nModifiers |= (GetKeyState(VK_LWIN ) & 0x80 ? MetaLeft : 0);
+ nModifiers |= (GetKeyState(VK_RWIN ) & 0x80 ? MetaRight : 0);
+ // Add Lock keys to the same bits
+ nModifiers |= (GetKeyState(VK_CAPITAL ) & 0x01 ? CapsLock : 0);
+ nModifiers |= (GetKeyState(VK_NUMLOCK ) & 0x01 ? NumLock : 0);
+ nModifiers |= (GetKeyState(VK_SCROLL ) & 0x01 ? ScrollLock : 0);
+ }
+
+ int state = 0;
+ state |= (nModifiers & ShiftAny ? Qt::ShiftModifier : 0);
+ state |= (nModifiers & ControlAny ? Qt::ControlModifier : 0);
+ state |= (nModifiers & AltAny ? Qt::AltModifier : 0);
+ state |= (nModifiers & MetaAny ? Qt::MetaModifier : 0);
+
+ return Qt::KeyboardModifier(state);
+}
+
+void QInputGeneratorPrivate::ensureModifiers(Qt::KeyboardModifiers desiredMod)
+{
+ Qt::KeyboardModifiers currentMod = currentModifiers();
+
+ // For each modifier..
+ for (unsigned i = 0; i < sizeof(q->AllModifiers)/sizeof(Qt::KeyboardModifier); ++i) {
+ Qt::KeyboardModifier thisMod = q->AllModifiers[i];
+ // If the modifier is currently disabled but we want it enabled, or vice-versa...
+ if ((desiredMod & thisMod) && !(currentMod & thisMod)) {
+ QINPUTGENERATOR_DEBUG() << "Enabling modifier" << (void*)thisMod << "by press";
+ // press to enable
+ keyEvent(q->modifierToKey(thisMod), true);
+ } else if (!(desiredMod & thisMod) && (currentMod & thisMod)) {
+ QINPUTGENERATOR_DEBUG() << "Disabling modifier" << (void*)thisMod << "by release";
+ // release to disable
+ keyEvent(q->modifierToKey(thisMod), false);
+ }
+ }
+
+ if (currentMod != desiredMod) {
+ currentMod = desiredMod;
+ for (int i = 0;
+ i < 1000 && QApplication::keyboardModifiers() != desiredMod;
+ i += 50, QtUiTest::wait(50))
+ {}
+
+ if (QApplication::keyboardModifiers() != desiredMod)
+ qWarning() << "QtUitest: couldn't set all modifiers to desired state! "
+ "Current state:" << (void*)(int)QApplication::keyboardModifiers() <<
+ "Desired:" << (void*)(int)desiredMod;
+ }
+
+}
+
+void QInputGeneratorPrivate::keyEvent(Qt::Key key, bool is_press)
+{
+ int sym = 0;
+ Qt::KeyboardModifiers mod = 0;
+
+ do {
+ if (key >= Qt::Key_0 && key <= Qt::Key_9 ||
+ key >= Qt::Key_A && key <= Qt::Key_Z) {
+ sym = QChar(key).toUpper().toAscii();
+ break;
+ }
+
+ if (key >= Qt::Key_Space && key <= Qt::Key_AsciiTilde) {
+ sym = VkKeyScan(QChar(key).toAscii());
+ if (sym & 0x0100) mod |= Qt::ShiftModifier;
+ if (sym & 0x0200) mod |= Qt::ControlModifier;
+ if (sym & 0x0400) mod |= Qt::AltModifier;
+ break;
+ }
+
+ QMap<int,int>::const_iterator found = keyMap.find(key);
+ if (found != keyMap.end()) {
+ sym = *found;
+ break;
+ }
+
+ qWarning() << "QInputGenerator: don't know how to translate Qt key"
+ << (void*)key << "into Windows virtual key";
+ return;
+
+ } while(0);
+
+ if (mod) {
+ ensureModifiers(mod);
+ }
+
+ QINPUTGENERATOR_DEBUG() << (is_press ? "press" : "release") << sym;
+
+ KEYBDINPUT kbi = {0};
+ INPUT input = {0};
+
+ kbi.wVk = sym;
+ if (!is_press) kbi.dwFlags = KEYEVENTF_KEYUP;
+
+ input.ki = kbi;
+ input.type = INPUT_KEYBOARD;
+ SendInput(1, &input, sizeof(input));
+}
+
+void QInputGenerator::keyPress(Qt::Key key, Qt::KeyboardModifiers mod, bool autoRepeat)
+{
+ Q_UNUSED(autoRepeat);
+ d->ensureModifiers(mod);
+ d->keyEvent(key, true);
+}
+
+void QInputGenerator::keyRelease(Qt::Key key, Qt::KeyboardModifiers mod)
+{
+ d->ensureModifiers(mod);
+ d->keyEvent(key, false);
+}
+
+void QInputGenerator::keyClick(Qt::Key key, Qt::KeyboardModifiers mod)
+{
+ keyPress(key,mod);
+ keyRelease(key,mod);
+}
+
+void QInputGeneratorPrivate::mouseEvent(QPoint const& pos, Qt::MouseButtons state)
+{
+ if (currentPos != pos) {
+ currentPos = pos;
+
+ MOUSEINPUT mi = {0};
+ INPUT input = {0};
+
+ QRect rect = QApplication::desktop()->screenGeometry(); // FIXME: Uses default screen for now
+
+ mi.dx = LONG(pos.x() * 65535.0 / rect.width() + 8);
+ mi.dy = LONG(pos.y() * 65535.0 / rect.height() + 8);
+ mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
+ input.mi = mi;
+ input.type = INPUT_MOUSE;
+ SendInput(1, &input, sizeof(input));
+
+ for (int i = 0;
+ i < 1000 && QCursor::pos() != pos;
+ i += 50, QtUiTest::wait(50))
+ {}
+
+ if (QCursor::pos() != pos)
+ qWarning() << "QtUitest: couldn't move cursor to desired point! "
+ "Current position:" << QCursor::pos() <<
+ "Desired:" << pos;
+
+ }
+
+ typedef QPair<uint,uint> ButtonEvent;
+ QList<ButtonEvent> buttonEvents;
+
+ foreach (int button, buttonDownMap.keys()) {
+ bool desired = button & state;
+ bool current = button & currentButtons;
+
+ // Do we need to release?
+ if (!desired && current) {
+ buttonEvents << qMakePair(buttonUpMap[button], buttonMouseDataMap[button]);
+ }
+
+ // Do we need to press?
+ if (desired && !current) {
+ buttonEvents << qMakePair(buttonDownMap[button], buttonMouseDataMap[button]);
+ }
+ }
+
+ foreach (ButtonEvent const& event, buttonEvents) {
+ MOUSEINPUT mi = {0};
+ INPUT input = {0};
+
+ mi.dwFlags = event.first;
+ mi.mouseData = event.second;
+ input.mi = mi;
+ input.type = INPUT_MOUSE;
+ SendInput(1, &input, sizeof(input));
+ }
+
+ currentButtons = state;
+}
+
+void QInputGenerator::mousePress(QPoint const& pos, Qt::MouseButtons state)
+{
+ QINPUTGENERATOR_DEBUG() << "Mouse press" << pos << (void*)(int)state;
+ d->mouseEvent(pos, d->currentButtons | state);
+}
+
+void QInputGenerator::mouseRelease(QPoint const& pos, Qt::MouseButtons state)
+{
+ QINPUTGENERATOR_DEBUG() << "Mouse release" << pos << (void*)(int)(d->currentButtons & ~state);
+ d->mouseEvent(pos, d->currentButtons & ~state);
+}
+
+void QInputGenerator::mouseClick(QPoint const& pos, Qt::MouseButtons state)
+{
+ mousePress (pos,state);
+ mouseRelease(pos,state);
+}
+
diff --git a/old/libqtuitest/qinputgenerator_x11.cpp b/old/libqtuitest/qinputgenerator_x11.cpp
new file mode 100644
index 0000000..11bb7e1
--- /dev/null
+++ b/old/libqtuitest/qinputgenerator_x11.cpp
@@ -0,0 +1,514 @@
+/****************************************************************************
+**
+** 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 "qinputgenerator_p.h"
+
+#include <QtCore>
+#include <QtGui>
+#include <QX11Info>
+#include <X11/extensions/XTest.h>
+#include <X11/keysym.h>
+
+#include "qtuitestnamespace.h"
+
+#define QINPUTGENERATOR_DEBUG() if (1); else qDebug() << "QInputGenerator:"
+
+
+QMap<int,int> qt_key_to_keysym_make()
+{
+ QMap<int,int> m;
+
+#define QT_K(Qt,X) m.insert(Qt,X)
+ QT_K( '\n', XK_Return );
+ QT_K( Qt::Key_Escape, XK_Escape );
+ QT_K( Qt::Key_Tab, XK_Tab );
+ QT_K( Qt::Key_Backtab, XK_ISO_Left_Tab );
+ QT_K( Qt::Key_Backspace, XK_BackSpace );
+ QT_K( Qt::Key_Return, XK_Return );
+ QT_K( Qt::Key_Enter, XK_KP_Enter );
+ QT_K( Qt::Key_Insert, XK_Insert );
+ QT_K( Qt::Key_Delete, XK_Delete );
+ QT_K( Qt::Key_Pause, XK_Pause );
+ QT_K( Qt::Key_Print, XK_Print );
+ QT_K( Qt::Key_SysReq, XK_Sys_Req );
+ QT_K( Qt::Key_Home, XK_Home );
+ QT_K( Qt::Key_End, XK_End );
+ QT_K( Qt::Key_Left, XK_Left );
+ QT_K( Qt::Key_Up, XK_Up );
+ QT_K( Qt::Key_Right, XK_Right );
+ QT_K( Qt::Key_Down, XK_Down );
+ QT_K( Qt::Key_CapsLock, XK_Caps_Lock );
+ QT_K( Qt::Key_NumLock, XK_Num_Lock );
+ QT_K( Qt::Key_ScrollLock, XK_Scroll_Lock );
+ QT_K( Qt::Key_F1, XK_F1 );
+ QT_K( Qt::Key_F2, XK_F2 );
+ QT_K( Qt::Key_F3, XK_F3 );
+ QT_K( Qt::Key_F4, XK_F4 );
+ QT_K( Qt::Key_F5, XK_F5 );
+ QT_K( Qt::Key_F6, XK_F6 );
+ QT_K( Qt::Key_F7, XK_F7 );
+ QT_K( Qt::Key_F8, XK_F8 );
+ QT_K( Qt::Key_F9, XK_F9 );
+ QT_K( Qt::Key_F10, XK_F10 );
+ QT_K( Qt::Key_F11, XK_F11 );
+ QT_K( Qt::Key_F12, XK_F12 );
+ QT_K( Qt::Key_F13, XK_F13 );
+ QT_K( Qt::Key_F14, XK_F14 );
+ QT_K( Qt::Key_F15, XK_F15 );
+ QT_K( Qt::Key_F16, XK_F16 );
+ QT_K( Qt::Key_F17, XK_F17 );
+ QT_K( Qt::Key_F18, XK_F18 );
+ QT_K( Qt::Key_F19, XK_F19 );
+ QT_K( Qt::Key_F20, XK_F20 );
+ QT_K( Qt::Key_F21, XK_F21 );
+ QT_K( Qt::Key_F22, XK_F22 );
+ QT_K( Qt::Key_F23, XK_F23 );
+ QT_K( Qt::Key_F24, XK_F24 );
+ QT_K( Qt::Key_F25, XK_F25 );
+ QT_K( Qt::Key_F26, XK_F26 );
+ QT_K( Qt::Key_F27, XK_F27 );
+ QT_K( Qt::Key_F28, XK_F28 );
+ QT_K( Qt::Key_F29, XK_F29 );
+ QT_K( Qt::Key_F30, XK_F30 );
+ QT_K( Qt::Key_F31, XK_F31 );
+ QT_K( Qt::Key_F32, XK_F32 );
+ QT_K( Qt::Key_F33, XK_F33 );
+ QT_K( Qt::Key_F34, XK_F34 );
+ QT_K( Qt::Key_F35, XK_F35 );
+ QT_K( Qt::Key_Super_L, XK_Super_L );
+ QT_K( Qt::Key_Super_R, XK_Super_R );
+ QT_K( Qt::Key_Menu, XK_Menu );
+ QT_K( Qt::Key_Hyper_L, XK_Hyper_L );
+ QT_K( Qt::Key_Hyper_R, XK_Hyper_R );
+ QT_K( Qt::Key_Help, XK_Help );
+ QT_K( '/', XK_KP_Divide );
+// QT_K( '*', XK_KP_Multiply );
+ QT_K( '-', XK_KP_Subtract );
+ QT_K( '+', XK_KP_Add );
+ QT_K( Qt::Key_Return, XK_KP_Enter );
+ QT_K( Qt::Key_Kanji, XK_Kanji );
+ QT_K( Qt::Key_Muhenkan, XK_Muhenkan );
+ QT_K( Qt::Key_Henkan, XK_Henkan );
+ QT_K( Qt::Key_Romaji, XK_Romaji );
+ QT_K( Qt::Key_Hiragana, XK_Hiragana );
+ QT_K( Qt::Key_Katakana, XK_Katakana );
+ QT_K( Qt::Key_Hiragana_Katakana, XK_Hiragana_Katakana );
+ QT_K( Qt::Key_Zenkaku, XK_Zenkaku );
+ QT_K( Qt::Key_Hankaku, XK_Hankaku );
+ QT_K( Qt::Key_Zenkaku_Hankaku, XK_Zenkaku_Hankaku );
+ QT_K( Qt::Key_Touroku, XK_Touroku );
+ QT_K( Qt::Key_Massyo, XK_Massyo );
+ QT_K( Qt::Key_Kana_Lock, XK_Kana_Lock );
+ QT_K( Qt::Key_Kana_Shift, XK_Kana_Shift );
+ QT_K( Qt::Key_Eisu_Shift, XK_Eisu_Shift );
+ QT_K( Qt::Key_Eisu_toggle,XK_Eisu_toggle );
+ QT_K( Qt::Key_Hangul, XK_Hangul );
+ QT_K( Qt::Key_Hangul_Start, XK_Hangul_Start );
+ QT_K( Qt::Key_Hangul_End, XK_Hangul_End );
+ QT_K( Qt::Key_Hangul_Hanja, XK_Hangul_Hanja );
+ QT_K( Qt::Key_Hangul_Jamo, XK_Hangul_Jamo );
+ QT_K( Qt::Key_Hangul_Romaja, XK_Hangul_Romaja );
+ QT_K( Qt::Key_Hangul_Jeonja, XK_Hangul_Jeonja );
+ QT_K( Qt::Key_Hangul_Banja, XK_Hangul_Banja );
+ QT_K( Qt::Key_Hangul_PreHanja, XK_Hangul_PreHanja );
+ QT_K( Qt::Key_Hangul_PostHanja,XK_Hangul_PostHanja );
+ QT_K( Qt::Key_Hangul_Special, XK_Hangul_Special );
+
+ // Modifiers
+ QT_K( Qt::ShiftModifier, XK_Shift_L );
+ QT_K( Qt::Key_Shift, XK_Shift_L );
+ QT_K( Qt::ControlModifier,XK_Control_L );
+ QT_K( Qt::Key_Control, XK_Control_L );
+// QT_K( Qt::AltModifier, XK_Alt_L );
+// QT_K( Qt::Key_Alt, XK_Alt_L );
+ QT_K( Qt::MetaModifier, XK_Meta_L );
+ QT_K( Qt::Key_Meta, XK_Meta_L );
+
+ QT_K( Qt::AltModifier, XK_ISO_Level3_Shift );
+ QT_K( Qt::Key_Alt, XK_ISO_Level3_Shift );
+ // FIXME support Qt::KeypadModifier
+
+#undef QT_K
+
+ return m;
+}
+
+QMap<int,uint> qt_button_to_x_button_make()
+{
+ QMap<int,uint> m;
+
+ m.insert(Qt::LeftButton, 1);
+ m.insert(Qt::MidButton, 2);
+ m.insert(Qt::RightButton, 3);
+
+ return m;
+}
+
+QMap<int,int> qt_modifier_to_x_modmask_make()
+{
+ QMap<int,int> m;
+
+ m.insert( Qt::ShiftModifier, ShiftMask );
+ m.insert( Qt::ControlModifier, ControlMask );
+// m.insert( Qt::AltModifier, Mod1Mask );
+ m.insert( Qt::MetaModifier, Mod4Mask );
+ m.insert( Qt::AltModifier, Mod5Mask );
+
+ return m;
+}
+
+struct QInputGeneratorPrivate
+{
+ QInputGeneratorPrivate();
+ QInputGenerator* q;
+
+ void keyEvent(Qt::Key, bool);
+ void mouseEvent(QPoint const&, Qt::MouseButtons);
+
+ void ensureModifiers(Qt::KeyboardModifiers);
+ Qt::KeyboardModifiers currentModifiers() const;
+
+ QMap<int,int> const keymap;
+ QMap<int,uint> const buttonmap;
+
+ QPoint currentPos;
+ Qt::MouseButtons currentButtons;
+};
+
+QInputGeneratorPrivate::QInputGeneratorPrivate()
+ : keymap(qt_key_to_keysym_make()),
+ buttonmap(qt_button_to_x_button_make()),
+ currentPos(),
+ currentButtons(0)
+{}
+
+QInputGenerator::QInputGenerator(QObject* parent)
+ : QObject(parent),
+ d(new QInputGeneratorPrivate)
+{
+ d->q = this;
+ QINPUTGENERATOR_DEBUG() << "constructor";
+}
+
+QInputGenerator::~QInputGenerator()
+{
+ QINPUTGENERATOR_DEBUG() << "destructor";
+
+ /*
+ Restore all keyboard modifiers to off.
+ If we don't do this, the current modifiers stay activated for the current X server
+ even when this application is closed.
+ Note that there is no guarantee this code actually gets run.
+ */
+ d->ensureModifiers(0);
+ if (d->currentButtons) {
+ d->mouseEvent(d->currentPos, 0);
+ }
+
+ d->q = 0;
+ delete d;
+ d = 0;
+}
+
+/*
+ Returns the Qt keyboard modifiers which are currently pressed.
+*/
+Qt::KeyboardModifiers QInputGeneratorPrivate::currentModifiers() const
+{
+ Display* dpy = QX11Info::display();
+ if (!dpy) {
+ /* No X connection */
+ return 0;
+ }
+
+ Window root = 0;
+ Window child = 0;
+ int root_x = 0;
+ int root_y = 0;
+ int win_x = 0;
+ int win_y = 0;
+ uint buttons = 0;
+
+ // Grab all of the pointer info, though all we really care about is the modifiers.
+ bool ok = false;
+ for (int i = 0; i < ScreenCount(dpy) && !ok; ++i) {
+ if (XQueryPointer(dpy, (Window)QX11Info::appRootWindow(i), &root, &child, &root_x, &root_y,
+ &win_x, &win_y, &buttons))
+ ok = true;
+ }
+
+ if (!ok) {
+ qWarning() <<
+ "QInputGenerator: could not determine current state of keyboard modifiers. "
+ "Simulated key events may be incorrect.";
+ return 0;
+ }
+
+ // Convert to Qt::KeyboardModifiers.
+ static const QMap<int,int> modmap = qt_modifier_to_x_modmask_make();
+
+ Qt::KeyboardModifiers ret(0);
+ for (unsigned i = 0; i < sizeof(q->AllModifiers)/sizeof(Qt::KeyboardModifier); ++i) {
+ Qt::KeyboardModifier thisMod = q->AllModifiers[i];
+ int mask = modmap.value(thisMod);
+ if (buttons & mask) {
+ QINPUTGENERATOR_DEBUG() << "mod enabled:" << (void*)(int)thisMod << (void*)mask;
+ ret |= thisMod;
+ }
+ }
+
+ QINPUTGENERATOR_DEBUG() << "current modifiers:" << (void*)buttons << (void*)(int)ret;
+
+ return ret;
+}
+
+void QInputGeneratorPrivate::ensureModifiers(Qt::KeyboardModifiers desiredMod)
+{
+ Qt::KeyboardModifiers currentMod = currentModifiers();
+
+ // For each modifier..
+ for (unsigned i = 0; i < sizeof(q->AllModifiers)/sizeof(Qt::KeyboardModifier); ++i) {
+ Qt::KeyboardModifier thisMod = q->AllModifiers[i];
+ // If the modifier is currently disabled but we want it enabled, or vice-versa...
+ if ((desiredMod & thisMod) && !(currentMod & thisMod)) {
+ QINPUTGENERATOR_DEBUG() << "Enabling modifier" << (void*)thisMod << "by press";
+ // press to enable
+ keyEvent(q->modifierToKey(thisMod), true);
+ } else if (!(desiredMod & thisMod) && (currentMod & thisMod)) {
+ QINPUTGENERATOR_DEBUG() << "Disabling modifier" << (void*)thisMod << "by release";
+ // release to disable
+ keyEvent(q->modifierToKey(thisMod), false);
+ }
+ }
+
+// if (currentMod != desiredMod) {
+// currentMod = desiredMod;
+// for (int i = 0;
+// i < 1000 && QApplication::keyboardModifiers() != desiredMod;
+// i += 50, QtUiTest::wait(50))
+// {}
+//
+// if (QApplication::keyboardModifiers() != desiredMod)
+// qWarning() << "QtUitest: couldn't set all modifiers to desired state! "
+// "Current state:" << (void*)(int)QApplication::keyboardModifiers() <<
+// "Desired:" << (void*)(int)desiredMod;
+// }
+ if (currentMod != desiredMod) {
+ currentMod = desiredMod;
+ for (int i = 0;
+ i < 1000 && currentModifiers() != desiredMod;
+ i += 50, QtUiTest::wait(50))
+ {}
+
+ if (currentModifiers() != desiredMod)
+ qWarning() << "QtUitest: couldn't set all modifiers to desired state! "
+ "Current state:" << (void*)(int)currentModifiers() <<
+ "Desired:" << (void*)(int)desiredMod;
+ }
+
+}
+
+void QInputGeneratorPrivate::keyEvent(Qt::Key key, bool is_press)
+{
+ Display* dpy = QX11Info::display();
+ if (!dpy) {
+ /* No X connection */
+ return;
+ }
+
+ KeySym sym = 0;
+
+ do {
+// if ((key >= Qt::Key_0 && key <= Qt::Key_9) ||
+// (key >= Qt::Key_A && key <= Qt::Key_Z)) {
+// sym = QChar(key).toLower().unicode();
+// break;
+// }
+
+ if (key >= Qt::Key_A && key <= Qt::Key_Z) {
+ sym = QChar(key).toLower().unicode();
+ break;
+ }
+
+
+ QMap<int,int>::const_iterator found = keymap.find(key);
+ if (found != keymap.end()) {
+ sym = *found;
+ break;
+ }
+
+ if ((key < 0x1000 && key >= 0x20 )|| (key >= Qt::Key_0 && key <= Qt::Key_9) ){
+ sym = QChar(key).unicode();
+ KeyCode kc = XKeysymToKeycode(dpy, sym);
+ int syms_per_keycode;
+ KeySym *keymap = XGetKeyboardMapping(dpy, kc, 1, &syms_per_keycode);
+ for(int i=0; i<syms_per_keycode;i++)
+ {
+ QINPUTGENERATOR_DEBUG()<<"keymap["<<i<<"]is:"<<XKeysymToString(keymap[i]);
+ }
+
+ if (sym == keymap[1] && sym != keymap[0]) {
+ ensureModifiers(Qt::ShiftModifier);
+ }
+
+ else if (sym == keymap[4]) {
+ ensureModifiers(Qt::AltModifier);
+ }
+
+ XFree(keymap);
+ break;
+ }
+
+ qWarning() << "QInputGenerator: don't know how to translate Qt key"
+ << (void*)key << "into X11 keysym";
+ return;
+
+ } while(0);
+
+ QINPUTGENERATOR_DEBUG() << (is_press ? "press" : "release") << XKeysymToString(sym);
+
+ XTestFakeKeyEvent(
+ dpy,
+ XKeysymToKeycode(dpy, sym),
+ is_press,
+ 0
+ );
+}
+
+void QInputGenerator::keyPress(Qt::Key key, Qt::KeyboardModifiers mod, bool autoRepeat)
+{
+ Q_UNUSED(autoRepeat);
+ d->ensureModifiers(mod);
+ d->keyEvent(key, true);
+}
+
+void QInputGenerator::keyRelease(Qt::Key key, Qt::KeyboardModifiers mod)
+{
+ d->ensureModifiers(mod);
+ d->keyEvent(key, false);
+}
+
+void QInputGenerator::keyClick(Qt::Key key, Qt::KeyboardModifiers mod)
+{
+ keyPress(key,mod);
+ keyRelease(key,mod);
+}
+
+void QInputGeneratorPrivate::mouseEvent(QPoint const& pos, Qt::MouseButtons state)
+{
+ Display* dpy = QX11Info::display();
+ if (!dpy) {
+ /* No X connection */
+ return;
+ }
+
+ if (currentPos != pos) {
+ currentPos = pos;
+
+ XTestFakeMotionEvent(
+ dpy,
+ QX11Info::appScreen(),
+ pos.x(),
+ pos.y(),
+ 0
+ );
+
+ for (int i = 0;
+ i < 1000 && QCursor::pos() != pos;
+ i += 50, QtUiTest::wait(50))
+ {}
+
+ if (QCursor::pos() != pos)
+ qWarning() << "QtUitest: couldn't move cursor to desired point! "
+ "Current position:" << QCursor::pos() <<
+ "Desired:" << pos;
+
+ }
+
+ typedef QPair<uint,bool> ButtonEvent;
+ QList<ButtonEvent> buttonEvents;
+
+ foreach (int button, buttonmap.keys()) {
+ bool desired = button & state;
+ bool current = button & currentButtons;
+
+ // Do we need to press?
+ if (desired && !current) {
+ buttonEvents << qMakePair(buttonmap[button], true);
+ }
+
+ // Do we need to release?
+ if (!desired && current) {
+ buttonEvents << qMakePair(buttonmap[button], false);
+ }
+ }
+
+ foreach (ButtonEvent const& event, buttonEvents) {
+ QINPUTGENERATOR_DEBUG() << "Button event at" << pos << ":" << event.first << event.second;
+ XTestFakeButtonEvent(
+ dpy,
+ event.first,
+ event.second,
+ 0
+ );
+ }
+
+ currentButtons = state;
+}
+
+void QInputGenerator::mousePress(QPoint const& pos, Qt::MouseButtons state)
+{
+ QINPUTGENERATOR_DEBUG() << "Mouse press" << pos << (void*)(int)state;
+ d->mouseEvent(pos, d->currentButtons | state);
+}
+
+void QInputGenerator::mouseRelease(QPoint const& pos, Qt::MouseButtons state)
+{
+ QINPUTGENERATOR_DEBUG() << "Mouse release" << pos << (void*)(int)(d->currentButtons & ~state);
+ d->mouseEvent(pos, d->currentButtons & ~state);
+}
+
+void QInputGenerator::mouseClick(QPoint const& pos, Qt::MouseButtons state)
+{
+ mousePress (pos,state);
+ mouseRelease(pos,state);
+}
+
diff --git a/old/libqtuitest/qtestprotocol.cpp b/old/libqtuitest/qtestprotocol.cpp
new file mode 100644
index 0000000..713d217
--- /dev/null
+++ b/old/libqtuitest/qtestprotocol.cpp
@@ -0,0 +1,1162 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+/*
+ This cpp file contains a number of socket related classes that are used heavily in QtUiTest.
+ The classes are documented later in the file.
+*/
+
+#include "qtestprotocol_p.h"
+#include "qtuitestnamespace.h"
+
+#include <QApplication>
+#include <QString>
+#include <QTimer>
+#include <QUuid>
+#include <QFileInfo>
+#include <QDir>
+#include <QTcpSocket>
+#include <QTcpServer>
+#include <QHostAddress>
+#include <QHostInfo>
+#include <QPointer>
+
+#include <QDebug>
+#define qLog(A) if (1); else qDebug()
+
+#if defined(Q_OS_WIN32) && !defined(Q_OS_TEMP)
+# include <io.h>
+#endif
+
+static const int CONNECT_TIMEOUT = 20000;
+
+static const quint32 TEST_MSG_SIGNATURE = 0xEDBAEDBA;
+static const quint32 TEST_MSG_END = 0xEDBAABDE;
+static const quint8 TEST_MSG_VERSION = 3;
+static uint g_unique_id = 0;
+
+bool waitForSignal(QObject* object, const char* signal, int timeout)
+{
+#ifdef QTUITEST_TARGET
+ return QtUiTest::waitForSignal(object, signal, timeout);
+#else
+ QEventLoop loop;
+ QTimer dummy;
+ dummy.setInterval(1000);
+ if (!QObject::connect(object, signal, &dummy, SLOT(start())))
+ return false;
+ if (!QObject::connect(object, signal, &loop, SLOT(quit())))
+ return false;
+ QTimer::singleShot(timeout, &loop, SLOT(quit()));
+ loop.exec();
+ return dummy.isActive();
+#endif
+}
+
+void wait(int timeout)
+{
+#ifdef QTUITEST_TARGET
+ QtUiTest::wait(timeout);
+#else
+ QEventLoop loop;
+ QTimer::singleShot(timeout, &loop, SLOT(quit()));
+ loop.exec();
+#endif
+}
+
+// ********************************************************************************
+// ****************************** QTestMessage ************************************
+// ********************************************************************************
+
+/*
+ \class QTestMessage QTestMessage.h
+ \inpublicgroup QtUiTestModule
+
+ \brief The QTestMessage class can be used for exchanging messages between separate
+ processes. The class is never used directly but instead is used by QTestProtocol.
+
+ The class basically wraps a number of strings (i.e. 'event' and 'message') and binary data
+ (i.e. a bytearray or a file) into a datastream that is sent to a peer using a socket
+ connection. On the receiving side a QTestMessage instance is decoding the datastream
+ and performs a number of sanity checks to make it a bit more robost.
+
+ A TCP connection 'should' be reliable but in exceptional cases bytes may be lost. This
+ would result in the connection becoming useless because all future data reception would
+ be out of sync. To solve this a 'resync' function is implemented that can re-sync the datastream
+ by throwing away bytes until the data seems in sync again. The obvious downside is that
+ at least one message will be lost.
+
+ Message format is as follows:
+
+ Field: Length: Remarks:
+
+ Start signature 4 Fixed value - 0xEDBAEDBA
+ Protocol version 1 Fixed value - 3
+ Message number 2
+ Event length 4 Length of following string
+ Event string Event length QString value
+ Message length 4 Length of following string
+ Messaga string Message length QString value
+ Data length 4 Length of following binary data
+ File data Data length Binary data
+ End signature 4 Fixed value - 0xEDBAABDE
+*/
+
+/*
+ \internal
+
+ Constructs a default (empty) message.
+*/
+
+QTestMessage::QTestMessage(QString const &event, QVariantMap const &map)
+ : m_phase(0)
+ , m_msg_id(0)
+ , m_event(event)
+ , m_map(map)
+{
+}
+
+QTestMessage::QTestMessage(QString const &event, const QTestMessage &other )
+ : m_phase(0)
+ , m_msg_id(other.m_msg_id)
+ , m_map(other.m_map)
+{
+ m_event = event;
+}
+
+QTestMessage::QTestMessage(QString const &event, QString const &queryApp, QString const &queryPath )
+ : m_phase(0)
+ , m_msg_id(0)
+ , m_event(event)
+ , m_map(QVariantMap())
+{
+ m_map["queryapp"] = queryApp;
+ m_map["querypath"] = queryPath;
+}
+
+/*
+ \internal
+
+ Copy constructor.
+*/
+
+QTestMessage::QTestMessage(const QTestMessage &other)
+ : m_phase(0)
+ , m_msg_id(other.m_msg_id)
+ , m_event(other.m_event)
+ , m_map(other.m_map)
+{
+}
+
+/*
+ \internal
+
+ Destroys the message.
+*/
+
+QTestMessage::~QTestMessage()
+{
+}
+
+/*
+ \internal
+
+ Assignment operator.
+*/
+
+QTestMessage& QTestMessage::operator=(const QTestMessage &other)
+{
+ m_msg_id = other.m_msg_id;
+ m_event = other.m_event;
+ m_map = other.m_map;
+
+ return *this;
+}
+
+QVariant &QTestMessage::operator[](QString const &key)
+{
+ return m_map[key.toLower()];
+}
+
+QVariant const QTestMessage::operator[](QString const &key) const
+{
+ return m_map[key.toLower()];
+}
+
+bool QTestMessage::contains(QString const &key) const
+{
+ return m_map.contains(key.toLower());
+}
+
+QList<QString> QTestMessage::keys() const
+{
+ return m_map.keys();
+}
+
+QString QTestMessage::toString() const
+{
+ QString ret;
+ foreach(QString k, m_map.keys()) {
+ if (!m_map[k].isValid()) continue;
+ ret += k + ": ";
+ if (m_map[k].canConvert<QStringList>()) ret += "'" + m_map[k].toStringList().join("','") + "'";
+ else if (m_map[k].canConvert<QString>()) ret += "'" + m_map[k].toString() + "'";
+ else ret += "(data)";
+ ret += "\n";
+ }
+ if (ret.endsWith("\n")) ret.chop(1);
+ return ret;
+}
+
+/*
+ \internal
+ Returns the event that was received.
+*/
+
+QString QTestMessage::event() const
+{
+ return m_event;
+}
+
+/*
+ \internal
+ Returns the message number.
+*/
+
+quint16 QTestMessage::msgId() const
+{
+ return m_msg_id;
+}
+
+bool QTestMessage::statusOK() const
+{
+ return m_map.contains("status") && m_map["status"].toString() == "OK";
+}
+
+bool QTestMessage::isNull() const
+{
+ return m_map.isEmpty();
+}
+
+
+// ********************************************************************************
+// ************************* QTestServerSocket ************************************
+// ********************************************************************************
+
+/* !
+ \class QTestServerSocket qtestserversocket.h
+ \inpublicgroup QtUiTestModule
+
+ \brief The QTestServerSocket class provides a TCP-based server.
+
+ This class is a convenience class for accepting incoming TCP
+ connections. You can specify the port or have QTestServerSocket pick
+ one, and listen on just one address or on all the machine's
+ addresses.
+
+ Using the API is very simple: subclass QTestServerSocket, call the
+ constructor of your choice, and implement onNewConnection() to
+ handle new incoming connections. There is nothing more to do.
+
+ (Note that due to lack of support in the underlying APIs,
+ QTestServerSocket cannot accept or reject connections conditionally.)
+
+ \sa QTcpSocket, QTcpServer, QHostAddress, QSocketNotifier
+*/
+
+
+/* !
+ Creates a server socket object, that will serve the given \a port
+ on all the addresses of this host. If \a port is 0, QTestServerSocket
+ will pick a suitable port in a system-dependent manner. Use \a
+ backlog to specify how many pending connections the server can
+ have.
+
+ \warning On Tru64 Unix systems a value of 0 for \a backlog means
+ that you don't accept any connections at all; you should specify a
+ value larger than 0.
+*/
+
+QTestServerSocket::QTestServerSocket( quint16 port, int backlog )
+ : QTcpServer()
+{
+ setMaxPendingConnections( backlog );
+ listen( QHostAddress::Any, port );
+
+ if (this->serverPort() == 0) {
+ qWarning( QString("ERROR: port '%1' is already in use, application is aborted.").arg(port).toAscii() );
+ QApplication::exit(777);
+ }
+}
+
+/* !
+ Destroys the socket.
+
+ This causes any backlogged connections (connections that have
+ reached the host, but not yet been completely set up
+ to be severed.
+
+ Existing connections continue to exist; this only affects the
+ acceptance of new connections.
+*/
+QTestServerSocket::~QTestServerSocket()
+{
+}
+
+/* !
+ Returns true if the construction succeeded; otherwise returns false.
+*/
+bool QTestServerSocket::ok() const
+{
+ return serverPort() > 0;
+}
+
+/* !
+ Returns the port number on which this server socket listens. This
+ is always non-zero; if you specify 0 in the constructor,
+ QTestServerSocket will pick a non-zero port itself. ok() must be true
+ before calling this function.
+
+ \sa address()
+*/
+quint16 QTestServerSocket::port() const
+{
+ return serverPort();
+}
+
+/* !
+ Returns the address on which this object listens, or 0.0.0.0 if
+ this object listens on more than one address. ok() must be true
+ before calling this function.
+
+ \sa port()
+*/
+QString QTestServerSocket::address() const
+{
+ return serverAddress().toString();
+}
+
+void QTestServerSocket::incomingConnection( int socket )
+{
+ onNewConnection( socket );
+}
+
+// ********************************************************************************
+// *************************** QTestProtocol ************************************
+// ********************************************************************************
+
+/*
+ \class QTestProtocol qtestprotocol.h
+ \inpublicgroup QtUiTestModule
+
+ \brief The QTestProtocol class can be used for exchanging messages between separate
+ processes.
+
+ It is intended to be fast but at the same time ultra reliable and robust communication protocol.
+
+ The main function that is used on the sending side is:
+ \code
+ myConnection.postMessage( "My-Event", "My-Message", ptr_to_my_data );
+ \endcode
+
+ On the receiving side the main function is a re-implemented 'processMessage':
+ \code
+ void MyTestConnection::processMessage( QTestMessage *msg )
+ {
+ if (msg->event() == "My-Event") {
+ print( msg->message() );
+ }
+ }
+ \endcode
+*/
+
+#include <stdio.h>
+
+QTestProtocol::QTestProtocol()
+ : QTcpSocket()
+ , tx_msg_id(1)
+ , host()
+ , port(0)
+ , onData_busy(false)
+ , enable_reconnect(false)
+ , reconnect_interval(10000)
+ , connect_timer()
+ , last_data_received(false)
+ , connection_valid(false)
+ , ping_enabled(false)
+ , ping_interval(10000)
+ , ping_timer()
+ , ping_count(0)
+ , ping_timeout_warning_issued(false)
+ , last_send_cmd("")
+ , unique_id()
+ , debug_on(false)
+{
+ static int id1 = qRegisterMetaType<QTestMessage>(); Q_UNUSED(id1);
+ static int id2 = qRegisterMetaType<QTestMessage*>(); Q_UNUSED(id2);
+ static int id3 = qRegisterMetaType<const QTestMessage*>(); Q_UNUSED(id3);
+
+ unique_id = QString("%1").arg(++g_unique_id);
+ if (debug_on) {
+ qLog(QtUitest) << QString("%1 QTestProtocol::QTestProtocol()").arg(uniqueId()).toLatin1();
+ }
+ cur_message = 0;
+ rx_busy = false;
+
+ QObject::connect( &connect_timer, SIGNAL(timeout()), this, SLOT(connectTimeout()), Qt::DirectConnection );
+
+ QObject::connect( this,SIGNAL(connected()),this,SLOT(onSocketConnected()), Qt::DirectConnection );
+ QObject::connect( this,SIGNAL(disconnected()),this,SLOT(onSocketClosed()), Qt::DirectConnection );
+ QObject::connect( this,SIGNAL(readyRead()),this,SLOT(onData()), Qt::DirectConnection );
+
+ // initialize. Any time is better than no time.
+ rx_timer.start();
+}
+
+/*!
+ Destructs the instance of QTestProtocol.
+*/
+
+QTestProtocol::~QTestProtocol()
+{
+ if (debug_on) {
+ qLog(QtUitest) << QString("%1 QTestProtocol::~QTestProtocol()").arg(uniqueId()).toLatin1();
+ }
+ enableReconnect( false, 0 );
+
+ // we can't send any more messages so disable pinging
+ enablePing( false );
+
+ // anything that is still in the tx buffer gets lost
+ abort();
+ close();
+
+ while (send_msg_replies.count() > 0)
+ delete send_msg_replies.takeFirst();
+ while (unhandled_msg.count() > 0)
+ delete unhandled_msg.takeFirst();
+}
+
+void QTestProtocol::setSocket( int socket )
+{
+ if (debug_on) {
+ qLog(QtUitest) << ( QString("%1 QTestProtocol::setSocket(socket=%2)").
+ arg(uniqueId()).
+ arg(socket).toLatin1());
+ }
+ setSocketDescriptor( socket );
+
+ rx_timer.start();
+ testConnection();
+}
+
+void QTestProtocol::enableReconnect( bool enable, uint reconnectInterval )
+{
+ if (debug_on) {
+ qLog(QtUitest) << ( QString("%1 QTestProtocol::enableReconnect( enable=%2, interval=%3)").
+ arg(uniqueId()).
+ arg(enable).
+ arg(reconnectInterval).toLatin1());
+ }
+ enable_reconnect = enable;
+ reconnect_interval = reconnectInterval;
+}
+
+/*!
+ Opens a socket connection to the specified \a hostname and \a port.
+
+ After a connection is successfully opened the instance will listen for and process
+ incoming commands received from the remote host.
+*/
+void QTestProtocol::connect( const QString& hostname, int port )
+{
+ if (debug_on) {
+ qLog(QtUitest) << ( QString("%1 QTestProtocol::connect(%2:%3)").
+ arg(uniqueId()).
+ arg(hostname).
+ arg(port).toLatin1());
+ }
+
+ if (state() == ConnectedState) {
+ if (hostname == this->host && port == this->port)
+ return;
+ disconnect();
+ }
+
+ rx_timer.start();
+
+ this->host = hostname;
+ this->port = port;
+
+ reconnect();
+}
+
+void QTestProtocol::disconnect( bool disableReconnect )
+{
+ if (state() == ConnectedState) {
+ if (debug_on) {
+ qLog(QtUitest) << ( QString("%1 QTestProtocol::disconnect(disableReconnect=%2)").
+ arg(uniqueId()).
+ arg(disableReconnect).toLatin1());
+ }
+ // be polite and tell the other side we are closing
+ postMessage( QTestMessage("QTEST_CLOSING_CONNECTION") );
+
+ // we are closing ourselves, so we don't want to reconnect
+ if (disableReconnect) enable_reconnect = false;
+
+ onSocketClosed();
+ }
+}
+
+bool QTestProtocol::isConnected()
+{
+ return (state() == ConnectedState && connection_valid);
+}
+
+bool QTestProtocol::waitForConnected( int timeout )
+{
+ QtUiTestElapsedTimer t;
+ if (QTcpSocket::waitForConnected(timeout)) {
+ if (debug_on) {
+ qLog(QtUitest) << QString("%1 QTestProtocol::waitForConnected() ... testing connection").arg(uniqueId()).toLatin1();
+ }
+ while (t.elapsed() < timeout && !isConnected()) {
+ wait(500);
+ postMessage( QTestMessage("QTEST_NEW_CONNECTION") );
+ }
+ }
+ bool ok = isConnected();
+ if (debug_on) {
+ qLog(QtUitest) << QString("%1 QTestProtocol::waitForConnected() ... %2").arg(uniqueId()).arg(ok ? "OK" : "FAILED" ).toLatin1();
+ }
+ return ok;
+}
+
+/*!
+ \internal
+ Posts (e.g. non blocking) an \a event, \a message and contents of \a fileName to the remote host.
+*/
+
+uint QTestProtocol::postMessage(QTestMessage const &message )
+{
+ if (debug_on && message.event() != "PING" && message.event() != "PONG") {
+ qLog(QtUitest) << ( QString("%1 QTestProtocol::postMessage(%2)").
+ arg(uniqueId()).
+ arg(message.event()).toLatin1());
+ }
+ if (state() != ConnectedState)
+ return 0;
+ QTestMessage msg(message);
+ msg.m_msg_id = tx_msg_id++;
+ send( msg );
+ return msg.m_msg_id;
+}
+
+void QTestProtocol::onReplyReceived( QTestMessage* /*reply*/ )
+{
+}
+
+/*!
+ \internal
+ Sends an \a event, \a message and \a data to the remote host and waits for up to
+ \a timeout milliseconds for a reply. If a reply is received, the reply's message
+ string is placed in \a reply.
+*/
+bool QTestProtocol::sendMessage( QTestMessage const &message, QTestMessage &reply, int timeout )
+{
+ QTestMessage msg(message);
+ QPointer<QTestProtocol> safeThis(this);
+ bool safeDebugOn(debug_on);
+ QString safeUniqueId(uniqueId());
+
+ last_send_cmd = message.event();
+
+ if (state() == ConnectingState) {
+ wait(4000);
+ }
+
+ if (state() == ConnectedState) {
+ msg.m_msg_id = tx_msg_id++;
+
+ if (debug_on) {
+ qLog(QtUitest) << ( QString("%1 QTestProtocol::sendMessage(%2) msgid=%3)").
+ arg(uniqueId()).
+ arg(msg.event()).
+ arg(msg.msgId()).
+ toLatin1());
+ }
+
+ send( msg );
+
+ QtUiTestElapsedTimer t;
+ QtUiTestElapsedTimer t2;
+ bool first_time = true;
+ while ( (state() == ConnectedState) && (timeout < 0 || t.elapsed() < timeout) ) {
+
+ if (debug_on) {
+ if (first_time || t2.elapsed() > 1000) {
+ qLog(QtUitest) << ( QString("%1 QTestProtocol::sendMessage(%2) ... waiting for reply").
+ arg(uniqueId()).
+ arg(message.event()).toLatin1());
+ t2.start();
+ first_time = false;
+ }
+ }
+
+
+ waitForSignal(this, SIGNAL(replyReceived()), 500);
+
+ if (!safeThis) {
+ if (message["expectClose"].isValid()) {
+ return true;
+ }
+ if (safeDebugOn) {
+ qLog(QtUitest) << ( QString("%1 QTestProtocol::sendMessage(%2) ... object deleted unexpectedly").
+ arg(safeUniqueId).
+ arg(message.event()).toLatin1());
+ }
+ reply["status"] = "ERROR: Connection was terminated unexpectedly. This may be caused by an application crash.";
+ reply["_q_inResponseTo"] = QString("%1\n%2").arg(message.event()).arg(message.toString());
+ return false;
+ } else {
+ if (send_msg_replies.count() > 0) {
+ if (debug_on) {
+ qLog(QtUitest) << ( QString("%1 QTestProtocol::sendMessage(%2) ... check replies").
+ arg(uniqueId()).
+ arg(message.event()).toLatin1());
+ }
+ for (int i=0; i<send_msg_replies.size(); i++) {
+ QTestMessage * possible_reply = send_msg_replies.at(i);
+ if (possible_reply && possible_reply->m_msg_id == msg.m_msg_id) {
+
+ reply = *possible_reply;
+ delete send_msg_replies.takeAt( i );
+
+ if (debug_on) {
+ qLog(QtUitest) << ( QString("%1 QTestProtocol::sendMessage(%2) ... reply received").
+ arg(uniqueId()).
+ arg(message.event()).toLatin1());
+ }
+
+ onReplyReceived(&reply);
+ return true;
+ }
+ }
+ }
+ }
+ }
+ if (state() != ConnectedState) {
+ reply["status"] = "ERROR: Connection lost. This is likely caused by a crash in the Application Under Test.";
+ reply["_q_inResponseTo"] = QString("%1\n%2").arg(message.event()).arg(message.toString());
+ }
+ else {
+ reply["status"] = "ERROR_REPLY_TIMEOUT";
+ reply["_q_inResponseTo"] = QString("%1\n%2").arg(message.event()).arg(message.toString());
+ }
+ reply["location"] = QString("%1:%2").arg(__FILE__).arg(__LINE__);
+ } else {
+ reply["status"] = "ERROR_NO_CONNECTION";
+ reply["_q_inResponseTo"] = QString("%1\n%2").arg(message.event()).arg(message.toString());
+ reply["location"] = QString("%1:%2").arg(__FILE__).arg(__LINE__);
+ }
+
+ if (debug_on) {
+ qLog(QtUitest) << ( QString("%1 QTestProtocol::sendMessage(%2) ... done. Status: %3").
+ arg(uniqueId()).
+ arg(message.event()).arg(reply["status"].toString()).toLatin1());
+ }
+
+ return false;
+}
+
+/*!
+ Send the string \a result as a reply to \a originalMsg.
+*/
+
+void QTestProtocol::replyMessage( QTestMessage *originalMsg, QTestMessage const &message )
+{
+ if (debug_on) {
+ qLog(QtUitest) << ( QString("%1 QTestProtocol::replyMessage(%2)").
+ arg(uniqueId()).
+ arg(originalMsg->event()).toLatin1());
+ }
+
+ QTestMessage msg(message);
+ msg.m_msg_id = originalMsg->msgId();
+ msg.m_event = "@REPLY@";
+ send( msg );
+}
+
+bool QTestProtocol::lastDataReceived()
+{
+ return last_data_received;
+}
+
+QString QTestProtocol::errorStr()
+{
+ QString S = "Connection error: ";
+ switch (error()) {
+ case ConnectionRefusedError: S += "A connection attempt was rejected by the peer"; break;
+ case HostNotFoundError: S += "Host not found"; break;
+ case RemoteHostClosedError: S += "RemoteHostClosedError"; break;
+ case SocketAccessError: S += "SocketAccessError"; break;
+ case SocketResourceError: S += "SocketResourceError"; break;
+ case SocketTimeoutError: S += "SocketTimeoutError"; break;
+ case DatagramTooLargeError: S += "DatagramTooLargeError"; break;
+ case NetworkError: S += "NetworkError"; break;
+ case AddressInUseError: S += "AddressInUseError"; break;
+ case SocketAddressNotAvailableError: S += "SocketAddressNotAvailableError"; break;
+ case UnsupportedSocketOperationError: S += "UnsupportedSocketOperationError"; break;
+ case UnknownSocketError: S += "UnknownSocketError"; break;
+ default: S += " Unknown error";
+ }
+
+ return S;
+}
+
+void QTestProtocol::onConnectionFailed( const QString &reason )
+{
+ emit connectionFailed( this, reason );
+}
+
+void QTestProtocol::testConnection()
+{
+ if (debug_on) {
+ qLog(QtUitest) << QString("%1 QTestProtocol::testConnection()").arg(uniqueId()).toLatin1();
+ }
+
+ while (send_msg_replies.count() > 0)
+ delete send_msg_replies.takeFirst();
+
+ enablePing( true );
+ postMessage( QTestMessage("QTEST_NEW_CONNECTION") );
+}
+
+void QTestProtocol::send( QTestMessage const &message )
+{
+ QByteArray data;
+ if (!message.m_map.isEmpty()) {
+ QDataStream s(&data, QIODevice::WriteOnly);
+ s << message.m_map;
+ }
+
+ QDataStream tmp(this);
+ sendPreamble( &tmp, message.msgId(), message.event() );
+
+ quint32 len = data.count();
+ tmp << len; // phase 2
+ if (len > 0) {
+ tmp.writeRawData( data.data(), (int)len ); // phase 3
+ }
+
+ tmp << TEST_MSG_END; // phase 4
+
+ flush(); // Force socket to send data now
+}
+
+void QTestProtocol::sendPreamble( QDataStream *ds, quint16 msgId, const QString &event )
+{
+ quint32 len;
+ *ds << TEST_MSG_SIGNATURE; // phase 0
+ *ds << TEST_MSG_VERSION;
+ *ds << msgId;
+
+ len = (event.length() *2) + 4;
+ *ds << len;
+ *ds << event; // phase 1
+}
+
+bool QTestProtocol::receive( QTestMessage *msg, bool &syncError )
+{
+ syncError = false;
+
+ QDataStream stream(this);
+
+ quint8 rx_version;
+ if (msg->m_phase == uint(0)) {
+ msg->m_len = 0;
+ quint32 sig;
+ if (bytesAvailable() >= sizeof( sig ) + sizeof( rx_version ) + sizeof( msg->m_msg_id ) + sizeof( msg->m_len )) {
+ stream >> sig;
+ if (sig != TEST_MSG_SIGNATURE) {
+ qWarning( QString("QTestMessage::receive(), Invalid start signature (0x%1)").arg(sig,8,16).toLatin1() );
+ syncError = true;
+ return false;
+ } else {
+ stream >> rx_version; // FIXME: something should be done to verify the version.
+ stream >> msg->m_msg_id;
+ stream >> msg->m_len;
+ msg->m_phase++;
+ }
+ }
+ }
+
+ if (msg->m_phase == uint(1)) {
+ if (bytesAvailable() >= msg->m_len) {
+ stream >> msg->m_event;
+ msg->m_phase++;
+ }
+ }
+
+ if (msg->m_phase == uint(2)) {
+ if (bytesAvailable() >= sizeof( msg->m_len )) {
+ stream >> msg->m_len;
+ msg->m_phase++;
+ }
+ }
+
+ if (msg->m_phase == uint(3)) {
+ if (msg->m_len > 0) {
+ QByteArray buf;
+ quint32 len = msg->m_len;
+ uint bytes_available = bytesAvailable();
+ if (bytes_available < len)
+ len = bytes_available;
+ buf.resize( len );
+ stream.readRawData( buf.data(), len );
+
+ static QMap<QTestMessage*, QByteArray> data;
+ data[msg].append(buf);
+
+ msg->m_len -= len;
+ if (msg->m_len == 0) {
+ QDataStream s(&data[msg], QIODevice::ReadOnly);
+ s >> msg->m_map;
+ data.remove(msg);
+ msg->m_phase++;
+ // received OK
+ } else {
+ // waiting for more data
+ return false;
+ }
+ } else {
+ msg->m_phase++;
+ }
+ }
+
+ if (msg->m_phase == uint(4)) {
+ quint32 id2;
+ if (bytesAvailable() >= sizeof( id2 )) {
+ stream >> id2;
+ msg->m_phase = 0;
+ if (id2 != TEST_MSG_END) {
+ qWarning( QString("QTestMessage::receive(), Invalid end signature (0x%2)").arg(id2,8,16).toLatin1() );
+ syncError = true;
+ return false;
+ } else {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool QTestProtocol::rxBusy()
+{
+ return rx_busy;
+}
+
+/*!
+ Reads the remote control connection and responds to received commands.
+*/
+
+void QTestProtocol::onData()
+{
+ if (onData_busy) return;
+ onData_busy = true;
+
+ int sync_error_count = 0;
+ bool msg_received = true;
+ while (msg_received && bytesAvailable() > 0) {
+ msg_received = false;
+ // set the time to now :-)
+ rx_timer.start();
+ ping_timeout_warning_issued = false;
+
+ bool sync_error;
+ if (cur_message == 0)
+ cur_message = new QTestMessage();
+
+ if (receive( cur_message, sync_error )) {
+ msg_received = true;
+ QString last_event = cur_message->event();
+
+ if (debug_on) {
+ qLog(QtUitest) << ( QString("%1 QTestProtocol::onData(%2) msgid = %3").
+ arg(uniqueId()).
+ arg(last_event).
+ arg(cur_message->m_msg_id).
+ toLatin1());
+ }
+
+ // We received a full message
+ if (last_event == "@REPLY@") {
+ send_msg_replies.append( cur_message ); // add the reply to a list
+ int id = cur_message->m_msg_id;
+ QTestMessage *received_message(cur_message);
+ cur_message = 0; // and make sure we create a new one
+ emit replyReceived( id, received_message );
+ } else if (last_event == "QTEST_NEW_CONNECTION") {
+ postMessage( QTestMessage("QTEST_ACK_CONNECTION") ); // Acknowledge the other side we can receive data
+ } else if (last_event == "QTEST_ACK_CONNECTION") {
+ connection_valid = true; // we don't assume we have a connection until both sides have actually received data from the other side
+ onConnected();
+ connect_timer.stop();
+ } else if (last_event == "QTEST_CLOSING_CONNECTION") {
+ last_data_received = true;
+ QTimer::singleShot( 0, this, SLOT(onSocketClosed()));
+ } else if (last_event == "PONG") {
+ // Do nothing
+ } else if (last_event == "TEST") {
+ if (!debug_on) {
+ // don't show the same information twice
+ qLog(QtUitest) << QString("%1 Test message received").arg(uniqueId()).toLatin1();
+ }
+ } else if (last_event == "PING") {
+ postMessage( QTestMessage("PONG") );
+ } else {
+ unhandled_msg.append( cur_message ); // add the msg to a list
+ cur_message = 0;
+ QTimer::singleShot(0,this,SLOT(processMessages()));
+ }
+
+ delete cur_message;
+ cur_message = 0;
+ } else {
+ // We didn't receive a full message
+ if (sync_error) {
+ sync_error_count++;
+ if (sync_error_count > 10)
+ return;
+ // receiving garbage messages - nothing can be done but closing the connection and try again.
+ delete cur_message;
+ cur_message = 0;
+ disconnect(!enable_reconnect);
+ reconnect();
+ }
+ // else we are waiting on more fragments to arrive
+ }
+ }
+ onData_busy = false;
+}
+
+void QTestProtocol::processMessages()
+{
+ while (!rx_busy && unhandled_msg.count() > 0) {
+ QTestMessage *tmp = unhandled_msg.takeFirst();
+ if (tmp) {
+ rx_busy = true;
+ processMessage( tmp );
+ delete tmp;
+ rx_busy = false;
+ }
+ }
+}
+
+/*!
+ Signals the instance that the other side has closed the connection.
+*/
+void QTestProtocol::onSocketClosed()
+{
+ if (debug_on) {
+ qLog(QtUitest) << QString("%1 QTestProtocol::onSocketClosed()").arg(uniqueId()).toLatin1();
+ }
+
+ // we can't send any more messages so disable pinging
+ enablePing( false );
+
+ // anything that is still in the tx buffer gets lost
+ abort();
+
+ close();
+
+ connection_valid = false;
+
+ // if the close was spontaneous and we want to keep the connection alive, we try to reconnect
+ if (enable_reconnect) {
+ if (debug_on) {
+ qLog(QtUitest) <<
+ QString("%1 QTestProtocol::onSocketClosed() singleshot reconnect in .5 seconds").arg(uniqueId()).toLatin1();
+ }
+ QTimer::singleShot(500,this,SLOT(reconnect()));
+ }
+
+ // tell the world we are closed
+ QTimer::singleShot(0, this, SLOT(emitConnectionClosed()));
+}
+
+/*!
+ Signals the instance that a connection is established with a remote control host.
+*/
+void QTestProtocol::onSocketConnected()
+{
+ connect_timer.stop();
+ if (debug_on) {
+ qLog(QtUitest) << QString("%1 QTestProtocol::onSocketConnected()").arg(uniqueId()).toLatin1();
+ }
+ testConnection();
+}
+
+void QTestProtocol::reconnect()
+{
+ if (host != "" && state() != ConnectedState) {
+ if (debug_on) {
+ qLog(QtUitest) << QString("%1 QTestProtocol::reconnect()").arg(uniqueId()).toLatin1();
+ }
+
+ connect_timer.stop();
+ connect_timer.start( CONNECT_TIMEOUT );
+
+ // if we are trying to connect to the local machine, always use 127.0.0.1
+ // (and avoid the need for dns)
+ QString hostname = QHostInfo::localHostName().toUpper();
+ if (hostname == host.toUpper() || hostname.startsWith( host.toUpper() + "." ))
+ host = "127.0.0.1";
+
+ close();
+ connectToHost( host, port );
+ } else {
+ if (host == "") {
+ qWarning( "QTestProtocol::reconnect() FAILED, no host specified" );
+ enable_reconnect = false;
+ }
+ }
+}
+
+void QTestProtocol::connectTimeout()
+{
+ if (debug_on) {
+ qLog(QtUitest) << QString("%1 QTestProtocol::connectTimeout()").arg(uniqueId()).toLatin1();
+ }
+
+ connect_timer.stop();
+ if (enable_reconnect) {
+ reconnect();
+ } else {
+ onConnectionFailed( errorStr() );
+ }
+}
+
+void QTestProtocol::pingTimeout()
+{
+ if (!ping_enabled) return;
+
+ if (state() == ConnectedState) {
+ int elapsed = rx_timer.elapsed();
+ if (state() == ClosingState) {
+ if (elapsed > 30000) { // no activity for x seconds when we are closing?
+ enablePing( false );
+ if (enable_reconnect) {
+ disconnect();
+ // close has reset the enable_reconnect value, so enable it again
+ enableReconnect( true, reconnect_interval );
+ reconnect();
+ } else {
+ disconnect();
+ }
+ } else if (elapsed > 2000 ) {
+ postMessage( QTestMessage("PING") );
+ }
+ } else {
+ if (elapsed > 10000) {
+ postMessage( QTestMessage("PING") );
+ if (elapsed > 300000) { // no activity for 5 minutes in 'normal' cases??
+ if (!ping_timeout_warning_issued)
+ qWarning( QString("%1 QTestProtocol::pingTimeout() WARNING: Did not receive a msg for %2 ms").arg(uniqueId()).arg(elapsed).toLatin1() );
+ ping_timeout_warning_issued = true;
+ }
+ }
+ }
+ } else {
+ if (enable_reconnect) {
+ // Connection seems to be closed, try to reconnect
+ disconnect();
+
+ // disconnect has reset the enable_reconnect value, so enable it again
+ enableReconnect( true, reconnect_interval );
+ reconnect();
+ }
+ }
+}
+
+void QTestProtocol::emitConnectionClosed()
+{
+ if (debug_on) {
+ qLog(QtUitest) << ( QString("%1 QTestProtocol::emitConnectionClosed()").arg(uniqueId()).toLatin1());
+ }
+
+ emit replyReceived(); // force sendMessage to quit
+ emit connectionClosed( this );
+}
+
+void QTestProtocol::enablePing( bool enable )
+{
+ if (ping_enabled != enable) {
+ ping_timer.stop();
+ ping_enabled = enable;
+ if (enable) {
+ QObject::connect( &ping_timer, SIGNAL(timeout()), this, SLOT(pingTimeout()), Qt::DirectConnection );
+ ping_timer.start( ping_interval );
+ } else {
+ QObject::disconnect( &ping_timer, SIGNAL(timeout()), this, SLOT(pingTimeout()) );
+ }
+ }
+}
+
+QString QTestProtocol::uniqueId()
+{
+ return QString("%1 %2").arg(unique_id).arg(qApp->applicationName());
+}
+
+void QTestProtocol::enableDebug( bool debugOn )
+{
+ debug_on = debugOn;
+ qLog(QtUitest) << QString("Debugging is switched %1 for Test Protocol %2").arg(debugOn ? "ON" : "OFF").arg(uniqueId()).toLatin1() ;
+}
+
+void QTestProtocol::disableDebug()
+{
+ debug_on = false;
+ qLog(QtUitest) << QString("Debugging is switched %1 for Test Protocol %2").arg(debug_on ? "ON" : "OFF").arg(uniqueId()).toLatin1() ;
+}
+
diff --git a/old/libqtuitest/qtestprotocol_p.h b/old/libqtuitest/qtestprotocol_p.h
new file mode 100644
index 0000000..ca274f3
--- /dev/null
+++ b/old/libqtuitest/qtestprotocol_p.h
@@ -0,0 +1,228 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QTESTPROTOCOL_P_H
+#define QTESTPROTOCOL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtUiTest API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QTimer>
+#include <QTime>
+#include <QObject>
+#include <QString>
+#include <QFile>
+#include <QVariant>
+#include <QMap>
+#include <QtNetwork/QTcpSocket>
+#include <QtNetwork/QTcpServer>
+#include <qtuitestglobal.h>
+
+#include "qtuitestelapsedtimer_p.h"
+
+#define REMOTE_CONNECT_ERROR 99
+
+class QTUITEST_EXPORT QTestMessage
+{
+public:
+ QTestMessage(QString const &event = QString(), QVariantMap const &map = QVariantMap() );
+ QTestMessage(QString const &event, const QTestMessage &other );
+ QTestMessage(QString const &event, QString const &queryApp, QString const &queryPath = QString() );
+ QTestMessage(const QTestMessage &other);
+ virtual ~QTestMessage();
+
+ QTestMessage& operator=(const QTestMessage &other);
+
+ QString event() const;
+ quint16 msgId() const;
+
+ QVariant const operator[](QString const &key) const;
+ QVariant &operator[](QString const &key);
+ bool contains(QString const &key) const;
+ QList<QString> keys() const;
+
+ QString toString() const;
+
+ bool statusOK() const;
+ bool isNull() const;
+
+protected:
+ uint m_phase;
+ quint32 m_len;
+
+ quint16 m_msg_id;
+ QString m_event;
+
+ QVariantMap m_map;
+
+ friend class QTestProtocol;
+};
+Q_DECLARE_METATYPE( QTestMessage )
+Q_DECLARE_METATYPE( QTestMessage* )
+Q_DECLARE_METATYPE( const QTestMessage* )
+
+class QTUITEST_EXPORT QTestServerSocket : public QTcpServer
+{
+ Q_OBJECT
+public:
+ QTestServerSocket( quint16 port, int backlog = 1 );
+ virtual ~QTestServerSocket();
+
+ bool ok() const;
+ quint16 port() const;
+ QString address() const;
+
+ virtual void onNewConnection( int socket ) = 0;
+
+private:
+ virtual void incomingConnection( int socket );
+};
+
+class QTUITEST_EXPORT QTestProtocol : public QTcpSocket
+{
+ Q_OBJECT
+public:
+
+ QTestProtocol();
+ virtual ~QTestProtocol();
+
+ virtual void setSocket( int socket );
+
+ void enableReconnect( bool enable, uint reconnectInterval = 5000 );
+
+ void connect( const QString& hostname, int port );
+ void disconnect( bool disableReconnect = true );
+ bool isConnected();
+ virtual bool waitForConnected( int timeout = 10000 );
+
+ virtual uint postMessage( QTestMessage const &message );
+
+ virtual bool sendMessage( QTestMessage const &message, QTestMessage &reply, int timeout );
+ virtual void replyMessage( QTestMessage *originalMsg, QTestMessage const &message );
+
+ bool lastDataReceived();
+ bool rxBusy();
+ virtual void onReplyReceived( QTestMessage *reply );
+
+ QString errorStr();
+
+ virtual void onConnectionFailed( const QString &reason );
+ virtual void onConnected() {}; // re-implement in derived class
+
+ QString uniqueId();
+ void enableDebug( bool debugOn );
+
+public slots:
+ void reconnect();
+ void disableDebug();
+
+protected:
+ virtual void processMessage( QTestMessage *msg ) = 0;
+
+ void send( QTestMessage const &message );
+ static void sendPreamble( QDataStream *ds, quint16 msgId, const QString &event );
+
+ bool receive( QTestMessage *msg, bool &syncError );
+
+signals:
+ void connectionClosed( QTestProtocol *socket );
+ void connectionFailed( QTestProtocol *socket, const QString &reason );
+ void replyReceived(int id = -1, QTestMessage const *message = 0);
+ void replyConfirmed();
+
+protected slots:
+ void onData();
+ void onSocketConnected();
+ void onSocketClosed();
+ void connectTimeout();
+ void pingTimeout();
+ void emitConnectionClosed();
+ void processMessages();
+ void testConnection();
+
+private:
+ void enablePing( bool enable );
+
+ quint16 tx_msg_id;
+ QString host;
+ int port;
+ bool onData_busy;
+ bool enable_reconnect;
+ uint reconnect_interval;
+ QTimer connect_timer;
+ QtUiTestElapsedTimer rx_timer;
+ bool last_data_received;
+ bool rx_busy;
+ bool connection_valid;
+
+ QList<QTestMessage*> send_msg_replies;
+ QList<QTestMessage*> unhandled_msg;
+ QTestMessage *cur_message;
+
+ bool ping_enabled;
+ uint ping_interval;
+ QTimer ping_timer;
+ uint ping_count;
+ bool ping_timeout_warning_issued;
+ QString last_send_cmd;
+ QString unique_id;
+ bool debug_on;
+};
+
+#define TAB_BAR_ALIAS ">@TAB_BAR@<"
+#define OPTIONS_MENU_ALIAS ">@OPTIONS_MENU@<"
+#define LAUNCHER_MENU_ALIAS ">@LAUNCHER_MENU@<" // launcher menu _can_ be a grid menu, but also a wheel menu, etc
+#define SOFT_MENU_ALIAS ">@SOFT_MENU@<"
+#define PROGRESS_BAR_ALIAS ">@PROGRESS_BAR@<"
+#define CALL_ACCEPT_ALIAS ">@CALL_ACCEPT@<"
+#define CALL_HANGUP_ALIAS ">@CALL_HANGUP@<"
+#define MENU_BAR_ALIAS ">@MENU_BAR@<"
+
+#endif
+
diff --git a/old/libqtuitest/qtuitestconnectionmanager.cpp b/old/libqtuitest/qtuitestconnectionmanager.cpp
new file mode 100644
index 0000000..f7ae638
--- /dev/null
+++ b/old/libqtuitest/qtuitestconnectionmanager.cpp
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** 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 "qtuitestconnectionmanager_p.h"
+
+#include <QCoreApplication>
+#include <QObject>
+#include <QThread>
+
+// from qobject_p.h
+struct QSignalSpyCallbackSet
+{
+ typedef void (*BeginCallback)(QObject*,int,void**);
+ typedef void (*EndCallback)(QObject*,int);
+ BeginCallback signal_begin_callback,
+ slot_begin_callback;
+ EndCallback signal_end_callback,
+ slot_end_callback;
+};
+extern void Q_CORE_EXPORT qt_register_signal_spy_callbacks(QSignalSpyCallbackSet const&);
+void qtuitest_signal_begin(QObject*,int,void**);
+
+Q_GLOBAL_STATIC(QtUiTestConnectionManager,_q_qtUiTestConnectionManager);
+
+QtUiTestConnectionManager::QtUiTestConnectionManager()
+{
+ QSignalSpyCallbackSet callbacks = { qtuitest_signal_begin, 0, 0, 0 };
+ qt_register_signal_spy_callbacks(callbacks);
+}
+
+QtUiTestConnectionManager::~QtUiTestConnectionManager()
+{
+ QSignalSpyCallbackSet callbacks = { 0, 0, 0, 0 };
+ qt_register_signal_spy_callbacks(callbacks);
+}
+
+void qtuitestconnectionmanager_cleanup()
+{ delete _q_qtUiTestConnectionManager(); }
+
+QtUiTestConnectionManager* QtUiTestConnectionManager::instance()
+{
+ return _q_qtUiTestConnectionManager();
+}
+
+void qtuitest_signal_begin(QObject* sender, int signal, void** argv)
+{
+ QtUiTestConnectionManager* cm = QtUiTestConnectionManager::instance();
+
+ // Should only ever be null when the application is shutting down, but in that case,
+ // this callback should already have been unregistered.
+ Q_ASSERT(cm);
+
+ // During the destructor it isn't safe to check which thread we are.
+ // We'll just ignore all signals during this time.
+ if (QCoreApplication::closingDown()) return;
+
+ // Connections are only supported in the main thread.
+ if (QThread::currentThread() != QCoreApplication::instance()->thread()) return;
+
+ cm->activateConnections(sender,signal,argv);
+}
+
+void QtUiTestConnectionManager::connect(QObject const* sender, int senderMethod,
+ QObject const* receiver, int receiverMethod)
+{
+ Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread());
+
+ Connection c = {
+ const_cast<QObject*>(sender), senderMethod,
+ const_cast<QObject*>(receiver), receiverMethod
+ };
+ m_connections << c;
+}
+
+bool QtUiTestConnectionManager::disconnect(QObject const* sender, int senderMethod,
+ QObject const* receiver, int receiverMethod)
+{
+ Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread());
+
+ bool ret = false;
+
+ QList<Connection>::iterator iter = m_connections.begin();
+ while (iter != m_connections.end())
+ {
+ bool remove = true;
+
+ if (sender && (sender != iter->sender)) remove = false;
+ if ((senderMethod != -1) && (senderMethod != iter->senderMethod)) remove = false;
+ if (receiver && (receiver != iter->receiver)) remove = false;
+ if ((receiverMethod != -1) && (receiverMethod != iter->receiverMethod)) remove = false;
+
+ if (remove) {
+ ret = true;
+ iter = m_connections.erase(iter);
+ }
+ else {
+ ++iter;
+ }
+ }
+
+ return ret;
+}
+
+void QtUiTestConnectionManager::activateConnections(QObject* sender, int senderMethod, void** argv)
+{
+ static const int destroyedMethod = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
+ const bool destroyed = (senderMethod == destroyedMethod);
+
+ // Find all of the connections we need to activate.
+ QList<Connection> toActivate;
+ QList<Connection>::iterator iter = m_connections.begin();
+ while (iter != m_connections.end())
+ {
+ if (sender == iter->sender && senderMethod == iter->senderMethod)
+ toActivate << *iter;
+
+ // Remove this connection if either the sender or receiver is being destroyed
+ if (destroyed && (sender == iter->sender || sender == iter->receiver))
+ iter = m_connections.erase(iter);
+ else
+ ++iter;
+ }
+
+ foreach (Connection const& c, toActivate)
+ { c.receiver->qt_metacall(QMetaObject::InvokeMetaMethod, c.receiverMethod, argv); }
+}
+
diff --git a/old/libqtuitest/qtuitestconnectionmanager_p.h b/old/libqtuitest/qtuitestconnectionmanager_p.h
new file mode 100644
index 0000000..13a1017
--- /dev/null
+++ b/old/libqtuitest/qtuitestconnectionmanager_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QTUITESTCONNECTIONMANAGER_P_H
+#define QTUITESTCONNECTIONMANAGER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtUiTest API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QList>
+#include <qtuitestglobal.h>
+
+class QObject;
+
+class QTUITEST_EXPORT QtUiTestConnectionManager
+{
+public:
+ static QtUiTestConnectionManager* instance();
+
+ void connect (QObject const*,int,QObject const*,int);
+ bool disconnect(QObject const*,int,QObject const*,int);
+
+ QtUiTestConnectionManager();
+ ~QtUiTestConnectionManager();
+
+ void activateConnections(QObject*,int,void**);
+
+ struct Connection {
+ QObject* sender;
+ int senderMethod;
+ QObject* receiver;
+ int receiverMethod;
+ };
+ QList<Connection> m_connections;
+};
+
+#endif
+
diff --git a/old/libqtuitest/qtuitestelapsedtimer.cpp b/old/libqtuitest/qtuitestelapsedtimer.cpp
new file mode 100644
index 0000000..5e9a593
--- /dev/null
+++ b/old/libqtuitest/qtuitestelapsedtimer.cpp
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** 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 "qtuitestelapsedtimer_p.h"
+
+#include <time.h>
+#include <errno.h>
+#include <string.h>
+#include <QtGlobal>
+
+/*!
+ \internal
+ \class QtUiTestElapsedTimer
+ \inpublicgroup QtUiTestModule
+
+ QtUiTestElapsedTimer provides a lightweight
+ subset of the QTime API while keeping correct time even if the system time
+ is changed.
+*/
+
+int qtuitestelapsedtimer_gettime() {
+#if _POSIX_TIMERS
+ struct timespec tms;
+ if (-1 == clock_gettime(
+#ifdef _POSIX_MONOTONIC_CLOCK
+ CLOCK_MONOTONIC
+#else
+ CLOCK_REALTIME
+#endif
+ , &tms)) {
+ qFatal("QtUitest: clock_gettime failed: %s",
+ strerror(errno));
+ }
+ return tms.tv_sec*1000 + tms.tv_sec/1000000;
+#else
+ /*
+ FIXME: won't keep correct time if system time is changed during test.
+ Should warn about this?
+ */
+ return time(0)*1000;
+#endif
+}
+
+/*!
+ Creates a new timer.
+ start() is automatically called on the new timer.
+*/
+QtUiTestElapsedTimer::QtUiTestElapsedTimer()
+{ start(); }
+
+/*!
+ Starts or restarts the timer.
+*/
+void QtUiTestElapsedTimer::start()
+{ start_ms = qtuitestelapsedtimer_gettime(); }
+
+/*!
+ Returns the elapsed time (in milliseconds) since start() was called.
+
+ This function returns the correct value even if the system time has
+ been changed. The value may overflow, however.
+ */
+int QtUiTestElapsedTimer::elapsed()
+{ return qtuitestelapsedtimer_gettime() - start_ms; }
+
diff --git a/old/libqtuitest/qtuitestelapsedtimer_p.h b/old/libqtuitest/qtuitestelapsedtimer_p.h
new file mode 100644
index 0000000..1536d88
--- /dev/null
+++ b/old/libqtuitest/qtuitestelapsedtimer_p.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QTUITESTELAPSEDTIMER_P_H
+#define QTUITESTELAPSEDTIMER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtUiTest API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <qtuitestglobal.h>
+
+class QTUITEST_EXPORT QtUiTestElapsedTimer
+{
+public:
+ QtUiTestElapsedTimer();
+
+ void start();
+ int elapsed();
+
+private:
+ int start_ms;
+};
+
+#endif
+
diff --git a/old/libqtuitest/qtuitestglobal.h b/old/libqtuitest/qtuitestglobal.h
new file mode 100644
index 0000000..cb46581
--- /dev/null
+++ b/old/libqtuitest/qtuitestglobal.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QTUITEST_GLOBAL_H
+#define QTUITEST_GLOBAL_H
+
+#include <QtGlobal>
+
+#if defined(Q_OS_WIN32)
+# if defined(QTUITEST_TARGET)
+# define QTUITEST_EXPORT Q_DECL_EXPORT
+# else
+# define QTUITEST_EXPORT Q_DECL_IMPORT
+# endif
+# if defined(QTSLAVE_TARGET)
+# define QTSLAVE_EXPORT Q_DECL_EXPORT
+# else
+# define QTSLAVE_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define QTUITEST_EXPORT Q_DECL_EXPORT
+# define QTSLAVE_EXPORT Q_DECL_EXPORT
+#endif
+
+#if defined(Q_OS_WIN32) || defined(Q_OS_SYMBIAN)
+# if defined(QSYSTEMTEST_TARGET)
+# define QSYSTEMTEST_EXPORT Q_DECL_EXPORT
+# else
+# define QSYSTEMTEST_EXPORT Q_DECL_IMPORT
+# endif
+# if defined(QTUITESTRUNNER_TARGET)
+# define QTUITESTRUNNER_EXPORT Q_DECL_EXPORT
+# else
+# define QTUITESTRUNNER_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define QSYSTEMTEST_EXPORT Q_DECL_EXPORT
+# define QTUITESTRUNNER_EXPORT Q_DECL_EXPORT
+#endif
+
+#endif
+
diff --git a/old/libqtuitest/qtuitestnamespace.cpp b/old/libqtuitest/qtuitestnamespace.cpp
new file mode 100644
index 0000000..09d838f
--- /dev/null
+++ b/old/libqtuitest/qtuitestnamespace.cpp
@@ -0,0 +1,1085 @@
+/****************************************************************************
+**
+** 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 "qtuitestnamespace.h"
+
+#include "qalternatestack_p.h"
+#include "qtuitestelapsedtimer_p.h"
+#include "qeventwatcher_p.h"
+#include "qtuitestconnectionmanager_p.h"
+#include "qtuitestwidgets_p.h"
+
+#include <QAction>
+#include <QDebug>
+#include <QEventLoop>
+#include <QKeyEvent>
+#include <QKeySequence>
+#include <QPointer>
+#include <QTimer>
+
+/*
+ A simple auto pointer class which deletes the pointed-to QObject
+ later via deleteLater()
+*/
+template <typename T>
+class QDelayedAutoPointer
+{
+public:
+ inline QDelayedAutoPointer(T* thing)
+ : raw(thing)
+ {}
+ inline ~QDelayedAutoPointer()
+ {
+ QObject::disconnect(raw, 0, 0, 0);
+ raw->deleteLater();
+ }
+
+ inline T* operator->()
+ { return raw; }
+
+ inline operator T*()
+ { return raw; }
+
+private:
+ T* raw;
+};
+
+/*
+ A helper class to encapsulate generation of input events
+*/
+struct QtUiTestInput
+{
+ virtual ~QtUiTestInput() {}
+ virtual void post() const =0;
+ virtual QString toString() const =0;
+};
+
+
+namespace QtUiTest {
+ QString objectName(QObject* obj)
+ {
+ QString ret = obj->objectName();
+ QAction* act(0);
+ if (ret.isEmpty() && (act = qobject_cast<QAction*>(obj))) {
+ ret = act->text();
+ if (ret.isEmpty()) ret = act->iconText();
+ }
+ return ret;
+ }
+ QString toString(QObject* obj)
+ {
+ if (!obj) return "QObject(0x0)";
+ return QString("%1(0x%2 \"%3\")")
+ .arg(obj->metaObject()->className())
+ .arg(QString::number(qptrdiff(obj), 16))
+ .arg(objectName(obj))
+ ;
+ }
+
+ QString toString(QEvent::Type type)
+ {
+#define DO(A) if (type == QEvent::A) return #A
+ DO(KeyPress);
+ DO(KeyRelease);
+ DO(MouseButtonPress);
+ DO(MouseButtonRelease);
+ DO(Show);
+ DO(Hide);
+ DO(FocusIn);
+ DO(FocusOut);
+#ifdef QT_KEYPAD_NAVIGATION
+ DO(EnterEditFocus);
+ DO(LeaveEditFocus);
+#endif
+ DO(WindowBlocked);
+#undef DO
+ return QString::number(int(type));
+ }
+
+ QString toString(QList<QEvent::Type> const& types)
+ {
+ QString ret;
+ QString sep;
+ foreach (QEvent::Type type, types) {
+ ret += sep + toString(type);
+ sep = ",";
+ }
+ return ret;
+ }
+
+ QString toString(Qt::Key key)
+ { return QKeySequence(key).toString(); }
+
+ QString toString(QPoint const& pos)
+ { return QString("(%1,%2)").arg(pos.x()).arg(pos.y()); }
+
+ QString toString(Qt::MouseButtons const& buttons)
+ {
+ QStringList ret;
+#define DO(A) if (buttons & Qt::A) ret << #A
+ DO(LeftButton);
+ DO(RightButton);
+ DO(MidButton);
+ DO(XButton1);
+ DO(XButton2);
+#undef DO
+ return ret.join(",");
+ }
+
+ bool keyClick(QObject*, QList<QEvent::Type> const&, int, Qt::KeyboardModifiers,
+ QtUiTest::InputOption);
+ bool mouseClick(QObject*, QList<QEvent::Type> const&, QPoint const&, Qt::MouseButtons,
+ QtUiTest::InputOption);
+ bool inputWithEvent(QObject*, QList<QEventWatcherFilter*> const&, QtUiTestInput const&);
+ bool inputWithSignal(QObject*, QByteArray const&, QtUiTestInput const&);
+};
+
+struct QtUiTestKeyClick : public QtUiTestInput
+{
+ QtUiTestKeyClick(Qt::Key key, Qt::KeyboardModifiers modifiers, QtUiTest::InputOption options)
+ : m_key(key), m_modifiers(modifiers), m_options(options)
+ {}
+
+ virtual void post() const
+ { QtUiTest::keyClick(m_key, m_modifiers, m_options); }
+
+ virtual QString toString() const
+ { return QString("Key click \"%1\"").arg(QtUiTest::toString(m_key)); }
+
+ Qt::Key m_key;
+ Qt::KeyboardModifiers m_modifiers;
+ QtUiTest::InputOption m_options;
+};
+
+struct QtUiTestMouseClick : public QtUiTestInput
+{
+ QtUiTestMouseClick(QPoint const& pos, Qt::MouseButtons buttons, QtUiTest::InputOption options)
+ : m_pos(pos), m_buttons(buttons), m_options(options)
+ {}
+
+ virtual void post() const
+ { QtUiTest::mouseClick(m_pos, m_buttons, m_options); }
+
+ virtual QString toString() const
+ {
+ return QString("Mouse click \"%1\" at %2")
+ .arg(QtUiTest::toString(m_buttons))
+ .arg(QtUiTest::toString(m_pos))
+ ;
+ }
+
+ QPoint const& m_pos;
+ Qt::MouseButtons m_buttons;
+ QtUiTest::InputOption m_options;
+};
+
+/*
+ Filter which implements watching for events of a specific type.
+*/
+class QEventWatcherTypeFilter : public QEventWatcherFilter
+{
+public:
+ QEventWatcherTypeFilter(QEvent::Type type)
+ : m_type(type)
+ {}
+
+protected:
+ virtual bool accept(QObject*,QEvent* e) const
+ { return e->type() == m_type; }
+
+ virtual QString toString() const
+ { return QString("event of type %1").arg(QtUiTest::toString(m_type)); }
+
+private:
+ QEvent::Type m_type;
+};
+
+/*
+ Filter which implements watching for specific key events.
+*/
+
+class QEventWatcherKeyFilter : public QEventWatcherTypeFilter
+{
+public:
+ QEventWatcherKeyFilter(Qt::Key key, QEvent::Type type)
+ : QEventWatcherTypeFilter(type)
+ , m_key(key)
+ {}
+
+ static QEvent::Type keyPressType()
+ { static int ret = QEvent::registerEventType(); return QEvent::Type(ret); }
+
+ static QEvent::Type keyReleaseType()
+ { static int ret = QEvent::registerEventType(); return QEvent::Type(ret); }
+
+protected:
+ virtual bool accept(QObject* o, QEvent* e) const
+ {
+ if (!QEventWatcherTypeFilter::accept(o,e))
+ return false;
+ if (e->type() != QEvent::KeyPress && e->type() != QEvent::KeyRelease)
+ return false;
+ return static_cast<QKeyEvent*>(e)->key() == m_key;
+ }
+
+ virtual QString toString() const
+ {
+ return QString("%1 (key:%2)")
+ .arg(QEventWatcherTypeFilter::toString())
+ .arg(QtUiTest::toString(m_key));
+ }
+
+private:
+ Qt::Key m_key;
+};
+
+
+/*!
+ \preliminary
+ \namespace QtUiTest
+ \inpublicgroup QtUiTestModule
+
+ \brief The QtUiTest namespace provides the plugin interfaces used for
+ customizing the behaviour of QtUiTest.
+
+ When running a \l{QSystemTest}{QtUiTest system test}, functions such as
+ \l{QSystemTest::}{select()} and \l{QSystemTest::}{getText()} are used to
+ perform actions and retrieve information from widgets.
+ This is implemented by wrapping each conceptual widget (which is not
+ necessarily a QWidget) with a test widget class.
+
+ These test widgets each implement one or more of the widget interfaces
+ in the QtUiTest namespace. The interfaces are used to determine
+ what actions can be taken on a particular widget, and how to perform
+ them.
+
+ For example, when the following system test code executes:
+ \code
+ select("Dog", "Favorite Animal");
+ \endcode
+
+ QtUiTest will first look up the QWidget which is labelled by the
+ text "Favorite Animal". It will then use qtuitest_cast to cast
+ this widget to a QtUiTest::SelectWidget. If this is successful, it
+ will then call \l{QtUiTest::SelectWidget::select()}{select("Dog")}
+ on the list widget.
+
+ It is possible to customize the behavior of QtUiTest for particular
+ widgets by creating custom test widget classes and a
+ QtUiTest::WidgetFactory factory class to wrap QObject instances in
+ test widgets.
+*/
+
+/*!
+ \fn T QtUiTest::qtuitest_cast_helper(QObject* object,T dummy)
+ \internal
+*/
+
+/*!
+ \relates QtUiTest
+ \fn T qtuitest_cast(const QObject *object)
+
+ Casts \a object to the specified QtUiTest test widget interface \c{T}.
+
+ If \a object already implements \c{T}, it is simply casted and returned.
+ Otherwise, QtUiTest will attempt to find or create a test widget to
+ wrap \a object, using all loaded QtUiTest::WidgetFactory plugins.
+ If a test widget cannot be created to wrap \a object, 0 is returned.
+
+ In either case, the returned value must not be deleted by the caller.
+
+ Example:
+ \code
+ // Attempt to select the item "Foo" from the given widget
+ bool selectFoo(QWidget *widget) {
+ QtUiTest::SelectWidget* sw
+ = qtuitest_cast<QtUiTest::SelectWidget*>(widget);
+ if (!sw || !sw->canSelect("Foo")) {
+ return false;
+ }
+ return sw->select("Foo");
+ }
+ \endcode
+*/
+
+
+/*!
+ \enum QtUiTest::InputOption
+
+ This enum type specifies the options to be used when simulating key
+ and mouse events.
+
+ \value NoOptions no options.
+ \value DemoMode when simulating, force artificial delays between key
+ and mouse events, and animate some events.
+ \value KeyRepeat when simulating key press events, simulate auto-repeat
+ key press events. The default is to simulate regular key
+ press events.
+*/
+
+/*!
+ \enum QtUiTest::WidgetType
+
+ This enum type specifies different types of widgets which can be retrieved
+ via QtUiTest::findWidget().
+
+ \value Focus The widget which currently has keyboard focus. Note that this
+ need not be located in the current application.
+ \value InputMethod A currently active input method widget.
+ \value SoftMenu A currently displayed \l{QSoftMenuBar}{soft menu bar}.
+ \value OptionsMenu The context/options menu which is currently shown, or
+ would be shown if the user attempted to raise a context
+ menu (typically by pressing Qt::Key_Context1).
+ \value TabBar The \l{QTabBar}{tab bar} for the currently active
+ \l{QTabWidget}{tab widget}, if one exists.
+ QtUiTest is not designed to handle multiple nested
+ tab widgets.
+ \value HomeScreen The home screen widget.
+ \value Launcher The widget (typically a grid-like menu) in the server
+ process used for launching applications.
+*/
+
+/*!
+ \enum QtUiTest::Key
+
+ This enum provides mappings for high-level conceptual keys to platform-specific
+ values of Qt::Key.
+
+ \value Key_Activate Key used to activate generic UI elements.
+ \value Key_ActivateButton Key used to activate buttons.
+ \value Key_Select Key used to select an item from lists.
+*/
+
+/*!
+ Set or clear the specified \a option for subsequent simulated input
+ events. The option is set if \a on is true, otherwise it is cleared.
+*/
+void QtUiTest::setInputOption(QtUiTest::InputOption option, bool on)
+{ QtUiTestWidgets::instance()->setInputOption(option, on); }
+
+/*!
+ Returns true if \a option is currently set.
+*/
+bool QtUiTest::testInputOption(QtUiTest::InputOption option)
+{ return QtUiTestWidgets::instance()->testInputOption(option); }
+
+/*!
+ Simulate a mouse press event at the co-ordinates given by \a pos,
+ for the specified \a buttons. \a options are applied to the simulated
+ event.
+
+ \a pos is interpreted as local co-ordinates for the currently active
+ window in this application.
+*/
+void QtUiTest::mousePress(QPoint const& pos, Qt::MouseButtons buttons,
+ QtUiTest::InputOption options)
+{ QtUiTestWidgets::instance()->mousePress(pos, buttons, options); }
+
+
+/*!
+ Simulate a mouse release event at the global co-ordinates given by \a pos,
+ for the specified \a buttons. \a options are applied to the simulated
+ event.
+
+ \a pos is interpreted as local co-ordinates for the currently active
+ window in this application.
+*/
+void QtUiTest::mouseRelease(QPoint const& pos, Qt::MouseButtons buttons,
+ QtUiTest::InputOption options)
+{ QtUiTestWidgets::instance()->mouseRelease(pos, buttons, options); }
+
+/*!
+ Simulate a mouse click event at the global co-ordinates given by \a pos,
+ for the specified \a buttons. \a options are applied to the simulated
+ event.
+
+ \a pos is interpreted as local co-ordinates for the currently active
+ window in this application.
+*/
+void QtUiTest::mouseClick(QPoint const& pos, Qt::MouseButtons buttons,
+ QtUiTest::InputOption options)
+{ QtUiTestWidgets::instance()->mouseClick(pos, buttons, options); }
+
+/*!
+ \overload
+ Simulate a mouse click event.
+ Returns true if the event appears to be delivered to \a object within maximumUiTimeout()
+ milliseconds.
+ If it does not, the errorString() will be set accordingly.
+*/
+bool QtUiTest::mouseClick(QObject* object, QPoint const& pos, Qt::MouseButtons buttons,
+ QtUiTest::InputOption options)
+{
+ return mouseClick(object,
+ QList<QEvent::Type>() << QEvent::MouseButtonRelease << QEvent::Hide << QEvent::WindowBlocked,
+ pos, buttons, options
+ );
+}
+
+/*!
+ \internal
+*/
+bool QtUiTest::mouseClick(QObject* object, QList<QEvent::Type> const& types, QPoint const& pos,
+ Qt::MouseButtons buttons, QtUiTest::InputOption options)
+{
+ QList<QEventWatcherFilter*> filters;
+ foreach (QEvent::Type type, types) {
+ filters << new QEventWatcherTypeFilter(type);
+ }
+ return inputWithEvent(object, filters, QtUiTestMouseClick(pos, buttons, options));
+}
+
+/*!
+ \overload
+ Simulate a mouse click event.
+ Returns true if the event causes \a object to emit \a signal within maximumUiTimeout()
+ milliseconds.
+ If it does not, the errorString() will be set accordingly.
+*/
+bool QtUiTest::mouseClick(QObject* object, QByteArray const& signal, QPoint const& pos,
+ Qt::MouseButtons buttons, QtUiTest::InputOption options)
+{ return inputWithSignal(object, signal, QtUiTestMouseClick(pos, buttons, options)); }
+
+/*!
+ Simulate a key press event, using the given \a key and \a modifiers.
+ \a key must be a valid Qt::Key or QtUiTest::Key.
+ \a options are applied to the simulated event.
+*/
+void QtUiTest::keyPress(int key, Qt::KeyboardModifiers modifiers,
+ QtUiTest::InputOption options)
+{ QtUiTestWidgets::instance()->keyPress(static_cast<Qt::Key>(key), modifiers, options); }
+
+/*!
+ Simulate a key release event, using the given \a key and \a modifiers.
+ \a key must be a valid Qt::Key or QtUiTest::Key.
+ \a options are applied to the simulated event.
+*/
+void QtUiTest::keyRelease(int key, Qt::KeyboardModifiers modifiers,
+ QtUiTest::InputOption options)
+{ QtUiTestWidgets::instance()->keyRelease(static_cast<Qt::Key>(key), modifiers, options); }
+
+/*!
+ Simulate a key click event, using the given \a key and \a modifiers.
+ \a key must be a valid Qt::Key or QtUiTest::Key.
+ \a options are applied to the simulated event.
+*/
+void QtUiTest::keyClick(int key, Qt::KeyboardModifiers modifiers,
+ QtUiTest::InputOption options)
+{ QtUiTestWidgets::instance()->keyClick(static_cast<Qt::Key>(key), modifiers, options); }
+
+/*!
+ \overload
+ Simulate a key click event.
+ Returns true if the event appears to be delivered to \a object within maximumUiTimeout()
+ milliseconds.
+ If it does not, the errorString() will be set accordingly.
+*/
+bool QtUiTest::keyClick(QObject* object, int key, Qt::KeyboardModifiers modifiers,
+ QtUiTest::InputOption options)
+{
+ return keyClick(object,
+ QList<QEvent::Type>() << QEventWatcherKeyFilter::keyReleaseType()
+ << QEvent::Hide << QEvent::WindowBlocked << QEvent::Show,
+ key, modifiers, options
+ );
+}
+
+/*!
+ \internal
+*/
+bool QtUiTest::inputWithEvent(QObject* object, QList<QEventWatcherFilter*> const& filters,
+ QtUiTestInput const& event)
+{
+ QPointer<QObject> sender = object;
+ QDelayedAutoPointer<QEventWatcher> w = new QEventWatcher;
+ w->addObject(sender);
+ foreach (QEventWatcherFilter* filter, filters)
+ w->addFilter(filter);
+
+ event.post();
+
+ if (!w->count() && !QtUiTest::waitForSignal(w, SIGNAL(event(QObject*,int)))) {
+ setErrorString(QString(
+ "%1 was expected to result in %2 receiving an event matching one of the following, "
+ "but it didn't:\n%3")
+ .arg(event.toString())
+ .arg(toString(sender))
+ .arg(w->toString()));
+ return false;
+ }
+ return true;
+}
+
+/*!
+ \internal
+*/
+bool QtUiTest::inputWithSignal(QObject* object, QByteArray const& signal,
+ QtUiTestInput const& event)
+{
+ if (signal.isEmpty()) return false;
+ QPointer<QObject> sender = object;
+
+ QTimer dummy;
+ dummy.setInterval(1000);
+ if (!QtUiTest::connectFirst(sender, signal, &dummy, SLOT(start()))) {
+ setErrorString(QString("Object %1 has no signal %2").arg(toString(sender)).arg(&signal.constData()[1]));
+ return false;
+ }
+
+ // Ensure connectNotify is called
+ if (!QObject::connect(sender, signal, &dummy, SLOT(start())))
+ Q_ASSERT(0);
+
+ event.post();
+
+ if (!dummy.isActive() && !QtUiTest::waitForSignal(sender, signal)) {
+ setErrorString(QString(
+ "%1 was expected to result in %2 emitting the signal %3, "
+ "but it didn't.")
+ .arg(event.toString())
+ .arg(toString(sender))
+ .arg(&signal.constData()[1]));
+ return false;
+ }
+ return true;
+}
+
+/*!
+ \internal
+ \overload
+ Simulate a key click event.
+ Returns true if \a object receives any event of the given \a types within maximumUiTimeout()
+ milliseconds.
+ If it does not, the errorString() will be set accordingly.
+*/
+bool QtUiTest::keyClick(QObject* object, QList<QEvent::Type> const& types, int key,
+ Qt::KeyboardModifiers modifiers, QtUiTest::InputOption options)
+{
+ QList<QEventWatcherFilter*> filters;
+ foreach (QEvent::Type type, types) {
+ // These cases result in waiting for specific key events rather than just "any key press".
+ if (type == QEventWatcherKeyFilter::keyPressType()) {
+ filters << new QEventWatcherKeyFilter(Qt::Key(key), QEvent::KeyPress);
+ } else if (type == QEventWatcherKeyFilter::keyReleaseType()) {
+ filters << new QEventWatcherKeyFilter(Qt::Key(key), QEvent::KeyRelease);
+ } else {
+ filters << new QEventWatcherTypeFilter(type);
+ }
+ }
+ return inputWithEvent(object, filters, QtUiTestKeyClick(Qt::Key(key), modifiers, options));
+}
+
+/*!
+ \overload
+ Simulate a key click event.
+ Returns true if \a object emits \a signal within maximumUiTimeout()
+ milliseconds.
+ If it does not, the errorString() will be set accordingly.
+*/
+bool QtUiTest::keyClick(QObject* object, QByteArray const& signal, int key, Qt::KeyboardModifiers modifiers,
+ QtUiTest::InputOption options)
+{ return inputWithSignal(object, signal, QtUiTestKeyClick(Qt::Key(key), modifiers, options)); }
+
+/*!
+ Returns true if widget interaction should prefer mouse events over
+ key events.
+
+ On most platforms the default returns true, unless the environment variable
+ QTUITEST_NO_MOUSE is set.
+*/
+bool QtUiTest::mousePreferred()
+{
+ return QtUiTestWidgets::instance()->mousePreferred();
+}
+
+void QtUiTest::setMousePreferred(bool useMouse)
+{
+ QtUiTestWidgets::instance()->setMousePreferred(useMouse);
+}
+
+QtUiTest::LabelOrientation QtUiTest::labelOrientation()
+{
+ return QtUiTestWidgets::instance()->labelOrientation();
+}
+
+void QtUiTest::setLabelOrientation(QtUiTest::LabelOrientation orientation)
+{
+ QtUiTestWidgets::instance()->setLabelOrientation(orientation);
+}
+
+/*!
+ Returns the maximum amount of time, in milliseconds, the user interface is allowed to take
+ to generate some response to a user's action.
+
+ This value is useful to determine how long test widgets should wait for certain events to occur
+ after simulating key/mouse events. The value may be device-specific.
+*/
+int QtUiTest::maximumUiTimeout()
+{ return 2000; }
+
+/*!
+ Returns the Qt::Key corresponding to \a c.
+
+ This function is commonly used in conjunction with keyClick() to enter
+ a string of characters using the keypad.
+
+ Example:
+ \code
+ using namespace QtUiTest;
+ QString text = "hello world";
+ // ...
+ foreach (QChar c, text) {
+ keyClick( asciiToKey(c.toLatin1()), asciiToModifiers(c.toLatin1()) );
+ }
+ \endcode
+*/
+Qt::Key QtUiTest::asciiToKey(char c)
+{ return static_cast<Qt::Key>(QKeySequence(QString(QChar(c)))[0]); }
+
+/*!
+ Returns any Qt::KeyboardModifiers which would be required to input \a c.
+
+ This function is commonly used in conjunction with keyClick() to enter
+ a string of characters using the keypad.
+
+ Example:
+ \code
+ using namespace QtUiTest;
+ QString text = "hello world";
+ // ...
+ foreach (QChar c, text) {
+ keyClick( asciiToKey(c.toLatin1()), asciiToModifiers(c.toLatin1()) );
+ }
+ \endcode
+*/
+Qt::KeyboardModifiers QtUiTest::asciiToModifiers(char c)
+{
+ Qt::KeyboardModifiers ret = Qt::NoModifier;
+ if (QChar(c).isUpper()) ret |= Qt::ShiftModifier;
+ return ret;
+}
+
+/*!
+ Returns a human-readable error string describing the last error which
+ occurred while accessing a testwidget.
+
+ The error string is used to report directly to a tester any unexpected
+ errors. The string will typically be used as a test failure message.
+
+ \sa setErrorString()
+*/
+QString QtUiTest::errorString()
+{ return QtUiTestWidgets::instance()->errorString(); }
+
+/*!
+ Sets the human-readable \a error string describing the last error which
+ occurred while accessing a testwidget.
+
+ \sa errorString()
+*/
+void QtUiTest::setErrorString(QString const& error)
+{ QtUiTestWidgets::instance()->setErrorString(error); }
+
+/*!
+ Returns a widget or test widget wrapper of \a type.
+
+ QtUiTest will attempt to find widgets by calling
+ QtUiTest::WidgetFactory::find() on all loaded widget factories.
+
+ Note that it is possible to call this function from an application where
+ the only widget of \a type exists in the server. In this case, the
+ reference implementation returns a special wrapper which transparently
+ communicates with the server when calling functions. However, if custom
+ factories are used which do not do this, this function is likely to return
+ 0 in this case.
+
+ Example:
+ \code
+ using namespace QtUiTest;
+ bool MyTextEdit::enter(QVariant const& item) {
+ // Instead of explicitly simulating mouse or key clicks,
+ // enter the text via the current input method.
+ // Note that this works whether or not the input method is located in
+ // the current process.
+ InputWidget *iw = qtuitest_cast<InputWidget*>(findWidget(InputMethod));
+ return (iw && iw->enter(item));
+ }
+ \endcode
+*/
+QObject* QtUiTest::findWidget(WidgetType type)
+{
+ return QtUiTestWidgets::instance()->findWidget(type);
+}
+
+/*!
+ \internal
+ Returns a test widget wrapper for \a object which implements
+ \a interface.
+*/
+QObject* QtUiTest::testWidget(QObject* object, const char* interface)
+{
+ return QtUiTestWidgets::instance()->testWidget(object, interface);
+}
+
+/*!
+ Causes the process to wait for \a ms milliseconds. While waiting, events will be processed.
+*/
+void QtUiTest::wait(int ms)
+{
+ // If we are currently in an alternate stack, make sure we wait on the main
+ // stack instead. This avoids hanging due to nested event loops (bug 194361).
+ foreach (QAlternateStack* stack, QAlternateStack::instances()) {
+ if (!stack->isCurrentStack()) continue;
+
+ // OK, we are running in this stack.
+
+ // We are about to switch from this stack back to the main stack.
+ // Arrange an event to occur so that we switch back to this stack
+ // after the given timeout.
+
+ // Must be created on the heap and destroyed with deleteLater(),
+ // because when we switch back to this stack, QCoreApplication::notify
+ // still holds a pointer to timer.
+
+ QDelayedAutoPointer<QTimer> timer = new QTimer;
+ timer->setObjectName("qtuitest_wait_timer");
+ timer->setSingleShot(true);
+ timer->setInterval(ms);
+
+ QObject::connect(timer, SIGNAL(timeout()), stack, SLOT(switchTo()));
+
+ // Now switch back to the main stack.
+ timer->start();
+ while (timer->isActive())
+ stack->switchFrom();
+
+ // OK, we've returned from the main stack to this stack, so we've
+ // waited for the given timeout and can now return.
+ return;
+ }
+
+ // If we get here, we are running in the main stack, so just do a usual
+ // possibly-hanging wait.
+ QEventLoop loop;
+ QTimer::singleShot(ms, &loop, SLOT(quit()));
+ loop.exec();
+}
+
+#include <QDebug>
+
+/*!
+ Causes the process to wait for \a ms milliseconds or until \a signal is
+ emitted from \a object, whichever comes first.
+
+ While waiting, events will be processed.
+
+ Returns true if \a signal was emitted from \a object before timing out.
+ When false is returned, errorString() is set accordingly.
+
+ If \a connectionType specifies a direct connection, this function will return
+ immediately when the signal occurs, possibly before some objects have
+ received the signal. If \a connectionType specifies a queued connection, this
+ function will return once the event loop has run following the emit.
+*/
+bool QtUiTest::waitForSignal(QObject* object, const char* signal, int ms, Qt::ConnectionType connectionType)
+{
+ if (ms < 0) return false;
+ if (!signal || !signal[0]) return false;
+
+ QPointer<QObject> sender = object;
+
+ // Dummy variable to detect signal emission.
+ QTimer dummy;
+ dummy.setInterval(1000);
+ if (!QtUiTest::connectFirst(sender, signal, &dummy, SLOT(start())))
+ return false;
+
+ // Ensure connectNotify is called
+ if (!QObject::connect(sender, signal, &dummy, SLOT(start())))
+ Q_ASSERT(0);
+
+ // If we are currently in an alternate stack, make sure we wait on the main
+ // stack instead. This avoids hanging due to nested event loops (bug 194361).
+ foreach (QAlternateStack* stack, QAlternateStack::instances()) {
+ if (!stack->isCurrentStack()) continue;
+
+ // OK, we are running in this stack.
+
+ // We are about to switch from this stack back to the main stack.
+ // Arrange an event to occur so that we switch back to this stack
+ // after the given timeout.
+
+ // Must be created on the heap and destroyed with deleteLater(),
+ // because when we switch back to this stack, QCoreApplication::notify
+ // still holds a pointer to timer.
+
+ QDelayedAutoPointer<QTimer> timer = new QTimer;
+ timer->setObjectName("qtuitest_waitForSignal_timer");
+ timer->setInterval(ms);
+ timer->setSingleShot(true);
+ QObject::connect(timer, SIGNAL(timeout()), stack, SLOT(switchTo()));
+ timer->start();
+
+ while (timer->isActive() && !dummy.isActive()) {
+ // Arrange it so that we switch back to this stack if the
+ // desired signal is emitted.
+ if (!QtUiTest::connectFirst(sender, signal, stack, SLOT(switchTo()))) {
+ return false;
+ }
+ // Now switch back to the main stack.
+ stack->switchFrom();
+ if (sender && !QtUiTest::disconnectFirst(sender, signal, stack, SLOT(switchTo())))
+ Q_ASSERT(0);
+ }
+
+ // OK, we've returned from the main stack to this stack, so we've
+ // timed out or got the signal. Check dummy to figure out which one.
+ if (!dummy.isActive()) {
+ setErrorString(QString("Object %1 was expected to emit %2 within %3 milliseconds, "
+ "but it didn't.")
+ .arg(toString(sender))
+ .arg(&signal[1])
+ .arg(ms)
+ );
+ return false;
+ }
+
+ // If we asked for a queued connection, fake it.
+ if (connectionType == Qt::QueuedConnection) {
+ QtUiTest::wait(0);
+ }
+ return true;
+ }
+
+ // We are running on the main stack. Use a (dangerous) nested event loop
+ // to wait.
+ QEventLoop loop;
+ if (!QObject::connect(sender, signal, &loop, SLOT(quit())))
+ return false;
+ QTimer::singleShot(ms, &loop, SLOT(quit()));
+
+ loop.exec();
+
+ return dummy.isActive();
+}
+
+/*!
+ Causes the process to wait for \a ms milliseconds or until an event of
+ any of the given \a types is received by \a object, whichever comes first.
+
+ While waiting, events will be processed.
+
+ Returns true if the event was received by \a object before timing out.
+ When false is returned, errorString() is set accordingly.
+
+ If \a connectionType specifies a direct connection, this function will return
+ immediately before the event is processed by \a object.
+ If \a connectionType specifies a queued connection, this function will return
+ once the event loop has run following the processing of the event.
+*/
+bool QtUiTest::waitForEvent(QObject* object, QList<QEvent::Type> const& types, int ms, Qt::ConnectionType connectionType)
+{
+ QPointer<QObject> sender = object;
+ QDelayedAutoPointer<QEventWatcher> w = new QEventWatcher;
+ w->setObjectName("qtuitest_waitForEvent_watcher");
+ w->addObject(sender);
+ foreach (QEvent::Type type, types)
+ w->addFilter(new QEventWatcherTypeFilter(type));
+
+ if (!QtUiTest::waitForSignal(w, SIGNAL(event(QObject*,int)), ms, connectionType)) {
+ setErrorString(QString("Object %1 was expected to receive an event of type(s) %2 within "
+ "%3 milliseconds, but it didn't.")
+ .arg(toString(sender))
+ .arg(toString(types))
+ .arg(ms)
+ );
+ return false;
+ }
+ return true;
+}
+
+/*!
+ \overload
+ Waits for an event of the given \a type.
+*/
+bool QtUiTest::waitForEvent(QObject* object, QEvent::Type type, int ms, Qt::ConnectionType connectionType)
+{ return waitForEvent(object, QList<QEvent::Type>() << type, ms, connectionType); }
+
+/*!
+ Creates a connection from the \a signal in the \a sender object to
+ the \a method in the \a receiver object. Returns true if the connection succeeds;
+ otherwise returns false.
+
+ This function behaves similarly to QObject::connect() with the following
+ important differences.
+ \list
+ \o The connection is guaranteed to be activated before
+ any connections made with QObject::connect().
+ \o The connection type is always Qt::DirectConnection.
+ \o The connection cannot be disconnected using QObject::disconnect()
+ (QtUiTest::disconnectFirst() must be used instead).
+ \o The connection does not affect the return value of QObject::receivers().
+ \o While \a method is being executed, the return value of
+ QObject::sender() is undefined.
+ \o QObject::connectNotify() is not called on the sending object.
+ \endlist
+
+ This function is primarily used in conjunction with QtUiTestRecorder to
+ ensure events are recorded in the correct order.
+
+ Note that this function cannot be used in a program which uses QSignalSpy.
+
+ \sa QObject::connect(), QtUiTest::disconnectFirst()
+*/
+bool QtUiTest::connectFirst(const QObject* sender, const char* signal,
+ const QObject* receiver, const char* method)
+{
+ // On failure, we use QObject::connect to get the same error message as
+ // we normally would.
+ if (sender == 0 || receiver == 0 || signal == 0 || method == 0) {
+ return QObject::connect(sender,signal,receiver,method);
+ }
+ if (qstrlen(signal) < 1 || qstrlen(method) < 1) {
+ return QObject::connect(sender,signal,receiver,method);
+ }
+
+ const QMetaObject* const senderMo = sender->metaObject();
+
+ QByteArray normalSignal = QByteArray::fromRawData(signal+1, qstrlen(signal)-1);
+ int signal_index = senderMo->indexOfSignal(normalSignal);
+
+ if (signal_index < 0) {
+ // See if we can find the signal after normalizing.
+ normalSignal = QMetaObject::normalizedSignature(normalSignal);
+ signal_index = senderMo->indexOfSignal(normalSignal);
+ }
+ if (signal_index < 0) {
+ // Nope, bail out.
+ return QObject::connect(sender,signal,receiver,method);
+ }
+
+ const QMetaObject* const receiverMo = receiver->metaObject();
+
+ QByteArray normalMethod = QByteArray::fromRawData(method+1, qstrlen(method)-1);
+ int method_index = receiverMo->indexOfMethod(normalMethod);
+
+ if (method_index < 0) {
+ // See if we can find the method after normalizing.
+ normalMethod = QMetaObject::normalizedSignature(normalMethod);
+ method_index = senderMo->indexOfMethod(normalMethod);
+ }
+ if (method_index < 0) {
+ // Nope, bail out.
+ return QObject::connect(sender,signal,receiver,method);
+ }
+
+ // Ensure signal and slot are compatible.
+ if (!QMetaObject::checkConnectArgs(normalSignal.constData(), normalMethod.constData())) {
+ return QObject::connect(sender,signal,receiver,method);
+ }
+
+ // If we get here, then everything is valid.
+ QtUiTestConnectionManager::instance()->connect(sender, signal_index, receiver, method_index);
+ return true;
+}
+
+/*!
+ Disconnects \a signal in object \a sender from \a method in object \a receiver. Returns true if the connection is successfully broken; otherwise returns false.
+
+ The connection must have been established with QtUiTest::connectFirst().
+
+ Passing null arguments has the same wildcard effects as documented in QObject::disconnect().
+
+ If the same connection has been established multiple times, disconnectFirst() will disconnect
+ all instances of the connection. There is no way to disconnect a single instance of a
+ connection. This behavior matches QObject::disconnect().
+
+ \sa QObject::disconnect(), QtUiTest::connectFirst()
+*/
+bool QtUiTest::disconnectFirst(const QObject* sender, const char* signal,
+ const QObject* receiver, const char* method)
+{
+ // On failure, we use QObject::disconnect to get the same error message as
+ // we normally would.
+ if (sender == 0) {
+ return QObject::disconnect(sender,signal,receiver,method);
+ }
+
+ const QMetaObject* const senderMo = sender->metaObject();
+
+ QByteArray normalSignal = (signal)
+ ? QByteArray::fromRawData(signal+1, qstrlen(signal)-1)
+ : QByteArray();
+ int signal_index = (signal) ? senderMo->indexOfSignal(normalSignal) : -1;
+ if (signal && (signal_index < 0)) {
+ // See if we can find the signal after normalizing.
+ normalSignal = QMetaObject::normalizedSignature(signal);
+ signal_index = senderMo->indexOfSignal(normalSignal);
+ }
+ if (signal && (signal_index < 0)) {
+ // Nope, bail out.
+ return QObject::disconnect(sender,signal,receiver,method);
+ }
+
+ if (method && !receiver) {
+ return QObject::disconnect(sender,signal,receiver,method);
+ }
+
+ const QMetaObject* const receiverMo = (receiver) ? receiver->metaObject() : 0;
+
+ QByteArray normalMethod = (method)
+ ? QByteArray::fromRawData(method+1, qstrlen(method)-1)
+ : QByteArray();
+ int method_index = (method) ? receiverMo->indexOfMethod(normalMethod) : -1;
+
+ if (method && (method_index < 0)) {
+ // See if we can find the method after normalizing.
+ normalMethod = QMetaObject::normalizedSignature(method);
+ method_index = senderMo->indexOfMethod(normalMethod);
+ }
+ if (method && (method_index < 0)) {
+ // Nope, bail out.
+ return QObject::disconnect(sender,signal,receiver,method);
+ }
+
+ return QtUiTestConnectionManager::instance()->disconnect(sender,signal_index,receiver,method_index);
+}
+
diff --git a/old/libqtuitest/qtuitestnamespace.h b/old/libqtuitest/qtuitestnamespace.h
new file mode 100644
index 0000000..41d88c6
--- /dev/null
+++ b/old/libqtuitest/qtuitestnamespace.h
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QTUITESTNAMESPACE_H
+#define QTUITESTNAMESPACE_H
+
+#include <qtuitestglobal.h>
+
+#include <QEvent>
+#include <QObject>
+#include <Qt>
+
+class QPoint;
+
+namespace QtUiTest
+{
+ enum InputOption {
+ NoOptions = 0x0,
+ DemoMode = 0x1,
+ KeyRepeat = 0x2
+ };
+
+ enum WidgetType {
+ InputMethod,
+ TabBar
+ };
+
+ enum Key {
+#ifdef Q_WS_QWS
+ Key_Activate = Qt::Key_Select,
+#else
+ Key_Activate = Qt::Key_Enter,
+#endif
+
+#ifdef Q_WS_QWS
+ Key_Select = Qt::Key_Select,
+#else
+ Key_Select = Qt::Key_Space,
+#endif
+
+#if defined(Q_WS_QWS) || defined (Q_OS_SYMBIAN)
+ Key_ActivateButton = Qt::Key_Select
+#else
+ Key_ActivateButton = Qt::Key_Space
+#endif
+ };
+
+ enum LabelOrientation {
+ LabelLeft = 0x01,
+ LabelRight = 0x02,
+ LabelAbove = 0x03,
+ LabelBelow = 0x04
+ };
+
+ QTUITEST_EXPORT void setInputOption(InputOption,bool = true);
+ QTUITEST_EXPORT bool testInputOption(InputOption);
+
+ QTUITEST_EXPORT QString errorString();
+ QTUITEST_EXPORT void setErrorString(QString const&);
+
+ QTUITEST_EXPORT void mousePress (QPoint const&,Qt::MouseButtons = Qt::LeftButton,
+ InputOption = NoOptions);
+ QTUITEST_EXPORT void mouseRelease(QPoint const&,Qt::MouseButtons = Qt::LeftButton,
+ InputOption = NoOptions);
+ QTUITEST_EXPORT void mouseClick (QPoint const&,Qt::MouseButtons = Qt::LeftButton,
+ InputOption = NoOptions);
+ QTUITEST_EXPORT bool mouseClick (QObject*,QPoint const&,Qt::MouseButtons = Qt::LeftButton,
+ InputOption = NoOptions);
+ QTUITEST_EXPORT bool mouseClick (QObject*,QByteArray const&,QPoint const&,
+ Qt::MouseButtons = Qt::LeftButton, InputOption = NoOptions);
+
+ QTUITEST_EXPORT void keyPress (int,Qt::KeyboardModifiers = 0,
+ InputOption = NoOptions);
+ QTUITEST_EXPORT void keyRelease(int,Qt::KeyboardModifiers = 0,
+ InputOption = NoOptions);
+ QTUITEST_EXPORT void keyClick (int,Qt::KeyboardModifiers = 0,
+ InputOption = NoOptions);
+ QTUITEST_EXPORT bool keyClick (QObject*,int,Qt::KeyboardModifiers = 0,
+ InputOption = NoOptions);
+ QTUITEST_EXPORT bool keyClick (QObject*,QByteArray const&,int,Qt::KeyboardModifiers = 0,
+ InputOption = NoOptions);
+
+ QTUITEST_EXPORT bool mousePreferred();
+ QTUITEST_EXPORT void setMousePreferred(bool);
+
+ QTUITEST_EXPORT LabelOrientation labelOrientation();
+ QTUITEST_EXPORT void setLabelOrientation(LabelOrientation);
+
+ QTUITEST_EXPORT int maximumUiTimeout();
+
+ QTUITEST_EXPORT Qt::Key asciiToKey(char);
+ QTUITEST_EXPORT Qt::KeyboardModifiers asciiToModifiers(char);
+
+ QTUITEST_EXPORT QObject* findWidget(WidgetType);
+
+ QTUITEST_EXPORT QObject* testWidget(QObject*,const char*);
+
+ QTUITEST_EXPORT bool connectFirst (const QObject*, const char*, const QObject*, const char*);
+ QTUITEST_EXPORT bool disconnectFirst(const QObject*, const char*, const QObject*, const char*);
+
+ template<class T> inline T qtuitest_cast_helper(QObject* object, T)
+ {
+ T ret;
+ if ((ret = qobject_cast<T>(object))) {}
+ else {
+ ret = qobject_cast<T>(QtUiTest::testWidget(object,
+ static_cast<T>(0)->_q_interfaceName()));
+ }
+ return ret;
+ }
+
+ QTUITEST_EXPORT void wait(int);
+ QTUITEST_EXPORT bool waitForSignal(QObject*, const char*, int = QtUiTest::maximumUiTimeout(), Qt::ConnectionType = Qt::QueuedConnection);
+ QTUITEST_EXPORT bool waitForEvent(QObject*, QEvent::Type, int = QtUiTest::maximumUiTimeout(), Qt::ConnectionType = Qt::QueuedConnection);
+ QTUITEST_EXPORT bool waitForEvent(QObject*, QList<QEvent::Type> const&, int = QtUiTest::maximumUiTimeout(), Qt::ConnectionType = Qt::QueuedConnection);
+};
+
+template<class T> inline
+T qtuitest_cast(const QObject* object)
+{
+ return QtUiTest::qtuitest_cast_helper<T>(const_cast<QObject*>(object),0);
+}
+
+#include <qtuitestwidgetinterface.h>
+
+#endif
+
diff --git a/old/libqtuitest/qtuitestrecorder.cpp b/old/libqtuitest/qtuitestrecorder.cpp
new file mode 100644
index 0000000..0a847b1
--- /dev/null
+++ b/old/libqtuitest/qtuitestrecorder.cpp
@@ -0,0 +1,367 @@
+/****************************************************************************
+**
+** 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 "qtuitestrecorder.h"
+#include "qtuitestnamespace.h"
+
+#include <QSet>
+#include <QApplication>
+#include <QWidget>
+#include <QMetaType>
+#include <QPointer>
+
+Q_DECLARE_METATYPE(QPointer<QObject>)
+
+/*!
+ \preliminary
+ \class QtUiTestRecorder
+ \inpublicgroup QtUiTestModule
+ \brief The QtUiTestRecorder class provides an interface for observing
+ application-wide high level user actions.
+
+ QtUiTestRecorder aggregates the signals declared in the
+ \l{QtUiTest}{QtUiTest widget interfaces} to provide a single object
+ capable of watching for user input.
+
+ Note that using this class is expensive because it involves watching
+ for signals on a large number of objects. When you create a
+ QtUiTestRecorder and connect to its signals, this will result in every
+ existing widget being wrapped in a \l{QtUiTest}{test widget}.
+ To avoid this, do not connect to the signals of a QtUiTestRecorder
+ unless you will definitely use the result.
+*/
+
+class WidgetWatcher;
+
+class QtUiTestRecorderPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ static WidgetWatcher* watcher;
+ static void createOrDestroyWatcher();
+
+public slots:
+ void on_gotFocus();
+ void on_activated();
+ void on_stateChanged(int);
+ void on_entered(QVariant const&);
+ void on_selected(QString const&);
+};
+
+WidgetWatcher* QtUiTestRecorderPrivate::watcher = 0;
+
+Q_GLOBAL_STATIC(QtUiTestRecorderPrivate, qtuitestRecorderPrivate);
+Q_GLOBAL_STATIC(QSet<QtUiTestRecorder*>, qtuitestRecorderInstances);
+
+/*! \internal */
+void QtUiTestRecorder::emitKeyEvent(int key, int mod, bool press, bool repeat)
+{
+ foreach(QtUiTestRecorder* r, *qtuitestRecorderInstances()) {
+ emit r->keyEvent(key, mod, press, repeat);
+ }
+}
+
+/*! \internal */
+void QtUiTestRecorder::emitMouseEvent(int x, int y, int state)
+{
+ foreach(QtUiTestRecorder* r, *qtuitestRecorderInstances()) {
+ emit r->mouseEvent(x, y, state);
+ }
+}
+
+void QtUiTestRecorderPrivate::on_gotFocus()
+{
+ foreach(QtUiTestRecorder* r, *qtuitestRecorderInstances()) {
+ emit r->gotFocus(sender());
+ }
+}
+
+void QtUiTestRecorderPrivate::on_activated()
+{
+ foreach(QtUiTestRecorder* r, *qtuitestRecorderInstances()) {
+ emit r->activated(sender());
+ }
+}
+
+void QtUiTestRecorderPrivate::on_stateChanged(int state)
+{
+ foreach(QtUiTestRecorder* r, *qtuitestRecorderInstances()) {
+ emit r->stateChanged(sender(), state);
+ }
+}
+
+void QtUiTestRecorderPrivate::on_entered(QVariant const& item)
+{
+ foreach(QtUiTestRecorder* r, *qtuitestRecorderInstances()) {
+ emit r->entered(sender(), item);
+ }
+}
+
+void QtUiTestRecorderPrivate::on_selected(QString const& item)
+{
+ foreach(QtUiTestRecorder* r, *qtuitestRecorderInstances()) {
+ emit r->selected(sender(), item);
+ }
+}
+
+/*
+ This helper class attempts to ensure that all created objects immediately
+ have wrappers constructed around them. This is necessary for event
+ recording to work properly, as it relies on test widgets emitting signals.
+
+ Since it is so expensive, an instance of this class should not be left
+ around whenever we don't have any QtUiTestRecorder instances.
+*/
+class WidgetWatcher : public QObject
+{
+ Q_OBJECT
+public:
+ WidgetWatcher();
+ void castAllChildren(QObject*);
+
+public slots:
+ bool eventFilter(QObject*,QEvent*);
+ void castAllChildren(QPointer<QObject>);
+};
+
+WidgetWatcher::WidgetWatcher()
+{
+ castAllChildren(qApp);
+ foreach(QWidget* w, qApp->topLevelWidgets()) {
+ castAllChildren(w);
+ }
+}
+
+bool WidgetWatcher::eventFilter(QObject* o, QEvent* e)
+{
+ if (e->type() == QEvent::ChildAdded) {
+ static struct Registrar {
+ Registrar() {
+ qRegisterMetaType< QPointer<QObject> >();
+ }
+ } r;
+ QPointer<QObject> ptr(o);
+ QMetaObject::invokeMethod(this, "castAllChildren",
+ Qt::QueuedConnection,
+ Q_ARG(QPointer<QObject>, ptr));
+ }
+ return false;
+}
+
+void WidgetWatcher::castAllChildren(QPointer<QObject> o)
+{ castAllChildren(static_cast<QObject*>(o)); }
+
+void WidgetWatcher::castAllChildren(QObject* o)
+{
+ if (!o) return;
+ qtuitest_cast<QtUiTest::Widget*>(o);
+ o->installEventFilter(this);
+ foreach (QObject* child, o->children())
+ castAllChildren(child);
+}
+
+void QtUiTestRecorderPrivate::createOrDestroyWatcher()
+{
+ QSet<QtUiTestRecorder*> const *recorders = qtuitestRecorderInstances();
+
+ bool need_watcher = false;
+ foreach (QtUiTestRecorder* rec, *recorders) {
+ if (rec->receivers(SIGNAL(gotFocus(QObject*)))
+ || rec->receivers(SIGNAL(activated(QObject*)))
+ || rec->receivers(SIGNAL(stateChanged(QObject*,int)))
+ || rec->receivers(SIGNAL(entered(QObject*,QVariant)))
+ || rec->receivers(SIGNAL(selected(QObject*,QString))))
+ need_watcher = true;
+
+ if (need_watcher) break;
+ }
+
+ if (watcher && !need_watcher) {
+ delete watcher;
+ watcher = 0;
+ } else if (!watcher && need_watcher) {
+ watcher = new WidgetWatcher;
+ }
+}
+
+
+/*!
+ Constructs a QtUiTestRecorder with the given \a parent.
+*/
+QtUiTestRecorder::QtUiTestRecorder(QObject* parent)
+ : QObject(parent)
+{
+ *qtuitestRecorderInstances() << this;
+}
+
+/*!
+ Destroys the QtUiTestRecorder.
+*/
+QtUiTestRecorder::~QtUiTestRecorder()
+{
+ qtuitestRecorderInstances()->remove(this);
+ QtUiTestRecorderPrivate::createOrDestroyWatcher();
+}
+
+/*!
+ \internal
+ May cause a WidgetWatcher to be created.
+*/
+void QtUiTestRecorder::connectNotify(char const*)
+{
+ QtUiTestRecorderPrivate::createOrDestroyWatcher();
+}
+
+/*!
+ \internal
+ May cause a WidgetWatcher to be destroyed.
+*/
+void QtUiTestRecorder::disconnectNotify(char const*)
+{
+ QtUiTestRecorderPrivate::createOrDestroyWatcher();
+}
+
+/*!
+ \fn void QtUiTestRecorder::gotFocus(QObject* widget)
+
+ Emitted when \a widget obtains focus by any means.
+
+ \sa QtUiTest::Widget::gotFocus()
+*/
+
+/*!
+ \fn void QtUiTestRecorder::activated(QObject* widget)
+
+ Emitted when \a widget is activated by any means.
+
+ In this context, "activated" means, for example, clicking a button.
+
+ \sa QtUiTest::ActivateWidget::activated()
+*/
+
+/*!
+ \fn void QtUiTestRecorder::stateChanged(QObject* widget, int state)
+
+ Emitted when the check state changes to \a state in \a widget.
+
+ \sa QtUiTest::CheckWidget::stateChanged()
+*/
+
+/*!
+ \fn void QtUiTestRecorder::entered(QObject* widget, QVariant const& item)
+
+ Emitted when \a item is entered into \a widget.
+
+ \sa QtUiTest::InputWidget::entered()
+*/
+
+/*!
+ \fn void QtUiTestRecorder::selected(QObject* widget, QString const& item)
+
+ Emitted when \a item is selected from \a widget.
+
+ \sa QtUiTest::SelectWidget::selected()
+*/
+
+/*!
+ \fn void QtUiTestRecorder::keyEvent(int key, int modifiers, bool isPress, bool isAutoRepeat)
+
+ Emitted when \a key (with \a modifiers) is pressed or released.
+
+ \a key is compatible with Qt::Key and \a modifiers is compatible with
+ Qt::KeyboardModifiers.
+
+ If the event is a press \a isPress is true, otherwise it is a release.
+ \a isAutoRepeat is true if the event is generated due to autorepeat.
+
+ This signal is only emitted within the server process, because individual
+ applications cannot monitor system-wide key events.
+*/
+
+/*!
+ \fn void QtUiTestRecorder::mouseEvent(int x, int y, int state)
+
+ Emitted when the mouse changes state.
+
+ \a x and \a y are the global co-ordinates of the event.
+ \a state is the current state of the mouse buttons, compatible with Qt::MouseButtons.
+
+ This signal is only emitted within the server process, because individual
+ applications cannot monitor system-wide mouse events.
+*/
+
+/*!
+ \internal
+ Connects all testwidget signals on \a object to all test recorder
+ instances.
+*/
+void QtUiTestRecorder::connectToAll(QObject* o)
+{
+ if (!o) return;
+
+ QMetaObject const* mo = o->metaObject();
+ QSet<QByteArray> _signals;
+
+#define _DO(Iface, Signal) \
+ if (qobject_cast<QtUiTest::Iface*>(o) && (-1 != mo->indexOfSignal(Signal))) { \
+ _signals << Signal; \
+ }
+
+ _DO(Widget, "gotFocus()");
+ _DO(ActivateWidget, "activated()");
+ _DO(CheckWidget, "stateChanged(int)");
+ _DO(InputWidget, "entered(QVariant)");
+ _DO(SelectWidget, "selected(QString)");
+
+#undef _DO
+
+ foreach (QByteArray sig, _signals) {
+ QByteArray recorder_slot = SLOT(on_) + sig;
+ sig.prepend(QSIGNAL_CODE);
+
+ /* Avoid multiple connections */
+ disconnect(o, sig, qtuitestRecorderPrivate(), recorder_slot);
+ connect( o, sig, qtuitestRecorderPrivate(), recorder_slot);
+ }
+}
+
+#include "qtuitestrecorder.moc"
+
diff --git a/old/libqtuitest/qtuitestrecorder.h b/old/libqtuitest/qtuitestrecorder.h
new file mode 100644
index 0000000..6d984bd
--- /dev/null
+++ b/old/libqtuitest/qtuitestrecorder.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QTUITESTRECORDER_H
+#define QTUITESTRECORDER_H
+
+#include <QObject>
+#include <qtuitestglobal.h>
+
+class QtUiTestRecorderPrivate;
+class QtUiTestWidgets;
+
+class QTUITEST_EXPORT QtUiTestRecorder : public QObject
+{
+ Q_OBJECT
+
+public:
+ QtUiTestRecorder(QObject* =0);
+ ~QtUiTestRecorder();
+
+ static void emitKeyEvent(int,int,bool,bool);
+ static void emitMouseEvent(int,int,int);
+
+protected:
+ virtual void connectNotify(char const*);
+ virtual void disconnectNotify(char const*);
+
+signals:
+ void gotFocus(QObject*);
+ void activated(QObject*);
+ void stateChanged(QObject*,int);
+ void entered(QObject*,QVariant const&);
+ void selected(QObject*,QString const&);
+
+ void keyEvent(int,int,bool,bool);
+ void mouseEvent(int,int,int);
+
+private:
+ static void connectToAll(QObject*);
+ friend class QtUiTestWidgets;
+ friend class QtUiTestRecorderPrivate;
+};
+
+#endif
+
diff --git a/old/libqtuitest/qtuitestwidgetinterface.cpp b/old/libqtuitest/qtuitestwidgetinterface.cpp
new file mode 100644
index 0000000..7a42a00
--- /dev/null
+++ b/old/libqtuitest/qtuitestwidgetinterface.cpp
@@ -0,0 +1,1102 @@
+/****************************************************************************
+**
+** 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 "qtuitestwidgetinterface.h"
+#include "qtuitestnamespace.h"
+
+#include <QRect>
+#include <QRegion>
+#include <QApplication>
+#include <QWidget>
+#include <QVariant>
+
+/*!
+ \preliminary
+ \class QtUiTest::WidgetFactory
+ \inpublicgroup QtUiTestModule
+ \brief The WidgetFactory class provides a factory interface
+ for QtUiTest widget wrapper classes.
+
+ QtUiTest::WidgetFactory is an abstract base class which enables the
+ creation of QtUiTest wrapper objects around Qt widgets.
+
+ Customizing QtUiTest behaviour for particular widgets is achieved by
+ implementing one or more test widget classes which inherit from
+ one or more QtUiTest widget interfaces,
+ subclassing QtUiTest::WidgetFactory, reimplementing the pure virtual
+ keys() and create() functions to create instances of the custom test
+ widget classes, and exporting the factory class using the
+ Q_EXPORT_PLUGIN2() macro.
+*/
+
+/*!
+ \fn QtUiTest::WidgetFactory::create(QObject* object)
+
+ Attempts to create a test widget to wrap \a object. Returns the created
+ test widget. Returns 0 if this factory does not support wrapping
+ \a object.
+
+ The returned object is suitable for use with
+ \l{QtUiTest}{qtuitest_cast}.
+
+ This function will only be called for objects which inherit one of the
+ classes returned by keys().
+*/
+
+/*!
+ Returns a widget or test widget of \a type, or 0 if none can be found.
+
+ Reimplement this function to provide custom behaviour for
+ QtUiTest::findWidget(). For example, if a custom soft menu widget is
+ being used rather than the shipped ContextLabel class, this function
+ must be reimplemented to return a pointer to the custom widget.
+
+ The base implementation always returns 0.
+*/
+QObject* QtUiTest::WidgetFactory::find(QtUiTest::WidgetType type)
+{ Q_UNUSED(type); return 0; }
+
+/*!
+ \fn QtUiTest::WidgetFactory::keys() const
+
+ Returns the list of C++ class names this factory can generate test widgets
+ for.
+
+ Note that returning a class from this function does not guarantee that the
+ factory will always be able to generate a test widget for that class.
+*/
+
+/*!
+ \preliminary
+ \class QtUiTest::Widget
+ \inpublicgroup QtUiTestModule
+ \brief The Widget class provides an abstract base class
+ for all test widgets.
+
+ QtUiTest::Widget contains functionality which maps
+ closely to QWidget. It encapsulates important information
+ and functionality related to two-dimensional GUI elements.
+
+ All test widgets should implement the QtUiTest::Widget interface,
+ using multiple inheritance to implement other QtUiTest interfaces
+ where suitable.
+*/
+
+/*!
+ \fn const QRect& QtUiTest::Widget::geometry() const
+
+ Returns the geometry of this widget in parent coordinates.
+
+ \sa QWidget::geometry()
+*/
+
+/*!
+ Returns the bounding rect of this widget in widget coordinates.
+
+ The base implementation returns geometry(), transformed to widget
+ coordinates.
+
+ \sa QWidget::rect()
+*/
+QRect QtUiTest::Widget::rect() const
+{
+ QRect ret(geometry());
+ ret.moveTopLeft(QPoint(0,0));
+ return ret;
+}
+
+/*!
+ Returns the left of the widget, in global coordinates.
+
+ \sa mapToGlobal()
+*/
+int QtUiTest::Widget::x() const
+{
+ return mapToGlobal(QPoint()).x();
+}
+
+/*!
+ Returns the top of the widget, in global coordinates.
+
+ \sa mapToGlobal()
+*/
+int QtUiTest::Widget::y() const
+{
+ return mapToGlobal(QPoint()).y();
+}
+
+/*!
+ Returns the width of the widget.
+
+ \sa geometry()
+*/
+int QtUiTest::Widget::width() const
+{
+ return geometry().width();
+}
+
+/*!
+ Returns the height of the widget.
+
+ \sa geometry()
+*/
+int QtUiTest::Widget::height() const
+{
+ return geometry().height();
+}
+
+/*!
+ \fn bool QtUiTest::Widget::isVisible() const
+
+ Returns true if this widget is currently visible.
+
+ In this context, "visible" has the same meaning as in QWidget::isVisible().
+ Therefore, this function returning \c{true} is not a guarantee that this
+ widget is currently on screen and unobscured. To test this,
+ visibleRegion() can be used.
+
+ \sa QWidget::isVisible(), visibleRegion()
+*/
+
+/*!
+ \fn QRegion QtUiTest::Widget::visibleRegion() const
+
+ Returns the currently on-screen, unobscured region of this widget,
+ in widget coordinates.
+
+ \sa QWidget::visibleRegion()
+*/
+
+/*!
+ \fn bool QtUiTest::Widget::ensureVisibleRegion(const QRegion& region)
+
+ Simulate whatever user input is necessary to ensure that \a region
+ (in local coordinates) is on-screen and unobscured.
+
+ Returns true if \a region was successfully made visible.
+
+ \sa visibleRegion()
+*/
+
+/*!
+ Simulate whatever user input is necessary to ensure that \a point
+ (in local coordinates) is on-screen and unobscured.
+
+ This convenience function calls ensureVisibleRegion() with a region
+ containing only \a point.
+
+ Returns true if \a point was successfully made visible.
+
+ \sa visibleRegion(), ensureVisibleRegion()
+*/
+bool QtUiTest::Widget::ensureVisiblePoint(const QPoint& point)
+{
+ return ensureVisibleRegion( QRegion(point.x(), point.y(), 1, 1) );
+}
+
+/*!
+ \fn QObject* QtUiTest::Widget::parent() const
+
+ Returns the parent of this widget, or 0 if this widget has no parent.
+
+ The returned object may be an actual QWidget, or may be a wrapping
+ test widget. Therefore, the only safe way to use the returned value
+ of this function is to cast it to the desired QtUiTest interface
+ using \l{QtUiTest}{qtuitest_cast}.
+
+ \sa QObject::parent(), QWidget::parentWidget(), children()
+*/
+
+/*!
+ Returns the window title (caption).
+
+ The returned string will typically be empty for all widgets other than
+ top-level widgets.
+
+ The default implementation returns an empty string.
+
+ \sa QWidget::windowTitle()
+*/
+QString QtUiTest::Widget::windowTitle() const
+{ return QString(); }
+
+/*!
+ \fn const QObjectList& QtUiTest::Widget::children() const
+
+ Returns all children of this widget.
+
+ The returned objects may be actual QWidget instances, or may be wrapping
+ test widgets. Therefore, the only safe way to use the returned objects
+ are to cast them to the desired QtUiTest interface using
+ \l{QtUiTest}{qtuitest_cast}.
+
+ Reimplementing this function allows widgets which are conceptually
+ widgets but are not QObject subclasses to be wrapped. This can be
+ achieved by returning a list of test widgets which do not necessarily
+ have underlying QWidget instances.
+
+ \sa QObject::children(), parent()
+*/
+
+/*!
+ Returns all descendants of this widget.
+
+ \sa children(), parent()
+*/
+void QtUiTest::Widget::descendants(QObjectList &list) const
+{
+ foreach (QObject *child, children()) {
+ if (!list.contains(child)) {
+ list << child;
+ QtUiTest::Widget* qw = qtuitest_cast<QtUiTest::Widget*>(child);
+ if (qw)
+ qw->descendants(list);
+ }
+ }
+}
+
+/*!
+ Returns the currently on-screen, unobscured region of all
+ child widgets of this widget, in widget coordinates. This does not
+ include the visible region of this widget.
+
+ The base implementation calculates the visible region by calling
+ visibleRegion() and childrenVisibleRegion() on all children().
+
+ \sa QWidget::visibleRegion(), children(), visibleRegion()
+*/
+QRegion QtUiTest::Widget::childrenVisibleRegion() const
+{
+ QRegion ret;
+ foreach (QObject *o, children()) {
+ Widget *w = qtuitest_cast<Widget*>(o);
+ if (w) ret |= ((w->childrenVisibleRegion() | w->visibleRegion())
+ .translated( -w->geometry().topLeft() ) );
+ }
+ return ret;
+}
+
+/*!
+ \fn QPoint QtUiTest::Widget::mapToGlobal(const QPoint& pos) const
+
+ Maps \a pos from widget coordinates to global screen coordinates and
+ returns the result.
+
+ \sa QWidget::mapToGlobal()
+*/
+
+/*!
+ \fn QPoint QtUiTest::Widget::mapFromGlobal(const QPoint& pos) const
+
+ Maps \a pos from global screen coordinates to widget coordinates and
+ returns the result.
+
+ \sa QWidget::mapFromGlobal()
+*/
+
+/*!
+ Returns the center point of the widget. The base implementation
+ returns geometry().center().
+
+ \sa QtUiTest::Widget::geometry()
+*/
+QPoint QtUiTest::Widget::center() const
+{
+ QPoint ret;
+ ret = mapToGlobal( geometry().center() );
+ return ret;
+}
+
+/*!
+ Simulate the user input necessary to move keyboard focus to this
+ widget.
+
+ The base implementation uses the result of hasFocus() to determine if the
+ widget currently has focus. If in keypad mode, a sequence of Up or Down
+ key presses will be used to move focus until this widget has focus.
+ If in mouse mode, the center of this widget will be clicked once.
+
+ Due to the way this function works in keypad mode, it is very important
+ that focusOutEvent() is correctly implemented for all widgets to dismiss
+ any "grab" effects on keyboard focus.
+
+ When reimplementing this function, it is necessary to call focusOutEvent()
+ on any widget before taking any action which could cause that widget to
+ lose focus.
+
+ Returns true if focus was successfully given to this widget, false
+ otherwise.
+
+ \sa QWidget::setFocus(), focusOutEvent()
+*/
+bool QtUiTest::Widget::setFocus()
+{
+ if (hasFocus()) return true;
+
+ // xxx Try using findWidget(Focus) here instead.
+ struct Focus {
+ static QWidget* focusWidget() {
+ QWidget *w = QApplication::focusWidget();
+ if (!w) w = QApplication::activeWindow();
+ if (!w) w = QApplication::activePopupWidget();
+ if (!w) w = QApplication::activeModalWidget();
+ return w;
+ }
+ };
+
+ using namespace QtUiTest;
+
+ if (!mousePreferred()) {
+ bool backwards = false;
+
+ QWidget *w = Focus::focusWidget();
+ QWidget *initialFocus = w;
+ Widget *tw = qtuitest_cast<Widget*>(w);
+ if (!tw) {
+ setErrorString("Can't find currently focused widget!");
+ return false;
+ }
+
+ if (y() < tw->y() || (y() == tw->y() && x() < tw->x())) {
+ backwards = true;
+ }
+
+ const int maxtries = 100;
+ int i = 0;
+ QWidget *pw = 0;
+
+ while (!hasFocus() && i < maxtries) {
+ tw->focusOutEvent();
+
+#if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)
+ if (backwards) {
+ keyClick(Qt::Key_Up);
+ } else {
+ keyClick(Qt::Key_Down);
+ }
+#else
+ if (backwards) {
+ keyClick(Qt::Key_Tab, Qt::ShiftModifier);
+ } else {
+ keyClick(Qt::Key_Tab);
+ }
+#endif
+ pw = w;
+ if (w != pw && !QtUiTest::waitForSignal(qApp, SIGNAL(focusChanged(QWidget*,QWidget*)))) {
+ setErrorString("Could not change widget focus using the keyboard");
+ return false;
+ }
+
+ //FIXME: Additional wait for Greenphone
+ QtUiTest::wait(200);
+ ++i;
+ w = Focus::focusWidget();
+ if (w == initialFocus && w != pw) {
+ // Back to square one...
+ break;
+ }
+ tw = qtuitest_cast<Widget*>(w);
+ if (!tw) {
+ setErrorString("Can't find currently focused widget!");
+ return false;
+ }
+ }
+
+ if (!hasFocus()) {
+ setErrorString(QString("Failed to give focus to widget after %1 keyclicks")
+ .arg(maxtries));
+ }
+ } else {
+ Widget* tw = qtuitest_cast<Widget*>(Focus::focusWidget());
+ if (tw) tw->focusOutEvent();
+
+ QPoint center = rect().center();
+ ensureVisiblePoint(center);
+
+ center = mapToGlobal(center);
+
+ // In the past, bugs have existed which make one click
+ // be consumed somewhere.
+ // Keep working in that case, but give a warning.
+ int i = 0;
+ do {
+ mouseClick( center );
+ QtUiTest::waitForSignal(qApp, SIGNAL(focusChanged(QWidget*,QWidget*)));
+ if (hasFocus()) break;
+ } while(++i < 2);
+
+ if (hasFocus() && 1 == i)
+ qWarning("QtUitest: possible bug, took more than one click to "
+ "give focus to a widget.");
+ }
+
+ return hasFocus();
+}
+
+/*!
+ \fn bool QtUiTest::Widget::setEditFocus(bool enable)
+ Simulate the user input necessary to \a enable or disable edit focus for
+ this widget. Enabling edit focus will implicitly call setFocus() when
+ necessary.
+
+ The concept of edit focus only exists in Qt Embedded. This function must
+ be implemented when using Qt Embedded. On other platforms,
+ this function will behave the same as setFocus() when enable is true, and
+ will have no effect when enable is false.
+
+ Returns true if edit focus was successfully enabled or disabled for this
+ widget, false otherwise.
+
+ \sa QWidget::setEditFocus(), hasEditFocus()
+*/
+#ifndef Q_WS_QWS
+bool QtUiTest::Widget::setEditFocus(bool enable)
+{
+ if (!enable) return true;
+
+ return hasFocus() || setFocus();
+}
+#endif
+
+/*!
+ \fn bool QtUiTest::Widget::hasEditFocus() const
+ Returns true if this widget currently has edit focus.
+
+ The concept of edit focus only exists in Qt Embedded. This function must
+ be implemented on Qt Embedded. On other platforms, the base implementation
+ will return the same as hasFocus().
+
+ \sa QWidget::hasEditFocus(), setEditFocus()
+*/
+#ifndef Q_WS_QWS
+bool QtUiTest::Widget::hasEditFocus() const
+{ return hasFocus(); }
+#endif
+
+/*!
+ This function is called when this widget is about to lose keyboard focus.
+ The base implementation does nothing.
+
+ This function should be reimplemented to put this widget in a state where
+ subsequent up/down key clicks will result in non-destructive navigation
+ between widgets.
+
+ For example, if this function is called on a combo box which
+ currently has a list popped up, it should dismiss the list
+ so that subsequent key clicks will navigate between widgets rather
+ than navigating within the list.
+
+ \code
+ void MyComboBox::focusOutEvent() {
+ // Assuming q is a QComboBox...
+ // If the list is currently popped up...
+ if (q->view()->isVisible()) {
+ // Press the Select key to commit the currently highlighted
+ // item and ensure we are ready to navigate by keys.
+ QtUiTest::keyClick(Qt::Key_Select);
+ }
+ }
+ \endcode
+
+ \sa QWidget::focusOutEvent(), setFocus(), hasFocus()
+*/
+void QtUiTest::Widget::focusOutEvent()
+{}
+
+/*!
+ \fn bool QtUiTest::Widget::hasFocus() const
+ Returns true if this widget currently has keyboard focus.
+
+ \sa QWidget::hasFocus()
+*/
+
+/*!
+ Returns the focus proxy of this widget, or 0 if this widget has no focus proxy.
+ A widget may "have focus", but have a child widget that actually handles the
+ focus.
+
+ The returned object may be an actual QWidget, or may be a wrapping
+ test widget. Therefore, the only safe way to use the returned value
+ of this function is to cast it to the desired QtUiTest interface
+ using \l{QtUiTest}{qtuitest_cast}.
+
+ \sa QWidget::focusProxy()
+*/
+QObject* QtUiTest::Widget::focusProxy() const
+{
+ return 0;
+}
+
+/*!
+ Returns the focus policy of this widget.
+
+ The default implementation returns Qt::NoFocus, indicating that the widget
+ does not accept focus.
+
+ \sa QWidget::focusPolicy()
+*/
+Qt::FocusPolicy QtUiTest::Widget::focusPolicy () const
+{
+ return Qt::NoFocus;
+}
+
+/*!
+ Returns the flags set on this widget.
+
+ The default implementation returns 0, which is equivalent to a plain
+ Qt::Widget with no special flags set.
+*/
+Qt::WindowFlags QtUiTest::Widget::windowFlags() const
+{ return 0; }
+
+/*!
+ Returns true if this widget is of the given \a type.
+
+ The base implementation always returns false.
+*/
+bool QtUiTest::Widget::inherits(QtUiTest::WidgetType type) const
+{ Q_UNUSED(type); return false; }
+
+/*!
+ Sets \a pixmap to image of the widget. Returns true on success.
+
+ The base implementation always returns false.
+*/
+bool QtUiTest::Widget::grabPixmap(QPixmap &pixmap) const
+{ Q_UNUSED(pixmap); return false; }
+
+/*!
+ Returns true if this widget should be ignored by QtUiTest. If
+ a widget is ignored, any child widgets will still be processed.
+
+ The base implementation always returns false.
+
+ \sa {Query Paths}, {Querying Objects}
+*/
+bool QtUiTest::Widget::ignoreScan() const
+{ return false; }
+
+/*!
+ Returns true if this widget should not considered a possible
+ buddy for a label when resolving query paths.
+
+ Note that if the widget is returned as a buddy by
+ QtUiTest::Label::buddy() then this value will be ignored.
+
+ The base implementation always returns false.
+
+ \sa QtUiTest::Label::buddy(), {Query Paths}, {Querying Objects}
+*/
+bool QtUiTest::Widget::ignoreBuddy() const
+{ return false; }
+
+/*!
+ \fn void QtUiTest::Widget::gotFocus()
+
+ This signal is emitted when this widget gains focus by any means.
+
+ \sa QApplication::focusChanged()
+*/
+
+QVariant QtUiTest::Widget::getProperty(const QString&) const
+{
+ return QVariant();
+}
+
+bool QtUiTest::Widget::setProperty(const QString&, const QVariant&)
+{
+ return false;
+}
+
+/*!
+ \preliminary
+ \class QtUiTest::ActivateWidget
+ \inpublicgroup QtUiTestModule
+ \brief The ActivateWidget class provides an abstract base class
+ for all test widgets which can conceptually be "activated" by a user.
+
+ "Activation" occurs when user input causes an action, possibly
+ non-reversible, on a widget which exists solely for the purpose of
+ causing that action.
+
+ Examples of widgets suitable for this interface include QAbstractButton.
+*/
+
+/*!
+ \fn bool QtUiTest::ActivateWidget::activate()
+ Simulate the user input necessary to activate this widget.
+
+ Returns true if this widget was successfully activated.
+
+ For example, a button would reimplement this function to simulate
+ a click on itself, or to navigate to itself and hit the "Select" key.
+*/
+
+/*!
+ \fn void QtUiTest::ActivateWidget::activated()
+
+ This signal is emitted when this widget is activated.
+*/
+
+/*!
+ \preliminary
+ \class QtUiTest::LabelWidget
+ \inpublicgroup QtUiTestModule
+ \brief The LabelWidget class provides an abstract base class
+ for all test widgets which are conceptually labels.
+
+ Some widgets may act as labels for themselves while also providing
+ other functionality. For example, a button widget labels itself
+ and is also an ActivateWidget.
+
+ Examples of widgets suitable for this interface include QLabel.
+*/
+
+/*!
+ \fn QString QtUiTest::LabelWidget::labelText() const
+
+ Returns the text displayed on this label.
+
+ Most label widgets will also implement \l{QtUiTest::TextWidget}.
+ Most commonly, labelText() returns the same value as \l{QtUiTest::TextWidget::text()}.
+*/
+
+/*!
+ Returns the label's buddy widget, or 0 if this widget has no buddy.
+ The buddy-label relationship is used by QtUiTest as part of query path
+ resolution.
+
+ The returned object may be an actual QWidget, or may be a wrapping
+ test widget. Therefore, the only safe way to use the returned value
+ of this function is to cast it to the desired QtUiTest interface
+ using \l{QtUiTest}{qtuitest_cast}.
+
+ \sa QLabel::buddy(), {Query Paths}, {Querying Objects}
+*/
+QObject* QtUiTest::LabelWidget::buddy() const
+{
+ return 0;
+}
+
+/*!
+ \preliminary
+ \class QtUiTest::CheckWidget
+ \inpublicgroup QtUiTestModule
+ \brief The CheckWidget class provides an abstract base class
+ for all test widgets which support 'checked' and 'unchecked' states.
+
+ QtUiTest::CheckWidget exposes the current check state of widgets
+ which can be checked or unchecked.
+
+ Examples of widgets suitable for this interface include QCheckBox
+ and QAbstractButton.
+*/
+
+/*!
+ Returns true if this widget has three possible states, i.e. the widget
+ can be in state Qt::PartiallyChecked.
+
+ The base implementation returns false.
+
+ \sa QCheckBox::isTristate()
+*/
+bool QtUiTest::CheckWidget::isTristate() const
+{ return false; }
+
+/*!
+ \fn Qt::CheckState QtUiTest::CheckWidget::checkState() const
+
+ Returns the current check state of this widget.
+
+ \sa QCheckBox::checkState(), setCheckState()
+*/
+
+/*!
+ Simulates the user input necessary to set the current check state
+ to \a state, returning true on success.
+
+ The default implementation does nothing and returns false.
+
+ \sa QCheckBox::setCheckState(), checkState()
+*/
+bool QtUiTest::CheckWidget::setCheckState(Qt::CheckState state)
+{ Q_UNUSED(state); return false; }
+
+/*!
+ \fn void QtUiTest::CheckWidget::stateChanged(int state)
+
+ This signal is emitted when the check state of this widget changes
+ to \a state. \a state is compatible with Qt::CheckState.
+*/
+
+/*!
+ \preliminary
+ \class QtUiTest::TextWidget
+ \inpublicgroup QtUiTestModule
+ \brief The TextWidget class provides an abstract base class
+ for all test widgets which display text to the user.
+
+ The QtUiTest::TextWidget interface should be implemented on any widget
+ which shows any text at all. This is the primary interface QtUiTest
+ uses to determine text->widget mappings, and it is used to implement
+ \l{QSystemTest::}{getText()}, a heavily used verification mechanism.
+
+ This interface is closely related to QtUiTest::InputWidget, which
+ provides an interface for entering text into a widget. Any widgets
+ which contain user-editable text will typically implement both
+ QtUiTest::InputWidget and QtUiTest::TextWidget.
+
+ Examples of widgets suitable for this interface include QLabel,
+ QAbstractButton, QLineEdit, QTextEdit and many more.
+
+ \sa QtUiTest::InputWidget
+*/
+
+/*!
+ Returns the text in this widget which is currently selected / highlighted.
+ If the widget does not support the concept of selected text, this function
+ should return the same as text().
+
+ The base implementation calls text().
+
+ \sa QLineEdit::selectedText()
+*/
+QString QtUiTest::TextWidget::selectedText() const
+{ return text(); }
+
+/*!
+ Returns the value in this widget which is currently selected / highlighted.
+ If the widget does not support the concept of a selected value, this function
+ should return the same as value().
+
+ The base implementation calls selectedText().
+*/
+QVariant QtUiTest::TextWidget::selectedValue() const
+{ return selectedText(); }
+
+/*!
+ \fn QString QtUiTest::TextWidget::text() const
+
+ Returns all of the text this widget is currently presenting to the user.
+*/
+
+/*!
+ Returns the value this widget is currently presenting to the user.
+
+ The returned value will be of whatever type is most appropriate for this widget.
+ For example, a QLineEdit would return a literal copy of its text (giving the same
+ result as the text() function), while a QTimeEdit may return a QTime.
+*/
+QVariant QtUiTest::TextWidget::value() const
+{ return text(); }
+
+/*!
+ \preliminary
+ \class QtUiTest::ListWidget
+ \inpublicgroup QtUiTestModule
+ \brief The ListWidget class provides an abstract base class
+ for all test widgets which display a list of items to the user.
+
+ QtUiTest::ListWidget allows a widget which is conceptually a list to
+ be enumerated. This is closely related to QtUiTest::SelectWidget,
+ which may be implemented to allow a user to select an item from a list.
+
+ Examples of widgets suitable for this interface include QAbstractItemView,
+ QComboBox and QMenu.
+
+ \sa QtUiTest::SelectWidget
+*/
+
+/*!
+ \fn QStringList QtUiTest::ListWidget::list() const
+
+ Returns a list containing a text representation of each item in this list
+ widget.
+*/
+
+/*!
+ \fn QRect QtUiTest::ListWidget::visualRect(const QString& item) const
+
+ Returns the bounding rect of \a item, in widget coordinates.
+ If \a item isn't currently shown in this widget, returns a null rect.
+
+ \sa QAbstractItemView::visualRect()
+*/
+
+/*!
+ Simulates the user input necessary to navigate this widget until \a item
+ is currently visible and return true on success.
+
+ For example, in a QAbstractItemView with vertical scrollbars, if \a item
+ exists further down the list than currently shown, this function might
+ simulate 'Down' key clicks until it becomes visible.
+
+ The base implementation does nothing and returns true.
+*/
+bool QtUiTest::ListWidget::ensureVisible(const QString& item)
+{ Q_UNUSED(item); return true; }
+
+/*!
+ \preliminary
+ \class QtUiTest::InputWidget
+ \inpublicgroup QtUiTestModule
+ \brief The InputWidget class provides an abstract base class
+ for all test widgets which allow the user to input text.
+
+ QtUiTest::InputWidget encapsulates a widget in which a user may enter
+ and remove text. This is closely related to QtUiTest::TextWidget, which
+ provides an interface for retrieving text from a widget. Any widgets
+ which contain user-editable text will typically implement both
+ QtUiTest::InputWidget and QtUiTest::TextWidget.
+
+ Examples of widgets suitable for this interface include QLineEdit and
+ QTextEdit.
+
+ \sa QtUiTest::TextWidget
+*/
+
+/*!
+ \fn bool QtUiTest::InputWidget::canEnter(const QVariant& item) const
+
+ Returns true if \a item can possibly be entered into this widget.
+
+ For example, for a QLineEdit, QLineEdit::validator() would be used to
+ ensure that \l{QVariant::toString()}{item.toString()} constitutes
+ valid input for this line edit.
+*/
+
+/*!
+ \fn bool QtUiTest::InputWidget::enter(const QVariant& item, bool noCommit)
+
+ Simulates the user input necessary to enter \a item into this widget.
+ Returns true on success.
+
+ \a item can potentially be any type representable in a QVariant.
+ Most widgets will only be interested in text, in which case
+ \l{QVariant::toString()}{item.toString()} can be called to retrieve
+ a string. Examples of widgets which may handle types other than text
+ are QDateEdit and QTimeEdit, which may handle dates and times.
+
+ If \a noCommit is true, no attempt is made to commit the input (for example,
+ by clicking the Select key). Normally this value will be false, which will
+ result in the input being committed. This value is not applicable to all
+ widget types.
+
+ If canEnter() returns true and this function returns false, an error
+ has occurred and this widget is left in an undefined state.
+*/
+
+/*!
+ Returns the input proxy of this widget, or 0 if this widget has no input proxy.
+
+ The input proxy is an object that receives input on behalf of the widget (for
+ example, an input method). It must be cast to the desired QtUiTest interface
+ using \l{QtUiTest}{qtuitest_cast}.
+*/
+QObject* QtUiTest::InputWidget::inputProxy() const
+{
+ return 0;
+}
+
+/*!
+ \fn void QtUiTest::InputWidget::entered(const QVariant& item)
+ This signal is emitted when \a item is entered into the widget
+ by the user.
+*/
+
+/*!
+ \preliminary
+ \class QtUiTest::SelectWidget
+ \inpublicgroup QtUiTestModule
+ \brief The SelectWidget class provides an abstract base class
+ for all test widgets which allow the user to select from a range of items.
+
+ QtUiTest::SelectWidget encapsulates a widget which provides the user
+ with a choice from a (possibly unlimited) range. This is closely related
+ to QtUiTest::ListWidget, which may be implemented to allow a user to
+ enumerate all items from a list.
+
+ Examples of widgets suitable for this interface include QAbstractItemView,
+ QComboBox and QMenu.
+
+ \sa QtUiTest::ListWidget
+*/
+
+/*!
+ Returns true if this widget supports the selection of multiple items at
+ the same time.
+
+ The base implementation returns false.
+*/
+bool QtUiTest::SelectWidget::isMultiSelection() const
+{ return false; }
+
+/*!
+ \fn bool QtUiTest::SelectWidget::canSelect(const QString& item) const
+
+ Returns true if \a item can possibly be selected from this widget.
+*/
+
+/*!
+ Returns true if all of the given \a items can be selected from this widget
+ at the same time.
+
+ The base implementation returns true if isMultiSelection() returns true
+ and canSelect() returns true for every item in \a items.
+*/
+bool QtUiTest::SelectWidget::canSelectMulti(const QStringList& items) const
+{
+ if (!isMultiSelection()) return false;
+ foreach (QString item, items)
+ if (!canSelect(item)) return false;
+ return true;
+}
+
+/*!
+ \fn bool QtUiTest::SelectWidget::select(const QString& item)
+
+ Simulates the user input necessary to select \a item from this widget.
+
+ Returns true if \a item was successfully selected.
+
+ If canSelect() returns true and this function returns false, an error
+ has occurred and this widget's state is undefined.
+*/
+
+/*!
+ Simulates the user input necessary to select all \a items from this widget
+ at the same time.
+
+ Returns true if \a items were all successfully selected.
+
+ If canSelectMulti() returns true and this function returns false, an error
+ has occurred and this widget's state is undefined.
+
+ The base implementation calls canSelectMulti() to check if \a items can
+ be selected, then calls select() on each item in \a items.
+*/
+bool QtUiTest::SelectWidget::selectMulti(const QStringList& items)
+{
+ if (!canSelectMulti(items)) return false;
+ foreach (QString item, items)
+ if (!select(item)) return false;
+ return true;
+}
+
+/*!
+ \fn void QtUiTest::SelectWidget::selected(const QString& item)
+ This signal is emitted when \a item is selected from this widget.
+*/
+
+
+/*!
+ \preliminary
+ \class QtUiTest::CheckItemWidget
+ \inpublicgroup QtUiTestModule
+ \brief The CheckItemWidget class provides an abstract base class for all
+ test widgets which include items that support 'checked' and 'unchecked' states.
+
+ Examples of widgets suitable for this interface include QMenu.
+*/
+
+/*!
+ Returns true if \a item can be checked (has a selectable on/off state).
+*/
+bool QtUiTest::CheckItemWidget::isCheckable(const QString& item)
+{ Q_UNUSED(item); return false; }
+
+/*!
+ \fn bool QtUiTest::CheckItemWidget::isChecked(const QString& item)
+ Returns the check state of the \a item specified.
+*/
+
+/*!
+ \fn bool QtUiTest::CheckItemWidget::setChecked(const QString& item, bool state)
+ Set the check state of the \a item. Returns false if the check state cannot be set.
+*/
+
+
+/*!
+ \preliminary
+ \class QtUiTest::IndexedWidget
+ \inpublicgroup QtUiTestModule
+ \brief The IndexedWidget class provides an abstract base class
+ for all test widgets which allow the user to select items based on index.
+
+ Examples of widgets suitable for this interface include QAbstractItemView.
+
+ \sa QtUiTest::ListWidget, QtUiTest::SelectWidget
+*/
+
+/*!
+ Selects the item with the specified \a index from an item view. The index should
+ be specified in QtScript as an array, in the form [parentRow, parentColumn, ..., row, column].
+
+ This function can be used in situations where \l{QSystemTest::}{select()} would be inappropriate,
+ typically in larger, more complex item views or those containing items with duplicate names.
+
+ \code
+ // Select row 3, column 5 from tableView
+ selectIndex([3, 5], tableView);
+
+ // Select row 2, column 4 beneath parent item at row 1, column 0 from treeView
+ selectIndex([1, 0, 2, 4], treeView);
+ \endcode
+
+ \sa select(), selectedIndex()
+*/
+bool QtUiTest::IndexedWidget::selectIndex(const QVariantList& index)
+{
+ Q_UNUSED(index);
+ return false;
+}
+
+
+/*!
+ Returns the index of the item currently selected in an item view. This is returned
+ as a QVariantList, as required by selectIndex().
+
+ \sa selectIndex()
+*/
+QVariantList QtUiTest::IndexedWidget::selectedIndex() const
+{
+ return QVariantList();
+}
diff --git a/old/libqtuitest/qtuitestwidgetinterface.h b/old/libqtuitest/qtuitestwidgetinterface.h
new file mode 100644
index 0000000..2bbecff
--- /dev/null
+++ b/old/libqtuitest/qtuitestwidgetinterface.h
@@ -0,0 +1,263 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QTUITESTWIDGETINTERFACE_H
+#define QTUITESTWIDGETINTERFACE_H
+
+#include <QStringList>
+#include <QVariantList>
+#include <QtGlobal>
+#include <qtuitestnamespace.h>
+#include <qtuitestglobal.h>
+
+class QRect;
+class QRegion;
+class QPoint;
+class QPixmap;
+
+namespace QtUiTest
+{
+#ifndef Q_QDOC
+ template<class T> T qtuitest_cast_helper(QObject*,T);
+#endif
+
+#define QTUITEST_INTERFACE(Klass) \
+ public: \
+ virtual ~Klass() {} \
+ static const char* _q_interfaceName() { return #Klass; } \
+ private: \
+ template<class T> friend T qtuitest_cast_helper(QObject*,T);
+
+ class QTUITEST_EXPORT WidgetFactory
+ {
+ QTUITEST_INTERFACE(WidgetFactory)
+ public:
+ virtual QObject* create(QObject*) = 0;
+ virtual QObject* find(QtUiTest::WidgetType);
+ virtual QStringList keys() const = 0;
+ };
+
+ class QTUITEST_EXPORT Widget
+ {
+ QTUITEST_INTERFACE(Widget)
+ public:
+ virtual const QRect& geometry() const = 0;
+ virtual QRect rect() const;
+ virtual int x() const;
+ virtual int y() const;
+ virtual int width() const;
+ virtual int height() const;
+ virtual bool isVisible() const = 0;
+ virtual QRegion visibleRegion() const = 0;
+ virtual QObject* parent() const = 0;
+ virtual QString windowTitle() const;
+ virtual const QObjectList &children() const = 0;
+ virtual void descendants(QObjectList &list) const;
+ virtual QRegion childrenVisibleRegion() const;
+ virtual QPoint mapToGlobal(const QPoint&) const = 0;
+ virtual QPoint mapFromGlobal(const QPoint&) const = 0;
+ virtual QPoint center() const;
+ virtual bool ensureVisibleRegion(const QRegion&) = 0;
+ bool ensureVisiblePoint(const QPoint&);
+ virtual bool setFocus();
+ virtual void focusOutEvent();
+ virtual bool hasFocus() const = 0;
+ virtual QObject* focusProxy() const;
+ virtual Qt::FocusPolicy focusPolicy () const;
+ virtual Qt::WindowFlags windowFlags() const;
+#ifdef Q_WS_QWS
+ virtual bool hasEditFocus() const = 0;
+ virtual bool setEditFocus(bool) = 0;
+#else
+ virtual bool hasEditFocus() const;
+ virtual bool setEditFocus(bool);
+#endif
+ virtual bool inherits(QtUiTest::WidgetType) const;
+ virtual bool grabPixmap(QPixmap &pixmap) const;
+ virtual bool ignoreScan() const;
+ virtual bool ignoreBuddy() const;
+ virtual QVariant getProperty(const QString&) const;
+ virtual bool setProperty(const QString&, const QVariant&);
+
+#ifdef Q_QDOC
+ signals:
+ void gotFocus();
+#endif
+ };
+
+ class QTUITEST_EXPORT ActivateWidget
+ {
+ QTUITEST_INTERFACE(ActivateWidget)
+ public:
+ virtual bool activate() = 0;
+
+#ifdef Q_QDOC
+ signals:
+ void activated();
+#endif
+ };
+
+ class QTUITEST_EXPORT LabelWidget
+ {
+ QTUITEST_INTERFACE(LabelWidget)
+ public:
+ virtual QString labelText() const = 0;
+ virtual QObject* buddy() const;
+ };
+
+ class QTUITEST_EXPORT CheckWidget
+ {
+ QTUITEST_INTERFACE(CheckWidget)
+ public:
+ virtual bool isTristate() const;
+ virtual Qt::CheckState checkState() const = 0;
+ virtual bool setCheckState(Qt::CheckState);
+
+#ifdef Q_QDOC
+ signals:
+ void stateChanged(int);
+#endif
+ };
+
+ class QTUITEST_EXPORT TextWidget
+ {
+ QTUITEST_INTERFACE(TextWidget)
+ public:
+ virtual QString selectedText() const;
+ virtual QVariant selectedValue() const;
+ virtual QString text() const = 0;
+ virtual QVariant value() const;
+ };
+
+ class QTUITEST_EXPORT ListWidget
+ {
+ QTUITEST_INTERFACE(ListWidget)
+ public:
+ virtual QStringList list() const = 0;
+ virtual QRect visualRect(const QString&) const = 0;
+ virtual bool ensureVisible(const QString&);
+ };
+
+ class QTUITEST_EXPORT InputWidget
+ {
+ QTUITEST_INTERFACE(InputWidget)
+ public:
+ virtual bool canEnter(const QVariant&) const = 0;
+ virtual bool enter(const QVariant&,bool) = 0;
+ virtual QObject *inputProxy() const;
+
+#ifdef Q_QDOC
+ signals:
+ void entered(const QVariant&);
+#endif
+ };
+
+ class QTUITEST_EXPORT SelectWidget
+ {
+ QTUITEST_INTERFACE(SelectWidget)
+ public:
+ virtual bool isMultiSelection() const;
+
+ virtual bool canSelect(const QString&) const = 0;
+ virtual bool canSelectMulti(const QStringList&) const;
+ virtual bool select(const QString&) = 0;
+ virtual bool selectMulti(const QStringList&);
+
+#ifdef Q_QDOC
+ signals:
+ void selected(const QString&);
+#endif
+ };
+
+ class QTUITEST_EXPORT CheckItemWidget
+ {
+ QTUITEST_INTERFACE(CheckItemWidget)
+ public:
+ virtual bool isCheckable(const QString&);
+ virtual bool isChecked(const QString&) const = 0;
+ virtual bool setChecked(const QString&, bool) = 0;
+ };
+
+ class QTUITEST_EXPORT IndexedWidget
+ {
+ QTUITEST_INTERFACE(IndexedWidget)
+ public:
+ virtual bool selectIndex(const QVariantList&);
+ virtual QVariantList selectedIndex() const;
+ };
+
+};
+
+Q_DECLARE_INTERFACE(
+ QtUiTest::WidgetFactory,
+ "com.nokia.qt.QtUiTest.WidgetFactory/1.0")
+Q_DECLARE_INTERFACE(
+ QtUiTest::Widget,
+ "com.nokia.qt.QtUiTest.Widget/1.0")
+Q_DECLARE_INTERFACE(
+ QtUiTest::ActivateWidget,
+ "com.nokia.qt.QtUiTest.ActivateWidget/1.0")
+Q_DECLARE_INTERFACE(
+ QtUiTest::LabelWidget,
+ "com.nokia.qt.QtUiTest.LabelWidget/1.0")
+Q_DECLARE_INTERFACE(
+ QtUiTest::CheckWidget,
+ "com.nokia.qt.QtUiTest.CheckWidget/1.0")
+Q_DECLARE_INTERFACE(
+ QtUiTest::TextWidget,
+ "com.nokia.qt.QtUiTest.TextWidget/1.0")
+Q_DECLARE_INTERFACE(
+ QtUiTest::ListWidget,
+ "com.nokia.qt.QtUiTest.ListWidget/1.0")
+Q_DECLARE_INTERFACE(
+ QtUiTest::InputWidget,
+ "com.nokia.qt.QtUiTest.InputWidget/1.0")
+Q_DECLARE_INTERFACE(
+ QtUiTest::SelectWidget,
+ "com.nokia.qt.QtUiTest.SelectWidget/1.0")
+Q_DECLARE_INTERFACE(
+ QtUiTest::CheckItemWidget,
+ "com.nokia.qt.QtUiTest.CheckItemWidget/1.0")
+Q_DECLARE_INTERFACE(
+ QtUiTest::IndexedWidget,
+ "com.nokia.qt.QtUiTest.IndexedWidget/1.0")
+#endif
+
diff --git a/old/libqtuitest/qtuitestwidgets.cpp b/old/libqtuitest/qtuitestwidgets.cpp
new file mode 100644
index 0000000..9d163ef
--- /dev/null
+++ b/old/libqtuitest/qtuitestwidgets.cpp
@@ -0,0 +1,657 @@
+/****************************************************************************
+**
+** 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 "qinputgenerator_p.h"
+#include "qtuitestrecorder.h"
+#include "qtuitestwidgetinterface.h"
+#include "qtuitestwidgets_p.h"
+
+#include <QDebug>
+#define qLog(A) if(1); else qDebug() << #A
+
+/*
+ If the QTUITEST_INPUT_DELAY environment variable is set, all calls to keyClick etc will
+ immediately return but the resulting event won't be generated until QTUITEST_INPUT_DELAY
+ milliseconds have passed.
+ This can be used to simulate a slow system to catch race conditions.
+ For example, setting QTUITEST_INPUT_DELAY to 500 roughly simulates running with a remote X
+ server over a link with a round trip time of 250ms.
+
+ Disable this define to disable the race condition testing code.
+*/
+#define QTUITEST_RACE_TEST
+
+#include <QApplication>
+#include <QDir>
+#include <QPluginLoader>
+#include <QPointer>
+#include <QStringList>
+#include <QTimer>
+
+/*!
+ \internal
+ \class QtUiTestWidgets
+ \brief The QtUiTestWidgets class provides an interface for creating and managing QtUiTest widgets.
+
+ QtUiTestWidgets manages the lifetime of all test widgets and allows
+ test widgets to simulate user interaction with the application.
+*/
+
+#ifdef QTUITEST_RACE_TEST
+enum QtUiTestInputType { QtUiTestPress, QtUiTestRelease, QtUiTestClick };
+struct QtUiTestKeyEvent
+{
+ QtUiTestInputType type;
+ Qt::Key key;
+ Qt::KeyboardModifiers mod;
+ QtUiTest::InputOption opt;
+};
+struct QtUiTestMouseEvent
+{
+ QtUiTestInputType type;
+ QPoint pos;
+ Qt::MouseButtons state;
+ QtUiTest::InputOption opt;
+};
+static int qtUiTestGetInputDelay()
+{
+ bool ok;
+ QByteArray value(qgetenv("QTUITEST_INPUT_DELAY"));
+ int ret = value.toInt(&ok);
+ if (!ok || ret < 0) ret = -1;
+ return ret;
+}
+static int qtUiTestInputDelay()
+{ static int ret = qtUiTestGetInputDelay(); return ret; }
+#endif
+
+
+class QtUiTestWidgetsPrivate
+{
+public:
+ QtUiTestWidgetsPrivate(QtUiTestWidgets* parent);
+
+ static QList<QByteArray> allImplementedInterfaces(QObject *o);
+
+ void _q_objectDestroyed();
+
+ QWidget *inputMethodsWidget() const;
+ QString currentInputMethod() const;
+
+ QtUiTestWidgets* q;
+
+ QHash< QByteArray, QSet<QtUiTest::WidgetFactory*> > factories;
+ QHash< QObject*, QHash<QByteArray, QPointer<QObject> > > testWidgets;
+ QSet< QtUiTest::WidgetFactory* > factorySet;
+
+ int inputOptions;
+ bool mousePreferred;
+ QtUiTest::LabelOrientation labelOrientation;
+
+ QString errorString;
+
+ QInputGenerator input;
+
+#ifdef QTUITEST_RACE_TEST
+ QList<QtUiTestKeyEvent> pendingKeyEvents;
+ QList<QtUiTestMouseEvent> pendingMouseEvents;
+ void _q_postNextKeyEvent();
+ void _q_postNextMouseEvent();
+#else
+ inline void _q_postNextKeyEvent() {}
+ inline void _q_postNextMouseEvent() {}
+#endif
+};
+
+class QTWOptStack
+{
+public:
+ QTWOptStack(QtUiTestWidgetsPrivate* obj,
+ QtUiTest::InputOption opt)
+ : d(obj), option(opt)
+ {
+ if (opt && (!(d->inputOptions & opt))) {
+ d->inputOptions |= opt;
+ } else {
+ d = 0;
+ }
+ }
+
+ ~QTWOptStack()
+ {
+ if (d) {
+ d->inputOptions &= ~option;
+ }
+ }
+
+ QtUiTestWidgetsPrivate *d;
+ QtUiTest::InputOption option;
+};
+
+QtUiTestWidgetsPrivate::QtUiTestWidgetsPrivate(QtUiTestWidgets* parent)
+ : q(parent),
+ inputOptions(QtUiTest::NoOptions)
+{
+ mousePreferred = true;
+ mousePreferred = qgetenv("QTUITEST_NO_MOUSE").isEmpty();
+
+ labelOrientation = QtUiTest::LabelLeft;
+ if (qApp && qApp->layoutDirection() == Qt::RightToLeft)
+ labelOrientation = QtUiTest::LabelRight;
+}
+
+QtUiTestWidgets::QtUiTestWidgets()
+ : QObject(),
+ d(new QtUiTestWidgetsPrivate(this))
+{
+ refreshPlugins();
+}
+
+QtUiTestWidgets::~QtUiTestWidgets()
+{
+ delete d;
+ d = 0;
+}
+
+/*!
+ Returns a static instance of QtUiTestWidgets.
+*/
+QtUiTestWidgets* QtUiTestWidgets::instance()
+{
+ static QtUiTestWidgets instance;
+ return &instance;
+}
+
+/*!
+ When an object is destroyed, deletes all test widgets pointing
+ to that object.
+*/
+void QtUiTestWidgetsPrivate::_q_objectDestroyed()
+{
+ QHash< QByteArray, QPointer<QObject> > toDestroy
+ = testWidgets.take(q->sender());
+
+ foreach (QPointer<QObject> tw, toDestroy.values()) {
+ if (tw) delete tw;
+ }
+}
+
+/*!
+ \internal
+ Destroy all test widgets and unregister all factories.
+ After calling this, refreshPlugins() must be called to be able to
+ construct testwidgets from factories.
+
+ For testing purposes only.
+*/
+void QtUiTestWidgets::clear()
+{
+ d->factories.clear();
+ d->factorySet.clear();
+
+ foreach (QObject *o, d->testWidgets.keys()) {
+ foreach (QPointer<QObject> tw, d->testWidgets[o].values()) {
+ if (tw && tw != o) delete tw;
+ }
+ }
+ d->testWidgets.clear();
+}
+
+/*!
+ Registers \a factory as a factory class for constructing test widgets.
+
+ It is not necessary to explicitly call this from QtUiTest widget plugins.
+ This function should only be called if a QtUiTest::WidgetFactory has been
+ created without using the standard plugin interface.
+*/
+void
+QtUiTestWidgets::registerFactory(QtUiTest::WidgetFactory* factory)
+{
+ if (!factory) return;
+
+ d->factorySet << factory;
+ foreach(QString k, factory->keys()) {
+ d->factories[k.toLatin1()].insert(factory);
+ }
+}
+
+/*!
+ Returns a human-readable error string describing the last error which
+ occurred while accessing a testwidget.
+
+ The error string is used to report directly to a tester any unexpected
+ errors. The string will typically be used as a test failure message.
+
+ \sa setErrorString()
+*/
+QString QtUiTestWidgets::errorString() const
+{ return d->errorString; }
+
+/*!
+ Sets the human-readable \a error string describing the last error which
+ occurred while accessing a testwidget.
+
+ \sa errorString()
+*/
+void QtUiTestWidgets::setErrorString(QString const& error)
+{
+ if (error == d->errorString) return;
+ d->errorString = error;
+}
+
+/*!
+ Returns a list of all QtUiTest widget interfaces implemented by \a o .
+*/
+QList<QByteArray> QtUiTestWidgetsPrivate::allImplementedInterfaces(QObject *o)
+{
+ // FIXME this function should not have to be explicitly implemented.
+ // Find some way to automatically handle all interfaces.
+ QList<QByteArray> ret;
+ if (qobject_cast<QtUiTest::Widget*>(o)) ret << "Widget";
+ if (qobject_cast<QtUiTest::ActivateWidget*>(o)) ret << "ActivateWidget";
+ if (qobject_cast<QtUiTest::LabelWidget*>(o)) ret << "LabelWidget";
+ if (qobject_cast<QtUiTest::CheckWidget*>(o)) ret << "CheckWidget";
+ if (qobject_cast<QtUiTest::CheckItemWidget*>(o)) ret << "CheckItemWidget";
+ if (qobject_cast<QtUiTest::TextWidget*>(o)) ret << "TextWidget";
+ if (qobject_cast<QtUiTest::ListWidget*>(o)) ret << "ListWidget";
+ if (qobject_cast<QtUiTest::InputWidget*>(o)) ret << "InputWidget";
+ if (qobject_cast<QtUiTest::SelectWidget*>(o)) ret << "SelectWidget";
+ if (qobject_cast<QtUiTest::IndexedWidget*>(o)) ret << "IndexedWidget";
+ return ret;
+}
+
+/*!
+ Returns a test widget wrapper for \a object implementing the given
+ \a interface. If a test widget implementing \a interface is already
+ wrapping \a object, that test widget will be returned. Otherwise,
+ a new test widget may be constructed using registered factories.
+
+ Returns 0 if the given \a interface is not implemented on \a object
+ or on any test widget which wraps \a object.
+
+ The returned object should not be deleted by the caller. QtUiTestWidgets
+ retains ownership of the returned test widget and deletes it when \a object
+ is destroyed.
+
+ \sa registerFactory()
+*/
+QObject* QtUiTestWidgets::testWidget(QObject* object, QByteArray const &interface)
+{
+ if (!object) return 0;
+
+ QMetaObject const *mo = object->metaObject();
+ QObject *ret = d->testWidgets.value( object ).value( interface );
+
+ bool watchingDestroyed = false;
+
+ if (!ret) {
+ QSet<QtUiTest::WidgetFactory*> usedFactories;
+ while (mo) {
+ foreach (QtUiTest::WidgetFactory *factory,
+ d->factories.value(mo->className()) - usedFactories) {
+
+ QObject *testWidget = factory->create(object);
+ usedFactories.insert(factory);
+ if (testWidget) {
+ bool isValuable = false;
+ foreach (QByteArray const& thisIface,
+ d->allImplementedInterfaces(testWidget)) {
+ QHash<QByteArray, QPointer<QObject> > &subhash
+ = d->testWidgets[object];
+ if (!subhash[thisIface]) {
+ isValuable = true;
+ subhash.insert( thisIface, testWidget );
+ watchingDestroyed = watchingDestroyed
+ || connect(object, SIGNAL(destroyed()),
+ this, SLOT(_q_objectDestroyed()));
+ }
+ }
+ if (!isValuable) {
+ delete testWidget;
+ } // if (!isValuable)
+ else {
+ QtUiTestRecorder::connectToAll(testWidget);
+ } // if (isValuable)
+ } // if (testWidget)
+ } // foreach factory
+ mo = mo->superClass();
+ }
+ ret = d->testWidgets.value( object ).value( interface );
+ }
+ return ret;
+}
+
+/*!
+ Returns a widget of \a type using factories.
+*/
+QObject* QtUiTestWidgets::findWidget(QtUiTest::WidgetType type)
+{
+ foreach (QtUiTest::WidgetFactory *factory, d->factorySet) {
+ if (QObject *ret = factory->find(type))
+ return ret;
+ }
+
+ return 0;
+}
+
+/*!
+ \internal
+ Load factories from all existing qtuitest_widgets plugins.
+*/
+void QtUiTestWidgets::refreshPlugins()
+{
+ /* First, handle static plugins. */
+ foreach (QObject *o, QPluginLoader::staticInstances()) {
+ registerFactory(qobject_cast<QtUiTest::WidgetFactory*>(o));
+ }
+
+ QSet<QString> pluginsToLoad;
+
+ QList<QDir> pluginDirs;
+ foreach (QByteArray const& split, qgetenv("QTUITEST_WIDGETS_PATH").split(':')) {
+ if (split.isEmpty()) continue;
+ QDir dir(split);
+ if (dir.exists()) pluginDirs << dir;
+ }
+
+ QString const pluginType("qtuitest_widgets");
+ QSet<QString> libPaths = QCoreApplication::libraryPaths().toSet();
+
+ foreach (QString const& libPath, libPaths) {
+ QDir dir(libPath + "/" + pluginType);
+ if (!dir.exists()) {
+ continue;
+ }
+ pluginDirs << dir;
+ }
+
+ foreach (QDir const& dir, pluginDirs) {
+ foreach (QString const& file, dir.entryList(QDir::Files|QDir::NoDotAndDotDot)) {
+ QString filename = dir.canonicalPath() + "/" + file;
+ if (!QLibrary::isLibrary(filename)) continue;
+ pluginsToLoad << filename;
+ }
+ }
+
+#ifdef Q_OS_SYMBIAN
+// This is a temporary hack for S60
+ pluginsToLoad << "qtwidgets.dll";
+#endif
+
+ QPluginLoader pluginLoader;
+ QSet<QString> lastPluginsToLoad;
+ QStringList errors;
+
+ // dumb dependency handling: keep trying to load plugins until we
+ // definitely can't progress.
+ while (lastPluginsToLoad != pluginsToLoad) {
+ lastPluginsToLoad = pluginsToLoad;
+ errors.clear();
+ foreach (QString const& plugin, pluginsToLoad) {
+ pluginLoader.setFileName(plugin);
+ // enable RTLD_GLOBAL, so plugins can access each other's symbols.
+ pluginLoader.setLoadHints(QLibrary::ExportExternalSymbolsHint);
+ pluginLoader.load();
+
+ QObject *instance = pluginLoader.instance();
+ QString error;
+ if (!instance)
+ error = "cannot resolve 'qt_plugin_instance': " + pluginLoader.errorString();
+
+ QtUiTest::WidgetFactory* fact = qobject_cast<QtUiTest::WidgetFactory*>(instance);
+ if (!fact) {
+ if (error.isEmpty()) error = pluginLoader.errorString();
+ QString formattedError;
+ QDebug(&formattedError)
+ << "QtUitest: failed to load qtuitest widgets plugin"
+ << "\n plugin" << plugin
+ << "\n instance" << instance
+ << "\n error" << error;
+ errors << formattedError;
+ } else {
+ pluginsToLoad -= plugin;
+ registerFactory(fact);
+ }
+ }
+ }
+
+ foreach (QString const& error, errors)
+ qWarning() << qPrintable(error);
+}
+
+/*!
+ Simulate a mouse press event at the global co-ordinates given by \a pos,
+ for the buttons in \a state. \a opt is applied to the simulated event.
+*/
+void QtUiTestWidgets::mousePress(QPoint const &pos, Qt::MouseButtons state,
+ QtUiTest::InputOption opt)
+{
+#ifdef QTUITEST_RACE_TEST
+ int delay;
+ if ((delay = qtUiTestInputDelay()) != -1) {
+ QtUiTestMouseEvent event = {QtUiTestPress, pos, state, opt};
+ d->pendingMouseEvents << event;
+ QTimer::singleShot(delay, this, SLOT(_q_postNextMouseEvent()));
+ return;
+ }
+#endif
+ QTWOptStack st(d, opt);
+ d->input.mousePress(pos, state);
+}
+
+/*!
+ Simulate a mouse release event at the global co-ordinates given by \a pos,
+ for the buttons in \a state. \a opt is applied to the simulated event.
+*/
+void QtUiTestWidgets::mouseRelease(QPoint const &pos, Qt::MouseButtons state,
+ QtUiTest::InputOption opt)
+{
+#ifdef QTUITEST_RACE_TEST
+ int delay;
+ if ((delay = qtUiTestInputDelay()) != -1) {
+ QtUiTestMouseEvent event = {QtUiTestRelease, pos, state, opt};
+ d->pendingMouseEvents << event;
+ QTimer::singleShot(delay, this, SLOT(_q_postNextMouseEvent()));
+ return;
+ }
+#endif
+ QTWOptStack st(d, opt);
+ d->input.mouseRelease(pos, state);
+}
+
+/*!
+ Simulate a mouse click event at the global co-ordinates given by \a pos,
+ for the buttons in \a state. \a opt is applied to the simulated event.
+*/
+void QtUiTestWidgets::mouseClick(QPoint const &pos, Qt::MouseButtons state,
+ QtUiTest::InputOption opt)
+{
+#ifdef QTUITEST_RACE_TEST
+ int delay;
+ if ((delay = qtUiTestInputDelay()) != -1) {
+ QtUiTestMouseEvent event = {QtUiTestClick, pos, state, opt};
+ d->pendingMouseEvents << event;
+ QTimer::singleShot(delay, this, SLOT(_q_postNextMouseEvent()));
+ return;
+ }
+#endif
+ QTWOptStack st(d, opt);
+ d->input.mouseClick(pos, state);
+}
+
+/*!
+ Simulate a key press event, using the given \a key and \a mod.
+ \a opt is applied to the simulated event.
+*/
+void QtUiTestWidgets::keyPress(Qt::Key key, Qt::KeyboardModifiers mod,
+ QtUiTest::InputOption opt)
+{
+#ifdef QTUITEST_RACE_TEST
+ int delay;
+ if ((delay = qtUiTestInputDelay()) != -1) {
+ QtUiTestKeyEvent event = {QtUiTestPress, key, mod, opt};
+ d->pendingKeyEvents << event;
+ QTimer::singleShot(delay, this, SLOT(_q_postNextKeyEvent()));
+ return;
+ }
+#endif
+ QTWOptStack st(d, opt);
+ d->input.keyPress(key, mod, opt & QtUiTest::KeyRepeat);
+}
+
+/*!
+ Simulate a key release event, using the given \a key and \a mod.
+ \a opt is applied to the simulated event.
+*/
+void QtUiTestWidgets::keyRelease(Qt::Key key, Qt::KeyboardModifiers mod,
+ QtUiTest::InputOption opt)
+{
+#ifdef QTUITEST_RACE_TEST
+ int delay;
+ if ((delay = qtUiTestInputDelay()) != -1) {
+ QtUiTestKeyEvent event = {QtUiTestRelease, key, mod, opt};
+ d->pendingKeyEvents << event;
+ QTimer::singleShot(delay, this, SLOT(_q_postNextKeyEvent()));
+ return;
+ }
+#endif
+ QTWOptStack st(d, opt);
+ d->input.keyRelease(key, mod);
+}
+
+/*!
+ Simulate a key click event, using the given \a key and \a mod.
+ \a opt is applied to the simulated event.
+*/
+void QtUiTestWidgets::keyClick(Qt::Key key, Qt::KeyboardModifiers mod,
+ QtUiTest::InputOption opt)
+{
+#ifdef QTUITEST_RACE_TEST
+ int delay;
+ if ((delay = qtUiTestInputDelay()) != -1) {
+ QtUiTestKeyEvent event = {QtUiTestClick, key, mod, opt};
+ d->pendingKeyEvents << event;
+ QTimer::singleShot(delay, this, SLOT(_q_postNextKeyEvent()));
+ return;
+ }
+#endif
+ QTWOptStack st(d, opt);
+ d->input.keyClick(key, mod);
+}
+
+#ifdef QTUITEST_RACE_TEST
+void QtUiTestWidgetsPrivate::_q_postNextMouseEvent()
+{
+ QtUiTestMouseEvent const event = pendingMouseEvents.takeAt(0);
+ QTWOptStack st(this, event.opt);
+ if (event.type == QtUiTestPress)
+ input.mousePress(event.pos, event.state);
+ else if (event.type == QtUiTestRelease)
+ input.mouseRelease(event.pos, event.state);
+ else if (event.type == QtUiTestClick)
+ input.mouseClick(event.pos, event.state);
+}
+
+void QtUiTestWidgetsPrivate::_q_postNextKeyEvent()
+{
+ QtUiTestKeyEvent const event = pendingKeyEvents.takeAt(0);
+ QTWOptStack st(this, event.opt);
+ if (event.type == QtUiTestPress)
+ input.keyPress(event.key, event.mod);
+ else if (event.type == QtUiTestRelease)
+ input.keyRelease(event.key, event.mod);
+ else if (event.type == QtUiTestClick)
+ input.keyClick(event.key, event.mod);
+}
+#endif
+
+/*!
+ Set or clear the specified \a option for subsequent simulated input
+ events. The option is set if \a on is true, otherwise it is cleared.
+*/
+void QtUiTestWidgets::setInputOption(QtUiTest::InputOption option, bool on)
+{
+ if (on)
+ d->inputOptions |= option;
+ else
+ d->inputOptions &= (~option);
+ qLog(QtUitest) << "set input options to" << d->inputOptions;
+}
+
+/*!
+ Returns true if \a option is currently set.
+*/
+bool QtUiTestWidgets::testInputOption(QtUiTest::InputOption option) const
+{
+ return (option == d->inputOptions)
+ || (option & d->inputOptions);
+}
+
+/*!
+ Returns true if the system will use mouse events in preference to key
+ events for widget and item selection.
+*/
+bool QtUiTestWidgets::mousePreferred() const
+{
+ return d->mousePreferred;
+}
+
+/*!
+ Set system to prefer mouse/touchscreen or keyboard for widget and item
+ selection. If \a useMouse is true then the mouse will be used, if false
+ then the keyboard will be used.
+*/
+void QtUiTestWidgets::setMousePreferred(bool useMouse)
+{
+ d->mousePreferred = useMouse;
+}
+
+QtUiTest::LabelOrientation QtUiTestWidgets::labelOrientation() const
+{
+ return d->labelOrientation;
+}
+
+void QtUiTestWidgets::setLabelOrientation(QtUiTest::LabelOrientation orientation)
+{
+ d->labelOrientation = orientation;
+}
+#include "moc_qtuitestwidgets_p.cpp"
+
diff --git a/old/libqtuitest/qtuitestwidgets_p.h b/old/libqtuitest/qtuitestwidgets_p.h
new file mode 100644
index 0000000..784b760
--- /dev/null
+++ b/old/libqtuitest/qtuitestwidgets_p.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QTUITESTWIDGETS_P_H
+#define QTUITESTWIDGETS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtUiTest API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QObject>
+#include <QMetaType>
+#include <QHash>
+#include <Qt>
+#include <qtuitestnamespace.h>
+
+class QtUiTestWidgetsPrivate;
+class QPoint;
+
+class QTUITEST_EXPORT QtUiTestWidgets : public QObject
+{
+ Q_OBJECT
+
+public:
+ static QtUiTestWidgets* instance();
+
+ virtual ~QtUiTestWidgets();
+
+ void setInputOption(QtUiTest::InputOption,bool = true);
+ bool testInputOption(QtUiTest::InputOption) const;
+
+ bool mousePreferred() const;
+ void setMousePreferred(bool);
+
+ QtUiTest::LabelOrientation labelOrientation() const;
+ void setLabelOrientation(QtUiTest::LabelOrientation);
+
+ QString errorString() const;
+ void setErrorString(QString const&);
+
+ void registerFactory(QtUiTest::WidgetFactory*);
+
+ void mousePress (QPoint const&,Qt::MouseButtons = Qt::LeftButton,
+ QtUiTest::InputOption = QtUiTest::NoOptions);
+ void mouseRelease(QPoint const&,Qt::MouseButtons = Qt::LeftButton,
+ QtUiTest::InputOption = QtUiTest::NoOptions);
+ void mouseClick (QPoint const&,Qt::MouseButtons = Qt::LeftButton,
+ QtUiTest::InputOption = QtUiTest::NoOptions);
+
+ void keyPress (Qt::Key,Qt::KeyboardModifiers = 0,QtUiTest::InputOption = QtUiTest::NoOptions);
+ void keyRelease(Qt::Key,Qt::KeyboardModifiers = 0,QtUiTest::InputOption = QtUiTest::NoOptions);
+ void keyClick (Qt::Key,Qt::KeyboardModifiers = 0,QtUiTest::InputOption = QtUiTest::NoOptions);
+
+private:
+ Q_DISABLE_COPY(QtUiTestWidgets)
+
+ friend class QtUiTestWidgetsPrivate;
+
+ QtUiTestWidgetsPrivate* d;
+
+ QtUiTestWidgets();
+ QObject* findWidget(QtUiTest::WidgetType);
+ QObject* testWidget(QObject*,QByteArray const&);
+
+ void refreshPlugins();
+ void clear();
+
+ Q_PRIVATE_SLOT(d, void _q_objectDestroyed())
+ Q_PRIVATE_SLOT(d, void _q_postNextKeyEvent())
+ Q_PRIVATE_SLOT(d, void _q_postNextMouseEvent())
+
+ friend QObject* QtUiTest::testWidget(QObject*,const char*);
+ friend QObject* QtUiTest::findWidget(QtUiTest::WidgetType);
+};
+
+#endif
+
diff --git a/old/libqtuitest/recordevent_p.h b/old/libqtuitest/recordevent_p.h
new file mode 100644
index 0000000..f8ad42a
--- /dev/null
+++ b/old/libqtuitest/recordevent_p.h
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef RECORDEVENT_P_H
+#define RECORDEVENT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtUiTest API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QString>
+#include <QVariant>
+
+struct RecordEvent {
+ enum Type {
+ GotFocus,
+ Entered,
+ Selected,
+ Activated,
+ CheckStateChanged,
+ TitleChanged,
+ MessageBoxShown
+ };
+ Type type;
+ QString widget;
+ QString focusWidget;
+ QVariant data;
+};
+
+#define Q_DECLARE_METATYPE_STREAM(TYPE) \
+ QT_BEGIN_NAMESPACE \
+ template <> \
+ struct QMetaTypeId< TYPE > \
+ { \
+ enum { Defined = 1 }; \
+ static int qt_metatype_id() \
+ { \
+ static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
+ if (!metatype_id) { \
+ metatype_id = qRegisterMetaType< TYPE >(#TYPE, \
+ reinterpret_cast< TYPE *>(quintptr(-1))); \
+ qRegisterMetaTypeStreamOperators< TYPE >(#TYPE); \
+ } \
+ return metatype_id; \
+ } \
+ }; \
+ QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE_STREAM(RecordEvent);
+Q_DECLARE_METATYPE_STREAM(QList<RecordEvent>);
+
+inline bool operator==(RecordEvent const& a, RecordEvent const& b)
+{ return a.type == b.type && a.widget == b.widget && a.focusWidget == b.focusWidget && a.data == b.data; }
+
+inline bool operator!=(RecordEvent const& a, RecordEvent const& b)
+{ return !(a == b); }
+
+inline QDataStream &operator<<(QDataStream &out, const RecordEvent &re)
+{ return (out << static_cast<int>(re.type) << re.widget << re.focusWidget << re.data); }
+
+inline QDataStream &operator>>(QDataStream &in, RecordEvent &re)
+{
+ int reType;
+ QDataStream &ret = (in >> reType >> re.widget >> re.focusWidget >> re.data);
+ re.type = static_cast<RecordEvent::Type>(reType);
+ return ret;
+}
+
+inline QDataStream &operator<<(QDataStream &out, const QList<RecordEvent> &l)
+{
+ out << l.count();
+ foreach (RecordEvent re, l) {
+ out << re;
+ }
+ return out;
+}
+inline QDataStream &operator>>(QDataStream &in, QList<RecordEvent> &l)
+{
+ int count = 0;
+ in >> count;
+ RecordEvent re;
+ for (int i = 0; i < count; ++i) {
+ in >> re;
+ l << re;
+ }
+ return in;
+}
+
+#endif
+
diff --git a/old/libqtuitest/testwidget.cpp b/old/libqtuitest/testwidget.cpp
new file mode 100644
index 0000000..15f5043
--- /dev/null
+++ b/old/libqtuitest/testwidget.cpp
@@ -0,0 +1,298 @@
+/****************************************************************************
+**
+** 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 "testwidget.h"
+
+#include <QAbstractScrollArea>
+#include <QApplication>
+#include <QScrollBar>
+#include <QVariant>
+#include <QWidget>
+#include <QGraphicsProxyWidget>
+#include <QInputContext>
+
+namespace QtUiTest {
+
+TestWidget::TestWidget(QObject* _q)
+ : q(qobject_cast<QWidget*>(_q))
+{ q->installEventFilter(this); }
+
+bool TestWidget::eventFilter(QObject*,QEvent* e)
+{
+ if (e->type() == QEvent::FocusIn) {
+ emit gotFocus();
+ }
+ return false;
+}
+
+const QRect& TestWidget::geometry() const
+{ return q->geometry(); }
+
+QRect TestWidget::rect() const
+{ return q->rect(); }
+
+bool TestWidget::isVisible() const
+{ return q->isVisible(); }
+
+QRegion TestWidget::visibleRegion() const
+{ return q->visibleRegion(); }
+
+bool TestWidget::ensureVisibleRegion(const QRegion& region)
+{
+ if (region.intersected(visibleRegion()) == region) return true;
+
+ if (!QtUiTest::mousePreferred()) {
+ /*
+ FIXME this is technically not correct, since we're assuming
+ that giving the widget keyboard focus makes the entire widget
+ visible. A low priority fix until we come across a case where
+ this matters.
+ */
+ return setFocus();
+ }
+
+ /* Try to find a scroll area which contains this widget, then scroll. */
+
+ QAbstractScrollArea *sa = 0;
+ QWidget *parent = q->parentWidget();
+ while (parent && !sa) {
+ sa = qobject_cast<QAbstractScrollArea*>(parent);
+ parent = parent->parentWidget();
+ }
+
+ if (!sa) return false;
+
+ /* Figure out the points to click for scrolling in each direction */
+ QScrollBar *vbar = sa->verticalScrollBar();
+ QScrollBar *hbar = sa->horizontalScrollBar();
+ QPoint up = vbar->mapToGlobal(QPoint(vbar->width()/2,5));
+ QPoint down = vbar->mapToGlobal(QPoint(vbar->width()/2,vbar->height()-5));
+ QPoint left = hbar->mapToGlobal(QPoint(5, hbar->height()/2));
+ QPoint right = hbar->mapToGlobal(QPoint(hbar->width()-5,hbar->height()/2));
+
+ QRect brect_origin = region.boundingRect();
+ QRect brect = brect_origin;
+ brect.moveTopLeft(q->mapTo(sa, brect.topLeft()));
+
+ static const int MAX_CLICKS = 200;
+ int clicks = 0;
+
+ /* Handle up... */
+ while (brect.top() < 0) {
+ if (!vbar->isVisible()) return false;
+ QtUiTest::mouseClick(up);
+ QtUiTest::waitForSignal(vbar, SIGNAL(valueChanged(int)));
+ brect = brect_origin;
+ brect.moveTopLeft(q->mapTo(sa, brect.topLeft()));
+ if (++clicks > MAX_CLICKS) return false;
+ }
+ /* Handle down... */
+ while (brect.bottom() > sa->height()) {
+ if (!vbar->isVisible()) return false;
+ QtUiTest::mouseClick(down);
+ QtUiTest::waitForSignal(vbar, SIGNAL(valueChanged(int)));
+ brect = brect_origin;
+ brect.moveTopLeft(q->mapTo(sa, brect.topLeft()));
+ if (++clicks > MAX_CLICKS) return false;
+ }
+ /* Handle left... */
+ while (brect.left() < 0) {
+ if (!hbar->isVisible()) return false;
+ QtUiTest::mouseClick(left);
+ QtUiTest::waitForSignal(hbar, SIGNAL(valueChanged(int)));
+ brect = brect_origin;
+ brect.moveTopLeft(q->mapTo(sa, brect.topLeft()));
+ if (++clicks > MAX_CLICKS) return false;
+ }
+ /* Handle right... */
+ while (brect.right() > sa->width()) {
+ if (!hbar->isVisible()) return false;
+ QtUiTest::mouseClick(right);
+ QtUiTest::waitForSignal(hbar, SIGNAL(valueChanged(int)));
+ brect = brect_origin;
+ brect.moveTopLeft(q->mapTo(sa, brect.topLeft()));
+ if (++clicks > MAX_CLICKS) return false;
+ }
+ return true;
+}
+
+const QObjectList &TestWidget::children() const
+{ return q->children(); }
+
+QObject* TestWidget::parent() const
+{ return q->graphicsProxyWidget() ? q->graphicsProxyWidget() : q->parent(); }
+
+QString TestWidget::windowTitle() const
+{ return q->windowTitle(); }
+
+QPoint TestWidget::mapToGlobal(QPoint const &local) const
+{
+ QGraphicsProxyWidget *pw;
+ if ( (pw = q->graphicsProxyWidget()) ) {
+ QtUiTest::Widget *w = qtuitest_cast<QtUiTest::Widget*>(pw);
+ if (w) {
+ return w->mapToGlobal(local);
+ }
+ }
+ return q->mapToGlobal(local);
+}
+
+QPoint TestWidget::mapFromGlobal(QPoint const &global) const
+{
+ return q->mapFromGlobal(global);
+}
+
+bool TestWidget::hasFocus() const
+{
+ return q->hasFocus();
+}
+
+Qt::WindowFlags TestWidget::windowFlags() const
+{
+ return q->windowFlags();
+}
+
+bool TestWidget::canEnter(QVariant const&) const
+{
+ return false;
+}
+
+bool TestWidget::enter(QVariant const& item, bool noCommit)
+{
+ Q_UNUSED(noCommit);
+ if (!hasFocus() && !setFocus()) return false;
+
+ using namespace QtUiTest;
+
+ /* If there's text currently in the field then erase it first */
+ if (QtUiTest::mousePreferred()) {
+ return false;
+ }
+
+ foreach (QChar const& c, item.toString()) {
+ keyClick( asciiToKey(c.toLatin1()), asciiToModifiers(c.toLatin1()) );
+ }
+ return true;
+}
+
+void TestWidget::focusOutEvent()
+{
+}
+
+#ifdef Q_WS_QWS
+bool TestWidget::hasEditFocus() const
+{ return q->hasEditFocus(); }
+#endif
+
+bool TestWidget::setEditFocus(bool enable)
+{
+ if (hasEditFocus() == enable) return true;
+
+ if (!hasFocus()) {
+ if (!setFocus()) return false;
+ }
+
+ // It is possible that giving us regular focus also gave us edit focus.
+ if (hasEditFocus() == enable) return true;
+
+#ifdef Q_WS_QWS
+ if (!QtUiTest::keyClick(q, QtUiTest::Key_Activate)) return false;
+ if (hasEditFocus() != enable && !QtUiTest::waitForEvent(q, enable ? QEvent::EnterEditFocus : QEvent::LeaveEditFocus)) {
+ return false;
+ }
+ return (hasEditFocus() == enable);
+#else
+ return true;
+#endif
+}
+
+QObject* TestWidget::focusProxy() const
+{
+ return q->focusProxy();
+}
+
+Qt::FocusPolicy TestWidget::focusPolicy () const
+{
+ return q->focusPolicy();
+}
+
+bool TestWidget::canWrap(QObject *o)
+{ return qobject_cast<QWidget*>(o); }
+
+QString TestWidget::printable(QString const& str)
+{
+ QString ret(str);
+
+ ret.replace(QChar::Nbsp, " ");
+ ret.remove(QChar(0x200E));
+ ret.remove(QChar(0x200F));
+ ret.remove(QChar(0x00AD));
+
+ return ret;
+}
+
+bool TestWidget::grabPixmap(QPixmap &pixmap) const
+{
+ pixmap = QPixmap::grabWidget( q );
+ return true;
+}
+
+QString TestWidget::labelText(const QString& text)
+{
+ return text.trimmed().replace(QRegExp("&(.)"), "\\1");
+}
+
+QVariant TestWidget::getProperty(const QString& name) const
+{
+ return q->property(name.toAscii());
+}
+
+bool TestWidget::setProperty(const QString& name, const QVariant& value)
+{
+ return q->setProperty(name.toAscii(), value);
+}
+
+QObject* TestWidget::inputProxy() const
+{
+ return q->inputContext();
+}
+
+} \ No newline at end of file
diff --git a/old/libqtuitest/testwidget.h b/old/libqtuitest/testwidget.h
new file mode 100644
index 0000000..6fb0dc5
--- /dev/null
+++ b/old/libqtuitest/testwidget.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef TESTWIDGET_H
+#define TESTWIDGET_H
+
+#include <QObject>
+#include <qtuitestwidgetinterface.h>
+
+class QWidget;
+
+namespace QtUiTest {
+
+class QTUITEST_EXPORT TestWidget : public QObject, public QtUiTest::Widget,
+ public QtUiTest::InputWidget
+{
+ Q_OBJECT
+ Q_INTERFACES(QtUiTest::Widget QtUiTest::InputWidget)
+
+public:
+ TestWidget(QObject*);
+
+ virtual const QRect& geometry() const;
+ virtual QRect rect() const;
+ virtual bool isVisible() const;
+ virtual QRegion visibleRegion() const;
+ virtual const QObjectList &children() const;
+ virtual QObject* parent() const;
+ virtual QString windowTitle() const;
+ virtual QPoint mapToGlobal(QPoint const&) const;
+ virtual QPoint mapFromGlobal(QPoint const&) const;
+ virtual bool hasFocus() const;
+ virtual Qt::WindowFlags windowFlags() const;
+ virtual bool ensureVisibleRegion(QRegion const&);
+ virtual bool canEnter(QVariant const&) const;
+ virtual bool enter(QVariant const&,bool);
+ virtual void focusOutEvent();
+
+#ifdef Q_WS_QWS
+ virtual bool hasEditFocus() const;
+#endif
+ virtual bool setEditFocus(bool);
+ virtual QObject* focusProxy() const;
+ virtual Qt::FocusPolicy focusPolicy () const;
+ virtual bool grabPixmap(QPixmap &pixmap) const;
+
+ static bool canWrap(QObject*);
+ static QString printable(QString const&);
+ static QString labelText(QString const&);
+ virtual QVariant getProperty(const QString&) const;
+ virtual bool setProperty(const QString&, const QVariant&);
+ virtual QObject *inputProxy() const;
+
+signals:
+ void gotFocus();
+
+protected:
+ bool eventFilter(QObject*,QEvent*);
+
+private:
+ QWidget *q;
+};
+
+}
+
+#endif
+