diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2009-09-21 07:09:33 (GMT) |
---|---|---|
committer | Aaron Kennedy <aaron.kennedy@nokia.com> | 2009-09-21 07:09:33 (GMT) |
commit | a14765de5b1bb26b4cbc6ebbdee71145e54650a8 (patch) | |
tree | 5ce3cd3acb9448a3d86eef96ac1f4129ce3b8936 /tools/qmlviewer | |
parent | 26bd84ec3625c825c04228b76dd37cd5e75fb36b (diff) | |
download | Qt-a14765de5b1bb26b4cbc6ebbdee71145e54650a8.zip Qt-a14765de5b1bb26b4cbc6ebbdee71145e54650a8.tar.gz Qt-a14765de5b1bb26b4cbc6ebbdee71145e54650a8.tar.bz2 |
Basic implementation of visual "test scripts"
Test scripts allow the qmlviewer to record a set of input actions, and the resulting visual frames.
Diffstat (limited to 'tools/qmlviewer')
-rw-r--r-- | tools/qmlviewer/main.cpp | 87 | ||||
-rw-r--r-- | tools/qmlviewer/qfxtester.cpp | 306 | ||||
-rw-r--r-- | tools/qmlviewer/qfxtester.h | 230 | ||||
-rw-r--r-- | tools/qmlviewer/qmlviewer.cpp | 28 | ||||
-rw-r--r-- | tools/qmlviewer/qmlviewer.h | 17 | ||||
-rw-r--r-- | tools/qmlviewer/qmlviewer.pro | 8 |
6 files changed, 663 insertions, 13 deletions
diff --git a/tools/qmlviewer/main.cpp b/tools/qmlviewer/main.cpp index c5bf868..7df1179 100644 --- a/tools/qmlviewer/main.cpp +++ b/tools/qmlviewer/main.cpp @@ -43,11 +43,28 @@ void usage() qWarning(" -translation <translationfile> ........... set the language to run in"); qWarning(" -L <directory> ........................... prepend to the library search path"); qWarning(" -opengl .................................. use a QGLWidget for the viewport"); + qWarning(" -script <path> ........................... set the script to use"); + qWarning(" -scriptopts <options>|help ............... set the script options to use"); + qWarning(" "); qWarning(" Press F1 for interactive help"); exit(1); } +void scriptOptsUsage() +{ + qWarning("Usage: qmlviewer -scriptopts <option>[,<option>...] ..."); + qWarning(" options:"); + qWarning(" record ................................... record a new script"); + qWarning(" play ..................................... playback an existing script"); + qWarning(" testimages ............................... compare images on playback"); + qWarning(" exitoncomplete ........................... cleanly exit the viewer on script completion"); + qWarning(" exitonfailure ............................ immediately exit the viewer on script failure"); + qWarning(" "); + qWarning(" One of record or play must be specified."); + exit(1); +} + int main(int argc, char ** argv) { //### default to using raster graphics backend for now @@ -78,6 +95,9 @@ int main(int argc, char ** argv) QStringList recordargs; QStringList libraries; QString skin; + QString script; + QString scriptopts; + bool runScript = false; bool devkeys = false; int cache = 0; QString translationFile; @@ -85,26 +105,34 @@ int main(int argc, char ** argv) bool fullScreen = false; for (int i = 1; i < argc; ++i) { + bool lastArg = (i == argc - 1); QString arg = argv[i]; if (arg == "-frameless") { frameless = true; } else if (arg == "-fullscreen") { fullScreen = true; } else if (arg == "-skin") { + if (lastArg) usage(); skin = QString(argv[++i]); } else if (arg == "-resizeview") { resizeview = true; } else if (arg == "-netcache") { + if (lastArg) usage(); cache = QString(argv[++i]).toInt(); } else if (arg == "-recordrate") { + if (lastArg) usage(); fps = QString(argv[++i]).toDouble(); } else if (arg == "-recordfile") { + if (lastArg) usage(); recordfile = QString(argv[++i]); } else if (arg == "-record") { + if (lastArg) usage(); recordargs << QString(argv[++i]); } else if (arg == "-recorddither") { + if (lastArg) usage(); dither = QString(argv[++i]); } else if (arg == "-autorecord") { + if (lastArg) usage(); QString range = QString(argv[++i]); int dash = range.indexOf('-'); if (dash > 0) @@ -116,14 +144,27 @@ int main(int argc, char ** argv) fprintf(stderr, "Qt Declarative UI Viewer version %s\n", QT_VERSION_STR); return 0; } else if (arg == "-translation") { - if(i + 1 >= argc) - usage(); - translationFile = argv[i + 1]; - ++i; + if (lastArg) usage(); + translationFile = argv[++i]; } else if (arg == "-opengl") { useGL = true; } else if (arg == "-L") { + if (lastArg) usage(); libraries << QString(argv[++i]); + } else if (arg == "-script") { + if (lastArg) usage(); + script = QString(argv[++i]); + } else if (arg == "-scriptopts") { + if (lastArg) usage(); + scriptopts = QString(argv[++i]); + } else if (arg == "-savescript") { + if (lastArg) usage(); + script = QString(argv[++i]); + runScript = false; + } else if (arg == "-playscript") { + if (lastArg) usage(); + script = QString(argv[++i]); + runScript = true; } else if (arg[0] != '-') { fileName = arg; } else if (1 || arg == "-help") { @@ -138,6 +179,44 @@ int main(int argc, char ** argv) } QmlViewer viewer(0, frameless ? Qt::FramelessWindowHint : Qt::Widget); + if (!scriptopts.isEmpty()) { + + QStringList options = + scriptopts.split(QLatin1Char(','), QString::SkipEmptyParts); + + QmlViewer::ScriptOptions scriptOptions = 0; + for (int i = 0; i < options.count(); ++i) { + const QString &option = options.at(i); + if (option == QLatin1String("help")) { + scriptOptsUsage(); + } else if (option == QLatin1String("play")) { + if (scriptOptions & QmlViewer::Record) scriptOptsUsage(); + scriptOptions |= QmlViewer::Play; + } else if (option == QLatin1String("record")) { + if (scriptOptions & QmlViewer::Play) scriptOptsUsage(); + scriptOptions |= QmlViewer::Record; + } else if (option == QLatin1String("testimages")) { + scriptOptions |= QmlViewer::TestImages; + } else if (option == QLatin1String("exitoncomplete")) { + scriptOptions |= QmlViewer::ExitOnComplete; + } else if (option == QLatin1String("exitonfailure")) { + scriptOptions |= QmlViewer::ExitOnFailure; + } else { + scriptOptsUsage(); + } + } + + if (script.isEmpty()) + usage(); + + if (!(scriptOptions & QmlViewer::Record) && !(scriptOptions & QmlViewer::Play)) + scriptOptsUsage(); + viewer.setScriptOptions(scriptOptions); + viewer.setScript(script); + } else if (!script.isEmpty()) { + usage(); + } + viewer.setUseGL(useGL); foreach (QString lib, libraries) viewer.addLibraryPath(lib); diff --git a/tools/qmlviewer/qfxtester.cpp b/tools/qmlviewer/qfxtester.cpp new file mode 100644 index 0000000..3732aaf --- /dev/null +++ b/tools/qmlviewer/qfxtester.cpp @@ -0,0 +1,306 @@ +/**************************************************************************** +** +** Copyright (C) 1992-$THISYEAR$ $TROLLTECH$. All rights reserved. +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include <qfxtester.h> +#include <QDebug> +#include <QApplication> +#include <QFxView> +#include <QFile> +#include <QmlComponent> +#include <QCryptographicHash> +#include <private/qabstractanimation_p.h> +#include <private/qfxitem_p.h> + +QT_BEGIN_NAMESPACE + +QML_DEFINE_TYPE(Qt.VisualTest, 4, 6, (QT_VERSION&0x00ff00)>>8, VisualTest, QFxVisualTest); +QML_DEFINE_TYPE(Qt.VisualTest, 4, 6, (QT_VERSION&0x00ff00)>>8, Frame, QFxVisualTestFrame); +QML_DEFINE_TYPE(Qt.VisualTest, 4, 6, (QT_VERSION&0x00ff00)>>8, Mouse, QFxVisualTestMouse); +QML_DEFINE_TYPE(Qt.VisualTest, 4, 6, (QT_VERSION&0x00ff00)>>8, Key, QFxVisualTestKey); + +QFxTester::QFxTester(const QString &script, QmlViewer::ScriptOptions opts, + QFxView *parent) +: QAbstractAnimation(parent), m_view(parent), filterEvents(true), options(opts), + testscript(0), hasFailed(false) +{ + parent->viewport()->installEventFilter(this); + parent->installEventFilter(this); + QUnifiedTimer::instance()->setConsistentTiming(true); + if (options & QmlViewer::Play) + this->run(script); + start(); +} + +int QFxTester::duration() const +{ + return -1; +} + +void QFxTester::addMouseEvent(Destination dest, QMouseEvent *me) +{ + MouseEvent e(me); + e.destination = dest; + m_mouseEvents << e; +} + +void QFxTester::addKeyEvent(Destination dest, QKeyEvent *ke) +{ + KeyEvent e(ke); + e.destination = dest; + m_keyEvents << e; +} + +bool QFxTester::eventFilter(QObject *o, QEvent *e) +{ + if (!filterEvents) + return false; + + Destination destination; + if (o == m_view) { + destination = View; + } else if (o == m_view->viewport()) { + destination = ViewPort; + } else { + return false; + } + + switch (e->type()) { + case QEvent::KeyPress: + case QEvent::KeyRelease: + addKeyEvent(destination, (QKeyEvent *)e); + return true; + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: + case QEvent::MouseButtonDblClick: + addMouseEvent(destination, (QMouseEvent *)e); + return true; + default: + break; + } + return false; +} + +void QFxTester::executefailure() +{ + hasFailed = true; + + if (options & QmlViewer::ExitOnFailure) + exit(-1); +} + +void QFxTester::imagefailure() +{ + hasFailed = true; + + if (options & QmlViewer::ExitOnFailure) + exit(-1); +} + +void QFxTester::complete() +{ + if (options & QmlViewer::ExitOnComplete) + QApplication::exit(hasFailed?-1:0); +} + +void QFxTester::run(const QString &name) +{ + QmlComponent c(m_view->engine(), name + QLatin1String(".qml")); + + testscript = qobject_cast<QFxVisualTest *>(c.create()); + if (testscript) testscript->setParent(this); + testscriptidx = 0; +} + +void QFxTester::save(const QString &name) +{ + QFile file(name + QLatin1String(".qml")); + file.open(QIODevice::WriteOnly); + QTextStream ts(&file); + + ts << "import Qt.VisualTest 4.6\n\n"; + ts << "VisualTest {\n"; + + int imgCount = 0; + for (int ii = 0; ii < m_savedFrameEvents.count(); ++ii) { + const FrameEvent &fe = m_savedFrameEvents.at(ii); + ts << " Frame {\n"; + ts << " msec: " << fe.msec << "\n"; + if (!fe.hash.isEmpty()) { + ts << " hash: \"" << fe.hash.toHex() << "\"\n"; + } else if (!fe.image.isNull()) { + QString filename = name + "." + QString::number(imgCount++) + ".png"; + fe.image.save(filename); + ts << " image: \"" << filename << "\"\n"; + } + ts << " }\n"; + + while (!m_savedMouseEvents.isEmpty() && + m_savedMouseEvents.first().msec == fe.msec) { + MouseEvent me = m_savedMouseEvents.takeFirst(); + + ts << " Mouse {\n"; + ts << " type: " << me.type << "\n"; + ts << " button: " << me.button << "\n"; + ts << " buttons: " << me.buttons << "\n"; + ts << " x: " << me.pos.x() << "; y: " << me.pos.y() << "\n"; + ts << " modifiers: " << me.modifiers << "\n"; + if (me.destination == ViewPort) + ts << " sendToViewport: true\n"; + ts << " }\n"; + } + + while (!m_savedKeyEvents.isEmpty() && + m_savedKeyEvents.first().msec == fe.msec) { + KeyEvent ke = m_savedKeyEvents.takeFirst(); + + ts << " Key {\n"; + ts << " type: " << ke.type << "\n"; + ts << " key: " << ke.key << "\n"; + ts << " modifiers: " << ke.modifiers << "\n"; + ts << " text: \"" << ke.text.toUtf8().toHex() << "\"\n"; + ts << " autorep: " << (ke.autorep?"true":"false") << "\n"; + ts << " count: " << ke.count << "\n"; + if (ke.destination == ViewPort) + ts << " sendToViewport: true\n"; + ts << " }\n"; + } + } + m_savedFrameEvents.clear(); + + ts << "}\n"; + file.close(); +} + +void QFxTester::updateCurrentTime(int msec) +{ + QFxItemPrivate::setConsistentTime(msec); + + QImage img(m_view->width(), m_view->height(), QImage::Format_RGB32); + + QPainter p(&img); + m_view->render(&p); + + FrameEvent fe; + fe.msec = msec; + if (msec == 0) { + // Skip first frame + } else if (0 == (m_savedFrameEvents.count() % 60)) { + fe.image = img; + } else { + QCryptographicHash hash(QCryptographicHash::Md5); + hash.addData((const char *)img.bits(), img.bytesPerLine() * img.height()); + fe.hash = hash.result(); + } + m_savedFrameEvents.append(fe); + + // Deliver mouse events + filterEvents = false; + + if (!testscript) { + for (int ii = 0; ii < m_mouseEvents.count(); ++ii) { + MouseEvent &me = m_mouseEvents[ii]; + me.msec = msec; + QMouseEvent event(me.type, me.pos, me.button, me.buttons, me.modifiers); + + if (me.destination == View) { + QCoreApplication::sendEvent(m_view, &event); + } else { + QCoreApplication::sendEvent(m_view->viewport(), &event); + } + } + + for (int ii = 0; ii < m_keyEvents.count(); ++ii) { + KeyEvent &ke = m_keyEvents[ii]; + ke.msec = msec; + QKeyEvent event(ke.type, ke.key, ke.modifiers, ke.text, ke.autorep, ke.count); + + if (ke.destination == View) { + QCoreApplication::sendEvent(m_view, &event); + } else { + QCoreApplication::sendEvent(m_view->viewport(), &event); + } + } + m_savedMouseEvents.append(m_mouseEvents); + m_savedKeyEvents.append(m_keyEvents); + } + + m_mouseEvents.clear(); + m_keyEvents.clear(); + + // Advance test script + static int imgCount = 0; + while (testscript && testscript->count() > testscriptidx) { + + QObject *event = testscript->event(testscriptidx); + + if (QFxVisualTestFrame *frame = qobject_cast<QFxVisualTestFrame *>(event)) { + if (frame->msec() < msec) { + if (options & QmlViewer::TestImages) { + qWarning() << "QFxTester: Extra frame. Seen:" + << msec << "Expected:" << frame->msec(); + imagefailure(); + } + } else if (frame->msec() == msec) { + if (frame->hash().toUtf8() != fe.hash.toHex()) { + if (options & QmlViewer::TestImages) { + qWarning() << "QFxTester: Mismatched frame hash. Seen:" + << fe.hash.toHex() << "Expected:" + << frame->hash().toUtf8(); + imagefailure(); + } + } + } else if (frame->msec() > msec) { + break; + } + + if (options & QmlViewer::TestImages && !frame->image().isEmpty()) { + QImage goodImage(frame->image()); + if (goodImage != img) { + QString reject(frame->image() + ".reject.png"); + qWarning() << "QFxTester: Image mismatch. Reject saved to:" + << reject; + img.save(reject); + imagefailure(); + } + } + } else if (QFxVisualTestMouse *mouse = qobject_cast<QFxVisualTestMouse *>(event)) { + QPoint pos(mouse->x(), mouse->y()); + QPoint globalPos = m_view->mapToGlobal(QPoint(0, 0)) + pos; + QMouseEvent event((QEvent::Type)mouse->type(), pos, globalPos, (Qt::MouseButton)mouse->button(), (Qt::MouseButtons)mouse->buttons(), (Qt::KeyboardModifiers)mouse->modifiers()); + + if (!mouse->sendToViewport()) { + QCoreApplication::sendEvent(m_view, &event); + } else { + QCoreApplication::sendEvent(m_view->viewport(), &event); + } + } else if (QFxVisualTestKey *key = qobject_cast<QFxVisualTestKey *>(event)) { + + QKeyEvent event((QEvent::Type)key->type(), key->key(), (Qt::KeyboardModifiers)key->modifiers(), QString::fromUtf8(QByteArray::fromHex(key->text().toUtf8())), key->autorep(), key->count()); + + if (!key->sendToViewport()) { + QCoreApplication::sendEvent(m_view, &event); + } else { + QCoreApplication::sendEvent(m_view->viewport(), &event); + } + } + testscriptidx++; + } + + filterEvents = true; + + if (testscript && testscript->count() <= testscriptidx) + complete(); +} + +QT_END_NAMESPACE diff --git a/tools/qmlviewer/qfxtester.h b/tools/qmlviewer/qfxtester.h new file mode 100644 index 0000000..e37d6aa --- /dev/null +++ b/tools/qmlviewer/qfxtester.h @@ -0,0 +1,230 @@ +/**************************************************************************** +** +** Copyright (C) 1992-$THISYEAR$ $TROLLTECH$. All rights reserved. +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef QFXTESTER_H +#define QFXTESTER_H + +#include <QEvent> +#include <QMouseEvent> +#include <QKeyEvent> +#include <qmlviewer.h> + +QT_BEGIN_NAMESPACE + +class QFxVisualTest : public QObject +{ + Q_OBJECT + Q_PROPERTY(QList<QObject *>* events READ events CONSTANT) + Q_CLASSINFO("DefaultProperty", "events") +public: + QFxVisualTest() {} + + QList<QObject *> *events() { return &m_events; } + + int count() const { return m_events.count(); } + QObject *event(int idx) { return m_events.at(idx); } + +private: + QList<QObject *> m_events; +}; +QML_DECLARE_TYPE(QFxVisualTest) + +class QFxVisualTestFrame : public QObject +{ + Q_OBJECT + Q_PROPERTY(int msec READ msec WRITE setMsec) + Q_PROPERTY(QString hash READ hash WRITE setHash) + Q_PROPERTY(QString image READ image WRITE setImage) +public: + QFxVisualTestFrame() : m_msec(-1) {} + + int msec() const { return m_msec; } + void setMsec(int m) { m_msec = m; } + + QString hash() const { return m_hash; } + void setHash(const QString &hash) { m_hash = hash; } + + QString image() const { return m_image; } + void setImage(const QString &image) { m_image = image; } + +private: + int m_msec; + QString m_hash; + QString m_image; +}; +QML_DECLARE_TYPE(QFxVisualTestFrame) + +class QFxVisualTestMouse : public QObject +{ + Q_OBJECT + Q_PROPERTY(int type READ type WRITE setType) + Q_PROPERTY(int button READ button WRITE setButton) + Q_PROPERTY(int buttons READ buttons WRITE setButtons) + Q_PROPERTY(int x READ x WRITE setX) + Q_PROPERTY(int y READ y WRITE setY) + Q_PROPERTY(int modifiers READ modifiers WRITE setModifiers) + Q_PROPERTY(bool sendToViewport READ sendToViewport WRITE setSendToViewport) +public: + QFxVisualTestMouse() : m_type(0), m_button(0), m_buttons(0), m_x(0), m_y(0), m_modifiers(0), m_viewport(false) {} + + int type() const { return m_type; } + void setType(int t) { m_type = t; } + + int button() const { return m_button; } + void setButton(int b) { m_button = b; } + + int buttons() const { return m_buttons; } + void setButtons(int b) { m_buttons = b; } + + int x() const { return m_x; } + void setX(int x) { m_x = x; } + + int y() const { return m_y; } + void setY(int y) { m_y = y; } + + int modifiers() const { return m_modifiers; } + void setModifiers(int modifiers) { m_modifiers = modifiers; } + + bool sendToViewport() const { return m_viewport; } + void setSendToViewport(bool v) { m_viewport = v; } +private: + int m_type; + int m_button; + int m_buttons; + int m_x; + int m_y; + int m_modifiers; + bool m_viewport; +}; +QML_DECLARE_TYPE(QFxVisualTestMouse) + +class QFxVisualTestKey : public QObject +{ + Q_OBJECT + Q_PROPERTY(int type READ type WRITE setType) + Q_PROPERTY(int key READ key WRITE setKey) + Q_PROPERTY(int modifiers READ modifiers WRITE setModifiers) + Q_PROPERTY(QString text READ text WRITE setText) + Q_PROPERTY(bool autorep READ autorep WRITE setAutorep) + Q_PROPERTY(int count READ count WRITE setCount) + Q_PROPERTY(bool sendToViewport READ sendToViewport WRITE setSendToViewport) +public: + QFxVisualTestKey() : m_type(0), m_key(0), m_modifiers(0), m_autorep(false), m_count(0), m_viewport(false) {} + + int type() const { return m_type; } + void setType(int t) { m_type = t; } + + int key() const { return m_key; } + void setKey(int k) { m_key = k; } + + int modifiers() const { return m_modifiers; } + void setModifiers(int m) { m_modifiers = m; } + + QString text() const { return m_text; } + void setText(const QString &t) { m_text = t; } + + bool autorep() const { return m_autorep; } + void setAutorep(bool a) { m_autorep = a; } + + int count() const { return m_count; } + void setCount(int c) { m_count = c; } + + bool sendToViewport() const { return m_viewport; } + void setSendToViewport(bool v) { m_viewport = v; } +private: + int m_type; + int m_key; + int m_modifiers; + QString m_text; + bool m_autorep; + int m_count; + bool m_viewport; +}; +QML_DECLARE_TYPE(QFxVisualTestKey) + +class QFxTester : public QAbstractAnimation +{ +public: + QFxTester(const QString &script, QmlViewer::ScriptOptions options, QFxView *parent); + + virtual int duration() const; + + void run(const QString &); + void save(const QString &); + + void executefailure(); +protected: + virtual void updateCurrentTime(int msecs); + virtual bool eventFilter(QObject *, QEvent *); + +private: + void imagefailure(); + void complete(); + + enum Destination { View, ViewPort }; + void addKeyEvent(Destination, QKeyEvent *); + void addMouseEvent(Destination, QMouseEvent *); + QFxView *m_view; + + struct MouseEvent { + MouseEvent(QMouseEvent *e) + : type(e->type()), button(e->button()), buttons(e->buttons()), + pos(e->pos()), modifiers(e->modifiers()), destination(View) {} + + QEvent::Type type; + Qt::MouseButton button; + Qt::MouseButtons buttons; + QPoint pos; + Qt::KeyboardModifiers modifiers; + Destination destination; + + int msec; + }; + struct KeyEvent { + KeyEvent(QKeyEvent *e) + : type(e->type()), key(e->key()), modifiers(e->modifiers()), text(e->text()), + autorep(e->isAutoRepeat()), count(e->count()), destination(View) {} + QEvent::Type type; + int key; + Qt::KeyboardModifiers modifiers; + QString text; + bool autorep; + ushort count; + Destination destination; + + int msec; + }; + struct FrameEvent { + QImage image; + QByteArray hash; + int msec; + }; + QList<MouseEvent> m_mouseEvents; + QList<KeyEvent> m_keyEvents; + + QList<MouseEvent> m_savedMouseEvents; + QList<KeyEvent> m_savedKeyEvents; + QList<FrameEvent> m_savedFrameEvents; + bool filterEvents; + + QmlViewer::ScriptOptions options; + int testscriptidx; + QFxVisualTest *testscript; + + bool hasFailed; +}; + + +QT_END_NAMESPACE + +#endif // QFXTESTER_H diff --git a/tools/qmlviewer/qmlviewer.cpp b/tools/qmlviewer/qmlviewer.cpp index 1c0f496..2894f1d 100644 --- a/tools/qmlviewer/qmlviewer.cpp +++ b/tools/qmlviewer/qmlviewer.cpp @@ -19,8 +19,8 @@ #include <QtDeclarative/qmlengine.h> #include "qml.h" #include <private/qperformancelog_p.h> -#include <QAbstractAnimation> #include <private/qabstractanimation_p.h> +#include <QAbstractAnimation> #include "deviceskin.h" #include <QSettings> @@ -51,6 +51,8 @@ #include <QGLWidget> #endif +#include <qfxtester.h> + QT_BEGIN_NAMESPACE class PreviewDeviceSkin : public DeviceSkin @@ -251,7 +253,8 @@ QString QmlViewer::getVideoFileName() QmlViewer::QmlViewer(QWidget *parent, Qt::WindowFlags flags) - : QWidget(parent, flags), frame_stream(0), scaleSkin(true), mb(0) + : QWidget(parent, flags), frame_stream(0), scaleSkin(true), mb(0), m_scriptOptions(0), + tester(0) { devicemode = false; skin = 0; @@ -291,6 +294,7 @@ QmlViewer::QmlViewer(QWidget *parent, Qt::WindowFlags flags) canvas->setFocus(); QObject::connect(canvas, SIGNAL(sceneResized(QSize)), this, SLOT(sceneResized(QSize))); + QObject::connect(canvas, SIGNAL(errors(QList<QmlError>)), this, SLOT(executeErrors())); QVBoxLayout *layout = new QVBoxLayout; layout->setMargin(0); @@ -589,10 +593,18 @@ void QmlViewer::open() } } +void QmlViewer::executeErrors() +{ + if (tester) tester->executefailure(); +} + void QmlViewer::openQml(const QString& fileName) { setWindowTitle(tr("%1 - Qt Declarative UI Viewer").arg(fileName)); + if (!m_script.isEmpty()) + tester = new QFxTester(m_script, m_scriptOptions, canvas); + canvas->reset(); currentFileName = fileName; @@ -617,6 +629,7 @@ void QmlViewer::openQml(const QString& fileName) foreach (const QmlError &error, errors) { qWarning() << error; } + if (tester) tester->executefailure(); } if (dummyData) { @@ -762,17 +775,19 @@ void QmlViewer::keyPressEvent(QKeyEvent *event) exit(0); else if (event->key() == Qt::Key_F1 || (event->key() == Qt::Key_1 && devicemode)) { qDebug() << "F1 - help\n" - << "F2 - toggle video recording\n" + << "F2 - save test script\n" << "F3 - take PNG snapshot\n" << "F4 - show items and state\n" << "F5 - reload QML\n" << "F6 - show object tree\n" << "F7 - show timing\n" << "F8 - show performance (if available)\n" + << "F9 - toggle video recording\n" << "device keys: 0=quit, 1..8=F1..F8" ; - } else if (event->key() == Qt::Key_F2 || (event->key() == Qt::Key_2 && devicemode)) { - toggleRecording(); + } else if (event->key() == Qt::Key_F2 || (event->key() == Qt::Key_3 && devicemode)) { + if (tester && m_scriptOptions & Record) + tester->save(m_script); } else if (event->key() == Qt::Key_F3 || (event->key() == Qt::Key_3 && devicemode)) { takeSnapShot(); } else if (event->key() == Qt::Key_F5 || (event->key() == Qt::Key_5 && devicemode)) { @@ -780,6 +795,8 @@ void QmlViewer::keyPressEvent(QKeyEvent *event) } else if (event->key() == Qt::Key_F8 || (event->key() == Qt::Key_8 && devicemode)) { QPerformanceLog::displayData(); QPerformanceLog::clear(); + } else if (event->key() == Qt::Key_F9 || (event->key() == Qt::Key_9 && devicemode)) { + toggleRecording(); } QWidget::keyPressEvent(event); @@ -1051,7 +1068,6 @@ void QmlViewer::setUseGL(bool useGL) } #endif } - QT_END_NAMESPACE #include "qmlviewer.moc" diff --git a/tools/qmlviewer/qmlviewer.h b/tools/qmlviewer/qmlviewer.h index e85acfa..f0e997c 100644 --- a/tools/qmlviewer/qmlviewer.h +++ b/tools/qmlviewer/qmlviewer.h @@ -26,6 +26,7 @@ class PreviewDeviceSkin; class QFxTestEngine; class QProcess; class RecordingDialog; +class QFxTester; class QmlViewer : public QWidget { @@ -33,6 +34,16 @@ Q_OBJECT public: QmlViewer(QWidget *parent=0, Qt::WindowFlags flags=0); + enum ScriptOption { + Play = 0x00000001, + Record = 0x00000002, + TestImages = 0x00000004, + ExitOnComplete = 0x00000008, + ExitOnFailure = 0x00000010 + }; + Q_DECLARE_FLAGS(ScriptOptions, ScriptOption) + void setScript(const QString &s) { m_script = s; } + void setScriptOptions(ScriptOptions opt) { m_scriptOptions = opt; } void setRecordDither(const QString& s) { record_dither = s; } void setRecordRate(int fps); void setRecordFile(const QString&); @@ -62,6 +73,7 @@ public slots: void showProxySettings (); void proxySettingsChanged (); void setScaleView(); + void executeErrors(); protected: virtual void keyPressEvent(QKeyEvent *); @@ -109,7 +121,12 @@ private: QWidget *ffmpegHelpWindow; bool ffmpegAvailable; bool convertAvailable; + + QString m_script; + ScriptOptions m_scriptOptions; + QFxTester *tester; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QmlViewer::ScriptOptions) QT_END_NAMESPACE diff --git a/tools/qmlviewer/qmlviewer.pro b/tools/qmlviewer/qmlviewer.pro index 77cae97..899a3ab 100644 --- a/tools/qmlviewer/qmlviewer.pro +++ b/tools/qmlviewer/qmlviewer.pro @@ -14,10 +14,12 @@ contains(QT_CONFIG, opengl) { # Input HEADERS += qmlviewer.h \ - proxysettings.h + proxysettings.h \ + qfxtester.h SOURCES += main.cpp \ - qmlviewer.cpp \ - proxysettings.cpp + qmlviewer.cpp \ + proxysettings.cpp \ + qfxtester.cpp FORMS = recopts.ui \ proxysettings.ui include($$QT_SOURCE_TREE/tools/shared/deviceskin/deviceskin.pri) |