diff options
Diffstat (limited to 'old/libqtuitest/qtuitestrecorder.cpp')
-rw-r--r-- | old/libqtuitest/qtuitestrecorder.cpp | 367 |
1 files changed, 367 insertions, 0 deletions
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" + |