summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/configure/configureapp.cpp12
-rw-r--r--tools/linguist/lupdate/lupdate.h1
-rw-r--r--tools/linguist/lupdate/lupdate.pro4
-rw-r--r--tools/linguist/lupdate/main.cpp5
-rw-r--r--tools/linguist/lupdate/qml.cpp240
-rw-r--r--tools/qdoc3/test/qml.qdocconf77
-rw-r--r--tools/qdoc3/test/qt-build-docs.qdocconf3
-rw-r--r--tools/qdoc3/test/qt-cpp-ignore.qdocconf1
-rw-r--r--tools/qdoc3/test/qt-inc.qdocconf1
-rw-r--r--tools/qdoc3/test/qt.qdocconf3
-rw-r--r--tools/qmldebugger/canvasframerate.cpp308
-rw-r--r--tools/qmldebugger/canvasframerate.h28
-rw-r--r--tools/qmldebugger/engine.cpp251
-rw-r--r--tools/qmldebugger/engine.h61
-rw-r--r--tools/qmldebugger/engine.pngbin0 -> 6394 bytes
-rw-r--r--tools/qmldebugger/engines.qml46
-rw-r--r--tools/qmldebugger/main.cpp137
-rw-r--r--tools/qmldebugger/qmldebugger.pro15
-rw-r--r--tools/qmldebugger/qmldebugger.qrc7
-rw-r--r--tools/qmldebugger/refresh.pngbin0 -> 6169 bytes
-rw-r--r--tools/qmlviewer/main.cpp167
-rw-r--r--tools/qmlviewer/proxysettings.cpp78
-rw-r--r--tools/qmlviewer/proxysettings.h40
-rw-r--r--tools/qmlviewer/proxysettings.ui115
-rw-r--r--tools/qmlviewer/qmlviewer.cpp1008
-rw-r--r--tools/qmlviewer/qmlviewer.h115
-rw-r--r--tools/qmlviewer/qmlviewer.pro28
-rw-r--r--tools/qmlviewer/recopts.ui513
-rw-r--r--tools/tools.pro1
29 files changed, 3262 insertions, 3 deletions
diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp
index 5b30b4e..e8b810c 100644
--- a/tools/configure/configureapp.cpp
+++ b/tools/configure/configureapp.cpp
@@ -249,6 +249,7 @@ Configure::Configure( int& argc, char** argv )
dictionary[ "MULTIMEDIA" ] = "yes";
dictionary[ "DIRECTSHOW" ] = "no";
dictionary[ "WEBKIT" ] = "auto";
+ dictionary[ "DECLARATIVE" ] = "yes";
dictionary[ "PLUGIN_MANIFESTS" ] = "yes";
QString version;
@@ -905,6 +906,10 @@ void Configure::parseCmdLine()
dictionary[ "WEBKIT" ] = "no";
} else if( configCmdLine.at(i) == "-webkit" ) {
dictionary[ "WEBKIT" ] = "yes";
+ } else if( configCmdLine.at(i) == "-no-declarative" ) {
+ dictionary[ "DECLARATIVE" ] = "no";
+ } else if( configCmdLine.at(i) == "-declarative" ) {
+ dictionary[ "DECLARATIVE" ] = "yes";
} else if( configCmdLine.at(i) == "-no-plugin-manifests" ) {
dictionary[ "PLUGIN_MANIFESTS" ] = "no";
} else if( configCmdLine.at(i) == "-plugin-manifests" ) {
@@ -1746,6 +1751,8 @@ bool Configure::displayHelp()
desc("SCRIPT", "yes", "-script", "Build the QtScript module.");
desc("SCRIPTTOOLS", "no", "-no-scripttools", "Do not build the QtScriptTools module.");
desc("SCRIPTTOOLS", "yes", "-scripttools", "Build the QtScriptTools module.");
+ desc("DECLARATIVE", "no", "-no-declarative", "Do not build the declarative module");
+ desc("DECLARATIVE", "yes", "-declarative", "Build the declarative module");
desc( "-arch <arch>", "Specify an architecture.\n"
"Available values for <arch>:");
@@ -2505,6 +2512,9 @@ void Configure::generateOutputVars()
if (dictionary["WEBKIT"] == "yes")
qtConfig += "webkit";
+ if (dictionary["DECLARATIVE"] == "yes")
+ qtConfig += "declarative";
+
// We currently have no switch for QtSvg, so add it unconditionally.
qtConfig += "svg";
@@ -2885,6 +2895,7 @@ void Configure::generateConfigfiles()
if(dictionary["DBUS"] == "no") qconfigList += "QT_NO_DBUS";
if(dictionary["IPV6"] == "no") qconfigList += "QT_NO_IPV6";
if(dictionary["WEBKIT"] == "no") qconfigList += "QT_NO_WEBKIT";
+ if(dictionary["DECLARATIVE"] == "no") qconfigList += "QT_NO_DECLARATIVE";
if(dictionary["PHONON"] == "no") qconfigList += "QT_NO_PHONON";
if(dictionary["MULTIMEDIA"] == "no") qconfigList += "QT_NO_MULTIMEDIA";
if(dictionary["XMLPATTERNS"] == "no") qconfigList += "QT_NO_XMLPATTERNS";
@@ -3156,6 +3167,7 @@ void Configure::displayConfig()
cout << "Phonon support.............." << dictionary[ "PHONON" ] << endl;
cout << "QtMultimedia support........" << dictionary[ "MULTIMEDIA" ] << endl;
cout << "WebKit support.............." << dictionary[ "WEBKIT" ] << endl;
+ cout << "Declarative support........." << dictionary[ "DECLARATIVE" ] << endl;
cout << "QtScript support............" << dictionary[ "SCRIPT" ] << endl;
cout << "QtScriptTools support......." << dictionary[ "SCRIPTTOOLS" ] << endl;
cout << "Graphics System............." << dictionary[ "GRAPHICS_SYSTEM" ] << endl;
diff --git a/tools/linguist/lupdate/lupdate.h b/tools/linguist/lupdate/lupdate.h
index 73dafb8..97b4732 100644
--- a/tools/linguist/lupdate/lupdate.h
+++ b/tools/linguist/lupdate/lupdate.h
@@ -79,6 +79,7 @@ void loadCPP(Translator &translator, const QStringList &filenames, ConversionDat
bool loadJava(Translator &translator, const QString &filename, ConversionData &cd);
bool loadQScript(Translator &translator, const QString &filename, ConversionData &cd);
bool loadUI(Translator &translator, const QString &filename, ConversionData &cd);
+bool loadQml(Translator &translator, const QString &filename, ConversionData &cd);
QT_END_NAMESPACE
diff --git a/tools/linguist/lupdate/lupdate.pro b/tools/linguist/lupdate/lupdate.pro
index ccc2d47..283d69f 100644
--- a/tools/linguist/lupdate/lupdate.pro
+++ b/tools/linguist/lupdate/lupdate.pro
@@ -15,6 +15,9 @@ build_all:!build_pass {
include(../shared/formats.pri)
include(../shared/proparser.pri)
+include($$QT_SOURCE_TREE/src/declarative/qml/parser/parser.pri)
+INCLUDEPATH += $$QT_SOURCE_TREE/src/declarative/qml
+
SOURCES += \
main.cpp \
merge.cpp \
@@ -23,6 +26,7 @@ SOURCES += \
cpp.cpp \
java.cpp \
qscript.cpp \
+ qml.cpp \
ui.cpp
HEADERS += \
diff --git a/tools/linguist/lupdate/main.cpp b/tools/linguist/lupdate/main.cpp
index d38533a..ca72a6b 100644
--- a/tools/linguist/lupdate/main.cpp
+++ b/tools/linguist/lupdate/main.cpp
@@ -435,7 +435,8 @@ int main(int argc, char **argv)
if (!fn.endsWith(QLatin1String(".java"))
&& !fn.endsWith(QLatin1String(".ui"))
&& !fn.endsWith(QLatin1String(".js"))
- && !fn.endsWith(QLatin1String(".qs"))) {
+ && !fn.endsWith(QLatin1String(".qs"))
+ && !fn.endsWith(QLatin1String(".qml"))) {
int offset = 0;
int depth = 0;
do {
@@ -526,6 +527,8 @@ int main(int argc, char **argv)
else if (it->endsWith(QLatin1String(".js"), Qt::CaseInsensitive)
|| it->endsWith(QLatin1String(".qs"), Qt::CaseInsensitive))
loadQScript(fetchedTor, *it, cd);
+ else if (it->endsWith(QLatin1String(".qml"), Qt::CaseInsensitive))
+ loadQml(fetchedTor, *it, cd);
else
sourceFilesCpp << *it;
}
diff --git a/tools/linguist/lupdate/qml.cpp b/tools/linguist/lupdate/qml.cpp
new file mode 100644
index 0000000..f66a6bd
--- /dev/null
+++ b/tools/linguist/lupdate/qml.cpp
@@ -0,0 +1,240 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt Linguist of the Qt Toolkit.
+**
+** $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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "lupdate.h"
+
+#include <translator.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QFile>
+#include <QtCore/QString>
+
+#include "parser/qmljsengine_p.h"
+#include "parser/qmljsparser_p.h"
+#include "parser/qmljslexer_p.h"
+#include "parser/qmljsnodepool_p.h"
+#include "parser/qmljsastvisitor_p.h"
+#include "parser/qmljsast_p.h"
+
+#include <QCoreApplication>
+#include <QFile>
+#include <QFileInfo>
+#include <QtDebug>
+#include <QStringList>
+
+#include <iostream>
+#include <cstdlib>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QmlJS;
+
+class FindTrCalls: protected AST::Visitor
+{
+public:
+ void operator()(Translator *translator, const QString &fileName, AST::Node *node)
+ {
+ m_translator = translator;
+ m_fileName = fileName;
+ m_component = QFileInfo(fileName).baseName(); //matches qsTr usage in QScriptEngine
+ accept(node);
+ }
+
+protected:
+ using AST::Visitor::visit;
+ using AST::Visitor::endVisit;
+
+ void accept(AST::Node *node)
+ { AST::Node::acceptChild(node, this); }
+
+ virtual void endVisit(AST::CallExpression *node)
+ {
+ if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(node->base)) {
+ if (idExpr->name->asString() == QLatin1String("qsTr") ||
+ idExpr->name->asString() == QLatin1String("QT_TR_NOOP")) {
+ if (node->arguments && AST::cast<AST::StringLiteral *>(node->arguments->expression)) {
+ AST::StringLiteral *literal = AST::cast<AST::StringLiteral *>(node->arguments->expression);
+ const QString source = literal->value->asString();
+
+ QString comment;
+ bool plural = false;
+ AST::ArgumentList *commentNode = node->arguments->next;
+ if (commentNode) {
+ literal = AST::cast<AST::StringLiteral *>(commentNode->expression);
+ comment = literal->value->asString();
+
+ AST::ArgumentList *nNode = commentNode->next;
+ if (nNode) {
+ AST::NumericLiteral *numLiteral = AST::cast<AST::NumericLiteral *>(nNode->expression);
+ if (numLiteral) {
+ plural = true;
+ }
+ }
+ }
+
+ TranslatorMessage msg(m_component, source,
+ comment, QString(), m_fileName,
+ node->firstSourceLocation().startLine, QStringList(),
+ TranslatorMessage::Unfinished, plural);
+ m_translator->extend(msg);
+ }
+ } else if (idExpr->name->asString() == QLatin1String("qsTranslate") ||
+ idExpr->name->asString() == QLatin1String("QT_TRANSLATE_NOOP")) {
+ if (node->arguments && AST::cast<AST::StringLiteral *>(node->arguments->expression)) {
+ AST::StringLiteral *literal = AST::cast<AST::StringLiteral *>(node->arguments->expression);
+ const QString context = literal->value->asString();
+
+ QString source;
+ QString comment;
+ bool plural = false;
+ AST::ArgumentList *sourceNode = node->arguments->next;
+ if (sourceNode) {
+ literal = AST::cast<AST::StringLiteral *>(sourceNode->expression);
+ source = literal->value->asString();
+ AST::ArgumentList *commentNode = sourceNode->next;
+ if (commentNode) {
+ literal = AST::cast<AST::StringLiteral *>(commentNode->expression);
+ comment = literal->value->asString();
+
+ AST::ArgumentList *nNode = commentNode->next;
+ if (nNode) {
+ AST::NumericLiteral *numLiteral = AST::cast<AST::NumericLiteral *>(nNode->expression);
+ if (numLiteral) {
+ plural = true;
+ }
+ }
+ }
+ }
+
+ TranslatorMessage msg(context, source,
+ comment, QString(), m_fileName,
+ node->firstSourceLocation().startLine, QStringList(),
+ TranslatorMessage::Unfinished, plural);
+ m_translator->extend(msg);
+ }
+
+ }
+ }
+ }
+
+private:
+ Translator *m_translator;
+ QString m_fileName;
+ QString m_component;
+};
+
+QString createErrorString(const QString &filename, const QString &code, Parser &parser)
+{
+ // print out error
+ QStringList lines = code.split(QLatin1Char('\n'));
+ lines.append(QLatin1String("\n")); // sentinel.
+ QString errorString;
+
+ foreach (const DiagnosticMessage &m, parser.diagnosticMessages()) {
+
+ if (m.isWarning())
+ continue;
+
+ QString error = filename + QLatin1Char(':') + QString::number(m.loc.startLine)
+ + QLatin1Char(':') + QString::number(m.loc.startColumn) + QLatin1String(": error: ")
+ + m.message + QLatin1Char('\n');
+
+ int line = 0;
+ if (m.loc.startLine > 0)
+ line = m.loc.startLine - 1;
+
+ const QString textLine = lines.at(line);
+
+ error += textLine + QLatin1Char('\n');
+
+ int column = m.loc.startColumn - 1;
+ if (column < 0)
+ column = 0;
+
+ column = qMin(column, textLine.length());
+
+ for (int i = 0; i < column; ++i) {
+ const QChar ch = textLine.at(i);
+ if (ch.isSpace())
+ error += ch.unicode();
+ else
+ error += QLatin1Char(' ');
+ }
+ error += QLatin1String("^\n");
+ errorString += error;
+ }
+ return errorString;
+}
+
+bool loadQml(Translator &translator, const QString &filename, ConversionData &cd)
+{
+ cd.m_sourceFileName = filename;
+ QFile file(filename);
+ if (!file.open(QIODevice::ReadOnly)) {
+ cd.appendError(QString::fromLatin1("Cannot open %1: %2")
+ .arg(filename, file.errorString()));
+ return false;
+ }
+
+ const QString code = QTextStream(&file).readAll();
+
+ Engine driver;
+ Parser parser(&driver);
+
+ NodePool nodePool(filename, &driver);
+ driver.setNodePool(&nodePool);
+
+ Lexer lexer(&driver);
+ lexer.setCode(code, /*line = */ 1);
+ driver.setLexer(&lexer);
+
+ if (parser.parse()) {
+ FindTrCalls trCalls;
+ trCalls(&translator, filename, parser.ast());
+ } else {
+ QString error = createErrorString(filename, code, parser);
+ cd.appendError(error);
+ return false;
+ }
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/tools/qdoc3/test/qml.qdocconf b/tools/qdoc3/test/qml.qdocconf
new file mode 100644
index 0000000..3a7d76a
--- /dev/null
+++ b/tools/qdoc3/test/qml.qdocconf
@@ -0,0 +1,77 @@
+include(compat.qdocconf)
+include(macros.qdocconf)
+include(qt-cpp-ignore.qdocconf)
+include(qt-html-templates.qdocconf)
+include(qt-defines.qdocconf)
+
+project = Qml
+description = Qml Reference Documentation
+url = http://doc.qtsoftware.com/4.6
+
+edition.Console.modules = QtCore QtDBus QtNetwork QtScript QtSql QtXml \
+ QtXmlPatterns QtTest
+edition.Desktop.modules = QtCore QtDBus QtGui QtNetwork QtOpenGL QtScript QtSql QtSvg \
+ QtWebKit QtXml QtXmlPatterns Qt3Support QtHelp \
+ QtDesigner QtAssistant QAxContainer Phonon \
+ QAxServer QtUiTools QtTest QtDBus
+edition.DesktopLight.modules = QtCore QtDBus QtGui Qt3SupportLight QtTest
+edition.DesktopLight.groups = -graphicsview-api
+
+qhp.projects = Qml
+
+qhp.Qml.file = qml.qhp
+qhp.Qml.namespace = com.trolltech.qml.460
+qhp.Qml.virtualFolder = qdoc
+qhp.Qml.indexTitle = Qml Reference
+
+# Files not referenced in any qdoc file
+# See also extraimages.HTML
+qhp.Qml.extraFiles = classic.css \
+ images/qt-logo.png
+
+qhp.Qml.filterAttributes = qt 4.6.0 qtrefdoc
+qhp.Qml.customFilters.Qt.name = Qt 4.6.0
+qhp.Qml.customFilters.Qt.filterAttributes = qt 4.6.0
+qhp.Qml.subprojects = classes
+qhp.Qml.subprojects.classes.title = Elements
+qhp.Qml.subprojects.classes.indexTitle = Qml Elements
+qhp.Qml.subprojects.classes.selectors = fake:qmlclass
+qhp.Qml.subprojects.classes.sortPages = true
+
+language = Cpp
+
+headerdirs = $QT_SOURCE_TREE/src/declarative
+sourcedirs = $QT_SOURCE_TREE/src/declarative \
+ $QT_SOURCE_TREE/doc/src/declarative
+
+sources += $QT_SOURCE_TREE/doc/src/tutorials/declarative.qdoc
+
+sources.fileextensions = "*.cpp *.qdoc"
+examples.fileextensions = "*.cpp *.h *.js *.qml"
+
+exampledirs = $QT_SOURCE_TREE/doc/src \
+ $QT_SOURCE_TREE/examples \
+ $QT_SOURCE_TREE/examples/tutorials \
+ $QT_SOURCE_TREE \
+ $QT_SOURCE_TREE/qmake/examples \
+ $QT_SOURCE_TREE/src/3rdparty/webkit/WebKit/qt/docs
+imagedirs = $QT_SOURCE_TREE/doc/src/images \
+ $QT_SOURCE_TREE/examples \
+ $QT_SOURCE_TREE/doc/src/declarative/pics
+outputdir = $QT_BUILD_TREE/doc-build/html-qml
+tagfile = $QT_BUILD_TREE/doc-build/html-qml/qt.tags
+base = file:$QT_BUILD_TREE/doc/html-qml
+
+HTML.stylesheets = classic.css
+
+HTML.postheader = "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n" \
+ "<tr>\n" \
+ "<td align=\"left\" valign=\"top\">" \
+ "<img src=\"images/qt-logo.png\" align=\"left\" border=\"0\"/>" \
+ "</td>\n" \
+ "<td width=\"1\">&nbsp;&nbsp;</td>" \
+ "<td class=\"postheader\" valign=\"center\" align=\"left\">" \
+ "<a href=\"qmlreference.html\">" \
+ "<font color=\"#004faf\">Home</font></a>" \
+ "</td>\n" \
+ "</tr></table>"
diff --git a/tools/qdoc3/test/qt-build-docs.qdocconf b/tools/qdoc3/test/qt-build-docs.qdocconf
index 70e3b4f..deaf8a8 100644
--- a/tools/qdoc3/test/qt-build-docs.qdocconf
+++ b/tools/qdoc3/test/qt-build-docs.qdocconf
@@ -107,7 +107,8 @@ exampledirs = $QT_SOURCE_TREE/doc/src \
$QT_SOURCE_TREE/qmake/examples \
$QT_SOURCE_TREE/src/3rdparty/webkit/WebKit/qt/docs
imagedirs = $QT_SOURCE_TREE/doc/src/images \
- $QT_SOURCE_TREE/examples
+ $QT_SOURCE_TREE/examples \
+ $QT_SOURCE_TREE/doc/src/declarative/pics
outputdir = $QT_BUILD_TREE/doc/html
tagfile = $QT_BUILD_TREE/doc/html/qt.tags
base = file:$QT_BUILD_TREE/doc/html
diff --git a/tools/qdoc3/test/qt-cpp-ignore.qdocconf b/tools/qdoc3/test/qt-cpp-ignore.qdocconf
index 709e336..5be9fa5 100644
--- a/tools/qdoc3/test/qt-cpp-ignore.qdocconf
+++ b/tools/qdoc3/test/qt-cpp-ignore.qdocconf
@@ -68,6 +68,7 @@ Cpp.ignoretokens = QAXFACTORY_EXPORT \
QT_END_NAMESPACE \
QT_END_INCLUDE_NAMESPACE \
PHONON_EXPORT \
+ Q_DECLARATIVE_EXPORT \
Q_GADGET \
QWEBKIT_EXPORT
Cpp.ignoredirectives = Q_DECLARE_HANDLE \
diff --git a/tools/qdoc3/test/qt-inc.qdocconf b/tools/qdoc3/test/qt-inc.qdocconf
index 4ef32b8..32f2af7 100644
--- a/tools/qdoc3/test/qt-inc.qdocconf
+++ b/tools/qdoc3/test/qt-inc.qdocconf
@@ -100,6 +100,7 @@ Cpp.ignoretokens = QAXFACTORY_EXPORT \
Q_TYPENAME \
Q_XML_EXPORT \
QDBUS_EXPORT \
+ Q_DECLARATIVE_EXPORT \
Q_GADGET \
QWEBKIT_EXPORT
Cpp.ignoredirectives = Q_DECLARE_HANDLE \
diff --git a/tools/qdoc3/test/qt.qdocconf b/tools/qdoc3/test/qt.qdocconf
index 942d023..7bd4e52 100644
--- a/tools/qdoc3/test/qt.qdocconf
+++ b/tools/qdoc3/test/qt.qdocconf
@@ -109,7 +109,8 @@ exampledirs = $QTDIR/doc/src \
$QTDIR/qmake/examples \
$QTDIR/src/3rdparty/webkit/WebKit/qt/docs
imagedirs = $QTDIR/doc/src/images \
- $QTDIR/examples
+ $QTDIR/examples \
+ $QTDIR/doc/src/declarative/pics
outputdir = $QTDIR/doc/html
tagfile = $QTDIR/doc/html/qt.tags
base = file:$QTDIR/doc/html
diff --git a/tools/qmldebugger/canvasframerate.cpp b/tools/qmldebugger/canvasframerate.cpp
new file mode 100644
index 0000000..d0be579
--- /dev/null
+++ b/tools/qmldebugger/canvasframerate.cpp
@@ -0,0 +1,308 @@
+#include "canvasframerate.h"
+#include <QtGui/qwidget.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qscrollbar.h>
+#include <QtDeclarative/qmldebugclient.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qdatastream.h>
+#include <QtGui/qboxlayout.h>
+#include <QResizeEvent>
+#include <QShowEvent>
+#include <QTabWidget>
+#include <QPushButton>
+#include <QLineEdit>
+#include <QCheckBox>
+
+QT_BEGIN_NAMESPACE
+
+class QLineGraph : public QWidget
+{
+Q_OBJECT
+public:
+ QLineGraph(QWidget * = 0);
+
+ void setPosition(int);
+
+public slots:
+ void addSample(int, int, int, int, bool);
+
+protected:
+ virtual void paintEvent(QPaintEvent *);
+ virtual QSize sizeHint() const;
+
+private slots:
+ void scrollbarChanged(int);
+
+private:
+ void updateScrollbar();
+ void drawSample(QPainter *, int, const QRect &);
+ void drawTime(QPainter *, const QRect &);
+ struct Sample {
+ int sample[4];
+ bool isBreak;
+ };
+ QList<Sample> _samples;
+
+ QScrollBar sb;
+ int position;
+ int samplesPerWidth;
+ int resolutionForHeight;
+ bool ignoreScroll;
+};
+
+QLineGraph::QLineGraph(QWidget *parent)
+: QWidget(parent), sb(Qt::Horizontal, this), position(-1), samplesPerWidth(99), resolutionForHeight(50), ignoreScroll(false)
+{
+ sb.setMaximum(0);
+ sb.setMinimum(0);
+ sb.setSingleStep(1);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ setLayout(layout);
+ layout->addStretch(2);
+ layout->addWidget(&sb);
+ QObject::connect(&sb, SIGNAL(valueChanged(int)), this, SLOT(scrollbarChanged(int)));
+}
+
+QSize QLineGraph::sizeHint() const
+{
+ return QSize(800, 600);
+}
+
+void QLineGraph::scrollbarChanged(int v)
+{
+ if(ignoreScroll)
+ return;
+
+ if (v == sb.maximum())
+ position = -1;
+ else
+ position = v;
+ update();
+}
+
+void QLineGraph::updateScrollbar()
+{
+ ignoreScroll = true;
+ sb.setMaximum(qMax(0, _samples.count() - samplesPerWidth - 1));
+
+ if(position == -1) {
+ sb.setValue(sb.maximum());
+ } else {
+ sb.setValue(position);
+ }
+ ignoreScroll = false;
+}
+
+void QLineGraph::addSample(int a, int b, int c, int d, bool isBreak)
+{
+ Sample s;
+ s.isBreak = isBreak;
+ s.sample[0] = a;
+ s.sample[1] = b;
+ s.sample[2] = c;
+ s.sample[3] = d;
+ _samples << s;
+ updateScrollbar();
+ update();
+}
+
+void QLineGraph::setPosition(int p)
+{
+ scrollbarChanged(p);
+}
+
+void QLineGraph::drawTime(QPainter *p, const QRect &rect)
+{
+ if(_samples.isEmpty())
+ return;
+
+ int first = position;
+ if(first == -1)
+ first = qMax(0, _samples.count() - samplesPerWidth - 1);
+ int last = qMin(_samples.count() - 1, first + samplesPerWidth);
+
+ qreal scaleX = qreal(rect.width()) / qreal(samplesPerWidth);
+
+ int t = 0;
+
+ for(int ii = first; ii <= last; ++ii) {
+ int sampleTime = _samples.at(ii).sample[3] / 1000;
+ if(sampleTime != t) {
+
+ int xEnd = rect.left() + scaleX * (ii - first);
+ p->drawLine(xEnd, rect.bottom(), xEnd, rect.bottom() + 7);
+
+ QRect text(xEnd - 30, rect.bottom() + 10, 60, 30);
+
+ p->drawText(text, Qt::AlignHCenter | Qt::AlignTop, QString::number(_samples.at(ii).sample[3]));
+
+ t = sampleTime;
+ }
+ }
+
+}
+
+void QLineGraph::drawSample(QPainter *p, int s, const QRect &rect)
+{
+ if(_samples.isEmpty())
+ return;
+
+ int first = position;
+ if(first == -1)
+ first = qMax(0, _samples.count() - samplesPerWidth - 1);
+ int last = qMin(_samples.count() - 1, first + samplesPerWidth);
+
+ qreal scaleY = rect.height() / resolutionForHeight;
+ qreal scaleX = qreal(rect.width()) / qreal(samplesPerWidth);
+
+ int xEnd;
+ int lastXEnd = rect.left();
+
+ p->save();
+ p->setPen(Qt::NoPen);
+ for(int ii = first + 1; ii <= last; ++ii) {
+
+ xEnd = rect.left() + scaleX * (ii - first);
+ int yEnd = rect.bottom() - _samples.at(ii).sample[s] * scaleY;
+
+ if (!(s == 0 && _samples.at(ii).isBreak))
+ p->drawRect(QRect(lastXEnd, yEnd, scaleX, _samples.at(ii).sample[s] * scaleY));
+
+ lastXEnd = xEnd;
+ }
+ p->restore();
+}
+
+void QLineGraph::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+ p.setRenderHint(QPainter::Antialiasing);
+
+
+ QRect r(50, 10, width() - 60, height() - 60);
+ p.setBrush(QColor("lightsteelblue"));
+ drawSample(&p, 0, r);
+
+ p.setBrush(QColor("pink"));
+ drawSample(&p, 1, r);
+
+ p.setBrush(QColor("green"));
+ drawSample(&p, 2, r);
+
+ p.setBrush(Qt::NoBrush);
+ p.drawRect(r);
+
+ for(int ii = 0; ii <= resolutionForHeight; ++ii) {
+ int y = 1 + r.bottom() - ii * r.height() / resolutionForHeight;
+
+ if((ii % 10) == 0) {
+ p.drawLine(r.left() - 20, y, r.left(), y);
+ QRect text(r.left() - 20 - 53, y - 10, 50, 20);
+ p.drawText(text, Qt::AlignRight | Qt::AlignVCenter, QString::number(ii));
+ } else {
+ p.drawLine(r.left() - 7, y, r.left(), y);
+ }
+ }
+
+ drawTime(&p, r);
+}
+
+class CanvasFrameRatePlugin : public QmlDebugClient
+{
+Q_OBJECT
+public:
+ CanvasFrameRatePlugin(QmlDebugConnection *client);
+
+signals:
+ void sample(int, int, int, int, bool);
+
+protected:
+ virtual void messageReceived(const QByteArray &);
+
+private:
+ int la;
+ int lb;
+ int ld;
+};
+
+CanvasFrameRatePlugin::CanvasFrameRatePlugin(QmlDebugConnection *client)
+: QmlDebugClient(QLatin1String("CanvasFrameRate"), client), la(-1)
+{
+}
+
+void CanvasFrameRatePlugin::messageReceived(const QByteArray &data)
+{
+ QByteArray rwData = data;
+ QDataStream stream(&rwData, QIODevice::ReadOnly);
+
+ int a; int b; int c; int d; bool isBreak;
+ stream >> a >> b >> c >> d >> isBreak;
+
+ if (la != -1)
+ emit sample(c, lb, la, ld, isBreak);
+
+ la = a;
+ lb = b;
+ ld = d;
+}
+
+CanvasFrameRate::CanvasFrameRate(QmlDebugConnection *client, QWidget *parent)
+: QWidget(parent)
+{
+ m_plugin = new CanvasFrameRatePlugin(client);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->setContentsMargins(0,0,0,0);
+ layout->setSpacing(0);
+ setLayout(layout);
+
+ m_tabs = new QTabWidget(this);
+ layout->addWidget(m_tabs);
+
+ QHBoxLayout *bottom = new QHBoxLayout;
+ layout->addLayout(bottom);
+ bottom->addStretch(2);
+
+ QCheckBox *check = new QCheckBox("Enable", this);
+ bottom->addWidget(check);
+ QObject::connect(check, SIGNAL(stateChanged(int)),
+ this, SLOT(stateChanged(int)));
+
+ QPushButton *pb = new QPushButton(tr("New Tab"), this);
+ QObject::connect(pb, SIGNAL(clicked()), this, SLOT(newTab()));
+ bottom->addWidget(pb);
+
+ newTab();
+}
+
+void CanvasFrameRate::newTab()
+{
+ if (m_tabs->count()) {
+ QWidget *w = m_tabs->widget(m_tabs->count() - 1);
+ QObject::disconnect(m_plugin, SIGNAL(sample(int,int,int,int,bool)),
+ w, SLOT(addSample(int,int,int,int,bool)));
+ }
+
+ int id = m_tabs->count();
+
+ QLineGraph *graph = new QLineGraph(this);
+ QObject::connect(m_plugin, SIGNAL(sample(int,int,int,int,bool)),
+ graph, SLOT(addSample(int,int,int,int,bool)));
+
+ QString name = QLatin1String("Graph ") + QString::number(id);
+ m_tabs->addTab(graph, name);
+ m_tabs->setCurrentIndex(id);
+}
+
+void CanvasFrameRate::stateChanged(int s)
+{
+ bool checked = s != 0;
+
+ static_cast<QmlDebugClient *>(m_plugin)->setEnabled(checked);
+}
+
+QT_END_NAMESPACE
+
+#include "canvasframerate.moc"
diff --git a/tools/qmldebugger/canvasframerate.h b/tools/qmldebugger/canvasframerate.h
new file mode 100644
index 0000000..912412b
--- /dev/null
+++ b/tools/qmldebugger/canvasframerate.h
@@ -0,0 +1,28 @@
+#ifndef CANVASFRAMERATE_H
+#define CANVASFRAMERATE_H
+
+#include <QWidget>
+
+QT_BEGIN_NAMESPACE
+
+class QmlDebugConnection;
+class QTabWidget;
+class CanvasFrameRate : public QWidget
+{
+ Q_OBJECT
+public:
+ CanvasFrameRate(QmlDebugConnection *, QWidget *parent = 0);
+
+private slots:
+ void newTab();
+ void stateChanged(int);
+
+private:
+ QTabWidget *m_tabs;
+ QObject *m_plugin;
+};
+
+QT_END_NAMESPACE
+
+#endif // CANVASFRAMERATE_H
+
diff --git a/tools/qmldebugger/engine.cpp b/tools/qmldebugger/engine.cpp
new file mode 100644
index 0000000..1f4bcc2
--- /dev/null
+++ b/tools/qmldebugger/engine.cpp
@@ -0,0 +1,251 @@
+#include "engine.h"
+#include <QtDeclarative/qmldebugclient.h>
+#include <QPushButton>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QLineEdit>
+#include <QTreeWidget>
+#include <QTableWidget>
+#include <QFile>
+#include <private/qmlenginedebug_p.h>
+#include <QtDeclarative/qmlcomponent.h>
+#include <QtDeclarative/qfxitem.h>
+
+QT_BEGIN_NAMESPACE
+
+class DebuggerEngineItem : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString name READ name CONSTANT);
+ Q_PROPERTY(int engineId READ engineId CONSTANT);
+
+public:
+ DebuggerEngineItem(const QString &name, int id)
+ : m_name(name), m_engineId(id) {}
+
+ QString name() const { return m_name; }
+ int engineId() const { return m_engineId; }
+
+private:
+ QString m_name;
+ int m_engineId;
+};
+
+EnginePane::EnginePane(QmlDebugConnection *client, QWidget *parent)
+: QWidget(parent), m_client(client), m_engines(0), m_context(0), m_object(0)
+{
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->setContentsMargins(0, 0, 0, 0);
+
+ setLayout(layout);
+
+ QFile enginesFile(":/engines.qml");
+ enginesFile.open(QFile::ReadOnly);
+ Q_ASSERT(enginesFile.isOpen());
+
+ m_engineView = new QFxView(this);
+ m_engineView->rootContext()->setContextProperty("engines", qVariantFromValue(&m_engineItems));
+ m_engineView->setContentResizable(true);
+ m_engineView->setQml(enginesFile.readAll());
+ m_engineView->execute();
+ m_engineView->setFixedHeight(100);
+ QObject::connect(m_engineView->root(), SIGNAL(engineClicked(int)),
+ this, SLOT(engineSelected(int)));
+ QObject::connect(m_engineView->root(), SIGNAL(refreshEngines()),
+ this, SLOT(queryEngines()));
+
+ layout->addWidget(m_engineView);
+
+
+ m_text = new QLineEdit(this);
+ layout->addWidget(m_text);
+
+ QPushButton *query = new QPushButton("Fetch object", this);
+ QObject::connect(query, SIGNAL(clicked()), this, SLOT(fetchClicked()));
+ layout->addWidget(query);
+
+ QHBoxLayout *hbox = new QHBoxLayout;
+ hbox->setContentsMargins(0, 0, 0, 0);
+
+ m_objTree = new QTreeWidget(this);
+ m_objTree->setHeaderHidden(true);
+ connect(m_objTree, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(itemClicked(QTreeWidgetItem *)));
+ hbox->addWidget(m_objTree);
+
+ m_propTable = new QTableWidget(this);
+ m_propTable->setColumnCount(2);
+ m_propTable->setColumnWidth(0, 150);
+ m_propTable->setColumnWidth(1, 400);
+ m_propTable->setHorizontalHeaderLabels(QStringList() << "name" << "value");
+ hbox->addWidget(m_propTable);
+ hbox->setStretchFactor(m_propTable, 2);
+
+ layout->addLayout(hbox);
+}
+
+void EnginePane::engineSelected(int id)
+{
+ qWarning() << "Engine selected" << id;
+ queryContext(id);
+}
+
+void EnginePane::itemClicked(QTreeWidgetItem *item)
+{
+ m_propTable->clearContents();
+
+ if (m_object) {
+ delete m_object;
+ m_object = 0;
+ }
+
+ m_object = m_client.queryObjectRecursive(QmlDebugObjectReference(item->data(0, Qt::UserRole).toInt()), this);
+ if (!m_object->isWaiting())
+ showProperties();
+ else
+ QObject::connect(m_object, SIGNAL(stateChanged(State)),
+ this, SLOT(showProperties()));
+}
+
+void EnginePane::showProperties()
+{
+ QmlDebugObjectReference obj = m_object->object();
+ m_propTable->setRowCount(obj.properties().count());
+ for (int ii = 0; ii < obj.properties().count(); ++ii) {
+ QTableWidgetItem *name = new QTableWidgetItem(obj.properties().at(ii).name());
+ m_propTable->setItem(ii, 0, name);
+ QTableWidgetItem *value;
+ if (!obj.properties().at(ii).binding().isEmpty())
+ value = new QTableWidgetItem(obj.properties().at(ii).binding());
+ else
+ value = new QTableWidgetItem(obj.properties().at(ii).value().toString());
+ m_propTable->setItem(ii, 1, value);
+ }
+ delete m_object; m_object = 0;
+}
+
+void EnginePane::queryContext(int id)
+{
+ if (m_context) {
+ delete m_context;
+ m_context = 0;
+ }
+
+ m_context = m_client.queryRootContexts(QmlDebugEngineReference(id), this);
+ if (!m_context->isWaiting())
+ contextChanged();
+ else
+ QObject::connect(m_context, SIGNAL(stateChanged(State)),
+ this, SLOT(contextChanged()));
+}
+
+void EnginePane::contextChanged()
+{
+ dump(m_context->rootContext(), 0);
+ foreach (const QmlDebugObjectReference &object, m_context->rootContext().objects())
+ fetchObject(object.debugId());
+ delete m_context; m_context = 0;
+}
+
+void EnginePane::dump(const QmlDebugContextReference &ctxt, int ind)
+{
+ QByteArray indent(ind * 4, ' ');
+ qWarning().nospace() << indent.constData() << ctxt.debugId() << " "
+ << qPrintable(ctxt.name());
+
+ for (int ii = 0; ii < ctxt.contexts().count(); ++ii)
+ dump(ctxt.contexts().at(ii), ind + 1);
+
+ for (int ii = 0; ii < ctxt.objects().count(); ++ii)
+ dump(ctxt.objects().at(ii), ind);
+}
+
+void EnginePane::dump(const QmlDebugObjectReference &obj, int ind)
+{
+ QByteArray indent(ind * 4, ' ');
+ qWarning().nospace() << indent.constData() << qPrintable(obj.className())
+ << " " << qPrintable(obj.name()) << " "
+ << obj.debugId();
+
+ for (int ii = 0; ii < obj.children().count(); ++ii)
+ dump(obj.children().at(ii), ind + 1);
+}
+
+
+void EnginePane::buildTree(const QmlDebugObjectReference &obj, QTreeWidgetItem *parent)
+{
+ if (!parent)
+ m_objTree->clear();
+ m_objTree->expandAll();
+
+ QTreeWidgetItem *item = parent ? new QTreeWidgetItem(parent) : new QTreeWidgetItem(m_objTree);
+ item->setText(0, obj.className());
+ item->setData(0, Qt::UserRole, obj.debugId());
+
+ for (int ii = 0; ii < obj.children().count(); ++ii)
+ buildTree(obj.children().at(ii), item);
+
+ if (!parent)
+ m_objTree->expandAll();
+}
+
+void EnginePane::queryEngines()
+{
+ if (m_engines)
+ return;
+
+ m_engines = m_client.queryAvailableEngines(this);
+ if (!m_engines->isWaiting())
+ enginesChanged();
+ else
+ QObject::connect(m_engines, SIGNAL(stateChanged(State)),
+ this, SLOT(enginesChanged()));
+}
+
+void EnginePane::enginesChanged()
+{
+ qDeleteAll(m_engineItems);
+ m_engineItems.clear();
+
+ QList<QmlDebugEngineReference> engines = m_engines->engines();
+ delete m_engines; m_engines = 0;
+
+ for (int ii = 0; ii < engines.count(); ++ii)
+ m_engineItems << new DebuggerEngineItem(engines.at(ii).name(),
+ engines.at(ii).debugId());
+
+ m_engineView->rootContext()->setContextProperty("engines", qVariantFromValue(&m_engineItems));
+}
+
+void EnginePane::fetchClicked()
+{
+ int id = m_text->text().toInt();
+ fetchObject(id);
+}
+
+void EnginePane::fetchObject(int id)
+{
+ if (m_object) {
+ delete m_object;
+ m_object = 0;
+ }
+
+ m_object = m_client.queryObjectRecursive(QmlDebugObjectReference(id), this);
+ if (!m_object->isWaiting())
+ objectFetched();
+ else
+ QObject::connect(m_object, SIGNAL(stateChanged(State)),
+ this, SLOT(objectFetched()));
+}
+
+void EnginePane::objectFetched()
+{
+ dump(m_object->object(), 0);
+ buildTree(m_object->object(), 0);
+ delete m_object; m_object = 0;
+}
+
+
+#include "engine.moc"
+
+QT_END_NAMESPACE
+
diff --git a/tools/qmldebugger/engine.h b/tools/qmldebugger/engine.h
new file mode 100644
index 0000000..52f0608
--- /dev/null
+++ b/tools/qmldebugger/engine.h
@@ -0,0 +1,61 @@
+#ifndef ENGINE_H
+#define ENGINE_H
+
+#include <QWidget>
+#include <QtDeclarative/qmlengine.h>
+#include <QtDeclarative/qmlcontext.h>
+#include <QtDeclarative/qfxview.h>
+#include <QtDeclarative/qmldebug.h>
+
+QT_BEGIN_NAMESPACE
+
+class QmlDebugConnection;
+class EngineClientPlugin;
+class QLineEdit;
+class QTreeWidget;
+class QTreeWidgetItem;
+class QTableWidget;
+class EnginePane : public QWidget
+{
+Q_OBJECT
+public:
+ EnginePane(QmlDebugConnection *, QWidget *parent = 0);
+
+private slots:
+ void queryEngines();
+ void enginesChanged();
+
+ void queryContext(int);
+ void contextChanged();
+
+ void fetchClicked();
+ void fetchObject(int);
+ void objectFetched();
+
+ void engineSelected(int);
+
+ void itemClicked(QTreeWidgetItem *);
+ void showProperties();
+
+private:
+ void dump(const QmlDebugContextReference &, int);
+ void dump(const QmlDebugObjectReference &, int);
+ void buildTree(const QmlDebugObjectReference &, QTreeWidgetItem *parent);
+
+ QmlEngineDebug m_client;
+ QmlDebugEnginesQuery *m_engines;
+ QmlDebugRootContextQuery *m_context;
+ QmlDebugObjectQuery *m_object;
+
+ QLineEdit *m_text;
+ QTreeWidget *m_objTree;
+ QTableWidget *m_propTable;
+
+ QFxView *m_engineView;
+ QList<QObject *> m_engineItems;
+};
+
+QT_END_NAMESPACE
+
+#endif // ENGINE_H
+
diff --git a/tools/qmldebugger/engine.png b/tools/qmldebugger/engine.png
new file mode 100644
index 0000000..a0a8a04
--- /dev/null
+++ b/tools/qmldebugger/engine.png
Binary files differ
diff --git a/tools/qmldebugger/engines.qml b/tools/qmldebugger/engines.qml
new file mode 100644
index 0000000..1652ebd
--- /dev/null
+++ b/tools/qmldebugger/engines.qml
@@ -0,0 +1,46 @@
+import Qt 4.6
+
+Item {
+ height: 100
+ id: Root
+ signal engineClicked(int id)
+ signal refreshEngines()
+
+ Row {
+ anchors.fill: parent
+ Repeater {
+ dataSource: engines
+ Item {
+ width: 100; height: 100;
+ Image {
+ id: Image;
+ source: "qrc:/engine.png"
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ Text {
+ anchors.top: Image.bottom;
+ text: modelData.name + "(" + modelData.engineId + ")"
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ MouseRegion {
+ anchors.fill: parent
+ onClicked: Root.engineClicked(modelData.engineId);
+ }
+ }
+ }
+ }
+
+
+ Image {
+ y: 15
+ source: "qrc:/refresh.png";
+ width: 75;
+ height: 63;
+ smooth: true
+ anchors.right: parent.right
+ MouseRegion {
+ anchors.fill: parent
+ onClicked: Root.refreshEngines()
+ }
+ }
+}
diff --git a/tools/qmldebugger/main.cpp b/tools/qmldebugger/main.cpp
new file mode 100644
index 0000000..a37a437
--- /dev/null
+++ b/tools/qmldebugger/main.cpp
@@ -0,0 +1,137 @@
+#include <QtNetwork/qtcpsocket.h>
+#include <QtGui/qapplication.h>
+#include <QtGui/qwidget.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qscrollbar.h>
+#include <QtDeclarative/qmldebugclient.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qdatastream.h>
+#include "canvasframerate.h"
+#include "engine.h"
+#include <QVBoxLayout>
+#include <QPushButton>
+#include <QLineEdit>
+#include <QTabWidget>
+#include <QSpinBox>
+#include <QLabel>
+
+class Shell : public QWidget
+{
+Q_OBJECT
+public:
+ Shell(QWidget * = 0);
+
+private slots:
+ void connectToHost();
+ void disconnectFromHost();
+ void connectionStateChanged();
+
+private:
+ QmlDebugConnection client;
+
+ QLabel *m_connectionState;
+ QLineEdit *m_host;
+ QSpinBox *m_port;
+ QPushButton *m_connectButton;
+ QPushButton *m_disconnectButton;
+};
+
+Shell::Shell(QWidget *parent)
+: QWidget(parent)
+{
+ QVBoxLayout *layout = new QVBoxLayout;
+ setLayout(layout);
+
+
+ QHBoxLayout *connectLayout = new QHBoxLayout;
+ layout->addLayout(connectLayout);
+ connectLayout->addStretch(2);
+
+ m_connectionState = new QLabel(this);
+ connectLayout->addWidget(m_connectionState);
+ m_host = new QLineEdit(this);
+ m_host->setText("127.0.0.1");
+ connectLayout->addWidget(m_host);
+ m_port = new QSpinBox(this);
+ m_port->setMinimum(1024);
+ m_port->setMaximum(20000);
+ m_port->setValue(3768);
+ connectLayout->addWidget(m_port);
+ m_connectButton = new QPushButton(tr("Connect"), this);
+ QObject::connect(m_connectButton, SIGNAL(clicked()),
+ this, SLOT(connectToHost()));
+ connectLayout->addWidget(m_connectButton);
+ m_disconnectButton = new QPushButton(tr("Disconnect"), this);
+ QObject::connect(m_disconnectButton, SIGNAL(clicked()),
+ this, SLOT(disconnectFromHost()));
+ m_disconnectButton->setEnabled(false);
+ connectLayout->addWidget(m_disconnectButton);
+
+ QTabWidget *tabs = new QTabWidget(this);
+ layout->addWidget(tabs);
+
+ CanvasFrameRate *cfr = new CanvasFrameRate(&client, this);
+ tabs->addTab(cfr, tr("Frame Rate"));
+
+ EnginePane *ep = new EnginePane(&client, this);
+ tabs->addTab(ep, tr("QML Engine"));
+
+ QObject::connect(&client, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(connectionStateChanged()));
+ connectionStateChanged();
+}
+
+void Shell::connectionStateChanged()
+{
+ switch (client.state()) {
+ default:
+ case QAbstractSocket::UnconnectedState:
+ m_connectionState->setText(tr("Disconnected"));
+ m_connectButton->setEnabled(true);
+ m_disconnectButton->setEnabled(false);
+ break;
+ case QAbstractSocket::HostLookupState:
+ m_connectionState->setText(tr("Resolving"));
+ m_connectButton->setEnabled(false);
+ m_disconnectButton->setEnabled(true);
+ break;
+ case QAbstractSocket::ConnectingState:
+ m_connectionState->setText(tr("Connecting"));
+ m_connectButton->setEnabled(false);
+ m_disconnectButton->setEnabled(true);
+ break;
+ case QAbstractSocket::ConnectedState:
+ m_connectionState->setText(tr("Connected"));
+ m_connectButton->setEnabled(false);
+ m_disconnectButton->setEnabled(true);
+ break;
+ case QAbstractSocket::ClosingState:
+ m_connectionState->setText(tr("Closing"));
+ m_connectButton->setEnabled(false);
+ m_disconnectButton->setEnabled(false);
+ break;
+ }
+}
+
+void Shell::connectToHost()
+{
+ client.connectToHost(m_host->text(), m_port->value());
+}
+
+void Shell::disconnectFromHost()
+{
+ client.disconnectFromHost();
+}
+
+int main(int argc, char ** argv)
+{
+ QApplication app(argc, argv);
+
+ Shell shell;
+ shell.show();
+
+
+ return app.exec();
+}
+
+#include "main.moc"
diff --git a/tools/qmldebugger/qmldebugger.pro b/tools/qmldebugger/qmldebugger.pro
new file mode 100644
index 0000000..3935351
--- /dev/null
+++ b/tools/qmldebugger/qmldebugger.pro
@@ -0,0 +1,15 @@
+DESTDIR = ../../bin
+QT += network declarative
+contains(QT_CONFIG, opengles2)|contains(QT_CONFIG, opengles1): QT += opengl
+
+# Input
+HEADERS += canvasframerate.h engine.h
+SOURCES += main.cpp canvasframerate.cpp engine.cpp
+RESOURCES += qmldebugger.qrc
+
+OTHER_FILES += engines.qml
+
+target.path=$$[QT_INSTALL_BINS]
+INSTALLS += target
+
+CONFIG += console
diff --git a/tools/qmldebugger/qmldebugger.qrc b/tools/qmldebugger/qmldebugger.qrc
new file mode 100644
index 0000000..cb53ad5
--- /dev/null
+++ b/tools/qmldebugger/qmldebugger.qrc
@@ -0,0 +1,7 @@
+<RCC>
+ <qresource prefix="/">
+ <file>engines.qml</file>
+ <file>engine.png</file>
+ <file>refresh.png</file>
+ </qresource>
+</RCC>
diff --git a/tools/qmldebugger/refresh.png b/tools/qmldebugger/refresh.png
new file mode 100644
index 0000000..8befc80
--- /dev/null
+++ b/tools/qmldebugger/refresh.png
Binary files differ
diff --git a/tools/qmlviewer/main.cpp b/tools/qmlviewer/main.cpp
new file mode 100644
index 0000000..a4ed054
--- /dev/null
+++ b/tools/qmlviewer/main.cpp
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** 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 "qml.h"
+#include "qmlviewer.h"
+#include <QWidget>
+#include <QDir>
+#include <QApplication>
+#include <QTranslator>
+#include <QDebug>
+
+void usage()
+{
+ qWarning("Usage: qmlviewer [options] <filename>");
+ qWarning(" ");
+ qWarning(" options:");
+ qWarning(" -v, -version ............................. display version");
+ qWarning(" -frameless ............................... run with no window frame");
+ qWarning(" -skin <qvfbskindir> ...................... run with a skin window frame");
+ qWarning(" \"list\" for a list of built-ins");
+ qWarning(" -resizeview .............................. resize the view, not the skin");
+ qWarning(" -recordfile <output> ..................... set video recording file");
+ qWarning(" - ImageMagick 'convert' for GIF)");
+ qWarning(" - png file for raw frames");
+ qWarning(" - 'ffmpeg' for other formats");
+ qWarning(" -recorddither ordered|threshold|floyd .... set GIF dither recording mode");
+ qWarning(" -recordrate <fps> ........................ set recording frame rate");
+ qWarning(" -record arg .............................. add a recording process argument");
+ qWarning(" -autorecord [from-]<tomilliseconds> ...... set recording to start and stop");
+ qWarning(" -devicekeys .............................. use numeric keys (see F1)");
+ qWarning(" -netcache <size> ......................... set disk cache to size bytes");
+ qWarning(" -translation <translationfile> ........... set the language to run in");
+ qWarning(" -L <directory> ........................... prepend to the library search path");
+ qWarning(" ");
+ qWarning(" Press F1 for interactive help");
+ exit(1);
+}
+
+int main(int argc, char ** argv)
+{
+ //### default to using raster graphics backend for now
+ bool gsSpecified = false;
+ for (int i = 0; i < argc; ++i) {
+ QString arg = argv[i];
+ if (arg == "-graphicssystem") {
+ gsSpecified = true;
+ break;
+ }
+ }
+ if (!gsSpecified)
+ QApplication::setGraphicsSystem("raster");
+
+ QApplication app(argc, argv);
+ app.setApplicationName("viewer");
+ app.setOrganizationName("Nokia");
+ app.setOrganizationDomain("nokia.com");
+
+ bool frameless = false;
+ bool resizeview = false;
+ QString fileName;
+ double fps = 0;
+ int autorecord_from = 0;
+ int autorecord_to = 0;
+ QString dither = "none";
+ QString recordfile;
+ QStringList recordargs;
+ QStringList libraries;
+ QString skin;
+ bool devkeys = false;
+ int cache = 0;
+ QString translationFile;
+
+ for (int i = 1; i < argc; ++i) {
+ QString arg = argv[i];
+ if (arg == "-frameless") {
+ frameless = true;
+ } else if (arg == "-skin") {
+ skin = QString(argv[++i]);
+ } else if (arg == "-resizeview") {
+ resizeview = true;
+ } else if (arg == "-netcache") {
+ cache = QString(argv[++i]).toInt();
+ } else if (arg == "-recordrate") {
+ fps = QString(argv[++i]).toDouble();
+ } else if (arg == "-recordfile") {
+ recordfile = QString(argv[++i]);
+ } else if (arg == "-record") {
+ recordargs << QString(argv[++i]);
+ } else if (arg == "-recorddither") {
+ dither = QString(argv[++i]);
+ } else if (arg == "-autorecord") {
+ QString range = QString(argv[++i]);
+ int dash = range.indexOf('-');
+ if (dash > 0)
+ autorecord_from = range.left(dash).toInt();
+ autorecord_to = range.mid(dash+1).toInt();
+ } else if (arg == "-devicekeys") {
+ devkeys = true;
+ } else if (arg == QLatin1String("-v") || arg == QLatin1String("-version")) {
+ 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;
+ } else if (arg == "-L") {
+ libraries << QString(argv[++i]);
+ } else if (arg[0] != '-') {
+ fileName = arg;
+ } else if (1 || arg == "-help") {
+ usage();
+ }
+ }
+
+ QTranslator qmlTranslator;
+ if (!translationFile.isEmpty()) {
+ qmlTranslator.load(translationFile);
+ app.installTranslator(&qmlTranslator);
+ }
+
+ QmlViewer viewer(0, frameless ? Qt::FramelessWindowHint : Qt::Widget);
+ foreach (QString lib, libraries)
+ viewer.addLibraryPath(lib);
+ viewer.setNetworkCacheSize(cache);
+ viewer.setRecordFile(recordfile);
+ if (resizeview)
+ viewer.setScaleView();
+ if (fps>0)
+ viewer.setRecordRate(fps);
+ if (autorecord_to)
+ viewer.setAutoRecord(autorecord_from,autorecord_to);
+ if (!skin.isEmpty()) {
+ if (skin == "list") {
+ foreach (QString s, viewer.builtinSkins())
+ qWarning(s.toUtf8());
+ exit(0);
+ } else {
+ viewer.setSkin(skin);
+ }
+ }
+ if (devkeys)
+ viewer.setDeviceKeys(true);
+ viewer.setRecordDither(dither);
+ if (recordargs.count())
+ viewer.setRecordArgs(recordargs);
+ if (!fileName.isEmpty()) {
+ viewer.openQml(fileName);
+ viewer.show();
+ } else {
+ viewer.show();
+ viewer.open();
+ }
+ viewer.raise();
+
+ return app.exec();
+}
diff --git a/tools/qmlviewer/proxysettings.cpp b/tools/qmlviewer/proxysettings.cpp
new file mode 100644
index 0000000..f232fd1
--- /dev/null
+++ b/tools/qmlviewer/proxysettings.cpp
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** 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 <QIntValidator>
+#include <QSettings>
+
+#include "proxysettings.h"
+
+ProxySettings::ProxySettings (QWidget * parent)
+ : QDialog (parent), Ui::ProxySettings()
+{
+ setupUi (this);
+
+ proxyServerEdit->setInputMask ("000.000.000.000;_");
+ QIntValidator *validator = new QIntValidator (0, 9999, this);
+ proxyPortEdit->setValidator (validator);
+
+ QSettings settings;
+ proxyCheckBox->setChecked (settings.value ("http_proxy/use", 0).toBool ());
+ proxyServerEdit->insert (settings.value ("http_proxy/hostname", "").toString ());
+ proxyPortEdit->insert (settings.value ("http_proxy/port", "80").toString ());
+ usernameEdit->insert (settings.value ("http_proxy/username", "").toString ());
+ passwordEdit->insert (settings.value ("http_proxy/password", "").toString ());
+}
+
+ProxySettings::~ProxySettings()
+{
+}
+
+void ProxySettings::accept ()
+{
+ QSettings settings;
+
+ settings.setValue ("http_proxy/use", proxyCheckBox->isChecked ());
+ settings.setValue ("http_proxy/hostname", proxyServerEdit->text ());
+ settings.setValue ("http_proxy/port", proxyPortEdit->text ());
+ settings.setValue ("http_proxy/username", usernameEdit->text ());
+ settings.setValue ("http_proxy/password", passwordEdit->text ());
+
+ QDialog::accept ();
+}
+
+QNetworkProxy ProxySettings::httpProxy ()
+{
+ QSettings settings;
+ QNetworkProxy proxy;
+
+ bool proxyInUse = settings.value ("http_proxy/use", 0).toBool ();
+ if (proxyInUse) {
+ proxy.setType (QNetworkProxy::HttpProxy);
+ proxy.setHostName (settings.value ("http_proxy/hostname", "").toString ());// "192.168.220.5"
+ proxy.setPort (settings.value ("http_proxy/port", 80).toInt ()); // 8080
+ proxy.setUser (settings.value ("http_proxy/username", "").toString ());
+ proxy.setPassword (settings.value ("http_proxy/password", "").toString ());
+ //QNetworkProxy::setApplicationProxy (proxy);
+ }
+ else {
+ proxy.setType (QNetworkProxy::NoProxy);
+ }
+ return proxy;
+}
+
+bool ProxySettings::httpProxyInUse()
+{
+ QSettings settings;
+ return settings.value ("http_proxy/use", 0).toBool ();
+}
diff --git a/tools/qmlviewer/proxysettings.h b/tools/qmlviewer/proxysettings.h
new file mode 100644
index 0000000..1d4d577
--- /dev/null
+++ b/tools/qmlviewer/proxysettings.h
@@ -0,0 +1,40 @@
+/****************************************************************************
+**
+** 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 PROXYSETTINGS_H
+#define PROXYSETTINGS_H
+
+#include <QDialog>
+#include <QNetworkProxy>
+#include "ui_proxysettings.h"
+
+/**
+*/
+class ProxySettings : public QDialog, public Ui::ProxySettings
+{
+
+Q_OBJECT
+
+public:
+ ProxySettings(QWidget * parent = 0);
+
+ ~ProxySettings();
+
+ static QNetworkProxy httpProxy ();
+ static bool httpProxyInUse ();
+
+public slots:
+ virtual void accept ();
+};
+
+#endif // PROXYSETTINGS_H
diff --git a/tools/qmlviewer/proxysettings.ui b/tools/qmlviewer/proxysettings.ui
new file mode 100644
index 0000000..84e39fe
--- /dev/null
+++ b/tools/qmlviewer/proxysettings.ui
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ProxySettings</class>
+ <widget class="QDialog" name="ProxySettings">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>318</width>
+ <height>199</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0" colspan="2">
+ <widget class="QCheckBox" name="proxyCheckBox">
+ <property name="text">
+ <string>Use http proxy</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="serverAddressLabel">
+ <property name="text">
+ <string>Server Address:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="proxyServerEdit"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Port:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="proxyPortEdit"/>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="usernameLabel">
+ <property name="text">
+ <string>Username:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="usernameEdit"/>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="passwordLabel">
+ <property name="text">
+ <string>Password:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLineEdit" name="passwordEdit">
+ <property name="echoMode">
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0" colspan="2">
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ProxySettings</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ProxySettings</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/tools/qmlviewer/qmlviewer.cpp b/tools/qmlviewer/qmlviewer.cpp
new file mode 100644
index 0000000..272ebcb
--- /dev/null
+++ b/tools/qmlviewer/qmlviewer.cpp
@@ -0,0 +1,1008 @@
+/****************************************************************************
+**
+** 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 <qfxview.h>
+#include "ui_recopts.h"
+
+#include "qmlviewer.h"
+#include <QtDeclarative/qmlcontext.h>
+#include <QtDeclarative/qmlengine.h>
+#include "qml.h"
+#include <private/qperformancelog_p.h>
+#include <QAbstractAnimation>
+#include <private/qabstractanimation_p.h>
+#include "deviceskin.h"
+
+#include <QNetworkDiskCache>
+#include <QNetworkAccessManager>
+#include <QSignalMapper>
+#include <QmlComponent>
+#include <QWidget>
+#include <QApplication>
+#include <QDir>
+#include <QTextBrowser>
+#include <QFile>
+#include <QFileInfo>
+#include <QVBoxLayout>
+#include <QProgressDialog>
+#include <QProcess>
+#include <QMenuBar>
+#include <QMenu>
+#include <QAction>
+#include <QFileDialog>
+#include <QTimer>
+#include <QNetworkProxyFactory>
+#include <QKeyEvent>
+#include "proxysettings.h"
+
+QT_BEGIN_NAMESPACE
+
+class PreviewDeviceSkin : public DeviceSkin
+{
+ Q_OBJECT
+public:
+ explicit PreviewDeviceSkin(const DeviceSkinParameters &parameters, QWidget *parent);
+
+ void setPreview(QWidget *formWidget);
+ void setPreviewAndScale(QWidget *formWidget);
+
+ void setScreenSize(const QSize& size)
+ {
+ QMatrix fit;
+ fit = fit.scale(qreal(size.width())/m_screenSize.width(),
+ qreal(size.height())/m_screenSize.height());
+ setTransform(fit);
+ QApplication::syncX();
+ }
+
+ QSize standardScreenSize() const { return m_screenSize; }
+
+ QMenu* menu;
+
+private slots:
+ void slotSkinKeyPressEvent(int code, const QString& text, bool autorep);
+ void slotSkinKeyReleaseEvent(int code, const QString& text, bool autorep);
+ void slotPopupMenu();
+
+private:
+ const QSize m_screenSize;
+};
+
+
+PreviewDeviceSkin::PreviewDeviceSkin(const DeviceSkinParameters &parameters, QWidget *parent) :
+ DeviceSkin(parameters, parent),
+ m_screenSize(parameters.screenSize())
+{
+ menu = new QMenu(this);
+ connect(this, SIGNAL(skinKeyPressEvent(int,QString,bool)),
+ this, SLOT(slotSkinKeyPressEvent(int,QString,bool)));
+ connect(this, SIGNAL(skinKeyReleaseEvent(int,QString,bool)),
+ this, SLOT(slotSkinKeyReleaseEvent(int,QString,bool)));
+ connect(this, SIGNAL(popupMenu()), this, SLOT(slotPopupMenu()));
+}
+
+void PreviewDeviceSkin::setPreview(QWidget *formWidget)
+{
+ formWidget->setFixedSize(m_screenSize);
+ formWidget->setParent(this, Qt::SubWindow);
+ formWidget->setAutoFillBackground(true);
+ setView(formWidget);
+}
+
+void PreviewDeviceSkin::setPreviewAndScale(QWidget *formWidget)
+{
+ setScreenSize(formWidget->sizeHint());
+ formWidget->setParent(this, Qt::SubWindow);
+ formWidget->setAutoFillBackground(true);
+ setView(formWidget);
+}
+
+void PreviewDeviceSkin::slotSkinKeyPressEvent(int code, const QString& text, bool autorep)
+{
+ if (QWidget *focusWidget = QApplication::focusWidget()) {
+ QKeyEvent e(QEvent::KeyPress,code,0,text,autorep);
+ QApplication::sendEvent(focusWidget, &e);
+ }
+
+}
+
+void PreviewDeviceSkin::slotSkinKeyReleaseEvent(int code, const QString& text, bool autorep)
+{
+ if (QWidget *focusWidget = QApplication::focusWidget()) {
+ QKeyEvent e(QEvent::KeyRelease,code,0,text,autorep);
+ QApplication::sendEvent(focusWidget, &e);
+ }
+}
+
+void PreviewDeviceSkin::slotPopupMenu()
+{
+ menu->exec(QCursor::pos());
+}
+
+static struct { const char *name, *args; } ffmpegprofiles[] = {
+ {"Maximum Quality", "-sameq"},
+ {"High Quality", "-qmax 2"},
+ {"Medium Quality", "-qmax 6"},
+ {"Low Quality", "-qmax 16"},
+ {"Custom ffmpeg arguments", ""},
+ {0,0}
+};
+
+class RecordingDialog : public QDialog, public Ui::RecordingOptions {
+ Q_OBJECT
+
+public:
+ RecordingDialog(QWidget *parent) : QDialog(parent)
+ {
+ setupUi(this);
+ hz->setValidator(new QDoubleValidator(hz));
+ for (int i=0; ffmpegprofiles[i].name; ++i) {
+ profile->addItem(ffmpegprofiles[i].name);
+ }
+ }
+
+ void setArguments(QString a)
+ {
+ int i;
+ for (i=0; ffmpegprofiles[i].args[0]; ++i) {
+ if (ffmpegprofiles[i].args == a) {
+ profile->setCurrentIndex(i);
+ args->setText(QLatin1String(ffmpegprofiles[i].args));
+ return;
+ }
+ }
+ customargs = a;
+ args->setText(a);
+ profile->setCurrentIndex(i);
+ }
+
+ QString arguments() const
+ {
+ int i = profile->currentIndex();
+ return ffmpegprofiles[i].args[0] ? QLatin1String(ffmpegprofiles[i].args) : customargs;
+ }
+
+private slots:
+ void pickProfile(int i)
+ {
+ if (ffmpegprofiles[i].args[0]) {
+ args->setText(QLatin1String(ffmpegprofiles[i].args));
+ } else {
+ args->setText(customargs);
+ }
+ }
+
+ void storeCustomArgs(QString s)
+ {
+ setArguments(s);
+ }
+
+private:
+ QString customargs;
+};
+
+class ConfiguredNetworkAccessManager : public QNetworkAccessManager {
+public:
+ ConfiguredNetworkAccessManager() { }
+
+ QNetworkReply *createRequest (Operation op, const QNetworkRequest &req, QIODevice * outgoingData)
+ {
+ QNetworkRequest request = req;
+ request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
+ request.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
+ return QNetworkAccessManager::createRequest(op,request,outgoingData);
+ }
+};
+
+QString QmlViewer::getVideoFileName()
+{
+ QString title = convertAvailable || ffmpegAvailable ? tr("Save Video File") : tr("Save PNG Frames");
+ QStringList types;
+ if (ffmpegAvailable) types += tr("Common Video files")+QLatin1String(" (*.avi *.mpeg *.mov)");
+ if (convertAvailable) types += tr("GIF Animation")+QLatin1String(" (*.gif)");
+ types += tr("Individual PNG frames")+QLatin1String(" (*.png)");
+ if (ffmpegAvailable) types += tr("All ffmpeg formats (*.*)");
+ return QFileDialog::getSaveFileName(this, title, "", types.join(";; "));
+}
+
+
+QmlViewer::QmlViewer(QWidget *parent, Qt::WindowFlags flags)
+ : QWidget(parent, flags), frame_stream(0), scaleSkin(true), mb(0)
+{
+ devicemode = false;
+ skin = 0;
+ canvas = 0;
+ record_autotime = 0;
+ record_rate = 50;
+ record_args += QLatin1String("-sameq");
+
+ recdlg = new RecordingDialog(this);
+ connect(recdlg->pickfile, SIGNAL(clicked()), this, SLOT(pickRecordingFile()));
+ senseFfmpeg();
+ senseImageMagick();
+ if (!ffmpegAvailable)
+ recdlg->ffmpegOptions->hide();
+ if (!ffmpegAvailable && !convertAvailable)
+ recdlg->rateOptions->hide();
+ QString warn;
+ if (!ffmpegAvailable) {
+ if (!convertAvailable)
+ warn = tr("ffmpeg and ImageMagick not available - no video output");
+ else
+ warn = tr("ffmpeg not available - GIF and PNG outputs only");
+ recdlg->warning->setText(warn);
+ } else {
+ recdlg->warning->hide();
+ }
+
+
+ if (!(flags & Qt::FramelessWindowHint))
+ createMenu(menuBar(),0);
+
+ canvas = new QFxView(this);
+ canvas->setAttribute(Qt::WA_OpaquePaintEvent);
+ canvas->setAttribute(Qt::WA_NoSystemBackground);
+ canvas->setContentResizable(!skin || !scaleSkin);
+ canvas->engine()->setNetworkAccessManager(new ConfiguredNetworkAccessManager);
+ canvas->setFocus();
+
+ QObject::connect(canvas, SIGNAL(sceneResized(QSize)), this, SLOT(sceneResized(QSize)));
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->setMargin(0);
+ layout->setSpacing(0);
+ setLayout(layout);
+ if (mb)
+ layout->addWidget(mb);
+ layout->addWidget(canvas);
+
+ setupProxy();
+
+ connect(&autoStartTimer, SIGNAL(triggered()), this, SLOT(autoStartRecording()));
+ connect(&autoStopTimer, SIGNAL(triggered()), this, SLOT(autoStopRecording()));
+ connect(&recordTimer, SIGNAL(triggered()), this, SLOT(recordFrame()));
+ autoStartTimer.setRunning(false);
+ autoStopTimer.setRunning(false);
+ recordTimer.setRunning(false);
+ recordTimer.setRepeating(true);
+}
+
+QMenuBar *QmlViewer::menuBar() const
+{
+ if (!mb)
+ mb = new QMenuBar((QWidget*)this);
+
+ return mb;
+}
+
+void QmlViewer::createMenu(QMenuBar *menu, QMenu *flatmenu)
+{
+ QObject *parent = flatmenu ? (QObject*)flatmenu : (QObject*)menu;
+
+ QMenu *fileMenu = flatmenu ? flatmenu : menu->addMenu(tr("&File"));
+
+ QAction *openAction = new QAction(tr("&Open..."), parent);
+ openAction->setShortcut(QKeySequence("Ctrl+O"));
+ connect(openAction, SIGNAL(triggered()), this, SLOT(open()));
+ fileMenu->addAction(openAction);
+
+ QAction *reloadAction = new QAction(tr("&Reload"), parent);
+ reloadAction->setShortcut(QKeySequence("Ctrl+R"));
+ connect(reloadAction, SIGNAL(triggered()), this, SLOT(reload()));
+ fileMenu->addAction(reloadAction);
+
+ if (flatmenu) flatmenu->addSeparator();
+
+ QMenu *recordMenu = flatmenu ? flatmenu : menu->addMenu(tr("&Recording"));
+
+ QAction *snapshotAction = new QAction(tr("&Take Snapsot\tF3"), parent);
+ connect(snapshotAction, SIGNAL(triggered()), this, SLOT(takeSnapShot()));
+ recordMenu->addAction(snapshotAction);
+
+ recordAction = new QAction(tr("Start Recording &Video\tF2"), parent);
+ connect(recordAction, SIGNAL(triggered()), this, SLOT(toggleRecordingWithSelection()));
+ recordMenu->addAction(recordAction);
+
+ QAction *recordOptions = new QAction(tr("Video &Options..."), parent);
+ connect(recordOptions, SIGNAL(triggered()), this, SLOT(chooseRecordingOptions()));
+
+ if (flatmenu)
+ flatmenu->addAction(recordOptions);
+
+ if (flatmenu) flatmenu->addSeparator();
+
+ QMenu *skinMenu = flatmenu ? flatmenu->addMenu(tr("&Skin")) : menu->addMenu(tr("&Skin"));
+
+ QActionGroup *skinActions;
+ QAction *skinAction;
+
+ skinActions = new QActionGroup(parent);
+ skinAction = new QAction(tr("Scale skin"), parent);
+ skinAction->setCheckable(true);
+ skinAction->setChecked(scaleSkin);
+ skinActions->addAction(skinAction);
+ skinMenu->addAction(skinAction);
+ connect(skinAction, SIGNAL(triggered()), this, SLOT(setScaleSkin()));
+ skinAction = new QAction(tr("Resize view"), parent);
+ skinAction->setCheckable(true);
+ skinAction->setChecked(!scaleSkin);
+ skinActions->addAction(skinAction);
+ skinMenu->addAction(skinAction);
+ connect(skinAction, SIGNAL(triggered()), this, SLOT(setScaleView()));
+ skinMenu->addSeparator();
+
+ skinActions = new QActionGroup(parent);
+ QSignalMapper *mapper = new QSignalMapper(parent);
+ skinAction = new QAction(tr("None"), parent);
+ skinAction->setCheckable(true);
+ if (currentSkin.isEmpty())
+ skinAction->setChecked(true);
+ skinActions->addAction(skinAction);
+ skinMenu->addAction(skinAction);
+ mapper->setMapping(skinAction, "");
+ connect(skinAction, SIGNAL(triggered()), mapper, SLOT(map()));
+ skinMenu->addSeparator();
+
+ foreach (QString name, builtinSkins()) {
+ skinAction = new QAction(name, parent);
+ skinActions->addAction(skinAction);
+ skinMenu->addAction(skinAction);
+ skinAction->setCheckable(true);
+ if (":skin/"+name+".skin" == currentSkin)
+ skinAction->setChecked(true);
+ mapper->setMapping(skinAction, name);
+ connect(skinAction, SIGNAL(triggered()), mapper, SLOT(map()));
+ }
+ connect(mapper, SIGNAL(mapped(QString)), this, SLOT(setSkin(QString)));
+
+ if (flatmenu) flatmenu->addSeparator();
+
+ QMenu *settingsMenu = flatmenu ? flatmenu : menu->addMenu(tr("S&ettings"));
+ QAction *proxyAction = new QAction(tr("Http &proxy..."), parent);
+ connect(proxyAction, SIGNAL(triggered()), this, SLOT(showProxySettings()));
+ settingsMenu->addAction(proxyAction);
+ if (!flatmenu)
+ settingsMenu->addAction(recordOptions);
+
+ if (flatmenu) flatmenu->addSeparator();
+
+ QMenu *helpMenu = flatmenu ? flatmenu : menu->addMenu(tr("&Help"));
+ QAction *aboutAction = new QAction(tr("&About Qt..."), parent);
+ connect(aboutAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
+ helpMenu->addAction(aboutAction);
+
+ QAction *quitAction = new QAction(tr("&Quit"), parent);
+ quitAction->setShortcut(QKeySequence("Ctrl+Q"));
+ connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
+ fileMenu->addSeparator();
+ fileMenu->addAction(quitAction);
+ if (menu) {
+ menu->setFixedHeight(menu->sizeHint().height());
+ menu->setMinimumWidth(10);
+ }
+}
+
+void QmlViewer::showProxySettings()
+{
+ ProxySettings settingsDlg (this);
+
+ connect (&settingsDlg, SIGNAL (accepted()), this, SLOT (proxySettingsChanged ()));
+
+ settingsDlg.exec();
+}
+
+void QmlViewer::proxySettingsChanged()
+{
+ setupProxy ();
+ reload ();
+}
+
+void QmlViewer::setScaleSkin()
+{
+ if (scaleSkin)
+ return;
+ scaleSkin = true;
+ canvas->setContentResizable(!skin || !scaleSkin);
+ if (skin) {
+ canvas->setFixedSize(canvas->sizeHint());
+ skin->setScreenSize(canvas->sizeHint());
+ }
+}
+
+void QmlViewer::setScaleView()
+{
+ if (!scaleSkin)
+ return;
+ scaleSkin = false;
+ if (skin) {
+ canvas->setContentResizable(!skin || !scaleSkin);
+ canvas->setMinimumSize(QSize(0,0));
+ canvas->setMaximumSize(QSize(16777215,16777215));
+ canvas->resize(skin->standardScreenSize());
+ skin->setScreenSize(skin->standardScreenSize());
+ }
+}
+
+
+void QmlViewer::takeSnapShot()
+{
+ static int snapshotcount = 1;
+ QString snapFileName = QString(QLatin1String("snapshot%1.png")).arg(snapshotcount);
+ QPixmap::grabWidget(canvas).save(snapFileName);
+ qDebug() << "Wrote" << snapFileName;
+ ++snapshotcount;
+}
+
+void QmlViewer::pickRecordingFile()
+{
+ QString fileName = getVideoFileName();
+ if (!fileName.isEmpty())
+ recdlg->file->setText(fileName);
+}
+
+void QmlViewer::chooseRecordingOptions()
+{
+ // File
+ recdlg->file->setText(record_file);
+
+ // Size
+ recdlg->sizeOriginal->setText(tr("Original (%1x%2)").arg(canvas->width()).arg(canvas->height()));
+ if (recdlg->sizeWidth->value()<=1) {
+ recdlg->sizeWidth->setValue(canvas->width());
+ recdlg->sizeHeight->setValue(canvas->height());
+ }
+
+ // Rate
+ if (record_rate == 24)
+ recdlg->hz24->setChecked(true);
+ else if (record_rate == 25)
+ recdlg->hz25->setChecked(true);
+ else if (record_rate == 50)
+ recdlg->hz50->setChecked(true);
+ else if (record_rate == 60)
+ recdlg->hz60->setChecked(true);
+ else {
+ recdlg->hzCustom->setChecked(true);
+ recdlg->hz->setText(QString::number(record_rate));
+ }
+
+ // Profile
+ recdlg->setArguments(record_args.join(" "));
+ if (recdlg->exec()) {
+ // File
+ record_file = recdlg->file->text();
+ // Size
+ if (recdlg->sizeOriginal->isChecked())
+ record_outsize = QSize();
+ else if (recdlg->size720p->isChecked())
+ record_outsize = QSize(1280,720);
+ else if (recdlg->sizeVGA->isChecked())
+ record_outsize = QSize(640,480);
+ else if (recdlg->sizeQVGA->isChecked())
+ record_outsize = QSize(320,240);
+ else
+ record_outsize = QSize(recdlg->sizeWidth->value(),recdlg->sizeHeight->value());
+ // Rate
+ if (recdlg->hz24->isChecked())
+ record_rate = 24;
+ else if (recdlg->hz25->isChecked())
+ record_rate = 25;
+ else if (recdlg->hz50->isChecked())
+ record_rate = 50;
+ else if (recdlg->hz60->isChecked())
+ record_rate = 60;
+ else {
+ record_rate = recdlg->hz->text().toDouble();
+ }
+ // Profile
+ record_args = recdlg->arguments().split(" ",QString::SkipEmptyParts);
+ }
+}
+
+void QmlViewer::toggleRecordingWithSelection()
+{
+ if (!recordTimer.isRunning()) {
+ if (record_file.isEmpty()) {
+ QString fileName = getVideoFileName();
+ if (fileName.isEmpty())
+ return;
+ if (!fileName.contains(QRegExp(".[^\\/]*$")))
+ fileName += ".avi";
+ setRecordFile(fileName);
+ }
+ }
+ toggleRecording();
+}
+
+void QmlViewer::toggleRecording()
+{
+ if (record_file.isEmpty()) {
+ toggleRecordingWithSelection();
+ return;
+ }
+ bool recording = !recordTimer.isRunning();
+ recordAction->setText(recording ? tr("&Stop Recording Video\tF2") : tr("&Start Recording Video\tF2"));
+ setRecording(recording);
+}
+
+void QmlViewer::addLibraryPath(const QString& lib)
+{
+ canvas->engine()->addImportPath(lib);
+}
+
+void QmlViewer::reload()
+{
+ openQml(currentFileName);
+}
+
+void QmlViewer::open()
+{
+ QString fileName = QFileDialog::getOpenFileName(this, tr("Open QML file"), "", tr("QML Files (*.qml)"));
+ if (!fileName.isEmpty()) {
+ openQml(fileName);
+ QTimer::singleShot(0, this, SLOT(reload()));
+ }
+}
+
+void QmlViewer::openQml(const QString& fileName)
+{
+ setWindowTitle(tr("%1 - Qt Declarative UI Viewer").arg(fileName));
+
+ canvas->reset();
+
+ currentFileName = fileName;
+ QUrl url(fileName);
+ QFileInfo fi(fileName);
+ if (fi.exists()) {
+ url = QUrl::fromLocalFile(fi.absoluteFilePath());
+ QmlContext *ctxt = canvas->rootContext();
+ QDir dir(fi.path()+"/dummydata", "*.qml");
+ QStringList list = dir.entryList();
+ for (int i = 0; i < list.size(); ++i) {
+ QString qml = list.at(i);
+ QFile f(dir.filePath(qml));
+ f.open(QIODevice::ReadOnly);
+ QByteArray data = f.readAll();
+ QmlComponent comp(canvas->engine());
+ comp.setData(data, QUrl());
+ QObject *dummyData = comp.create();
+
+ if(comp.isError()) {
+ QList<QmlError> errors = comp.errors();
+ foreach (const QmlError &error, errors) {
+ qWarning() << error;
+ }
+ }
+
+ if (dummyData) {
+ qWarning() << "Loaded dummy data:" << dir.filePath(qml);
+ qml.truncate(qml.length()-4);
+ ctxt->setContextProperty(qml, dummyData);
+ dummyData->setParent(this);
+ }
+ }
+ }
+
+ canvas->setUrl(url);
+
+ QTime t;
+ t.start();
+ canvas->execute();
+ qWarning() << "Wall startup time:" << t.elapsed();
+
+ if (!skin) {
+ canvas->resize(canvas->sizeHint());
+ resize(sizeHint());
+ } else {
+ if (scaleSkin)
+ canvas->resize(canvas->sizeHint());
+ else {
+ canvas->setFixedSize(skin->standardScreenSize());
+ canvas->resize(skin->standardScreenSize());
+ }
+ }
+
+#ifdef QTOPIA
+ show();
+#endif
+}
+
+QStringList QmlViewer::builtinSkins() const
+{
+ QDir dir(":/skins/","*.skin");
+ const QFileInfoList l = dir.entryInfoList();
+ QStringList r;
+ for (QFileInfoList::const_iterator it = l.begin(); it != l.end(); ++it) {
+ r += (*it).baseName();
+ }
+ return r;
+}
+
+void QmlViewer::setSkin(const QString& skinDirOrName)
+{
+ QString skinDirectory = skinDirOrName;
+
+ if (!QDir(skinDirOrName).exists() && QDir(":/skins/"+skinDirOrName+".skin").exists())
+ skinDirectory = ":/skins/"+skinDirOrName+".skin";
+
+ if (currentSkin == skinDirectory)
+ return;
+
+ currentSkin = skinDirectory;
+
+ // XXX QWidget::setMask does not handle changes well, and we may
+ // XXX have been signalled from an item in a menu we're replacing,
+ // XXX hence some rather convoluted resetting here...
+
+ QString err;
+ if (skin) {
+ skin->hide();
+ skin->deleteLater();
+ }
+
+ canvas->setContentResizable(!skin || !scaleSkin);
+
+ DeviceSkinParameters parameters;
+ if (!skinDirectory.isEmpty() && parameters.read(skinDirectory,DeviceSkinParameters::ReadAll,&err)) {
+ layout()->setEnabled(false);
+ //setMenuBar(0);
+ if (mb)
+ mb->hide();
+ if (!err.isEmpty())
+ qWarning() << err;
+ skin = new PreviewDeviceSkin(parameters,this);
+ canvas->resize(canvas->sizeHint());
+ if (scaleSkin)
+ skin->setPreviewAndScale(canvas);
+ else
+ skin->setPreview(canvas);
+ createMenu(0,skin->menu);
+ skin->show();
+ } else {
+ skin = 0;
+ clearMask();
+ menuBar()->clear();
+ canvas->setParent(this, Qt::SubWindow);
+ createMenu(menuBar(),0);
+ mb->show();
+ setMinimumSize(QSize(0,0));
+ setMaximumSize(QSize(16777215,16777215));
+ canvas->setMinimumSize(QSize(0,0));
+ canvas->setMaximumSize(QSize(16777215,16777215));
+ QRect g = geometry();
+ g.setSize(sizeHint());
+ setParent(0,windowFlags()); // recreate
+ canvas->move(0,menuBar()->sizeHint().height());
+ setGeometry(g);
+ layout()->setEnabled(true);
+ show();
+ }
+ canvas->show();
+}
+
+void QmlViewer::setAutoRecord(int from, int to)
+{
+ if (from==0) from=1; // ensure resized
+ record_autotime = to-from;
+ autoStartTimer.setInterval(from);
+ autoStartTimer.setRunning(true);
+}
+
+void QmlViewer::setRecordArgs(const QStringList& a)
+{
+ record_args = a;
+}
+
+void QmlViewer::setRecordFile(const QString& f)
+{
+ record_file = f;
+}
+
+void QmlViewer::setRecordRate(int fps)
+{
+ record_rate = fps;
+}
+
+void QmlViewer::sceneResized(QSize size)
+{
+ if (size.width() > 0 && size.height() > 0) {
+ if (skin && scaleSkin)
+ skin->setScreenSize(size);
+ }
+}
+
+void QmlViewer::keyPressEvent(QKeyEvent *event)
+{
+ if (event->key() == Qt::Key_0 && devicemode)
+ exit(0);
+ else if (event->key() == Qt::Key_F1 || (event->key() == Qt::Key_1 && devicemode)) {
+ qDebug() << "F1 - help\n"
+ << "F2 - toggle video recording\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"
+ << "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_F3 || (event->key() == Qt::Key_3 && devicemode)) {
+ takeSnapShot();
+ } else if (event->key() == Qt::Key_F5 || (event->key() == Qt::Key_5 && devicemode)) {
+ reload();
+ } else if (event->key() == Qt::Key_F8 || (event->key() == Qt::Key_8 && devicemode)) {
+ QPerformanceLog::displayData();
+ QPerformanceLog::clear();
+ }
+
+ QWidget::keyPressEvent(event);
+}
+
+void QmlViewer::senseImageMagick()
+{
+ QProcess proc;
+ proc.start("convert", QStringList() << "-h");
+ proc.waitForFinished(2000);
+ QString help = proc.readAllStandardOutput();
+ convertAvailable = help.contains("ImageMagick");
+}
+
+void QmlViewer::senseFfmpeg()
+{
+ QProcess proc;
+ proc.start("ffmpeg", QStringList() << "-h");
+ proc.waitForFinished(2000);
+ QString ffmpegHelp = proc.readAllStandardOutput();
+ ffmpegAvailable = ffmpegHelp.contains("-s ");
+ ffmpegHelp = tr("Video recording uses ffmpeg:")+"\n\n"+ffmpegHelp;
+
+ QDialog *d = new QDialog(recdlg);
+ QVBoxLayout *l = new QVBoxLayout(d);
+ QTextBrowser *b = new QTextBrowser(d);
+ QFont f = b->font();
+ f.setFamily("courier");
+ b->setFont(f);
+ b->setText(ffmpegHelp);
+ l->addWidget(b);
+ d->setLayout(l);
+ ffmpegHelpWindow = d;
+ connect(recdlg->ffmpegHelp,SIGNAL(clicked()), ffmpegHelpWindow, SLOT(show()));
+}
+
+void QmlViewer::setRecording(bool on)
+{
+ if (on == recordTimer.isRunning())
+ return;
+
+ int period = int(1000/record_rate+0.5);
+ QUnifiedTimer::instance()->setTimingInterval(on ? period:16);
+ QUnifiedTimer::instance()->setConsistentTiming(on);
+ if (on) {
+ canvas->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
+ recordTimer.setInterval(period);
+ recordTimer.setRunning(true);
+ frame_fmt = record_file.right(4).toLower();
+ frame = QImage(canvas->width(),canvas->height(),QImage::Format_RGB32);
+ if (frame_fmt != ".png" && (!convertAvailable || frame_fmt != ".gif")) {
+ // Stream video to ffmpeg
+
+ QProcess *proc = new QProcess(this);
+ connect(proc, SIGNAL(finished(int)), this, SLOT(ffmpegFinished(int)));
+ frame_stream = proc;
+
+ QStringList args;
+ args << "-y";
+ args << "-r" << QString::number(record_rate);
+ args << "-f" << "rawvideo";
+ args << "-pix_fmt" << (frame_fmt == ".gif" ? "rgb24" : "rgb32");
+ args << "-s" << QString("%1x%2").arg(canvas->width()).arg(canvas->height());
+ args << "-i" << "-";
+ if (record_outsize.isValid()) {
+ args << "-s" << QString("%1x%2").arg(record_outsize.width()).arg(record_outsize.height());
+ args << "-aspect" << QString::number(double(canvas->width())/canvas->height());
+ }
+ args += record_args;
+ args << record_file;
+ proc->start("ffmpeg",args);
+
+ } else {
+ // Store frames, save to GIF/PNG
+ frame_stream = 0;
+ }
+ } else {
+ canvas->setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate);
+ recordTimer.setRunning(false);
+ if (frame_stream) {
+ qDebug() << "Saving video...";
+ frame_stream->close();
+ qDebug() << "Wrote" << record_file;
+ } else {
+ QProgressDialog progress(tr("Saving frames..."), tr("Cancel"), 0, frames.count()+10, this);
+ progress.setWindowModality(Qt::WindowModal);
+
+ int frame=0;
+ QStringList inputs;
+ qDebug() << "Saving frames...";
+
+ QString framename;
+ bool png_output = false;
+ if (record_file.right(4).toLower()==".png") {
+ if (record_file.contains('%'))
+ framename = record_file;
+ else
+ framename = record_file.left(record_file.length()-4)+"%04d"+record_file.right(4);
+ png_output = true;
+ } else {
+ framename = "tmp-frame%04d.png";
+ png_output = false;
+ }
+ foreach (QImage* img, frames) {
+ progress.setValue(progress.value()+1);
+ if (progress.wasCanceled())
+ break;
+ QString name;
+ name.sprintf(framename.toLocal8Bit(),frame++);
+ if (record_outsize.isValid())
+ *img = img->scaled(record_outsize,Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
+ if (record_dither=="ordered")
+ img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither|Qt::OrderedDither).save(name);
+ else if (record_dither=="threshold")
+ img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither|Qt::ThresholdDither).save(name);
+ else if (record_dither=="floyd")
+ img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither).save(name);
+ else
+ img->save(name);
+ inputs << name;
+ delete img;
+ }
+
+ if (!progress.wasCanceled()) {
+ if (png_output) {
+ framename.replace(QRegExp("%\\d*."),"*");
+ qDebug() << "Wrote frames" << framename;
+ inputs.clear(); // don't remove them
+ } else {
+ // ImageMagick and gifsicle for GIF encoding
+ progress.setLabelText(tr("Converting frames to GIF file..."));
+ QStringList args;
+ args << "-delay" << QString::number(period/10);
+ args << inputs;
+ args << record_file;
+ qDebug() << "Converting..." << record_file << "(this may take a while)";
+ if (0!=QProcess::execute("convert", args)) {
+ qWarning() << "Cannot run ImageMagick 'convert' - recorded frames not converted";
+ inputs.clear(); // don't remove them
+ qDebug() << "Wrote frames tmp-frame*.png";
+ } else {
+ if (record_file.right(4).toLower() == ".gif") {
+ qDebug() << "Compressing..." << record_file;
+ if (0!=QProcess::execute("gifsicle", QStringList() << "-O2" << "-o" << record_file << record_file))
+ qWarning() << "Cannot run 'gifsicle' - not compressed";
+ }
+ qDebug() << "Wrote" << record_file;
+ }
+ }
+ }
+
+ progress.setValue(progress.maximum()-1);
+ foreach (QString name, inputs)
+ QFile::remove(name);
+
+ frames.clear();
+ }
+ }
+ qDebug() << "Recording: " << (recordTimer.isRunning()?"ON":"OFF");
+}
+
+void QmlViewer::ffmpegFinished(int code)
+{
+ qDebug() << "ffmpeg returned" << code << frame_stream->readAllStandardError();
+}
+
+void QmlViewer::autoStartRecording()
+{
+ setRecording(true);
+ autoStopTimer.setInterval(record_autotime);
+ autoStopTimer.setRunning(true);
+}
+
+void QmlViewer::autoStopRecording()
+{
+ setRecording(false);
+}
+
+void QmlViewer::recordFrame()
+{
+ canvas->QWidget::render(&frame);
+ if (frame_stream) {
+ if (frame_fmt == ".gif") {
+ // ffmpeg can't do 32bpp with gif
+ QImage rgb24 = frame.convertToFormat(QImage::Format_RGB888);
+ frame_stream->write((char*)rgb24.bits(),rgb24.numBytes());
+ } else {
+ frame_stream->write((char*)frame.bits(),frame.numBytes());
+ }
+ } else {
+ frames.append(new QImage(frame));
+ }
+}
+
+void QmlViewer::setDeviceKeys(bool on)
+{
+ devicemode = on;
+}
+
+void QmlViewer::setupProxy()
+{
+ class SystemProxyFactory : public QNetworkProxyFactory
+ {
+ public:
+ virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query)
+ {
+ QString protocolTag = query.protocolTag();
+ if (httpProxyInUse && (protocolTag == "http" || protocolTag == "https")) {
+ QList<QNetworkProxy> ret;
+ ret << httpProxy;
+ return ret;
+ }
+ return QNetworkProxyFactory::systemProxyForQuery(query);
+ }
+ void setHttpProxy (QNetworkProxy proxy)
+ {
+ httpProxy = proxy;
+ httpProxyInUse = true;
+ }
+ void unsetHttpProxy ()
+ {
+ httpProxyInUse = false;
+ }
+ private:
+ bool httpProxyInUse;
+ QNetworkProxy httpProxy;
+ };
+
+ QNetworkAccessManager * nam = canvas->engine()->networkAccessManager();
+ SystemProxyFactory *proxyFactory = new SystemProxyFactory;
+ if (ProxySettings::httpProxyInUse())
+ proxyFactory->setHttpProxy(ProxySettings::httpProxy());
+ else
+ proxyFactory->unsetHttpProxy();
+ nam->setProxyFactory(proxyFactory);
+}
+
+void QmlViewer::setNetworkCacheSize(int size)
+{
+ QNetworkAccessManager * nam = canvas->engine()->networkAccessManager();
+ QNetworkDiskCache *cache = qobject_cast<QNetworkDiskCache*>(nam->cache());
+ if (!cache) {
+ if (size==0)
+ return;
+ cache = new QNetworkDiskCache;
+ cache->setCacheDirectory(QDir::tempPath()+QLatin1String("/qml-duiviewer-network-cache"));
+ nam->setCache(cache);
+ }
+ if (size == cache->maximumCacheSize())
+ return;
+ if (size>0) {
+ // Setup a caching network manager
+ cache->setMaximumCacheSize(size);
+ } else {
+ nam->setCache(0);
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "qmlviewer.moc"
diff --git a/tools/qmlviewer/qmlviewer.h b/tools/qmlviewer/qmlviewer.h
new file mode 100644
index 0000000..c03c09f
--- /dev/null
+++ b/tools/qmlviewer/qmlviewer.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** 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 QMLVIEWER_H
+#define QMLVIEWER_H
+
+#include <QMenuBar>
+#include <QmlTimer>
+#include <QTime>
+#include <QList>
+
+QT_BEGIN_NAMESPACE
+
+class QFxView;
+class PreviewDeviceSkin;
+class QFxTestEngine;
+class QProcess;
+class RecordingDialog;
+
+class QmlViewer : public QWidget
+{
+Q_OBJECT
+public:
+ QmlViewer(QWidget *parent=0, Qt::WindowFlags flags=0);
+
+ void setRecordDither(const QString& s) { record_dither = s; }
+ void setRecordRate(int fps);
+ void setRecordFile(const QString&);
+ void setRecordArgs(const QStringList&);
+ void setRecording(bool on);
+ bool isRecording() const { return recordTimer.isRunning(); }
+ void setAutoRecord(int from, int to);
+ void setDeviceKeys(bool);
+ void setNetworkCacheSize(int size);
+ void addLibraryPath(const QString& lib);
+
+ QStringList builtinSkins() const;
+
+ QMenuBar *menuBar() const;
+
+public slots:
+ void sceneResized(QSize size);
+ void openQml(const QString& fileName);
+ void open();
+ void reload();
+ void takeSnapShot();
+ void toggleRecording();
+ void toggleRecordingWithSelection();
+ void ffmpegFinished(int code);
+ void setSkin(const QString& skinDirectory);
+ void showProxySettings ();
+ void proxySettingsChanged ();
+ void setScaleView();
+
+protected:
+ virtual void keyPressEvent(QKeyEvent *);
+
+ void createMenu(QMenuBar *menu, QMenu *flatmenu);
+
+private slots:
+ void autoStartRecording();
+ void autoStopRecording();
+ void recordFrame();
+ void chooseRecordingOptions();
+ void pickRecordingFile();
+ void setScaleSkin();
+
+private:
+ void setupProxy();
+ QString getVideoFileName();
+
+ QString currentFileName;
+ PreviewDeviceSkin *skin;
+ QSize skinscreensize;
+ QFxView *canvas;
+ QmlTimer recordTimer;
+ QString frame_fmt;
+ QImage frame;
+ QList<QImage*> frames;
+ QProcess* frame_stream;
+ QmlTimer autoStartTimer;
+ QmlTimer autoStopTimer;
+ QString record_dither;
+ QString record_file;
+ QSize record_outsize;
+ QStringList record_args;
+ int record_rate;
+ int record_autotime;
+ bool devicemode;
+ QAction *recordAction;
+ QString currentSkin;
+ bool scaleSkin;
+ mutable QMenuBar *mb;
+ RecordingDialog *recdlg;
+
+ void senseImageMagick();
+ void senseFfmpeg();
+ QWidget *ffmpegHelpWindow;
+ bool ffmpegAvailable;
+ bool convertAvailable;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/tools/qmlviewer/qmlviewer.pro b/tools/qmlviewer/qmlviewer.pro
new file mode 100644
index 0000000..bcf361e
--- /dev/null
+++ b/tools/qmlviewer/qmlviewer.pro
@@ -0,0 +1,28 @@
+TEMPLATE = app
+CONFIG += qt \
+ uic
+DESTDIR = ../../bin
+QT += declarative \
+ script \
+ network \
+ sql
+
+# Input
+HEADERS += qmlviewer.h \
+ proxysettings.h
+SOURCES += main.cpp \
+ qmlviewer.cpp \
+ proxysettings.cpp
+FORMS = recopts.ui \
+ proxysettings.ui
+include($$QT_SOURCE_TREE/tools/shared/deviceskin/deviceskin.pri)
+target.path = $$[QT_INSTALL_BINS]
+INSTALLS += target
+
+wince* {
+QT += scripttools \
+ xml \
+ xmlpatterns \
+ webkit \
+ phonon
+}
diff --git a/tools/qmlviewer/recopts.ui b/tools/qmlviewer/recopts.ui
new file mode 100644
index 0000000..ce2da30
--- /dev/null
+++ b/tools/qmlviewer/recopts.ui
@@ -0,0 +1,513 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>RecordingOptions</class>
+ <widget class="QDialog" name="RecordingOptions">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>316</width>
+ <height>436</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Video options</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>File:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="file"/>
+ </item>
+ <item>
+ <widget class="QToolButton" name="pickfile">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Size</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <widget class="QRadioButton" name="sizeOriginal">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QRadioButton" name="sizeVGA">
+ <property name="text">
+ <string>VGA</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QRadioButton" name="size720p">
+ <property name="text">
+ <string>720p</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QRadioButton" name="sizeQVGA">
+ <property name="text">
+ <string>QVGA</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" colspan="3">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QRadioButton" name="sizeCustom">
+ <property name="text">
+ <string>Width:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="sizeWidth">
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>9999</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Height:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="sizeHeight">
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>9999</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="2">
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="rateOptions">
+ <property name="title">
+ <string>Rate</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_4">
+ <item row="0" column="0">
+ <widget class="QRadioButton" name="hz60">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>60Hz</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QRadioButton" name="hz50">
+ <property name="text">
+ <string>50Hz</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QRadioButton" name="hz25">
+ <property name="text">
+ <string>25Hz</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" colspan="4">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QRadioButton" name="hzCustom">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="hz">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>60</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>100</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Hz</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="2">
+ <widget class="QRadioButton" name="hz24">
+ <property name="text">
+ <string>24Hz</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="1">
+ <spacer name="horizontalSpacer_5">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="ffmpegOptions">
+ <property name="title">
+ <string>Profile</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="0" column="0" colspan="3">
+ <widget class="QComboBox" name="profile"/>
+ </item>
+ <item row="1" column="0" colspan="2">
+ <widget class="QLineEdit" name="args"/>
+ </item>
+ <item row="1" column="2">
+ <widget class="QToolButton" name="ffmpegHelp">
+ <property name="text">
+ <string>Help</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="warning">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>file</tabstop>
+ <tabstop>pickfile</tabstop>
+ <tabstop>sizeOriginal</tabstop>
+ <tabstop>sizeVGA</tabstop>
+ <tabstop>size720p</tabstop>
+ <tabstop>sizeQVGA</tabstop>
+ <tabstop>sizeCustom</tabstop>
+ <tabstop>sizeWidth</tabstop>
+ <tabstop>sizeHeight</tabstop>
+ <tabstop>hz60</tabstop>
+ <tabstop>hz25</tabstop>
+ <tabstop>hz50</tabstop>
+ <tabstop>hz24</tabstop>
+ <tabstop>hzCustom</tabstop>
+ <tabstop>hz</tabstop>
+ <tabstop>profile</tabstop>
+ <tabstop>args</tabstop>
+ <tabstop>ffmpegHelp</tabstop>
+ <tabstop>buttonBox</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>hzCustom</sender>
+ <signal>clicked()</signal>
+ <receiver>hz</receiver>
+ <slot>setFocus()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>43</x>
+ <y>257</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>129</x>
+ <y>262</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>hz</sender>
+ <signal>textChanged(QString)</signal>
+ <receiver>hzCustom</receiver>
+ <slot>toggle()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>143</x>
+ <y>262</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>43</x>
+ <y>257</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>hz</sender>
+ <signal>selectionChanged()</signal>
+ <receiver>hzCustom</receiver>
+ <slot>toggle()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>143</x>
+ <y>262</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>43</x>
+ <y>257</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>RecordingOptions</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>258</x>
+ <y>424</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>60</x>
+ <y>219</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>RecordingOptions</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>258</x>
+ <y>424</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>92</x>
+ <y>219</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>profile</sender>
+ <signal>activated(int)</signal>
+ <receiver>RecordingOptions</receiver>
+ <slot>pickProfile(int)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>92</x>
+ <y>329</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>48</x>
+ <y>194</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>args</sender>
+ <signal>textEdited(QString)</signal>
+ <receiver>RecordingOptions</receiver>
+ <slot>storeCustomArgs(QString)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>128</x>
+ <y>357</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>102</x>
+ <y>189</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>sizeWidth</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>sizeCustom</receiver>
+ <slot>toggle()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>108</x>
+ <y>133</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>48</x>
+ <y>133</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>sizeHeight</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>sizeCustom</receiver>
+ <slot>toggle()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>212</x>
+ <y>133</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>64</x>
+ <y>129</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+ <slots>
+ <signal>filePicked(QString)</signal>
+ <signal>argumentsPicked(QString)</signal>
+ <slot>pickFile()</slot>
+ <slot>pickProfile(int)</slot>
+ <slot>storeCustomArgs(QString)</slot>
+ </slots>
+</ui>
diff --git a/tools/tools.pro b/tools/tools.pro
index a602892..03b5a94 100644
--- a/tools/tools.pro
+++ b/tools/tools.pro
@@ -25,6 +25,7 @@ mac {
embedded:SUBDIRS += kmap2qmap
+contains(QT_CONFIG, declarative):SUBDIRS += qmlviewer qmldebugger
contains(QT_CONFIG, dbus):SUBDIRS += qdbus
!wince*:contains(QT_CONFIG, xmlpatterns): SUBDIRS += xmlpatterns xmlpatternsvalidator
embedded: SUBDIRS += makeqpf