summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-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/cppcodemarker.cpp4
-rw-r--r--tools/qdoc3/test/qml.qdocconf80
-rw-r--r--tools/qdoc3/test/qt-build-docs.qdocconf3
-rw-r--r--tools/qdoc3/test/qt.qdocconf3
-rw-r--r--tools/qmldebugger/creatorplugin/QmlInspector.pluginspec28
-rw-r--r--tools/qmldebugger/creatorplugin/README5
-rw-r--r--tools/qmldebugger/creatorplugin/creatorplugin.pro30
-rw-r--r--tools/qmldebugger/creatorplugin/images/logo.pngbin0 -> 2662 bytes
-rw-r--r--tools/qmldebugger/creatorplugin/inspectoroutputpane.cpp150
-rw-r--r--tools/qmldebugger/creatorplugin/inspectoroutputpane.h95
-rw-r--r--tools/qmldebugger/creatorplugin/qmlinspector.h65
-rw-r--r--tools/qmldebugger/creatorplugin/qmlinspector.qrc6
-rw-r--r--tools/qmldebugger/creatorplugin/qmlinspectormode.cpp566
-rw-r--r--tools/qmldebugger/creatorplugin/qmlinspectormode.h133
-rw-r--r--tools/qmldebugger/creatorplugin/qmlinspectorplugin.cpp175
-rw-r--r--tools/qmldebugger/creatorplugin/qmlinspectorplugin.h90
-rw-r--r--tools/qmldebugger/creatorplugin/runcontrol.cpp175
-rw-r--r--tools/qmldebugger/creatorplugin/runcontrol.h105
-rw-r--r--tools/qmldebugger/qmldebugger.pro10
-rw-r--r--tools/qmldebugger/standalone/canvasframerate.cpp581
-rw-r--r--tools/qmldebugger/standalone/canvasframerate.h91
-rw-r--r--tools/qmldebugger/standalone/engine.cpp219
-rw-r--r--tools/qmldebugger/standalone/engine.h101
-rw-r--r--tools/qmldebugger/standalone/engine.pngbin0 -> 6394 bytes
-rw-r--r--tools/qmldebugger/standalone/engines.qml46
-rw-r--r--tools/qmldebugger/standalone/expressionquerywidget.cpp276
-rw-r--r--tools/qmldebugger/standalone/expressionquerywidget.h105
-rw-r--r--tools/qmldebugger/standalone/main.cpp77
-rw-r--r--tools/qmldebugger/standalone/objectpropertiesview.cpp274
-rw-r--r--tools/qmldebugger/standalone/objectpropertiesview.h93
-rw-r--r--tools/qmldebugger/standalone/objecttree.cpp231
-rw-r--r--tools/qmldebugger/standalone/objecttree.h96
-rw-r--r--tools/qmldebugger/standalone/qmldebugger.cpp181
-rw-r--r--tools/qmldebugger/standalone/qmldebugger.h90
-rw-r--r--tools/qmldebugger/standalone/qmldebugger.pri16
-rw-r--r--tools/qmldebugger/standalone/qmldebugger.qrc7
-rw-r--r--tools/qmldebugger/standalone/refresh.pngbin0 -> 6169 bytes
-rw-r--r--tools/qmldebugger/standalone/standalone.pro19
-rw-r--r--tools/qmldebugger/standalone/watchtable.cpp366
-rw-r--r--tools/qmldebugger/standalone/watchtable.h154
-rw-r--r--tools/qmlviewer/main.cpp300
-rw-r--r--tools/qmlviewer/proxysettings.cpp106
-rw-r--r--tools/qmlviewer/proxysettings.h68
-rw-r--r--tools/qmlviewer/proxysettings.ui115
-rw-r--r--tools/qmlviewer/qfxtester.cpp378
-rw-r--r--tools/qmlviewer/qfxtester.h262
-rw-r--r--tools/qmlviewer/qmlviewer.cpp1160
-rw-r--r--tools/qmlviewer/qmlviewer.h165
-rw-r--r--tools/qmlviewer/qmlviewer.pro35
-rw-r--r--tools/qmlviewer/recopts.ui513
54 files changed, 8093 insertions, 5 deletions
diff --git a/tools/linguist/lupdate/lupdate.h b/tools/linguist/lupdate/lupdate.h
index 45eee98..ae04218 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 bdaec4f..af40616 100644
--- a/tools/linguist/lupdate/main.cpp
+++ b/tools/linguist/lupdate/main.cpp
@@ -427,7 +427,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 {
@@ -518,6 +519,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..860d87c
--- /dev/null
+++ b/tools/linguist/lupdate/qml.cpp
@@ -0,0 +1,240 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "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/cppcodemarker.cpp b/tools/qdoc3/cppcodemarker.cpp
index a8f6a02..f3c8fa5 100644
--- a/tools/qdoc3/cppcodemarker.cpp
+++ b/tools/qdoc3/cppcodemarker.cpp
@@ -1127,7 +1127,7 @@ QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode,
"signal",
"signals");
FastSection qmlattachedsignals(qmlClassNode,
- "QML Attached Signals",
+ "Attached Signals",
"signal",
"signals");
FastSection qmlmethods(qmlClassNode,
@@ -1135,7 +1135,7 @@ QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode,
"method",
"methods");
FastSection qmlattachedmethods(qmlClassNode,
- "QML Attached Methods",
+ "Attached Methods",
"method",
"methods");
diff --git a/tools/qdoc3/test/qml.qdocconf b/tools/qdoc3/test/qml.qdocconf
new file mode 100644
index 0000000..3b5d8dc
--- /dev/null
+++ b/tools/qdoc3/test/qml.qdocconf
@@ -0,0 +1,80 @@
+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
+qmlonly = true
+
+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>&nbsp;&middot;" \
+ " <a href=\"qmlelements.html\">" \
+ "<font color=\"#004faf\">Elements</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 d1733e5..0848beb 100644
--- a/tools/qdoc3/test/qt-build-docs.qdocconf
+++ b/tools/qdoc3/test/qt-build-docs.qdocconf
@@ -105,7 +105,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.qdocconf b/tools/qdoc3/test/qt.qdocconf
index d70ef58..d019bdf 100644
--- a/tools/qdoc3/test/qt.qdocconf
+++ b/tools/qdoc3/test/qt.qdocconf
@@ -108,7 +108,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/creatorplugin/QmlInspector.pluginspec b/tools/qmldebugger/creatorplugin/QmlInspector.pluginspec
new file mode 100644
index 0000000..cdba135
--- /dev/null
+++ b/tools/qmldebugger/creatorplugin/QmlInspector.pluginspec
@@ -0,0 +1,28 @@
+<plugin name="QmlInspector" version="1.3.80" compatVersion="1.3.80">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008-2009 Nokia Corporation</copyright>
+ <license>
+Commercial Usage
+
+Licensees holding valid Qt Commercial licenses may use this plugin in
+accordance with the Qt Commercial License Agreement provided with the
+Software or, alternatively, in accordance with the terms contained in
+a written agreement between you and Nokia.
+
+GNU Lesser General Public License Usage
+
+Alternatively, this plugin may be used under the terms of the GNU Lesser
+General Public License version 2.1 as published by the Free Software
+Foundation. 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.</license>
+ <description>Qml support</description>
+ <url>http://qt.nokia.com</url>
+ <dependencyList>
+ <dependency name="QmlProjectManager" version="1.3.80"/>
+ <dependency name="ProjectExplorer" version="1.3.80"/>
+ <dependency name="CppTools" version="1.3.80"/>
+ <dependency name="CppEditor" version="1.3.80"/>
+ <dependency name="Help" version="1.3.80"/>
+ </dependencyList>
+</plugin> \ No newline at end of file
diff --git a/tools/qmldebugger/creatorplugin/README b/tools/qmldebugger/creatorplugin/README
new file mode 100644
index 0000000..e7e205e
--- /dev/null
+++ b/tools/qmldebugger/creatorplugin/README
@@ -0,0 +1,5 @@
+To enable this project, qmldebugger.pro requires that these two environment
+variables be defined:
+
+CREATOR_SRC_DIR -> source directory for Qt Creator
+CREATOR_BUILD_DIR -> build directory for Qt Creator
diff --git a/tools/qmldebugger/creatorplugin/creatorplugin.pro b/tools/qmldebugger/creatorplugin/creatorplugin.pro
new file mode 100644
index 0000000..ff7f3da
--- /dev/null
+++ b/tools/qmldebugger/creatorplugin/creatorplugin.pro
@@ -0,0 +1,30 @@
+TEMPLATE = lib
+TARGET = QmlInspector
+
+INCLUDEPATH += .
+DEPENDPATH += .
+
+include(../standalone/qmldebugger.pri)
+
+HEADERS += qmlinspectorplugin.h \
+ qmlinspector.h \
+ qmlinspectormode.h \
+ inspectoroutputpane.h \
+ runcontrol.h
+
+SOURCES += qmlinspectorplugin.cpp \
+ qmlinspectormode.cpp \
+ inspectoroutputpane.cpp \
+ runcontrol.cpp
+
+OTHER_FILES += QmlInspector.pluginspec
+RESOURCES += qmlinspector.qrc
+
+IDE_BUILD_TREE=$$(CREATOR_BUILD_DIR)
+
+include($$(CREATOR_SRC_DIR)/src/qtcreatorplugin.pri)
+include($$(CREATOR_SRC_DIR)/src/plugins/projectexplorer/projectexplorer.pri)
+include($$(CREATOR_SRC_DIR)/src/plugins/coreplugin/coreplugin.pri)
+include($$(CREATOR_SRC_DIR)/src/plugins/texteditor/texteditor.pri)
+LIBS += -L$$(CREATOR_BUILD_DIR)/lib/qtcreator
+
diff --git a/tools/qmldebugger/creatorplugin/images/logo.png b/tools/qmldebugger/creatorplugin/images/logo.png
new file mode 100644
index 0000000..5ac14a5
--- /dev/null
+++ b/tools/qmldebugger/creatorplugin/images/logo.png
Binary files differ
diff --git a/tools/qmldebugger/creatorplugin/inspectoroutputpane.cpp b/tools/qmldebugger/creatorplugin/inspectoroutputpane.cpp
new file mode 100644
index 0000000..b830007
--- /dev/null
+++ b/tools/qmldebugger/creatorplugin/inspectoroutputpane.cpp
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtGui/qtextedit.h>
+
+#include "inspectoroutputpane.h"
+
+InspectorOutputPane::InspectorOutputPane(QObject *parent)
+ : Core::IOutputPane(parent),
+ m_textEdit(new QTextEdit)
+{
+}
+
+InspectorOutputPane::~InspectorOutputPane()
+{
+ delete m_textEdit;
+}
+
+QWidget *InspectorOutputPane::outputWidget(QWidget *parent)
+{
+ Q_UNUSED(parent);
+ return m_textEdit;
+}
+
+QList<QWidget*> InspectorOutputPane::toolBarWidgets() const
+{
+ return QList<QWidget *>();
+}
+
+QString InspectorOutputPane::name() const
+{
+ return tr("Inspector Output");
+}
+
+int InspectorOutputPane::priorityInStatusBar() const
+{
+ return 1;
+}
+
+void InspectorOutputPane::clearContents()
+{
+ m_textEdit->clear();
+}
+
+void InspectorOutputPane::visibilityChanged(bool visible)
+{
+ Q_UNUSED(visible);
+}
+
+void InspectorOutputPane::setFocus()
+{
+ m_textEdit->setFocus();
+}
+
+bool InspectorOutputPane::hasFocus()
+{
+ return m_textEdit->hasFocus();
+}
+
+bool InspectorOutputPane::canFocus()
+{
+ return true;
+}
+
+bool InspectorOutputPane::canNavigate()
+{
+ return false;
+}
+
+bool InspectorOutputPane::canNext()
+{
+ return false;
+}
+
+bool InspectorOutputPane::canPrevious()
+{
+ return false;
+}
+
+void InspectorOutputPane::goToNext()
+{
+}
+
+void InspectorOutputPane::goToPrev()
+{
+}
+
+void InspectorOutputPane::addOutput(RunControl *, const QString &text)
+{
+ m_textEdit->insertPlainText(text);
+ m_textEdit->moveCursor(QTextCursor::End);
+}
+
+void InspectorOutputPane::addOutputInline(RunControl *, const QString &text)
+{
+ m_textEdit->insertPlainText(text);
+ m_textEdit->moveCursor(QTextCursor::End);
+}
+
+void InspectorOutputPane::addErrorOutput(RunControl *, const QString &text)
+{
+ m_textEdit->append(text);
+ m_textEdit->moveCursor(QTextCursor::End);
+}
+
+void InspectorOutputPane::addInspectorStatus(const QString &text)
+{
+ m_textEdit->setTextColor(Qt::darkGreen);
+ m_textEdit->append(text);
+ m_textEdit->moveCursor(QTextCursor::End);
+ m_textEdit->setTextColor(Qt::black);
+}
+
diff --git a/tools/qmldebugger/creatorplugin/inspectoroutputpane.h b/tools/qmldebugger/creatorplugin/inspectoroutputpane.h
new file mode 100644
index 0000000..04f506d
--- /dev/null
+++ b/tools/qmldebugger/creatorplugin/inspectoroutputpane.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef INSPECTOROUTPUTPANE_H
+#define INSPECTOROUTPUTPANE_H
+
+#include <QtCore/QObject>
+
+#include <coreplugin/ioutputpane.h>
+
+
+QT_BEGIN_NAMESPACE
+
+class QTextEdit;
+
+class RunControl;
+
+class InspectorOutputPane : public Core::IOutputPane
+{
+ Q_OBJECT
+public:
+ InspectorOutputPane(QObject *parent = 0);
+ virtual ~InspectorOutputPane();
+
+ virtual QWidget *outputWidget(QWidget *parent);
+ virtual QList<QWidget*> toolBarWidgets() const;
+ virtual QString name() const;
+
+ virtual int priorityInStatusBar() const;
+
+ virtual void clearContents();
+ virtual void visibilityChanged(bool visible);
+
+ virtual void setFocus();
+ virtual bool hasFocus();
+ virtual bool canFocus();
+
+ virtual bool canNavigate();
+ virtual bool canNext();
+ virtual bool canPrevious();
+ virtual void goToNext();
+ virtual void goToPrev();
+
+public slots:
+ void addOutput(RunControl *, const QString &text);
+ void addOutputInline(RunControl *, const QString &text);
+
+ void addErrorOutput(RunControl *, const QString &text);
+ void addInspectorStatus(const QString &text);
+
+private:
+ QTextEdit *m_textEdit;
+};
+
+QT_END_NAMESPACE
+
+#endif
+
diff --git a/tools/qmldebugger/creatorplugin/qmlinspector.h b/tools/qmldebugger/creatorplugin/qmlinspector.h
new file mode 100644
index 0000000..354e88e
--- /dev/null
+++ b/tools/qmldebugger/creatorplugin/qmlinspector.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QMLINSPECTOR_H
+#define QMLINSPECTOR_H
+
+#include <QString>
+
+namespace QmlInspector {
+ namespace Constants {
+ const char * const RUN = "QmlInspector.Run";
+ const char * const STOP = "QmlInspector.Stop";
+
+ const char * const C_INSPECTOR = "QmlInspector";
+ };
+
+ class StartParameters
+ {
+ public:
+ StartParameters() : port(0) {}
+ ~StartParameters() {}
+
+ QString address;
+ quint16 port;
+ };
+};
+
+#endif
diff --git a/tools/qmldebugger/creatorplugin/qmlinspector.qrc b/tools/qmldebugger/creatorplugin/qmlinspector.qrc
new file mode 100644
index 0000000..45e8dda
--- /dev/null
+++ b/tools/qmldebugger/creatorplugin/qmlinspector.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/qmlinspector" >
+ <file>images/logo.png</file>
+ </qresource>
+</RCC>
+
diff --git a/tools/qmldebugger/creatorplugin/qmlinspectormode.cpp b/tools/qmldebugger/creatorplugin/qmlinspectormode.cpp
new file mode 100644
index 0000000..aa7d292
--- /dev/null
+++ b/tools/qmldebugger/creatorplugin/qmlinspectormode.cpp
@@ -0,0 +1,566 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtCore/QStringList>
+#include <QtCore/QtPlugin>
+#include <QtCore/QDebug>
+
+#include <QtGui/qtoolbutton.h>
+#include <QtGui/qtoolbar.h>
+#include <QtGui/qboxlayout.h>
+#include <QtGui/qlabel.h>
+#include <QtGui/qdockwidget.h>
+#include <QtGui/qaction.h>
+#include <QtGui/qlineedit.h>
+#include <QtGui/qlabel.h>
+#include <QtGui/qspinbox.h>
+
+#include <coreplugin/basemode.h>
+#include <coreplugin/findplaceholder.h>
+#include <coreplugin/minisplitter.h>
+#include <coreplugin/outputpane.h>
+#include <coreplugin/rightpane.h>
+#include <coreplugin/navigationwidget.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/uniqueidmanager.h>
+
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+
+#include <texteditor/itexteditor.h>
+
+#include <projectexplorer/runconfiguration.h>
+#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/project.h>
+
+#include <utils/styledbar.h>
+#include <utils/fancymainwindow.h>
+
+#include <private/qmldebug_p.h>
+#include <private/qmldebugclient_p.h>
+
+#include "../standalone/objectpropertiesview.h"
+#include "../standalone/objecttree.h"
+#include "../standalone/watchtable.h"
+#include "../standalone/canvasframerate.h"
+#include "../standalone/expressionquerywidget.h"
+
+#include "qmlinspector.h"
+#include "qmlinspectormode.h"
+
+QT_BEGIN_NAMESPACE
+
+
+class EngineSpinBox : public QSpinBox
+{
+ Q_OBJECT
+public:
+ struct EngineInfo
+ {
+ QString name;
+ int id;
+ };
+
+ EngineSpinBox(QWidget *parent = 0);
+
+ void addEngine(int engine, const QString &name);
+ void clearEngines();
+
+protected:
+ virtual QString textFromValue(int value) const;
+ virtual int valueFromText(const QString &text) const;
+
+private:
+ QList<EngineInfo> m_engines;
+};
+
+EngineSpinBox::EngineSpinBox(QWidget *parent)
+ : QSpinBox(parent)
+{
+ setEnabled(false);
+ setReadOnly(true);
+ setRange(0, 0);
+}
+
+void EngineSpinBox::addEngine(int engine, const QString &name)
+{
+ EngineInfo info;
+ info.id = engine;
+ if (name.isEmpty())
+ info.name = tr("Engine %1", "engine number").arg(engine);
+ else
+ info.name = name;
+ m_engines << info;
+
+ setRange(0, m_engines.count()-1);
+}
+
+void EngineSpinBox::clearEngines()
+{
+ m_engines.clear();
+}
+
+QString EngineSpinBox::textFromValue(int value) const
+{
+ for (int i=0; i<m_engines.count(); i++) {
+ if (m_engines[i].id == value)
+ return m_engines[i].name;
+ }
+ return QLatin1String("<None>");
+}
+
+int EngineSpinBox::valueFromText(const QString &text) const
+{
+ for (int i=0; i<m_engines.count(); i++) {
+ if (m_engines[i].name == text)
+ return m_engines[i].id;
+ }
+ return -1;
+}
+
+
+QmlInspectorMode::QmlInspectorMode(QObject *parent)
+ : Core::BaseMode(parent),
+ m_conn(0),
+ m_client(0),
+ m_engineQuery(0),
+ m_contextQuery(0)
+{
+ m_watchTableModel = new WatchTableModel(0, this);
+
+ initActions();
+ setWidget(createModeWindow());
+
+ setName(tr("QML Inspect"));
+ setIcon(QIcon(":/qmlinspector/images/logo.png"));
+ setUniqueModeName("QML_INSPECT_MODE");
+}
+
+quint16 QmlInspectorMode::viewerPort() const
+{
+ return m_portSpinBox->value();
+}
+
+void QmlInspectorMode::connectToViewer()
+{
+ if (m_conn && m_conn->state() != QAbstractSocket::UnconnectedState)
+ return;
+
+ delete m_client; m_client = 0;
+
+ if (m_conn) {
+ m_conn->disconnectFromHost();
+ delete m_conn;
+ }
+
+ m_conn = new QmlDebugConnection(this);
+ connect(m_conn, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
+ SLOT(connectionStateChanged()));
+ connect(m_conn, SIGNAL(error(QAbstractSocket::SocketError)),
+ SLOT(connectionError()));
+ m_conn->connectToHost(m_addressEdit->text(), m_portSpinBox->value());
+}
+
+void QmlInspectorMode::disconnectFromViewer()
+{
+ m_conn->disconnectFromHost();
+}
+
+void QmlInspectorMode::connectionStateChanged()
+{
+ switch (m_conn->state()) {
+ default:
+ case QAbstractSocket::UnconnectedState:
+ {
+ emit statusMessage(tr("[Inspector] disconnected.\n\n"));
+ m_addressEdit->setEnabled(true);
+ m_portSpinBox->setEnabled(true);
+
+ delete m_engineQuery;
+ m_engineQuery = 0;
+ delete m_contextQuery;
+ m_contextQuery = 0;
+ break;
+ }
+ case QAbstractSocket::HostLookupState:
+ emit statusMessage(tr("[Inspector] resolving host..."));
+ break;
+ case QAbstractSocket::ConnectingState:
+ emit statusMessage(tr("[Inspector] connecting to debug server..."));
+ break;
+ case QAbstractSocket::ConnectedState:
+ {
+ emit statusMessage(tr("[Inspector] connected.\n"));
+ m_addressEdit->setEnabled(false);
+ m_portSpinBox->setEnabled(false);
+
+ if (!m_client) {
+ m_client = new QmlEngineDebug(m_conn, this);
+ m_objectTreeWidget->setEngineDebug(m_client);
+ m_propertiesWidget->setEngineDebug(m_client);
+ m_watchTableModel->setEngineDebug(m_client);
+ m_expressionWidget->setEngineDebug(m_client);
+ }
+
+ m_objectTreeWidget->clear();
+ m_propertiesWidget->clear();
+ m_expressionWidget->clear();
+ m_watchTableModel->removeAllWatches();
+ m_frameRateWidget->reset(m_conn);
+
+ reloadEngines();
+ break;
+ }
+ case QAbstractSocket::ClosingState:
+ emit statusMessage(tr("[Inspector] closing..."));
+ break;
+ }
+}
+
+void QmlInspectorMode::connectionError()
+{
+ emit statusMessage(tr("[Inspector] error: (%1) %2", "%1=error code, %2=error message")
+ .arg(m_conn->error()).arg(m_conn->errorString()));
+}
+
+void QmlInspectorMode::initActions()
+{
+ m_actions.startAction = new QAction(tr("Start Inspector"), this);
+ m_actions.startAction->setIcon(QIcon(ProjectExplorer::Constants::ICON_RUN));
+
+ m_actions.stopAction = new QAction(tr("Stop Inspector"), this);
+ m_actions.stopAction->setIcon(QIcon(ProjectExplorer::Constants::ICON_STOP));
+
+ Core::ICore *core = Core::ICore::instance();
+ Core::ActionManager *am = core->actionManager();
+ Core::UniqueIDManager *uidm = core->uniqueIDManager();
+
+ QList<int> context;
+ context << uidm->uniqueIdentifier(QmlInspector::Constants::C_INSPECTOR);
+
+ am->registerAction(m_actions.startAction, QmlInspector::Constants::RUN, context);
+ connect(m_actions.startAction, SIGNAL(triggered()), SIGNAL(startViewer()));
+
+ am->registerAction(m_actions.stopAction, QmlInspector::Constants::STOP, context);
+ connect(m_actions.stopAction, SIGNAL(triggered()), SIGNAL(stopViewer()));
+}
+
+
+QToolButton *QmlInspectorMode::createToolButton(QAction *action)
+{
+ QToolButton *button = new QToolButton;
+ button->setDefaultAction(action);
+ return button;
+}
+
+QWidget *QmlInspectorMode::createMainView()
+{
+ initWidgets();
+
+ Utils::FancyMainWindow *mainWindow = new Utils::FancyMainWindow;
+ mainWindow->setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North);
+ mainWindow->setDocumentMode(true);
+
+ QBoxLayout *editorHolderLayout = new QVBoxLayout;
+ editorHolderLayout->setMargin(0);
+ editorHolderLayout->setSpacing(0);
+
+ QWidget *editorAndFindWidget = new QWidget;
+ editorAndFindWidget->setLayout(editorHolderLayout);
+ editorHolderLayout->addWidget(new Core::EditorManagerPlaceHolder(this));
+ editorHolderLayout->addWidget(new Core::FindToolBarPlaceHolder(editorAndFindWidget));
+
+ Utils::StyledBar *treeOptionBar = new Utils::StyledBar;
+ QHBoxLayout *treeOptionBarLayout = new QHBoxLayout(treeOptionBar);
+ treeOptionBarLayout->setContentsMargins(5, 0, 5, 0);
+ treeOptionBarLayout->setSpacing(5);
+ treeOptionBarLayout->addWidget(new QLabel(tr("QML engine:")));
+ treeOptionBarLayout->addWidget(m_engineSpinBox);
+
+ QWidget *treeWindow = new QWidget;
+ QVBoxLayout *treeWindowLayout = new QVBoxLayout(treeWindow);
+ treeWindowLayout->setMargin(0);
+ treeWindowLayout->setSpacing(0);
+ treeWindowLayout->addWidget(treeOptionBar);
+ treeWindowLayout->addWidget(m_objectTreeWidget);
+
+ Core::MiniSplitter *documentAndTree = new Core::MiniSplitter;
+ documentAndTree->addWidget(editorAndFindWidget);
+ documentAndTree->addWidget(new Core::RightPanePlaceHolder(this));
+ documentAndTree->addWidget(treeWindow);
+ documentAndTree->setStretchFactor(0, 2);
+ documentAndTree->setStretchFactor(1, 0);
+ documentAndTree->setStretchFactor(2, 0);
+
+ Utils::StyledBar *configBar = new Utils::StyledBar;
+ configBar->setProperty("topBorder", true);
+
+ QHBoxLayout *configBarLayout = new QHBoxLayout(configBar);
+ configBarLayout->setMargin(0);
+ configBarLayout->setSpacing(5);
+
+ Core::ICore *core = Core::ICore::instance();
+ Core::ActionManager *am = core->actionManager();
+ configBarLayout->addWidget(createToolButton(am->command(QmlInspector::Constants::RUN)->action()));
+ configBarLayout->addWidget(createToolButton(am->command(QmlInspector::Constants::STOP)->action()));
+ configBarLayout->addWidget(m_addressEdit);
+ configBarLayout->addWidget(m_portSpinBox);
+ configBarLayout->addStretch();
+
+ QWidget *widgetAboveTabs = new QWidget;
+ QVBoxLayout *widgetAboveTabsLayout = new QVBoxLayout(widgetAboveTabs);
+ widgetAboveTabsLayout->setMargin(0);
+ widgetAboveTabsLayout->setSpacing(0);
+ widgetAboveTabsLayout->addWidget(documentAndTree);
+ widgetAboveTabsLayout->addWidget(configBar);
+
+ Core::MiniSplitter *mainSplitter = new Core::MiniSplitter(Qt::Vertical);
+ mainSplitter->addWidget(widgetAboveTabs);
+ mainSplitter->addWidget(createBottomWindow());
+ mainSplitter->setStretchFactor(0, 3);
+ mainSplitter->setStretchFactor(1, 1);
+
+ QWidget *centralWidget = new QWidget;
+ QVBoxLayout *centralLayout = new QVBoxLayout(centralWidget);
+ centralLayout->setMargin(0);
+ centralLayout->setSpacing(0);
+ centralLayout->addWidget(mainSplitter);
+
+ mainWindow->setCentralWidget(centralWidget);
+
+ return mainWindow;
+}
+
+QWidget *QmlInspectorMode::createBottomWindow()
+{
+ Utils::FancyMainWindow *win = new Utils::FancyMainWindow;
+ win->setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North);
+ win->setDocumentMode(true);
+ win->setTrackingEnabled(true);
+
+ Core::MiniSplitter *leftSplitter = new Core::MiniSplitter(Qt::Vertical);
+ leftSplitter->addWidget(m_propertiesWidget);
+ leftSplitter->addWidget(m_expressionWidget);
+ leftSplitter->setStretchFactor(0, 2);
+ leftSplitter->setStretchFactor(1, 1);
+
+ Core::MiniSplitter *propSplitter = new Core::MiniSplitter(Qt::Horizontal);
+ propSplitter->addWidget(leftSplitter);
+ propSplitter->addWidget(m_watchTableView);
+ propSplitter->setStretchFactor(0, 2);
+ propSplitter->setStretchFactor(1, 1);
+ propSplitter->setWindowTitle(tr("Properties and Watchers"));
+
+ QDockWidget *propertiesDock = win->addDockForWidget(propSplitter);
+ win->addDockWidget(Qt::TopDockWidgetArea, propertiesDock);
+
+ QDockWidget *frameRateDock = win->addDockForWidget(m_frameRateWidget);
+ win->addDockWidget(Qt::TopDockWidgetArea, frameRateDock);
+
+ // stack the dock widgets as tabs
+ win->tabifyDockWidget(frameRateDock, propertiesDock);
+
+ return win;
+}
+
+QWidget *QmlInspectorMode::createModeWindow()
+{
+ // right-side window with editor, output etc.
+ Core::MiniSplitter *mainWindowSplitter = new Core::MiniSplitter;
+ mainWindowSplitter->addWidget(createMainView());
+ mainWindowSplitter->addWidget(new Core::OutputPanePlaceHolder(this));
+ mainWindowSplitter->setStretchFactor(0, 10);
+ mainWindowSplitter->setStretchFactor(1, 0);
+ mainWindowSplitter->setOrientation(Qt::Vertical);
+
+ // navigation + right-side window
+ Core::MiniSplitter *splitter = new Core::MiniSplitter;
+ splitter->addWidget(new Core::NavigationWidgetPlaceHolder(this));
+ splitter->addWidget(mainWindowSplitter);
+ splitter->setStretchFactor(0, 0);
+ splitter->setStretchFactor(1, 1);
+ return splitter;
+}
+
+void QmlInspectorMode::initWidgets()
+{
+ m_objectTreeWidget = new ObjectTree;
+ m_propertiesWidget = new ObjectPropertiesView;
+ m_watchTableView = new WatchTableView(m_watchTableModel);
+ m_frameRateWidget = new CanvasFrameRate;
+ m_expressionWidget = new ExpressionQueryWidget(ExpressionQueryWidget::ShellMode);
+
+ // FancyMainWindow uses widgets' window titles for tab labels
+ m_objectTreeWidget->setWindowTitle(tr("Object Tree"));
+ m_frameRateWidget->setWindowTitle(tr("Frame rate"));
+
+ m_watchTableView->setModel(m_watchTableModel);
+ WatchTableHeaderView *header = new WatchTableHeaderView(m_watchTableModel);
+ m_watchTableView->setHorizontalHeader(header);
+
+ connect(m_objectTreeWidget, SIGNAL(activated(QmlDebugObjectReference)),
+ this, SLOT(treeObjectActivated(QmlDebugObjectReference)));
+
+ connect(m_objectTreeWidget, SIGNAL(currentObjectChanged(QmlDebugObjectReference)),
+ m_propertiesWidget, SLOT(reload(QmlDebugObjectReference)));
+
+ connect(m_objectTreeWidget, SIGNAL(expressionWatchRequested(QmlDebugObjectReference,QString)),
+ m_watchTableModel, SLOT(expressionWatchRequested(QmlDebugObjectReference,QString)));
+
+ connect(m_propertiesWidget, SIGNAL(activated(QmlDebugObjectReference,QmlDebugPropertyReference)),
+ m_watchTableModel, SLOT(togglePropertyWatch(QmlDebugObjectReference,QmlDebugPropertyReference)));
+
+ connect(m_watchTableModel, SIGNAL(watchCreated(QmlDebugWatch*)),
+ m_propertiesWidget, SLOT(watchCreated(QmlDebugWatch*)));
+
+ connect(m_watchTableModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
+ m_watchTableView, SLOT(scrollToBottom()));
+
+ connect(m_watchTableView, SIGNAL(objectActivated(int)),
+ m_objectTreeWidget, SLOT(setCurrentObject(int)));
+
+ connect(m_objectTreeWidget, SIGNAL(currentObjectChanged(QmlDebugObjectReference)),
+ m_expressionWidget, SLOT(setCurrentObject(QmlDebugObjectReference)));
+
+ m_addressEdit = new QLineEdit;
+ m_addressEdit->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
+ m_addressEdit->setText("127.0.0.1");
+
+ m_portSpinBox = new QSpinBox;
+ m_portSpinBox->setMinimum(1024);
+ m_portSpinBox->setMaximum(20000);
+ m_portSpinBox->setValue(3768);
+
+ m_engineSpinBox = new EngineSpinBox;
+ m_engineSpinBox->setEnabled(false);
+ connect(m_engineSpinBox, SIGNAL(valueChanged(int)),
+ SLOT(queryEngineContext(int)));
+}
+
+void QmlInspectorMode::reloadEngines()
+{
+ if (m_engineQuery) {
+ emit statusMessage("[Inspector] Waiting for response to previous engine query");
+ return;
+ }
+
+ m_engineSpinBox->setEnabled(false);
+
+ m_engineQuery = m_client->queryAvailableEngines(this);
+ if (!m_engineQuery->isWaiting())
+ enginesChanged();
+ else
+ QObject::connect(m_engineQuery, SIGNAL(stateChanged(QmlDebugQuery::State)),
+ this, SLOT(enginesChanged()));
+}
+
+void QmlInspectorMode::enginesChanged()
+{
+ m_engineSpinBox->clearEngines();
+
+ QList<QmlDebugEngineReference> engines = m_engineQuery->engines();
+ delete m_engineQuery; m_engineQuery = 0;
+
+ if (engines.isEmpty())
+ qWarning("qmldebugger: no engines found!");
+
+ m_engineSpinBox->setEnabled(true);
+
+ for (int i=0; i<engines.count(); i++)
+ m_engineSpinBox->addEngine(engines.at(i).debugId(), engines.at(i).name());
+
+ if (engines.count() > 0) {
+ m_engineSpinBox->setValue(engines.at(0).debugId());
+ queryEngineContext(engines.at(0).debugId());
+ }
+}
+
+void QmlInspectorMode::queryEngineContext(int id)
+{
+ if (id < 0)
+ return;
+
+ if (m_contextQuery) {
+ delete m_contextQuery;
+ m_contextQuery = 0;
+ }
+
+ m_contextQuery = m_client->queryRootContexts(QmlDebugEngineReference(id), this);
+ if (!m_contextQuery->isWaiting())
+ contextChanged();
+ else
+ QObject::connect(m_contextQuery, SIGNAL(stateChanged(QmlDebugQuery::State)),
+ this, SLOT(contextChanged()));
+}
+
+void QmlInspectorMode::contextChanged()
+{
+ //dump(m_contextQuery->rootContext(), 0);
+
+ foreach (const QmlDebugObjectReference &object, m_contextQuery->rootContext().objects())
+ m_objectTreeWidget->reload(object.debugId());
+
+ delete m_contextQuery; m_contextQuery = 0;
+}
+
+void QmlInspectorMode::treeObjectActivated(const QmlDebugObjectReference &obj)
+{
+ QmlDebugFileReference source = obj.source();
+ QString fileName = source.url().toLocalFile();
+
+ if (source.lineNumber() < 0 || !QFile::exists(fileName))
+ return;
+
+ Core::EditorManager *editorManager = Core::EditorManager::instance();
+ TextEditor::ITextEditor *editor = qobject_cast<TextEditor::ITextEditor*>(editorManager->openEditor(fileName));
+ if (editor) {
+ editorManager->ensureEditorManagerVisible();
+ editorManager->addCurrentPositionToNavigationHistory();
+ editor->gotoLine(source.lineNumber());
+ editor->widget()->setFocus();
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "qmlinspectormode.moc"
+
diff --git a/tools/qmldebugger/creatorplugin/qmlinspectormode.h b/tools/qmldebugger/creatorplugin/qmlinspectormode.h
new file mode 100644
index 0000000..b4158f1
--- /dev/null
+++ b/tools/qmldebugger/creatorplugin/qmlinspectormode.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QMLINSPECTORMODE_H
+#define QMLINSPECTORMODE_H
+
+#include <QAction>
+
+#include <coreplugin/basemode.h>
+#include <QtCore/QObject>
+
+QT_BEGIN_NAMESPACE
+
+class QToolButton;
+class QLineEdit;
+class QSpinBox;
+class QLabel;
+
+class QmlEngineDebug;
+class QmlDebugConnection;
+class QmlDebugEnginesQuery;
+class QmlDebugRootContextQuery;
+class QmlDebugObjectReference;
+class ObjectTree;
+class WatchTableModel;
+class WatchTableView;
+class ObjectPropertiesView;
+class CanvasFrameRate;
+class ExpressionQueryWidget;
+class EngineSpinBox;
+
+
+class QmlInspectorMode : public Core::BaseMode
+{
+ Q_OBJECT
+
+public:
+ QmlInspectorMode(QObject *parent = 0);
+
+
+ quint16 viewerPort() const;
+
+signals:
+ void startViewer();
+ void stopViewer();
+ void statusMessage(const QString &text);
+
+public slots:
+ void connectToViewer(); // using host, port from widgets
+ void disconnectFromViewer();
+
+private slots:
+ void connectionStateChanged();
+ void connectionError();
+ void reloadEngines();
+ void enginesChanged();
+ void queryEngineContext(int);
+ void contextChanged();
+ void treeObjectActivated(const QmlDebugObjectReference &obj);
+
+private:
+ struct Actions {
+ QAction *startAction;
+ QAction *stopAction;
+ };
+
+ void initActions();
+ QWidget *createModeWindow();
+ QWidget *createMainView();
+ void initWidgets();
+ QWidget *createBottomWindow();
+ QToolButton *createToolButton(QAction *action);
+
+ Actions m_actions;
+
+ QmlDebugConnection *m_conn;
+ QmlEngineDebug *m_client;
+
+ QmlDebugEnginesQuery *m_engineQuery;
+ QmlDebugRootContextQuery *m_contextQuery;
+
+ ObjectTree *m_objectTreeWidget;
+ ObjectPropertiesView *m_propertiesWidget;
+ WatchTableModel *m_watchTableModel;
+ WatchTableView *m_watchTableView;
+ CanvasFrameRate *m_frameRateWidget;
+ ExpressionQueryWidget *m_expressionWidget;
+
+ QLineEdit *m_addressEdit;
+ QSpinBox *m_portSpinBox;
+ EngineSpinBox *m_engineSpinBox;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/tools/qmldebugger/creatorplugin/qmlinspectorplugin.cpp b/tools/qmldebugger/creatorplugin/qmlinspectorplugin.cpp
new file mode 100644
index 0000000..cc42470
--- /dev/null
+++ b/tools/qmldebugger/creatorplugin/qmlinspectorplugin.cpp
@@ -0,0 +1,175 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtCore/QStringList>
+#include <QtCore/QtPlugin>
+#include <QtCore/QDebug>
+
+#include <coreplugin/icore.h>
+
+#include <projectexplorer/runconfiguration.h>
+#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/project.h>
+
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/uniqueidmanager.h>
+
+#include <extensionsystem/pluginmanager.h>
+
+#include <private/qmldebug_p.h>
+#include <private/qmldebugclient_p.h>
+
+#include "runcontrol.h"
+#include "qmlinspector.h"
+#include "qmlinspectormode.h"
+#include "inspectoroutputpane.h"
+#include "qmlinspectorplugin.h"
+
+QT_BEGIN_NAMESPACE
+
+
+QmlInspectorPlugin::QmlInspectorPlugin()
+ : m_inspectMode(0),
+ m_runControl(0)
+{
+}
+
+QmlInspectorPlugin::~QmlInspectorPlugin()
+{
+}
+
+void QmlInspectorPlugin::shutdown()
+{
+ removeObject(m_inspectMode);
+ delete m_inspectMode;
+ m_inspectMode = 0;
+
+ removeObject(m_outputPane);
+ delete m_outputPane;
+ m_outputPane = 0;
+}
+
+bool QmlInspectorPlugin::initialize(const QStringList &arguments, QString *errorString)
+{
+ Q_UNUSED(arguments);
+ Q_UNUSED(errorString);
+
+ Core::ICore *core = Core::ICore::instance();
+ Core::UniqueIDManager *uidm = core->uniqueIDManager();
+
+ QList<int> context;
+ context.append(uidm->uniqueIdentifier(QmlInspector::Constants::C_INSPECTOR));
+ context.append(uidm->uniqueIdentifier(Core::Constants::C_EDITORMANAGER));
+ context.append(uidm->uniqueIdentifier(Core::Constants::C_NAVIGATION_PANE));
+
+ m_inspectMode = new QmlInspectorMode(this);
+ connect(m_inspectMode, SIGNAL(startViewer()), SLOT(startViewer()));
+ connect(m_inspectMode, SIGNAL(stopViewer()), SLOT(stopViewer()));
+ m_inspectMode->setContext(context);
+ addObject(m_inspectMode);
+
+ m_outputPane = new InspectorOutputPane;
+ addObject(m_outputPane);
+
+ connect(m_inspectMode, SIGNAL(statusMessage(QString)),
+ m_outputPane, SLOT(addInspectorStatus(QString)));
+
+ m_runControlFactory = new QmlInspectorRunControlFactory(this);
+ addAutoReleasedObject(m_runControlFactory);
+
+ return true;
+}
+
+void QmlInspectorPlugin::extensionsInitialized()
+{
+}
+
+void QmlInspectorPlugin::startViewer()
+{
+ stopViewer();
+
+ ProjectExplorer::Project *project = 0;
+ ProjectExplorer::ProjectExplorerPlugin *plugin = ProjectExplorer::ProjectExplorerPlugin::instance();
+ if (plugin)
+ project = plugin->currentProject();
+ if (!project) {
+ qDebug() << "No project loaded"; // TODO should this just run the debugger without a viewer?
+ return;
+ }
+
+ QSharedPointer<ProjectExplorer::RunConfiguration> rc = project->activeRunConfiguration();
+
+ QmlInspector::StartParameters sp;
+ sp.port = m_inspectMode->viewerPort();
+
+ m_runControl = m_runControlFactory->create(rc, ProjectExplorer::Constants::RUNMODE, sp);
+
+ if (m_runControl) {
+ connect(m_runControl, SIGNAL(started()), m_inspectMode, SLOT(connectToViewer()));
+ connect(m_runControl, SIGNAL(finished()), m_inspectMode, SLOT(disconnectFromViewer()));
+
+ connect(m_runControl, SIGNAL(addToOutputWindow(RunControl*,QString)),
+ m_outputPane, SLOT(addOutput(RunControl*,QString)));
+ connect(m_runControl, SIGNAL(addToOutputWindowInline(RunControl*,QString)),
+ m_outputPane, SLOT(addOutputInline(RunControl*,QString)));
+ connect(m_runControl, SIGNAL(error(RunControl*,QString)),
+ m_outputPane, SLOT(addErrorOutput(RunControl*,QString)));
+
+ m_runControl->start();
+ m_outputPane->popup(false);
+ }
+
+}
+
+void QmlInspectorPlugin::stopViewer()
+{
+ if (m_runControl) {
+ m_runControl->stop();
+ m_runControl->deleteLater();
+ m_runControl = 0;
+ }
+}
+
+
+Q_EXPORT_PLUGIN(QmlInspectorPlugin)
+
+QT_END_NAMESPACE
+
diff --git a/tools/qmldebugger/creatorplugin/qmlinspectorplugin.h b/tools/qmldebugger/creatorplugin/qmlinspectorplugin.h
new file mode 100644
index 0000000..57d9fb3
--- /dev/null
+++ b/tools/qmldebugger/creatorplugin/qmlinspectorplugin.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QMLINSPECTORPLUGIN_H
+#define QMLINSPECTORPLUGIN_H
+
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QStringList;
+
+
+class QmlInspectorRunControlFactory;
+class QmlInspectorMode;
+class InspectorOutputPane;
+
+namespace ProjectExplorer
+{
+ class RunControl;
+}
+
+class QmlInspectorPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ QmlInspectorPlugin();
+ ~QmlInspectorPlugin();
+
+ virtual bool initialize(const QStringList &arguments, QString *errorString);
+ virtual void extensionsInitialized();
+ virtual void shutdown();
+
+private slots:
+ void startViewer();
+ void stopViewer();
+
+private:
+ QmlInspectorMode *m_inspectMode;
+ InspectorOutputPane *m_outputPane;
+
+ QmlInspectorRunControlFactory *m_runControlFactory;
+ QPointer<ProjectExplorer::RunControl> m_runControl;
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QMLINSPECTORPLUGIN_H
diff --git a/tools/qmldebugger/creatorplugin/runcontrol.cpp b/tools/qmldebugger/creatorplugin/runcontrol.cpp
new file mode 100644
index 0000000..279f287
--- /dev/null
+++ b/tools/qmldebugger/creatorplugin/runcontrol.cpp
@@ -0,0 +1,175 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtCore/qdebug.h>
+#include <QtCore/qtimer.h>
+
+#include <projectexplorer/applicationlauncher.h>
+#include <projectexplorer/applicationrunconfiguration.h>
+#include <projectexplorer/projectexplorerconstants.h>
+
+#include "runcontrol.h"
+
+using namespace ProjectExplorer;
+
+
+QmlInspectorRunControlFactory::QmlInspectorRunControlFactory(QObject *parent)
+ : ProjectExplorer::IRunControlFactory(parent)
+{
+}
+
+bool QmlInspectorRunControlFactory::canRun(const QSharedPointer<RunConfiguration> &runConfiguration, const QString &mode) const
+{
+ Q_UNUSED(runConfiguration);
+ if (mode != ProjectExplorer::Constants::RUNMODE)
+ return false;
+ return true;
+}
+
+ProjectExplorer::RunControl *QmlInspectorRunControlFactory::create(const QSharedPointer<RunConfiguration> &runConfiguration, const QString &mode)
+{
+ Q_UNUSED(mode);
+ return new QmlInspectorRunControl(runConfiguration);
+}
+
+ProjectExplorer::RunControl *QmlInspectorRunControlFactory::create(const QSharedPointer<ProjectExplorer::RunConfiguration> &runConfiguration,
+const QString &mode, const QmlInspector::StartParameters &sp)
+{
+ Q_UNUSED(mode);
+ return new QmlInspectorRunControl(runConfiguration, sp);
+}
+
+QString QmlInspectorRunControlFactory::displayName() const
+{
+ return tr("Qml Inspector");
+}
+
+QWidget *QmlInspectorRunControlFactory::configurationWidget(const QSharedPointer<RunConfiguration> &runConfiguration)
+{
+ Q_UNUSED(runConfiguration);
+ return 0;
+}
+
+
+
+QmlInspectorRunControl::QmlInspectorRunControl(const QSharedPointer<ProjectExplorer::RunConfiguration> &runConfiguration,
+const QmlInspector::StartParameters &sp)
+ : ProjectExplorer::RunControl(runConfiguration),
+ m_running(false),
+ m_viewerLauncher(0),
+ m_startParams(sp)
+{
+}
+
+QmlInspectorRunControl::~QmlInspectorRunControl()
+{
+}
+
+void QmlInspectorRunControl::start()
+{
+ if (m_running || m_viewerLauncher)
+ return;
+
+ m_viewerLauncher = new ProjectExplorer::ApplicationLauncher(this);
+ connect(m_viewerLauncher, SIGNAL(applicationError(QString)), SLOT(applicationError(QString)));
+ connect(m_viewerLauncher, SIGNAL(processExited(int)), SLOT(viewerExited()));
+ connect(m_viewerLauncher, SIGNAL(appendOutput(QString)), SLOT(appendOutput(QString)));
+ connect(m_viewerLauncher, SIGNAL(bringToForegroundRequested(qint64)),
+ this, SLOT(appStarted()));
+
+ QSharedPointer<LocalApplicationRunConfiguration> rc =
+ runConfiguration().objectCast<LocalApplicationRunConfiguration>();
+ if (rc.isNull()) { // TODO
+ return;
+ }
+
+ ProjectExplorer::Environment env = rc->environment();
+ env.set("QML_DEBUG_SERVER_PORT", QString::number(m_startParams.port));
+
+ QStringList arguments = rc->commandLineArguments();
+ arguments << QLatin1String("-stayontop");
+
+ m_viewerLauncher->setEnvironment(env.toStringList());
+ m_viewerLauncher->setWorkingDirectory(rc->workingDirectory());
+
+ m_running = true;
+
+ m_viewerLauncher->start(static_cast<ApplicationLauncher::Mode>(rc->runMode()),
+ rc->executable(), arguments);
+}
+
+void QmlInspectorRunControl::stop()
+{
+ if (m_viewerLauncher->isRunning())
+ m_viewerLauncher->stop();
+}
+
+bool QmlInspectorRunControl::isRunning() const
+{
+ return m_running;
+}
+
+void QmlInspectorRunControl::appStarted()
+{
+ QTimer::singleShot(500, this, SLOT(delayedStart()));
+}
+
+void QmlInspectorRunControl::appendOutput(const QString &s)
+{
+ emit addToOutputWindow(this, s);
+}
+
+void QmlInspectorRunControl::delayedStart()
+{
+ emit started();
+}
+
+void QmlInspectorRunControl::viewerExited()
+{
+ m_running = false;
+ emit finished();
+
+ deleteLater();
+}
+
+void QmlInspectorRunControl::applicationError(const QString &s)
+{
+ emit error(this, s);
+}
diff --git a/tools/qmldebugger/creatorplugin/runcontrol.h b/tools/qmldebugger/creatorplugin/runcontrol.h
new file mode 100644
index 0000000..312fe56
--- /dev/null
+++ b/tools/qmldebugger/creatorplugin/runcontrol.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QMLINSPECTORRUNCONTROL_H
+#define QMLINSPECTORRUNCONTROL_H
+
+#include <QtCore/qobject.h>
+
+#include <projectexplorer/runconfiguration.h>
+
+#include "qmlinspector.h"
+
+namespace ProjectExplorer {
+ class ApplicationLauncher;
+}
+
+class QmlInspectorRunControlFactory : public ProjectExplorer::IRunControlFactory
+{
+ Q_OBJECT
+
+public:
+ explicit QmlInspectorRunControlFactory(QObject *parent);
+
+ virtual bool canRun(
+ const QSharedPointer<ProjectExplorer::RunConfiguration> &runConfiguration,
+ const QString &mode) const;
+
+ virtual ProjectExplorer::RunControl *create(
+ const QSharedPointer<ProjectExplorer::RunConfiguration> &runConfiguration,
+ const QString &mode);
+
+ ProjectExplorer::RunControl *create(
+ const QSharedPointer<ProjectExplorer::RunConfiguration> &runConfiguration,
+ const QString &mode,
+ const QmlInspector::StartParameters &sp);
+
+ virtual QString displayName() const;
+
+ virtual QWidget *configurationWidget(const QSharedPointer<ProjectExplorer::RunConfiguration> &runConfiguration);
+};
+
+class QmlInspectorRunControl : public ProjectExplorer::RunControl
+{
+ Q_OBJECT
+
+public:
+ explicit QmlInspectorRunControl(const QSharedPointer<ProjectExplorer::RunConfiguration> &runConfiguration,
+ const QmlInspector::StartParameters &sp = QmlInspector::StartParameters());
+ ~QmlInspectorRunControl();
+
+ virtual void start();
+ virtual void stop();
+ virtual bool isRunning() const;
+
+private slots:
+ void appendOutput(const QString &s);
+ void appStarted();
+ void delayedStart();
+ void viewerExited();
+ void applicationError(const QString &error);
+
+private:
+ bool m_running;
+ ProjectExplorer::ApplicationLauncher *m_viewerLauncher;
+ QmlInspector::StartParameters m_startParams;
+};
+
+#endif
diff --git a/tools/qmldebugger/qmldebugger.pro b/tools/qmldebugger/qmldebugger.pro
new file mode 100644
index 0000000..2dd353a
--- /dev/null
+++ b/tools/qmldebugger/qmldebugger.pro
@@ -0,0 +1,10 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+
+SUBDIRS = standalone
+
+CREATOR_SRC = $$(CREATOR_SRC_DIR)
+CREATOR_BUILD = $$(CREATOR_BUILD_DIR)
+!isEmpty(CREATOR_SRC):!isEmpty(CREATOR_BUILD) {
+ SUBDIRS += creatorplugin
+}
diff --git a/tools/qmldebugger/standalone/canvasframerate.cpp b/tools/qmldebugger/standalone/canvasframerate.cpp
new file mode 100644
index 0000000..d956029
--- /dev/null
+++ b/tools/qmldebugger/standalone/canvasframerate.cpp
@@ -0,0 +1,581 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtCore/qdebug.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qdatastream.h>
+#include <QtCore/qmargins.h>
+
+#include <QtGui/qapplication.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qtooltip.h>
+#include <QtGui/qslider.h>
+#include <QtGui/qscrollbar.h>
+#include <QtGui/qspinbox.h>
+#include <QtGui/qgroupbox.h>
+#include <QtGui/qboxlayout.h>
+#include <QtGui/qlabel.h>
+#include <QtGui/qlineedit.h>
+#include <QtGui/qpushbutton.h>
+#include <QtGui/qtabwidget.h>
+
+#include <QResizeEvent>
+#include <QShowEvent>
+
+#include <private/qmldebugclient_p.h>
+#include "canvasframerate.h"
+
+QT_BEGIN_NAMESPACE
+
+class QLineGraph : public QWidget
+{
+Q_OBJECT
+public:
+ QLineGraph(QAbstractSlider *slider, QWidget * = 0);
+
+ void setPosition(int);
+
+public slots:
+ void addSample(int, int, int, bool);
+ void setResolutionForHeight(int);
+ void clear();
+
+protected:
+ virtual void paintEvent(QPaintEvent *);
+ virtual void mouseMoveEvent(QMouseEvent *);
+ virtual void leaveEvent(QEvent *);
+ virtual void wheelEvent(QWheelEvent *event);
+
+private slots:
+ void sliderChanged(int);
+
+private:
+ void updateSlider();
+ void drawSample(QPainter *, int, const QRect &, QList<QRect> *);
+ void drawTime(QPainter *, const QRect &);
+ QRect findContainingRect(const QList<QRect> &rects, const QPoint &pos) const;
+ struct Sample {
+ int sample[3];
+ bool isBreak;
+ };
+ QList<Sample> _samples;
+
+ QAbstractSlider *slider;
+ int position;
+ int samplesPerWidth;
+ int resolutionForHeight;
+ bool ignoreScroll;
+ QMargins graphMargins;
+
+ QList<QRect> rectsPaintTime; // time to do a paintEvent()
+ QList<QRect> rectsTimeBetween; // time between frames
+ QRect highlightedBar;
+};
+
+QLineGraph::QLineGraph(QAbstractSlider *slider, QWidget *parent)
+: QWidget(parent), slider(slider), position(-1), samplesPerWidth(99), resolutionForHeight(50),
+ ignoreScroll(false), graphMargins(65, 10, 71, 35)
+{
+ setMouseTracking(true);
+
+ slider->setMaximum(0);
+ slider->setMinimum(0);
+ slider->setSingleStep(1);
+
+ connect(slider, SIGNAL(valueChanged(int)), this, SLOT(sliderChanged(int)));
+}
+
+void QLineGraph::sliderChanged(int v)
+{
+ if(ignoreScroll)
+ return;
+
+ if (v == slider->maximum())
+ position = -1;
+ else
+ position = v;
+
+ update();
+
+ // update highlightedRect
+ QPoint pos = mapFromGlobal(QCursor::pos());
+ if (geometry().contains(pos)) {
+ QMouseEvent *me = new QMouseEvent(QEvent::MouseMove, pos,
+ Qt::NoButton, Qt::NoButton, Qt::NoModifier);
+ QApplication::postEvent(this, me);
+ }
+}
+
+void QLineGraph::clear()
+{
+ _samples.clear();
+ rectsPaintTime.clear();
+ rectsTimeBetween.clear();
+ highlightedBar = QRect();
+ position = -1;
+
+ updateSlider();
+ update();
+}
+
+void QLineGraph::updateSlider()
+{
+ ignoreScroll = true;
+ slider->setMaximum(qMax(0, _samples.count() - samplesPerWidth - 1));
+
+ if(position == -1) {
+ slider->setValue(slider->maximum());
+ } else {
+ slider->setValue(position);
+ }
+ ignoreScroll = false;
+}
+
+void QLineGraph::addSample(int a, int b, int d, bool isBreak)
+{
+ Sample s;
+ s.isBreak = isBreak;
+ s.sample[0] = a;
+ s.sample[1] = b;
+ s.sample[2] = d;
+ _samples << s;
+ updateSlider();
+ update();
+}
+
+void QLineGraph::setPosition(int p)
+{
+ sliderChanged(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[2] / 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[2]));
+
+ t = sampleTime;
+ }
+ }
+
+}
+
+void QLineGraph::drawSample(QPainter *p, int s, const QRect &rect, QList<QRect> *record)
+{
+ 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 = qreal(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)) {
+ QRect bar(lastXEnd, yEnd, scaleX, _samples.at(ii).sample[s] * scaleY);
+ record->append(bar);
+ p->drawRect(bar);
+ }
+
+ lastXEnd = xEnd;
+ }
+ p->restore();
+}
+
+void QLineGraph::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+ p.setRenderHint(QPainter::Antialiasing);
+
+ QRect r(graphMargins.left(), graphMargins.top(),
+ width() - graphMargins.right(), height() - graphMargins.bottom());
+
+ p.save();
+ p.rotate(-90);
+ p.translate(-r.height()/2 - r.width()/2 - graphMargins.right(), -r.height()/2);
+ p.drawText(r, Qt::AlignCenter, tr("Frame rate"));
+ p.restore();
+
+ p.setBrush(QColor("lightsteelblue"));
+ rectsTimeBetween.clear();
+ drawSample(&p, 0, r, &rectsTimeBetween);
+
+ p.setBrush(QColor("pink"));
+ rectsPaintTime.clear();
+ drawSample(&p, 1, r, &rectsPaintTime);
+
+ if (!highlightedBar.isNull()) {
+ p.setBrush(Qt::darkGreen);
+ p.drawRect(highlightedBar);
+ }
+
+ p.setBrush(Qt::NoBrush);
+ p.drawRect(r);
+
+ slider->setGeometry(x() + r.x(), slider->y(), r.width(), slider->height());
+
+ 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);
+}
+
+void QLineGraph::mouseMoveEvent(QMouseEvent *event)
+{
+ QPoint pos = event->pos();
+
+ QRect rect = findContainingRect(rectsPaintTime, pos);
+ if (rect.isNull())
+ rect = findContainingRect(rectsTimeBetween, pos);
+
+ if (!highlightedBar.isNull())
+ update(highlightedBar.adjusted(-1, -1, 1, 1));
+ highlightedBar = rect;
+
+ if (!rect.isNull()) {
+ QRect graph(graphMargins.left(), graphMargins.top(),
+ width() - graphMargins.right(), height() - graphMargins.bottom());
+ qreal scaleY = qreal(graph.height()) / resolutionForHeight;
+ QToolTip::showText(event->globalPos(), QString::number(qRound(rect.height() / scaleY)), this, rect);
+ update(rect.adjusted(-1, -1, 1, 1));
+ }
+}
+
+void QLineGraph::leaveEvent(QEvent *)
+{
+ if (!highlightedBar.isNull()) {
+ QRect bar = highlightedBar.adjusted(-1, -1, 1, 1);
+ highlightedBar = QRect();
+ update(bar);
+ }
+}
+
+void QLineGraph::wheelEvent(QWheelEvent *event)
+{
+ QWheelEvent we(QPoint(0,0), event->delta(), event->buttons(), event->modifiers(), event->orientation());
+ QApplication::sendEvent(slider, &we);
+}
+
+void QLineGraph::setResolutionForHeight(int resolution)
+{
+ resolutionForHeight = resolution;
+ update();
+}
+
+QRect QLineGraph::findContainingRect(const QList<QRect> &rects, const QPoint &pos) const
+{
+ for (int i=0; i<rects.count(); i++) {
+ if (rects[i].contains(pos))
+ return rects[i];
+ }
+ return QRect();
+}
+
+
+class GraphWindow : public QWidget
+{
+ Q_OBJECT
+public:
+ GraphWindow(QWidget *parent = 0);
+
+ virtual QSize sizeHint() const;
+
+public slots:
+ void addSample(int, int, int, bool);
+ void setResolutionForHeight(int);
+ void clear();
+
+private:
+ QLineGraph *m_graph;
+};
+
+GraphWindow::GraphWindow(QWidget *parent)
+ : QWidget(parent)
+{
+ QSlider *scroll = new QSlider(Qt::Horizontal);
+ scroll->setFocusPolicy(Qt::WheelFocus);
+ m_graph = new QLineGraph(scroll);
+
+ setFocusPolicy(Qt::WheelFocus);
+ setFocusProxy(scroll);
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->setContentsMargins(0, 0, 5, 0);
+ layout->setSpacing(0);
+ layout->addWidget(m_graph, 2);
+ layout->addWidget(new QLabel(tr("Total time elapsed (ms)")), 0, Qt::AlignHCenter);
+ layout->addWidget(scroll);
+}
+
+void GraphWindow::addSample(int a, int b, int d, bool isBreak)
+{
+ m_graph->addSample(a, b, d, isBreak);
+}
+
+void GraphWindow::setResolutionForHeight(int res)
+{
+ m_graph->setResolutionForHeight(res);
+}
+
+void GraphWindow::clear()
+{
+ m_graph->clear();
+}
+
+QSize GraphWindow::sizeHint() const
+{
+ return QSize(400, 220);
+}
+
+
+class CanvasFrameRatePlugin : public QmlDebugClient
+{
+ Q_OBJECT
+public:
+ CanvasFrameRatePlugin(QmlDebugConnection *client);
+
+signals:
+ void sample(int, int, int, bool);
+
+protected:
+ virtual void messageReceived(const QByteArray &);
+
+private:
+ int lb;
+ int ld;
+};
+
+CanvasFrameRatePlugin::CanvasFrameRatePlugin(QmlDebugConnection *client)
+: QmlDebugClient(QLatin1String("CanvasFrameRate"), client), lb(-1)
+{
+}
+
+void CanvasFrameRatePlugin::messageReceived(const QByteArray &data)
+{
+ QByteArray rwData = data;
+ QDataStream stream(&rwData, QIODevice::ReadOnly);
+
+ int b; int c; int d; bool isBreak;
+ stream >> b >> c >> d >> isBreak;
+
+ if (lb != -1)
+ emit sample(c, lb, ld, isBreak);
+
+ lb = b;
+ ld = d;
+}
+
+CanvasFrameRate::CanvasFrameRate(QWidget *parent)
+: QWidget(parent),
+ m_plugin(0)
+{
+ m_tabs = new QTabWidget(this);
+
+ QHBoxLayout *bottom = new QHBoxLayout;
+ bottom->setMargin(0);
+ bottom->setSpacing(10);
+
+ m_res = new QSpinBox;
+ m_res->setRange(30, 200);
+ m_res->setValue(m_res->minimum());
+ m_res->setSingleStep(10);
+ m_res->setSuffix(QLatin1String("ms"));
+ bottom->addWidget(new QLabel(tr("Resolution:")));
+ bottom->addWidget(m_res);
+
+ bottom->addStretch();
+
+ m_clearButton = new QPushButton(tr("Clear"));
+ connect(m_clearButton, SIGNAL(clicked()), SLOT(clearGraph()));
+ bottom->addWidget(m_clearButton);
+
+ QPushButton *pb = new QPushButton(tr("New Graph"), this);
+ connect(pb, SIGNAL(clicked()), this, SLOT(newTab()));
+ bottom->addWidget(pb);
+
+ m_group = new QGroupBox(tr("Enabled"));
+ m_group->setCheckable(true);
+ m_group->setChecked(false);
+ connect(m_group, SIGNAL(toggled(bool)), SLOT(enabledToggled(bool)));
+
+ QVBoxLayout *groupLayout = new QVBoxLayout(m_group);
+ groupLayout->setContentsMargins(5, 0, 5, 0);
+ groupLayout->setSpacing(2);
+ groupLayout->addWidget(m_tabs);
+ groupLayout->addLayout(bottom);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->setContentsMargins(0, 10, 0, 0);
+ layout->setSpacing(0);
+ layout->addWidget(m_group);
+ setLayout(layout);
+}
+
+void CanvasFrameRate::reset(QmlDebugConnection *conn)
+{
+ delete m_plugin;
+ m_plugin = 0;
+
+ QWidget *w;
+ for (int i=0; i<m_tabs->count(); i++) {
+ w = m_tabs->widget(i);
+ m_tabs->removeTab(i);
+ delete w;
+ }
+
+ if (conn) {
+ connect(conn, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
+ SLOT(connectionStateChanged(QAbstractSocket::SocketState)));
+ if (conn->state() == QAbstractSocket::ConnectedState)
+ handleConnected(conn);
+ }
+}
+
+void CanvasFrameRate::connectionStateChanged(QAbstractSocket::SocketState state)
+{
+ if (state == QAbstractSocket::UnconnectedState) {
+ delete m_plugin;
+ m_plugin = 0;
+ } else if (state == QAbstractSocket::ConnectedState) {
+ handleConnected(qobject_cast<QmlDebugConnection*>(sender()));
+ }
+}
+
+void CanvasFrameRate::handleConnected(QmlDebugConnection *conn)
+{
+ delete m_plugin;
+ m_plugin = new CanvasFrameRatePlugin(conn);
+ enabledToggled(m_group->isChecked());
+ newTab();
+}
+
+void CanvasFrameRate::setSizeHint(const QSize &size)
+{
+ m_sizeHint = size;
+}
+
+QSize CanvasFrameRate::sizeHint() const
+{
+ return m_sizeHint;
+}
+
+void CanvasFrameRate::clearGraph()
+{
+ if (m_tabs->count()) {
+ GraphWindow *w = qobject_cast<GraphWindow*>(m_tabs->currentWidget());
+ if (w)
+ w->clear();
+ }
+}
+
+void CanvasFrameRate::newTab()
+{
+ if (!m_plugin)
+ return;
+
+ if (m_tabs->count()) {
+ QWidget *w = m_tabs->widget(m_tabs->count() - 1);
+ QObject::disconnect(m_plugin, SIGNAL(sample(int,int,int,bool)),
+ w, SLOT(addSample(int,int,int,bool)));
+ }
+
+ int count = m_tabs->count();
+
+ GraphWindow *graph = new GraphWindow;
+ graph->setResolutionForHeight(m_res->value());
+ connect(m_plugin, SIGNAL(sample(int,int,int,bool)),
+ graph, SLOT(addSample(int,int,int,bool)));
+ connect(m_res, SIGNAL(valueChanged(int)),
+ graph, SLOT(setResolutionForHeight(int)));
+
+ QString name = QLatin1String("Graph ") + QString::number(count + 1);
+ m_tabs->addTab(graph, name);
+ m_tabs->setCurrentIndex(count);
+}
+
+void CanvasFrameRate::enabledToggled(bool checked)
+{
+ if (m_plugin)
+ static_cast<QmlDebugClient *>(m_plugin)->setEnabled(checked);
+}
+
+QT_END_NAMESPACE
+
+#include "canvasframerate.moc"
diff --git a/tools/qmldebugger/standalone/canvasframerate.h b/tools/qmldebugger/standalone/canvasframerate.h
new file mode 100644
index 0000000..f8eec59
--- /dev/null
+++ b/tools/qmldebugger/standalone/canvasframerate.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef CANVASFRAMERATE_H
+#define CANVASFRAMERATE_H
+
+#include <QtCore/qpointer.h>
+#include <QtGui/qwidget.h>
+
+#include <private/qmldebugclient_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTabWidget;
+class QSlider;
+class QGroupBox;
+class QLabel;
+class QSpinBox;
+class QPushButton;
+
+class CanvasFrameRatePlugin;
+
+class CanvasFrameRate : public QWidget
+{
+ Q_OBJECT
+public:
+ CanvasFrameRate(QWidget *parent = 0);
+
+ void reset(QmlDebugConnection *conn);
+
+ void setSizeHint(const QSize &);
+ virtual QSize sizeHint() const;
+
+private slots:
+ void clearGraph();
+ void newTab();
+ void enabledToggled(bool);
+ void connectionStateChanged(QAbstractSocket::SocketState state);
+
+private:
+ void handleConnected(QmlDebugConnection *conn);
+
+ QGroupBox *m_group;
+ QTabWidget *m_tabs;
+ QSpinBox *m_res;
+ QPushButton *m_clearButton;
+ CanvasFrameRatePlugin *m_plugin;
+ QSize m_sizeHint;
+};
+
+QT_END_NAMESPACE
+
+#endif // CANVASFRAMERATE_H
+
diff --git a/tools/qmldebugger/standalone/engine.cpp b/tools/qmldebugger/standalone/engine.cpp
new file mode 100644
index 0000000..6cfd82b
--- /dev/null
+++ b/tools/qmldebugger/standalone/engine.cpp
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QSplitter>
+#include <QTabWidget>
+#include <QFile>
+
+#include <private/qmlenginedebug_p.h>
+#include <private/qmldebugclient_p.h>
+#include <QtDeclarative/qmlcomponent.h>
+#include <QtDeclarative/qmlgraphicsitem.h>
+#include <private/qmldebugservice_p.h>
+
+#include "engine.h"
+#include "objectpropertiesview.h"
+#include "expressionquerywidget.h"
+#include "objecttree.h"
+#include "watchtable.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 *conn, QWidget *parent)
+: QWidget(parent), m_client(new QmlEngineDebug(conn, this)), m_engines(0), m_context(0), m_watchTableModel(0), m_exprQueryWidget(0)
+{
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->setContentsMargins(0, 0, 0, 0);
+
+ QFile enginesFile(":/engines.qml");
+ enginesFile.open(QFile::ReadOnly);
+ Q_ASSERT(enginesFile.isOpen());
+
+ m_engineView = new QmlView(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(refreshEngines()));
+
+ m_engineView->setVisible(false);
+ layout->addWidget(m_engineView);
+
+ QSplitter *splitter = new QSplitter;
+
+ m_objTree = new ObjectTree(m_client, this);
+ m_propertiesView = new ObjectPropertiesView(m_client);
+ m_watchTableModel = new WatchTableModel(m_client, this);
+
+ m_watchTableView = new WatchTableView(m_watchTableModel);
+ m_watchTableView->setModel(m_watchTableModel);
+ WatchTableHeaderView *header = new WatchTableHeaderView(m_watchTableModel);
+ m_watchTableView->setHorizontalHeader(header);
+
+ connect(m_objTree, SIGNAL(currentObjectChanged(QmlDebugObjectReference)),
+ m_propertiesView, SLOT(reload(QmlDebugObjectReference)));
+ connect(m_objTree, SIGNAL(expressionWatchRequested(QmlDebugObjectReference,QString)),
+ m_watchTableModel, SLOT(expressionWatchRequested(QmlDebugObjectReference,QString)));
+
+ connect(m_propertiesView, SIGNAL(activated(QmlDebugObjectReference,QmlDebugPropertyReference)),
+ m_watchTableModel, SLOT(togglePropertyWatch(QmlDebugObjectReference,QmlDebugPropertyReference)));
+
+ connect(m_watchTableModel, SIGNAL(watchCreated(QmlDebugWatch*)),
+ m_propertiesView, SLOT(watchCreated(QmlDebugWatch*)));
+
+ connect(m_watchTableView, SIGNAL(objectActivated(int)),
+ m_objTree, SLOT(setCurrentObject(int)));
+
+ m_exprQueryWidget = new ExpressionQueryWidget(ExpressionQueryWidget::SeparateEntryMode, m_client);
+ connect(m_objTree, SIGNAL(currentObjectChanged(QmlDebugObjectReference)),
+ m_exprQueryWidget, SLOT(setCurrentObject(QmlDebugObjectReference)));
+
+ QSplitter *propertiesTab = new QSplitter(Qt::Vertical);
+ propertiesTab->addWidget(m_propertiesView);
+ propertiesTab->addWidget(m_exprQueryWidget);
+ propertiesTab->setStretchFactor(0, 2);
+ propertiesTab->setStretchFactor(1, 1);
+
+ m_tabs = new QTabWidget(this);
+ m_tabs->addTab(propertiesTab, tr("Properties"));
+ m_tabs->addTab(m_watchTableView, tr("Watched"));
+
+ splitter->addWidget(m_objTree);
+ splitter->addWidget(m_tabs);
+ splitter->setStretchFactor(1, 2);
+ layout->addWidget(splitter);
+}
+
+void EnginePane::engineSelected(int id)
+{
+ qWarning() << "Engine selected" << id;
+ queryContext(id);
+}
+
+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(QmlDebugQuery::State)),
+ this, SLOT(contextChanged()));
+}
+
+void EnginePane::contextChanged()
+{
+ //dump(m_context->rootContext(), 0);
+
+ foreach (const QmlDebugObjectReference &object, m_context->rootContext().objects())
+ m_objTree->reload(object.debugId());
+
+ delete m_context; m_context = 0;
+}
+
+void EnginePane::refreshEngines()
+{
+ if (m_engines)
+ return;
+
+ m_engines = m_client->queryAvailableEngines(this);
+ if (!m_engines->isWaiting())
+ enginesChanged();
+ else
+ QObject::connect(m_engines, SIGNAL(stateChanged(QmlDebugQuery::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;
+
+ if (engines.isEmpty())
+ qWarning("qmldebugger: no engines found!");
+
+ 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));
+
+ m_engineView->setVisible(m_engineItems.count() > 1);
+ if (m_engineItems.count() == 1)
+ engineSelected(qobject_cast<DebuggerEngineItem*>(m_engineItems.at(0))->engineId());
+}
+
+
+#include "engine.moc"
+
+QT_END_NAMESPACE
+
diff --git a/tools/qmldebugger/standalone/engine.h b/tools/qmldebugger/standalone/engine.h
new file mode 100644
index 0000000..f4c4275
--- /dev/null
+++ b/tools/qmldebugger/standalone/engine.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef ENGINE_H
+#define ENGINE_H
+
+#include <QWidget>
+#include <QtCore/qpointer.h>
+#include <QtDeclarative/qmlengine.h>
+#include <QtDeclarative/qmlcontext.h>
+#include <QtDeclarative/qmlview.h>
+#include <private/qmldebug_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class ObjectPropertiesView;
+class QmlDebugConnection;
+class QmlDebugPropertyReference;
+class QmlDebugWatch;
+class ObjectTree;
+class WatchTableModel;
+class WatchTableView;
+class ExpressionQueryWidget;
+
+class QTabWidget;
+
+class EnginePane : public QWidget
+{
+Q_OBJECT
+public:
+ EnginePane(QmlDebugConnection *, QWidget *parent = 0);
+
+public slots:
+ void refreshEngines();
+
+private slots:
+ void enginesChanged();
+
+ void queryContext(int);
+ void contextChanged();
+
+ void engineSelected(int);
+
+private:
+ QmlEngineDebug *m_client;
+ QmlDebugEnginesQuery *m_engines;
+ QmlDebugRootContextQuery *m_context;
+
+ ObjectTree *m_objTree;
+ QTabWidget *m_tabs;
+ WatchTableView *m_watchTableView;
+ WatchTableModel *m_watchTableModel;
+ ExpressionQueryWidget *m_exprQueryWidget;
+
+ QmlView *m_engineView;
+ QList<QObject *> m_engineItems;
+
+ ObjectPropertiesView *m_propertiesView;
+};
+
+QT_END_NAMESPACE
+
+#endif // ENGINE_H
+
diff --git a/tools/qmldebugger/standalone/engine.png b/tools/qmldebugger/standalone/engine.png
new file mode 100644
index 0000000..a0a8a04
--- /dev/null
+++ b/tools/qmldebugger/standalone/engine.png
Binary files differ
diff --git a/tools/qmldebugger/standalone/engines.qml b/tools/qmldebugger/standalone/engines.qml
new file mode 100644
index 0000000..1e9335b
--- /dev/null
+++ b/tools/qmldebugger/standalone/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 {
+ model: engines
+ Item {
+ width: 100; height: 100;
+ Image {
+ id: EngineIcon;
+ source: "qrc:/engine.png"
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ Text {
+ anchors.top: EngineIcon.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/standalone/expressionquerywidget.cpp b/tools/qmldebugger/standalone/expressionquerywidget.cpp
new file mode 100644
index 0000000..cd59871
--- /dev/null
+++ b/tools/qmldebugger/standalone/expressionquerywidget.cpp
@@ -0,0 +1,276 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtCore/qdebug.h>
+
+#include <QtGui/qlabel.h>
+#include <QtGui/qtextedit.h>
+#include <QtGui/qlineedit.h>
+#include <QtGui/qpushbutton.h>
+#include <QtGui/qevent.h>
+#include <QtGui/qgroupbox.h>
+#include <QtGui/qtextobject.h>
+#include <QtGui/qlayout.h>
+
+#include "expressionquerywidget.h"
+
+ExpressionQueryWidget::ExpressionQueryWidget(Mode mode, QmlEngineDebug *client, QWidget *parent)
+ : QWidget(parent),
+ m_mode(mode),
+ m_client(client),
+ m_query(0),
+ m_textEdit(new QTextEdit),
+ m_lineEdit(0)
+{
+ m_prompt = QLatin1String(">> ");
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->setMargin(0);
+ layout->setSpacing(0);
+ layout->addWidget(m_textEdit);
+
+ updateTitle();
+
+ if (m_mode == SeparateEntryMode) {
+ m_lineEdit = new QLineEdit;
+ connect(m_lineEdit, SIGNAL(returnPressed()), SLOT(executeExpression()));
+ QHBoxLayout *hbox = new QHBoxLayout;
+ hbox->setMargin(5);
+ hbox->setSpacing(5);
+ hbox->addWidget(new QLabel(tr("Expression:")));
+ hbox->addWidget(m_lineEdit);
+ layout->addLayout(hbox);
+
+ m_textEdit->setReadOnly(true);
+ m_lineEdit->installEventFilter(this);
+ } else {
+ m_textEdit->installEventFilter(this);
+ appendPrompt();
+ }
+}
+
+void ExpressionQueryWidget::setEngineDebug(QmlEngineDebug *client)
+{
+ m_client = client;
+}
+
+void ExpressionQueryWidget::clear()
+{
+ m_textEdit->clear();
+ if (m_lineEdit)
+ m_lineEdit->clear();
+ if (m_mode == ShellMode)
+ appendPrompt();
+}
+
+void ExpressionQueryWidget::updateTitle()
+{
+ if (m_currObject.debugId() < 0) {
+ m_title = tr("Expression queries");
+ } else {
+ QString desc = QLatin1String("<")
+ + m_currObject.className() + QLatin1String(": ")
+ + (m_currObject.name().isEmpty() ? QLatin1String("<unnamed>") : m_currObject.name())
+ + QLatin1String(">");
+ m_title = tr("Expression queries (using context for %1)" , "Selected object").arg(desc);
+ }
+}
+
+void ExpressionQueryWidget::appendPrompt()
+{
+ m_textEdit->moveCursor(QTextCursor::End);
+
+ if (m_mode == SeparateEntryMode) {
+ m_textEdit->insertPlainText("\n");
+ } else {
+ m_textEdit->setTextColor(Qt::gray);
+ m_textEdit->append(m_prompt);
+ }
+}
+
+void ExpressionQueryWidget::setCurrentObject(const QmlDebugObjectReference &obj)
+{
+ m_currObject = obj;
+ updateTitle();
+}
+
+void ExpressionQueryWidget::checkCurrentContext()
+{
+ m_textEdit->moveCursor(QTextCursor::End);
+
+ if (m_currObject.debugId() != -1 && m_currObject.debugId() != m_objectAtLastFocus.debugId())
+ showCurrentContext();
+ m_objectAtLastFocus = m_currObject;
+}
+
+void ExpressionQueryWidget::showCurrentContext()
+{
+ if (m_mode == ShellMode) {
+ // clear the initial prompt
+ if (m_textEdit->document()->lineCount() == 1)
+ m_textEdit->clear();
+ }
+
+ m_textEdit->moveCursor(QTextCursor::End);
+ m_textEdit->setTextColor(Qt::darkGreen);
+ m_textEdit->append(m_currObject.className()
+ + QLatin1String(": ")
+ + (m_currObject.name().isEmpty() ? QLatin1String("<unnamed object>") : m_currObject.name()));
+ appendPrompt();
+}
+
+void ExpressionQueryWidget::executeExpression()
+{
+ if (!m_client)
+ return;
+
+ if (m_mode == SeparateEntryMode)
+ m_expr = m_lineEdit->text().trimmed();
+ else
+ m_expr = m_expr.trimmed();
+
+ if (!m_expr.isEmpty() && m_currObject.debugId() != -1) {
+ if (m_query)
+ delete m_query;
+ m_query = m_client->queryExpressionResult(m_currObject.debugId(), m_expr, this);
+ if (!m_query->isWaiting())
+ showResult();
+ else
+ QObject::connect(m_query, SIGNAL(stateChanged(QmlDebugQuery::State)),
+ this, SLOT(showResult()));
+
+ m_lastExpr = m_expr;
+ if (m_lineEdit)
+ m_lineEdit->clear();
+ }
+}
+
+void ExpressionQueryWidget::showResult()
+{
+ if (m_query) {
+ m_textEdit->moveCursor(QTextCursor::End);
+ QVariant value = m_query->result();
+ QString result;
+
+ if (value.type() == QVariant::List || value.type() == QVariant::StringList) {
+ result = tr("<%1 items>", "%1 = number of items").arg(value.toList().count());
+ } else if (value.isNull()) {
+ result = QLatin1String("<no value>");
+ } else {
+ result = value.toString();
+ }
+
+ if (m_mode == SeparateEntryMode) {
+ m_textEdit->setTextColor(Qt::black);
+ m_textEdit->setFontWeight(QFont::Bold);
+ m_textEdit->insertPlainText(m_expr + " : ");
+ m_textEdit->setFontWeight(QFont::Normal);
+ m_textEdit->insertPlainText(result);
+ } else {
+ m_textEdit->setTextColor(Qt::darkGreen);
+ m_textEdit->insertPlainText(" => ");
+ m_textEdit->setTextColor(Qt::black);
+ m_textEdit->insertPlainText(result);
+ }
+ appendPrompt();
+ m_expr.clear();
+ }
+}
+
+bool ExpressionQueryWidget::eventFilter(QObject *obj, QEvent *event)
+{
+ if (obj == m_textEdit) {
+ switch (event->type()) {
+ case QEvent::KeyPress:
+ {
+ QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
+ int key = keyEvent->key();
+ if (key == Qt::Key_Return || key == Qt::Key_Enter) {
+ executeExpression();
+ return true;
+ } else if (key == Qt::Key_Backspace) {
+ // ensure m_expr doesn't contain backspace characters
+ QTextCursor cursor = m_textEdit->textCursor();
+ bool atLastLine = !(cursor.block().next().isValid());
+ if (!atLastLine)
+ return true;
+ if (cursor.columnNumber() <= m_prompt.count())
+ return true;
+ cursor.deletePreviousChar();
+ m_expr = cursor.block().text().mid(m_prompt.count());
+ return true;
+ } else {
+ m_textEdit->moveCursor(QTextCursor::End);
+ m_textEdit->setTextColor(Qt::black);
+ m_expr += keyEvent->text();
+ }
+ break;
+ }
+ case QEvent::FocusIn:
+ checkCurrentContext();
+ m_textEdit->moveCursor(QTextCursor::End);
+ break;
+ default:
+ break;
+ }
+ } else if (obj == m_lineEdit) {
+ switch (event->type()) {
+ case QEvent::KeyPress:
+ {
+ QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
+ int key = keyEvent->key();
+ if (key == Qt::Key_Up && m_lineEdit->text() != m_lastExpr) {
+ m_expr = m_lineEdit->text();
+ if (!m_lastExpr.isEmpty())
+ m_lineEdit->setText(m_lastExpr);
+ } else if (key == Qt::Key_Down) {
+ m_lineEdit->setText(m_expr);
+ }
+ break;
+ }
+ case QEvent::FocusIn:
+ checkCurrentContext();
+ break;
+ default:
+ break;
+ }
+ }
+ return QWidget::eventFilter(obj, event);
+}
diff --git a/tools/qmldebugger/standalone/expressionquerywidget.h b/tools/qmldebugger/standalone/expressionquerywidget.h
new file mode 100644
index 0000000..8c224f8
--- /dev/null
+++ b/tools/qmldebugger/standalone/expressionquerywidget.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef EXPRESSIONQUERYWIDGET_H
+#define EXPRESSIONQUERYWIDGET_H
+
+#include <QWidget>
+
+#include <private/qmldebug_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGroupBox;
+class QTextEdit;
+class QLineEdit;
+class QPushButton;
+
+class ExpressionQueryWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ enum Mode {
+ SeparateEntryMode,
+ ShellMode
+ };
+
+ ExpressionQueryWidget(Mode mode = SeparateEntryMode, QmlEngineDebug *client = 0, QWidget *parent = 0);
+
+ void setEngineDebug(QmlEngineDebug *client);
+ void clear();
+
+protected:
+ bool eventFilter(QObject *obj, QEvent *event);
+
+public slots:
+ void setCurrentObject(const QmlDebugObjectReference &obj);
+
+private slots:
+ void executeExpression();
+ void showResult();
+
+private:
+ void appendPrompt();
+ void checkCurrentContext();
+ void showCurrentContext();
+ void updateTitle();
+
+ Mode m_mode;
+
+ QmlEngineDebug *m_client;
+ QmlDebugExpressionQuery *m_query;
+ QTextEdit *m_textEdit;
+ QLineEdit *m_lineEdit;
+ QPushButton *m_button;
+ QString m_prompt;
+ QString m_expr;
+ QString m_lastExpr;
+
+ QString m_title;
+
+ QmlDebugObjectReference m_currObject;
+ QmlDebugObjectReference m_objectAtLastFocus;
+};
+
+QT_END_NAMESPACE
+
+#endif
+
diff --git a/tools/qmldebugger/standalone/main.cpp b/tools/qmldebugger/standalone/main.cpp
new file mode 100644
index 0000000..715837e
--- /dev/null
+++ b/tools/qmldebugger/standalone/main.cpp
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtGui/qapplication.h>
+
+#include "qmldebugger.h"
+
+int main(int argc, char ** argv)
+{
+ QApplication app(argc, argv);
+ app.setApplicationName("QtQmlDebugger");
+ app.setOrganizationName("Nokia");
+ app.setOrganizationDomain("nokia.com");
+
+ QStringList args = app.arguments();
+
+ QmlDebugger win;
+ if (args.contains("--engine"))
+ win.showEngineTab();
+
+ for (int i=0; i<args.count(); i++) {
+ if (!args[i].contains(':'))
+ continue;
+ QStringList hostAndPort = args[i].split(':');
+ bool ok = false;
+ quint16 port = hostAndPort.value(1).toInt(&ok);
+ if (ok) {
+ qWarning() << "qmldebugger connecting to"
+ << hostAndPort[0] << port << "...";
+ win.setHost(hostAndPort[0]);
+ win.setPort(port);
+ win.connectToHost();
+ break;
+ }
+ }
+
+ win.show();
+
+ return app.exec();
+}
diff --git a/tools/qmldebugger/standalone/objectpropertiesview.cpp b/tools/qmldebugger/standalone/objectpropertiesview.cpp
new file mode 100644
index 0000000..3a8d8c8
--- /dev/null
+++ b/tools/qmldebugger/standalone/objectpropertiesview.cpp
@@ -0,0 +1,274 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtCore/qdebug.h>
+
+#include <QtGui/qtreewidget.h>
+#include <QtGui/qlayout.h>
+#include <QtGui/qheaderview.h>
+
+#include <private/qmldebugservice_p.h>
+#include <private/qmldebug_p.h>
+#include <private/qmldebugclient_p.h>
+
+#include "objectpropertiesview.h"
+
+QT_BEGIN_NAMESPACE
+
+class PropertiesViewItem : public QObject, public QTreeWidgetItem
+{
+ Q_OBJECT
+public:
+ enum Type {
+ BindingType,
+ OtherType
+ };
+
+ PropertiesViewItem(QTreeWidget *widget, Type type = OtherType);
+ PropertiesViewItem(QTreeWidgetItem *parent, Type type = OtherType);
+
+ QmlDebugPropertyReference property;
+ Type type;
+};
+
+PropertiesViewItem::PropertiesViewItem(QTreeWidget *widget, Type type)
+ : QTreeWidgetItem(widget), type(type)
+{
+}
+
+PropertiesViewItem::PropertiesViewItem(QTreeWidgetItem *parent, Type type)
+ : QTreeWidgetItem(parent), type(type)
+{
+}
+
+ObjectPropertiesView::ObjectPropertiesView(QmlEngineDebug *client, QWidget *parent)
+ : QWidget(parent),
+ m_client(client),
+ m_query(0),
+ m_watch(0)
+{
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->setSpacing(0);
+ setLayout(layout);
+
+ m_tree = new QTreeWidget(this);
+ m_tree->setAlternatingRowColors(true);
+ m_tree->setExpandsOnDoubleClick(false);
+ m_tree->setHeaderLabels(QStringList()
+ << tr("Name") << tr("Value") << tr("Type"));
+ QObject::connect(m_tree, SIGNAL(itemActivated(QTreeWidgetItem *, int)),
+ this, SLOT(itemActivated(QTreeWidgetItem *)));
+
+ m_tree->setColumnCount(3);
+ m_tree->header()->setDefaultSectionSize(150);
+
+ layout->addWidget(m_tree);
+}
+
+void ObjectPropertiesView::setEngineDebug(QmlEngineDebug *client)
+{
+ m_client = client;
+}
+
+void ObjectPropertiesView::clear()
+{
+ setObject(QmlDebugObjectReference());
+}
+
+void ObjectPropertiesView::reload(const QmlDebugObjectReference &obj)
+{
+ if (!m_client)
+ return;
+ if (m_query)
+ delete m_query;
+
+ m_query = m_client->queryObjectRecursive(obj, this);
+ if (!m_query->isWaiting())
+ queryFinished();
+ else
+ QObject::connect(m_query, SIGNAL(stateChanged(QmlDebugQuery::State)),
+ this, SLOT(queryFinished()));
+}
+
+void ObjectPropertiesView::queryFinished()
+{
+ if (!m_client || !m_query)
+ return;
+
+ QmlDebugObjectReference obj = m_query->object();
+
+ QmlDebugWatch *watch = m_client->addWatch(obj, this);
+ if (watch->state() == QmlDebugWatch::Dead) {
+ delete watch;
+ watch = 0;
+ } else {
+ if (m_watch) {
+ m_client->removeWatch(m_watch);
+ delete m_watch;
+ }
+ m_watch = watch;
+ QObject::connect(watch, SIGNAL(valueChanged(QByteArray,QVariant)),
+ this, SLOT(valueChanged(QByteArray,QVariant)));
+ }
+
+ delete m_query;
+ m_query = 0;
+
+ setObject(obj);
+}
+
+void ObjectPropertiesView::setPropertyValue(PropertiesViewItem *item, const QVariant &value, bool makeGray)
+{
+ if (value.type() == QVariant::List || value.type() == QVariant::StringList) {
+ PropertiesViewItem *bindingItem = static_cast<PropertiesViewItem*>(item->takeChild(item->childCount() - 1));
+ if (bindingItem && bindingItem->type != PropertiesViewItem::BindingType) {
+ delete bindingItem;
+ bindingItem = 0;
+ }
+
+ qDeleteAll(item->takeChildren());
+
+ QVariantList variants = value.toList();
+ item->setText(1, tr("<%1 items>", "%1 = number of items").arg(variants.count()));
+ item->setText(2, QString::fromUtf8(value.typeName()));
+
+ PropertiesViewItem *child;
+ for (int i=0; i<variants.count(); i++) {
+ child = new PropertiesViewItem(item);
+ setPropertyValue(child, variants[i], makeGray);
+ }
+
+ if (bindingItem)
+ item->addChild(bindingItem);
+
+ item->setExpanded(false);
+ } else {
+ item->setText(1, (value.isNull() ? QLatin1String("<no value>") : value.toString()));
+ item->setExpanded(true);
+ }
+
+ if (makeGray) {
+ for (int i=0; i<m_tree->columnCount(); i++)
+ item->setForeground(i, Qt::gray);
+ }
+}
+
+void ObjectPropertiesView::setObject(const QmlDebugObjectReference &object)
+{
+ m_object = object;
+ m_tree->clear();
+
+ QList<QmlDebugPropertyReference> properties = object.properties();
+ for (int i=0; i<properties.count(); i++) {
+ const QmlDebugPropertyReference &p = properties[i];
+
+ PropertiesViewItem *item = new PropertiesViewItem(m_tree);
+ item->property = p;
+
+ item->setText(0, p.name());
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+
+ setPropertyValue(item, p.value(), !p.hasNotifySignal());
+ item->setText(2, p.valueTypeName());
+
+ // binding is set after property value to ensure it is added to the end of the
+ // list, if the value is a list
+ if (!p.binding().isEmpty()) {
+ PropertiesViewItem *binding = new PropertiesViewItem(item, PropertiesViewItem::BindingType);
+ binding->setText(1, p.binding());
+ binding->setForeground(1, Qt::darkGreen);
+ }
+ }
+}
+
+void ObjectPropertiesView::watchCreated(QmlDebugWatch *watch)
+{
+ if (watch->objectDebugId() == m_object.debugId()
+ && qobject_cast<QmlDebugPropertyWatch*>(watch)) {
+ connect(watch, SIGNAL(stateChanged(QmlDebugWatch::State)), SLOT(watchStateChanged()));
+ setWatched(qobject_cast<QmlDebugPropertyWatch*>(watch)->name(), true);
+ }
+}
+
+void ObjectPropertiesView::watchStateChanged()
+{
+ QmlDebugWatch *watch = qobject_cast<QmlDebugWatch*>(sender());
+
+ if (watch->objectDebugId() == m_object.debugId()
+ && qobject_cast<QmlDebugPropertyWatch*>(watch)
+ && watch->state() == QmlDebugWatch::Inactive) {
+ setWatched(qobject_cast<QmlDebugPropertyWatch*>(watch)->name(), false);
+ }
+}
+
+void ObjectPropertiesView::setWatched(const QString &property, bool watched)
+{
+ for (int i=0; i<m_tree->topLevelItemCount(); i++) {
+ PropertiesViewItem *item = static_cast<PropertiesViewItem *>(m_tree->topLevelItem(i));
+ if (item->property.name() == property && item->property.hasNotifySignal()) {
+ QFont font = m_tree->font();
+ font.setBold(watched);
+ item->setFont(0, font);
+ }
+ }
+}
+
+void ObjectPropertiesView::valueChanged(const QByteArray &name, const QVariant &value)
+{
+ for (int i=0; i<m_tree->topLevelItemCount(); i++) {
+ PropertiesViewItem *item = static_cast<PropertiesViewItem *>(m_tree->topLevelItem(i));
+ if (item->property.name() == name) {
+ setPropertyValue(item, value, !item->property.hasNotifySignal());
+ return;
+ }
+ }
+}
+
+void ObjectPropertiesView::itemActivated(QTreeWidgetItem *i)
+{
+ PropertiesViewItem *item = static_cast<PropertiesViewItem *>(i);
+ if (!item->property.name().isEmpty())
+ emit activated(m_object, item->property);
+}
+
+QT_END_NAMESPACE
+
+#include "objectpropertiesview.moc"
diff --git a/tools/qmldebugger/standalone/objectpropertiesview.h b/tools/qmldebugger/standalone/objectpropertiesview.h
new file mode 100644
index 0000000..43413dc
--- /dev/null
+++ b/tools/qmldebugger/standalone/objectpropertiesview.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef PROPERTIESTABLEMODEL_H
+#define PROPERTIESTABLEMODEL_H
+
+#include <private/qmldebug_p.h>
+
+#include <QtGui/qwidget.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTreeWidget;
+class QTreeWidgetItem;
+class QmlDebugConnection;
+class PropertiesViewItem;
+
+class ObjectPropertiesView : public QWidget
+{
+ Q_OBJECT
+public:
+ ObjectPropertiesView(QmlEngineDebug *client = 0, QWidget *parent = 0);
+
+ void setEngineDebug(QmlEngineDebug *client);
+ void clear();
+
+signals:
+ void activated(const QmlDebugObjectReference &, const QmlDebugPropertyReference &);
+
+public slots:
+ void reload(const QmlDebugObjectReference &);
+ void watchCreated(QmlDebugWatch *);
+
+private slots:
+ void queryFinished();
+ void watchStateChanged();
+ void valueChanged(const QByteArray &name, const QVariant &value);
+ void itemActivated(QTreeWidgetItem *i);
+
+private:
+ void setObject(const QmlDebugObjectReference &object);
+ void setWatched(const QString &property, bool watched);
+ void setPropertyValue(PropertiesViewItem *item, const QVariant &value, bool makeGray);
+
+ QmlEngineDebug *m_client;
+ QmlDebugObjectQuery *m_query;
+ QmlDebugWatch *m_watch;
+
+ QTreeWidget *m_tree;
+ QmlDebugObjectReference m_object;
+};
+
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/tools/qmldebugger/standalone/objecttree.cpp b/tools/qmldebugger/standalone/objecttree.cpp
new file mode 100644
index 0000000..cf467f2
--- /dev/null
+++ b/tools/qmldebugger/standalone/objecttree.cpp
@@ -0,0 +1,231 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtGui/qevent.h>
+#include <QtGui/qmenu.h>
+#include <QtGui/qaction.h>
+
+#include <QInputDialog>
+
+#include <private/qmldebugservice_p.h>
+#include <private/qmldebug_p.h>
+#include <private/qmldebugclient_p.h>
+
+#include "objecttree.h"
+
+Q_DECLARE_METATYPE(QmlDebugObjectReference)
+
+ObjectTree::ObjectTree(QmlEngineDebug *client, QWidget *parent)
+ : QTreeWidget(parent),
+ m_client(client),
+ m_query(0)
+{
+ setHeaderHidden(true);
+ setMinimumWidth(250);
+ setExpandsOnDoubleClick(false);
+
+ connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
+ SLOT(currentItemChanged(QTreeWidgetItem *)));
+ connect(this, SIGNAL(itemActivated(QTreeWidgetItem *, int)),
+ SLOT(activated(QTreeWidgetItem *)));
+}
+
+void ObjectTree::setEngineDebug(QmlEngineDebug *client)
+{
+ m_client = client;
+}
+
+void ObjectTree::reload(int objectDebugId)
+{
+ if (!m_client)
+ return;
+
+ if (m_query) {
+ delete m_query;
+ m_query = 0;
+ }
+
+ m_query = m_client->queryObjectRecursive(QmlDebugObjectReference(objectDebugId), this);
+ if (!m_query->isWaiting())
+ objectFetched();
+ else
+ QObject::connect(m_query, SIGNAL(stateChanged(QmlDebugQuery::State)),
+ this, SLOT(objectFetched()));
+}
+
+void ObjectTree::setCurrentObject(int debugId)
+{
+ QTreeWidgetItem *item = findItemByObjectId(debugId);
+ if (item) {
+ setCurrentItem(item);
+ scrollToItem(item);
+ item->setExpanded(true);
+ }
+}
+
+void ObjectTree::objectFetched()
+{
+ dump(m_query->object(), 0);
+ buildTree(m_query->object(), 0);
+ setCurrentItem(topLevelItem(0));
+
+ delete m_query;
+ m_query = 0;
+}
+
+void ObjectTree::currentItemChanged(QTreeWidgetItem *item)
+{
+ if (!item)
+ return;
+
+ QmlDebugObjectReference obj = item->data(0, Qt::UserRole).value<QmlDebugObjectReference>();
+ if (obj.debugId() >= 0)
+ emit currentObjectChanged(obj);
+}
+
+void ObjectTree::activated(QTreeWidgetItem *item)
+{
+ if (!item)
+ return;
+
+ QmlDebugObjectReference obj = item->data(0, Qt::UserRole).value<QmlDebugObjectReference>();
+ if (obj.debugId() >= 0)
+ emit activated(obj);
+}
+
+void ObjectTree::buildTree(const QmlDebugObjectReference &obj, QTreeWidgetItem *parent)
+{
+ if (!parent)
+ clear();
+
+ QTreeWidgetItem *item = parent ? new QTreeWidgetItem(parent) : new QTreeWidgetItem(this);
+ item->setText(0, obj.className());
+ item->setData(0, Qt::UserRole, qVariantFromValue(obj));
+
+ if (parent && obj.contextDebugId() >= 0
+ && obj.contextDebugId() != parent->data(0, Qt::UserRole
+ ).value<QmlDebugObjectReference>().contextDebugId()) {
+ QmlDebugFileReference source = obj.source();
+ if (!source.url().isEmpty()) {
+ QString toolTipString = QLatin1String("URL: ") + source.url().toString();
+ item->setToolTip(0, toolTipString);
+ }
+ item->setForeground(0, QColor("orange"));
+ } else {
+ item->setExpanded(true);
+ }
+
+ if (obj.contextDebugId() < 0)
+ item->setForeground(0, Qt::lightGray);
+
+ for (int ii = 0; ii < obj.children().count(); ++ii)
+ buildTree(obj.children().at(ii), item);
+}
+
+void ObjectTree::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 ObjectTree::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);
+}
+
+QTreeWidgetItem *ObjectTree::findItemByObjectId(int debugId) const
+{
+ for (int i=0; i<topLevelItemCount(); i++) {
+ QTreeWidgetItem *item = findItem(topLevelItem(i), debugId);
+ if (item)
+ return item;
+ }
+
+ return 0;
+}
+
+QTreeWidgetItem *ObjectTree::findItem(QTreeWidgetItem *item, int debugId) const
+{
+ if (item->data(0, Qt::UserRole).value<QmlDebugObjectReference>().debugId() == debugId)
+ return item;
+
+ QTreeWidgetItem *child;
+ for (int i=0; i<item->childCount(); i++) {
+ child = findItem(item->child(i), debugId);
+ if (child)
+ return child;
+ }
+
+ return 0;
+}
+
+void ObjectTree::mousePressEvent(QMouseEvent *me)
+{
+ QTreeWidget::mousePressEvent(me);
+ if (!currentItem())
+ return;
+ if(me->button() == Qt::RightButton && me->type() == QEvent::MouseButtonPress) {
+ QAction action(tr("Add watch..."), 0);
+ QList<QAction *> actions;
+ actions << &action;
+ QmlDebugObjectReference obj =
+ currentItem()->data(0, Qt::UserRole).value<QmlDebugObjectReference>();
+ if (QMenu::exec(actions, me->globalPos())) {
+ bool ok = false;
+ QString watch = QInputDialog::getText(this, tr("Watch expression"),
+ tr("Expression:"), QLineEdit::Normal, QString(), &ok);
+ if (ok && !watch.isEmpty())
+ emit expressionWatchRequested(obj, watch);
+ }
+ }
+}
diff --git a/tools/qmldebugger/standalone/objecttree.h b/tools/qmldebugger/standalone/objecttree.h
new file mode 100644
index 0000000..c8d625c
--- /dev/null
+++ b/tools/qmldebugger/standalone/objecttree.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef OBJECTTREE_H
+#define OBJECTTREE_H
+
+#include <QtGui/qtreewidget.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTreeWidgetItem;
+
+class QmlEngineDebug;
+class QmlDebugObjectReference;
+class QmlDebugObjectQuery;
+class QmlDebugContextReference;
+class QmlDebugConnection;
+
+
+class ObjectTree : public QTreeWidget
+{
+ Q_OBJECT
+public:
+ ObjectTree(QmlEngineDebug *client = 0, QWidget *parent = 0);
+
+ void setEngineDebug(QmlEngineDebug *client);
+
+signals:
+ void currentObjectChanged(const QmlDebugObjectReference &);
+ void activated(const QmlDebugObjectReference &);
+ void expressionWatchRequested(const QmlDebugObjectReference &, const QString &);
+
+public slots:
+ void reload(int objectDebugId); // set the root object
+ void setCurrentObject(int debugId); // select an object in the tree
+
+protected:
+ virtual void mousePressEvent(QMouseEvent *);
+
+private slots:
+ void objectFetched();
+ void currentItemChanged(QTreeWidgetItem *);
+ void activated(QTreeWidgetItem *);
+
+private:
+ QTreeWidgetItem *findItemByObjectId(int debugId) const;
+ QTreeWidgetItem *findItem(QTreeWidgetItem *item, int debugId) const;
+ void dump(const QmlDebugContextReference &, int);
+ void dump(const QmlDebugObjectReference &, int);
+ void buildTree(const QmlDebugObjectReference &, QTreeWidgetItem *parent);
+
+ QmlEngineDebug *m_client;
+ QmlDebugObjectQuery *m_query;
+};
+
+QT_END_NAMESPACE
+
+
+#endif
diff --git a/tools/qmldebugger/standalone/qmldebugger.cpp b/tools/qmldebugger/standalone/qmldebugger.cpp
new file mode 100644
index 0000000..4d86377
--- /dev/null
+++ b/tools/qmldebugger/standalone/qmldebugger.cpp
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtCore/qtimer.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qsettings.h>
+
+#include <QtGui/qlayout.h>
+#include <QtGui/qpushbutton.h>
+#include <QtGui/qlineedit.h>
+#include <QtGui/qtabwidget.h>
+#include <QtGui/qspinbox.h>
+#include <QtGui/qlabel.h>
+
+#include "canvasframerate.h"
+#include "engine.h"
+#include "qmldebugger.h"
+
+QmlDebugger::QmlDebugger(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);
+ connectLayout->addWidget(m_host);
+ m_port = new QSpinBox(this);
+ m_port->setMinimum(1024);
+ m_port->setMaximum(20000);
+ 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);
+
+ m_tabs = new QTabWidget(this);
+ layout->addWidget(m_tabs);
+
+ CanvasFrameRate *cfr = new CanvasFrameRate(this);
+ cfr->reset(&client);
+ cfr->setSizeHint(QSize(800, 600));
+ m_tabs->addTab(cfr, tr("Frame Rate"));
+
+ m_enginePane = new EnginePane(&client, this);
+ m_tabs->addTab(m_enginePane, tr("QML Engine"));
+
+ QObject::connect(&client, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
+ this, SLOT(connectionStateChanged()));
+ connectionStateChanged();
+
+ QObject::connect(&client, SIGNAL(error(QAbstractSocket::SocketError)),
+ this, SLOT(connectionError(QAbstractSocket::SocketError)));
+
+ QSettings settings;
+ m_host->setText(settings.value("Host", "127.0.0.1").toString());
+ m_port->setValue(settings.value("Port", 3768).toInt());
+
+ connectToHost();
+}
+
+void QmlDebugger::setHost(const QString &host)
+{
+ m_host->setText(host);
+}
+
+void QmlDebugger::setPort(quint16 port)
+{
+ m_port->setValue(port);
+}
+
+void QmlDebugger::showEngineTab()
+{
+ m_tabs->setCurrentWidget(m_enginePane);
+}
+
+void QmlDebugger::closeEvent(QCloseEvent *event)
+{
+ QSettings settings;
+ settings.setValue("Host", m_host->text());
+ settings.setValue("Port", m_port->value());
+
+ QWidget::closeEvent(event);
+}
+
+void QmlDebugger::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);
+
+ QTimer::singleShot(0, m_enginePane, SLOT(refreshEngines()));
+ break;
+ case QAbstractSocket::ClosingState:
+ m_connectionState->setText(tr("Closing"));
+ m_connectButton->setEnabled(false);
+ m_disconnectButton->setEnabled(false);
+ break;
+ }
+}
+
+void QmlDebugger::connectionError(QAbstractSocket::SocketError socketError)
+{
+ qWarning() << "qmldebugger cannot connect:" << socketError
+ << client.errorString();
+}
+
+void QmlDebugger::connectToHost()
+{
+ client.connectToHost(m_host->text(), m_port->value());
+}
+
+void QmlDebugger::disconnectFromHost()
+{
+ client.disconnectFromHost();
+}
diff --git a/tools/qmldebugger/standalone/qmldebugger.h b/tools/qmldebugger/standalone/qmldebugger.h
new file mode 100644
index 0000000..da95ef9
--- /dev/null
+++ b/tools/qmldebugger/standalone/qmldebugger.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QMLDEBUGGER_H
+#define QMLDEBUGGER_H
+
+#include <private/qmldebugclient_p.h>
+#include <QtNetwork/qtcpsocket.h>
+#include <QtGui/qwidget.h>
+
+class QLabel;
+class QLineEdit;
+class QSpinBox;
+class QPushButton;
+class QTabWidget;
+
+class EnginePane;
+
+class QmlDebugger : public QWidget
+{
+ Q_OBJECT
+public:
+ QmlDebugger(QWidget * = 0);
+
+ void setHost(const QString &host);
+ void setPort(quint16 port);
+ void showEngineTab();
+
+public slots:
+ void connectToHost();
+ void disconnectFromHost();
+
+protected:
+ void closeEvent(QCloseEvent *);
+
+private slots:
+ void connectionStateChanged();
+ void connectionError(QAbstractSocket::SocketError socketError);
+
+private:
+ QmlDebugConnection client;
+
+ QLabel *m_connectionState;
+ QLineEdit *m_host;
+ QSpinBox *m_port;
+ QPushButton *m_connectButton;
+ QPushButton *m_disconnectButton;
+
+ EnginePane *m_enginePane;
+ QTabWidget *m_tabs;
+};
+
+#endif
diff --git a/tools/qmldebugger/standalone/qmldebugger.pri b/tools/qmldebugger/standalone/qmldebugger.pri
new file mode 100644
index 0000000..aad5eb1
--- /dev/null
+++ b/tools/qmldebugger/standalone/qmldebugger.pri
@@ -0,0 +1,16 @@
+QT += network declarative
+contains(QT_CONFIG, opengles2)|contains(QT_CONFIG, opengles1): QT += opengl
+
+# Input
+HEADERS += $$PWD/canvasframerate.h \
+ $$PWD/watchtable.h \
+ $$PWD/objecttree.h \
+ $$PWD/objectpropertiesview.h \
+ $$PWD/expressionquerywidget.h
+
+SOURCES += $$PWD/canvasframerate.cpp \
+ $$PWD/watchtable.cpp \
+ $$PWD/objecttree.cpp \
+ $$PWD/objectpropertiesview.cpp \
+ $$PWD/expressionquerywidget.cpp
+
diff --git a/tools/qmldebugger/standalone/qmldebugger.qrc b/tools/qmldebugger/standalone/qmldebugger.qrc
new file mode 100644
index 0000000..cb53ad5
--- /dev/null
+++ b/tools/qmldebugger/standalone/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/standalone/refresh.png b/tools/qmldebugger/standalone/refresh.png
new file mode 100644
index 0000000..8befc80
--- /dev/null
+++ b/tools/qmldebugger/standalone/refresh.png
Binary files differ
diff --git a/tools/qmldebugger/standalone/standalone.pro b/tools/qmldebugger/standalone/standalone.pro
new file mode 100644
index 0000000..72d051f
--- /dev/null
+++ b/tools/qmldebugger/standalone/standalone.pro
@@ -0,0 +1,19 @@
+DESTDIR = ../../../bin
+TARGET = qmldebugger
+
+include(qmldebugger.pri)
+
+HEADERS += $$PWD/qmldebugger.h \
+ $$PWD/engine.h
+
+SOURCES += $$PWD/qmldebugger.cpp \
+ $$PWD/engine.cpp \
+ $$PWD/main.cpp
+
+RESOURCES += $$PWD/qmldebugger.qrc
+OTHER_FILES += $$PWD/engines.qml
+
+target.path=$$[QT_INSTALL_BINS]
+INSTALLS += target
+
+CONFIG += console
diff --git a/tools/qmldebugger/standalone/watchtable.cpp b/tools/qmldebugger/standalone/watchtable.cpp
new file mode 100644
index 0000000..0e73de5
--- /dev/null
+++ b/tools/qmldebugger/standalone/watchtable.cpp
@@ -0,0 +1,366 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "watchtable.h"
+
+#include <QtCore/qdebug.h>
+#include <QtGui/qevent.h>
+#include <QtGui/qaction.h>
+#include <QtGui/qmenu.h>
+
+#include <private/qmldebug_p.h>
+#include <QtDeclarative/qmlmetatype.h>
+
+QT_BEGIN_NAMESPACE
+
+
+WatchTableModel::WatchTableModel(QmlEngineDebug *client, QObject *parent)
+ : QAbstractTableModel(parent),
+ m_client(client)
+{
+}
+
+WatchTableModel::~WatchTableModel()
+{
+ for (int i=0; i<m_columns.count(); i++)
+ delete m_columns[i].watch;
+}
+
+void WatchTableModel::setEngineDebug(QmlEngineDebug *client)
+{
+ m_client = client;
+}
+
+void WatchTableModel::addWatch(QmlDebugWatch *watch, const QString &title)
+{
+ QString property;
+ if (qobject_cast<QmlDebugPropertyWatch *>(watch))
+ property = qobject_cast<QmlDebugPropertyWatch *>(watch)->name();
+
+ connect(watch, SIGNAL(valueChanged(QByteArray,QVariant)),
+ SLOT(watchedValueChanged(QByteArray,QVariant)));
+
+ connect(watch, SIGNAL(stateChanged(QmlDebugWatch::State)), SLOT(watchStateChanged()));
+
+ int col = columnCount(QModelIndex());
+ beginInsertColumns(QModelIndex(), col, col);
+
+ WatchedEntity e;
+ e.title = title;
+ e.hasFirstValue = false;
+ e.property = property;
+ e.watch = watch;
+ m_columns.append(e);
+
+ endInsertColumns();
+}
+
+void WatchTableModel::removeWatch(QmlDebugWatch *watch)
+{
+ int column = columnForWatch(watch);
+ if (column == -1)
+ return;
+
+ WatchedEntity entity = m_columns.takeAt(column);
+
+ for (QList<Value>::Iterator iter = m_values.begin(); iter != m_values.end();) {
+ if (iter->column == column) {
+ iter = m_values.erase(iter);
+ } else {
+ if(iter->column > column)
+ --iter->column;
+ ++iter;
+ }
+ }
+
+ reset();
+}
+
+void WatchTableModel::updateWatch(QmlDebugWatch *watch, const QVariant &value)
+{
+ int column = columnForWatch(watch);
+ if (column == -1)
+ return;
+
+ addValue(column, value);
+
+ if (!m_columns[column].hasFirstValue) {
+ m_columns[column].hasFirstValue = true;
+ m_values[m_values.count() - 1].first = true;
+ }
+}
+
+QmlDebugWatch *WatchTableModel::findWatch(int column) const
+{
+ if (column < m_columns.count())
+ return m_columns.at(column).watch;
+ return 0;
+}
+
+QmlDebugWatch *WatchTableModel::findWatch(int objectDebugId, const QString &property) const
+{
+ for (int i=0; i<m_columns.count(); i++) {
+ if (m_columns[i].watch->objectDebugId() == objectDebugId
+ && m_columns[i].property == property) {
+ return m_columns[i].watch;
+ }
+ }
+ return 0;
+}
+
+int WatchTableModel::rowCount(const QModelIndex &) const
+{
+ return m_values.count();
+}
+
+int WatchTableModel::columnCount(const QModelIndex &) const
+{
+ return m_columns.count();
+}
+
+QVariant WatchTableModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (orientation == Qt::Horizontal) {
+ if (section < m_columns.count() && role == Qt::DisplayRole)
+ return m_columns.at(section).title;
+ } else {
+ if (role == Qt::DisplayRole)
+ return section + 1;
+ }
+ return QVariant();
+}
+
+QVariant WatchTableModel::data(const QModelIndex &idx, int role) const
+{
+ if (m_values.at(idx.row()).column == idx.column()) {
+ if (role == Qt::DisplayRole) {
+ const QVariant &value = m_values.at(idx.row()).variant;
+ QString str = value.toString();
+
+ if (str.isEmpty() && QmlMetaType::isObject(value.userType())) {
+ QObject *o = QmlMetaType::toQObject(value);
+ if(o) {
+ QString objectName = o->objectName();
+ if(objectName.isEmpty())
+ objectName = QLatin1String("<unnamed>");
+ str = QLatin1String(o->metaObject()->className()) +
+ QLatin1String(": ") + objectName;
+ }
+ }
+
+ if(str.isEmpty()) {
+ QDebug d(&str);
+ d << value;
+ }
+ return QVariant(str);
+ } else if(role == Qt::BackgroundRole) {
+ if(m_values.at(idx.row()).first)
+ return QColor(Qt::green);
+ else
+ return QVariant();
+ } else {
+ return QVariant();
+ }
+ } else {
+ return QVariant();
+ }
+}
+
+void WatchTableModel::watchStateChanged()
+{
+ QmlDebugWatch *watch = qobject_cast<QmlDebugWatch*>(sender());
+
+ if (watch && watch->state() == QmlDebugWatch::Inactive) {
+ removeWatch(watch);
+ watch->deleteLater();
+ }
+}
+
+int WatchTableModel::columnForWatch(QmlDebugWatch *watch) const
+{
+ for (int i=0; i<m_columns.count(); i++) {
+ if (m_columns.at(i).watch == watch)
+ return i;
+ }
+ return -1;
+}
+
+void WatchTableModel::addValue(int column, const QVariant &value)
+{
+ int row = columnCount(QModelIndex());
+ beginInsertRows(QModelIndex(), row, row);
+
+ Value v;
+ v.column = column;
+ v.variant = value;
+ v.first = false;
+ m_values.append(v);
+
+ endInsertRows();
+}
+
+void WatchTableModel::togglePropertyWatch(const QmlDebugObjectReference &object, const QmlDebugPropertyReference &property)
+{
+ if (!m_client || !property.hasNotifySignal())
+ return;
+
+ QmlDebugWatch *watch = findWatch(object.debugId(), property.name());
+ if (watch) {
+ // watch will be deleted in watchStateChanged()
+ m_client->removeWatch(watch);
+ return;
+ }
+
+ watch = m_client->addWatch(property, this);
+ if (watch->state() == QmlDebugWatch::Dead) {
+ delete watch;
+ watch = 0;
+ } else {
+ QString desc = property.name()
+ + QLatin1String(" on\n")
+ + object.className()
+ + QLatin1String(":\n")
+ + (object.name().isEmpty() ? QLatin1String("<unnamed object>") : object.name());
+ addWatch(watch, desc);
+ emit watchCreated(watch);
+ }
+}
+
+void WatchTableModel::watchedValueChanged(const QByteArray &propertyName, const QVariant &value)
+{
+ Q_UNUSED(propertyName);
+ QmlDebugWatch *watch = qobject_cast<QmlDebugWatch*>(sender());
+ if (watch)
+ updateWatch(watch, value);
+}
+
+void WatchTableModel::expressionWatchRequested(const QmlDebugObjectReference &obj, const QString &expr)
+{
+ if (!m_client)
+ return;
+
+ QmlDebugWatch *watch = m_client->addWatch(obj, expr, this);
+
+ if (watch->state() == QmlDebugWatch::Dead) {
+ delete watch;
+ watch = 0;
+ } else {
+ addWatch(watch, expr);
+ emit watchCreated(watch);
+ }
+}
+
+void WatchTableModel::removeWatchAt(int column)
+{
+ if (!m_client)
+ return;
+
+ QmlDebugWatch *watch = findWatch(column);
+ if (watch) {
+ m_client->removeWatch(watch);
+ delete watch;
+ watch = 0;
+ }
+}
+
+void WatchTableModel::removeAllWatches()
+{
+ for (int i=0; i<m_columns.count(); i++) {
+ if (m_client)
+ m_client->removeWatch(m_columns[i].watch);
+ else
+ delete m_columns[i].watch;
+ }
+ m_columns.clear();
+ m_values.clear();
+ reset();
+}
+
+//----------------------------------------------
+
+WatchTableHeaderView::WatchTableHeaderView(WatchTableModel *model, QWidget *parent)
+ : QHeaderView(Qt::Horizontal, parent),
+ m_model(model)
+{
+ setClickable(true);
+}
+
+void WatchTableHeaderView::mousePressEvent(QMouseEvent *me)
+{
+ QHeaderView::mousePressEvent(me);
+
+ if (me->button() == Qt::RightButton && me->type() == QEvent::MouseButtonPress) {
+ int col = logicalIndexAt(me->pos());
+ if (col >= 0) {
+ QAction action(tr("Stop watching"), 0);
+ QList<QAction *> actions;
+ actions << &action;
+ if (QMenu::exec(actions, me->globalPos()))
+ m_model->removeWatchAt(col);
+ }
+ }
+}
+
+
+//----------------------------------------------
+
+WatchTableView::WatchTableView(WatchTableModel *model, QWidget *parent)
+ : QTableView(parent),
+ m_model(model)
+{
+ setAlternatingRowColors(true);
+ connect(model, SIGNAL(watchCreated(QmlDebugWatch*)), SLOT(watchCreated(QmlDebugWatch*)));
+ connect(this, SIGNAL(activated(QModelIndex)), SLOT(indexActivated(QModelIndex)));
+}
+
+void WatchTableView::indexActivated(const QModelIndex &index)
+{
+ QmlDebugWatch *watch = m_model->findWatch(index.column());
+ if (watch)
+ emit objectActivated(watch->objectDebugId());
+}
+
+void WatchTableView::watchCreated(QmlDebugWatch *watch)
+{
+ int column = m_model->columnForWatch(watch);
+ resizeColumnToContents(column);
+}
+
+QT_END_NAMESPACE
diff --git a/tools/qmldebugger/standalone/watchtable.h b/tools/qmldebugger/standalone/watchtable.h
new file mode 100644
index 0000000..fd12d3d
--- /dev/null
+++ b/tools/qmldebugger/standalone/watchtable.h
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt QML Debugger 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef WATCHTABLEMODEL_H
+#define WATCHTABLEMODEL_H
+
+#include <QtCore/qpointer.h>
+#include <QtCore/qlist.h>
+
+#include <QWidget>
+#include <QHeaderView>
+#include <QAbstractTableModel>
+#include <QTableView>
+
+QT_BEGIN_NAMESPACE
+
+class QmlDebugWatch;
+class QmlEngineDebug;
+class QmlDebugConnection;
+class QmlDebugPropertyReference;
+class QmlDebugObjectReference;
+
+class WatchTableModel : public QAbstractTableModel
+{
+ Q_OBJECT
+public:
+ WatchTableModel(QmlEngineDebug *client = 0, QObject *parent = 0);
+ ~WatchTableModel();
+
+ void setEngineDebug(QmlEngineDebug *client);
+
+ QmlDebugWatch *findWatch(int column) const;
+ int columnForWatch(QmlDebugWatch *watch) const;
+
+ void removeWatchAt(int column);
+ void removeAllWatches();
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+signals:
+ void watchCreated(QmlDebugWatch *watch);
+
+public slots:
+ void togglePropertyWatch(const QmlDebugObjectReference &obj, const QmlDebugPropertyReference &prop);
+ void expressionWatchRequested(const QmlDebugObjectReference &, const QString &);
+
+private slots:
+ void watchStateChanged();
+ void watchedValueChanged(const QByteArray &propertyName, const QVariant &value);
+
+private:
+ void addWatch(QmlDebugWatch *watch, const QString &title);
+ void removeWatch(QmlDebugWatch *watch);
+ void updateWatch(QmlDebugWatch *watch, const QVariant &value);
+
+ QmlDebugWatch *findWatch(int objectDebugId, const QString &property) const;
+
+ void addValue(int column, const QVariant &value);
+
+ struct WatchedEntity
+ {
+ QString title;
+ bool hasFirstValue;
+ QString property;
+ QPointer<QmlDebugWatch> watch;
+ };
+
+ struct Value {
+ int column;
+ QVariant variant;
+ bool first;
+ };
+
+ QmlEngineDebug *m_client;
+ QList<WatchedEntity> m_columns;
+ QList<Value> m_values;
+};
+
+
+class WatchTableHeaderView : public QHeaderView
+{
+ Q_OBJECT
+public:
+ WatchTableHeaderView(WatchTableModel *model, QWidget *parent = 0);
+
+protected:
+ void mousePressEvent(QMouseEvent *me);
+
+private:
+ WatchTableModel *m_model;
+};
+
+
+class WatchTableView : public QTableView
+{
+ Q_OBJECT
+public:
+ WatchTableView(WatchTableModel *model, QWidget *parent = 0);
+
+signals:
+ void objectActivated(int objectDebugId);
+
+private slots:
+ void indexActivated(const QModelIndex &index);
+ void watchCreated(QmlDebugWatch *watch);
+
+private:
+ WatchTableModel *m_model;
+};
+
+
+QT_END_NAMESPACE
+
+#endif // WATCHTABLEMODEL_H
diff --git a/tools/qmlviewer/main.cpp b/tools/qmlviewer/main.cpp
new file mode 100644
index 0000000..ac0d732
--- /dev/null
+++ b/tools/qmlviewer/main.cpp
@@ -0,0 +1,300 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the tools applications 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "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(" -maximized................................ run maximized");
+ qWarning(" -fullscreen............................... run fullscreen");
+ qWarning(" -stayontop................................ keep viewer window on top");
+ 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(" -opengl .................................. use a QGLWidget for the viewport");
+ qWarning(" -script <path> ........................... set the script to use");
+ qWarning(" -scriptopts <options>|help ............... set the script options to use");
+
+ qWarning(" ");
+ qWarning(" Press F1 for interactive help");
+ exit(1);
+}
+
+void scriptOptsUsage()
+{
+ qWarning("Usage: qmlviewer -scriptopts <option>[,<option>...] ...");
+ qWarning(" options:");
+ qWarning(" record ................................... record a new script");
+ qWarning(" play ..................................... playback an existing script");
+ qWarning(" testimages ............................... record images or compare images on playback");
+ qWarning(" testerror ................................ test 'error' property of root item on playback");
+ qWarning(" exitoncomplete ........................... cleanly exit the viewer on script completion");
+ qWarning(" exitonfailure ............................ immediately exit the viewer on script failure");
+ qWarning(" saveonexit ............................... save recording on viewer exit");
+ qWarning(" ");
+ qWarning(" One of record, play or both must be specified.");
+ 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;
+ QString script;
+ QString scriptopts;
+ bool runScript = false;
+ bool devkeys = false;
+ int cache = 0;
+ QString translationFile;
+ bool useGL = false;
+ bool fullScreen = false;
+ bool stayOnTop = false;
+ bool maximized = false;
+
+ for (int i = 1; i < argc; ++i) {
+ bool lastArg = (i == argc - 1);
+ QString arg = argv[i];
+ if (arg == "-frameless") {
+ frameless = true;
+ } else if (arg == "-maximized") {
+ maximized = true;
+ } else if (arg == "-fullscreen") {
+ fullScreen = true;
+ } else if (arg == "-stayontop") {
+ stayOnTop = true;
+ } else if (arg == "-skin") {
+ if (lastArg) usage();
+ skin = QString(argv[++i]);
+ } else if (arg == "-resizeview") {
+ resizeview = true;
+ } else if (arg == "-netcache") {
+ if (lastArg) usage();
+ cache = QString(argv[++i]).toInt();
+ } else if (arg == "-recordrate") {
+ if (lastArg) usage();
+ fps = QString(argv[++i]).toDouble();
+ } else if (arg == "-recordfile") {
+ if (lastArg) usage();
+ recordfile = QString(argv[++i]);
+ } else if (arg == "-record") {
+ if (lastArg) usage();
+ recordargs << QString(argv[++i]);
+ } else if (arg == "-recorddither") {
+ if (lastArg) usage();
+ dither = QString(argv[++i]);
+ } else if (arg == "-autorecord") {
+ if (lastArg) usage();
+ QString range = QString(argv[++i]);
+ int dash = range.indexOf('-');
+ if (dash > 0)
+ 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 (lastArg) usage();
+ translationFile = argv[++i];
+ } else if (arg == "-opengl") {
+ useGL = true;
+ } else if (arg == "-L") {
+ if (lastArg) usage();
+ libraries << QString(argv[++i]);
+ } else if (arg == "-script") {
+ if (lastArg) usage();
+ script = QString(argv[++i]);
+ } else if (arg == "-scriptopts") {
+ if (lastArg) usage();
+ scriptopts = QString(argv[++i]);
+ } else if (arg == "-savescript") {
+ if (lastArg) usage();
+ script = QString(argv[++i]);
+ runScript = false;
+ } else if (arg == "-playscript") {
+ if (lastArg) usage();
+ script = QString(argv[++i]);
+ runScript = true;
+ } else if (arg[0] != '-') {
+ fileName = arg;
+ } else if (1 || arg == "-help") {
+ usage();
+ }
+ }
+
+ QTranslator qmlTranslator;
+ if (!translationFile.isEmpty()) {
+ qmlTranslator.load(translationFile);
+ app.installTranslator(&qmlTranslator);
+ }
+
+ Qt::WFlags wflags = (frameless ? Qt::FramelessWindowHint : Qt::Widget);
+ if (stayOnTop)
+ wflags |= Qt::WindowStaysOnTopHint;
+
+ QmlViewer viewer(0, wflags);
+ if (!scriptopts.isEmpty()) {
+ QStringList options =
+ scriptopts.split(QLatin1Char(','), QString::SkipEmptyParts);
+
+ QmlViewer::ScriptOptions scriptOptions = 0;
+ for (int i = 0; i < options.count(); ++i) {
+ const QString &option = options.at(i);
+ if (option == QLatin1String("help")) {
+ scriptOptsUsage();
+ } else if (option == QLatin1String("play")) {
+ scriptOptions |= QmlViewer::Play;
+ } else if (option == QLatin1String("record")) {
+ scriptOptions |= QmlViewer::Record;
+ } else if (option == QLatin1String("testimages")) {
+ scriptOptions |= QmlViewer::TestImages;
+ } else if (option == QLatin1String("testerror")) {
+ scriptOptions |= QmlViewer::TestErrorProperty;
+ } else if (option == QLatin1String("exitoncomplete")) {
+ scriptOptions |= QmlViewer::ExitOnComplete;
+ } else if (option == QLatin1String("exitonfailure")) {
+ scriptOptions |= QmlViewer::ExitOnFailure;
+ } else if (option == QLatin1String("saveonexit")) {
+ scriptOptions |= QmlViewer::SaveOnExit;
+ } else {
+ scriptOptsUsage();
+ }
+ }
+
+ if (script.isEmpty())
+ usage();
+
+ if (!(scriptOptions & QmlViewer::Record) && !(scriptOptions & QmlViewer::Play))
+ scriptOptsUsage();
+ viewer.setScriptOptions(scriptOptions);
+ viewer.setScript(script);
+ } else if (!script.isEmpty()) {
+ usage();
+ }
+
+ viewer.setUseGL(useGL);
+ foreach (QString lib, libraries)
+ viewer.addLibraryPath(lib);
+ 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 (fullScreen && maximized)
+ qWarning() << "Both -fullscreen and -maximized specified. Using -fullscreen.";
+ if (!fileName.isEmpty()) {
+ viewer.openQml(fileName);
+ fullScreen ? viewer.showFullScreen() : maximized ? viewer.showMaximized() : viewer.show();
+ } else {
+ fullScreen ? viewer.showFullScreen() : maximized ? viewer.showMaximized() : 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..52fa74f
--- /dev/null
+++ b/tools/qmlviewer/proxysettings.cpp
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the tools applications 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <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..b2f3e25
--- /dev/null
+++ b/tools/qmlviewer/proxysettings.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the tools applications 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef 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/qfxtester.cpp b/tools/qmlviewer/qfxtester.cpp
new file mode 100644
index 0000000..5484771
--- /dev/null
+++ b/tools/qmlviewer/qfxtester.cpp
@@ -0,0 +1,378 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the tools applications 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qfxtester.h>
+#include <QDebug>
+#include <QApplication>
+#include <qmlview.h>
+#include <QFile>
+#include <QmlComponent>
+#include <QDir>
+#include <QCryptographicHash>
+#include <private/qabstractanimation_p.h>
+#include <private/qmlgraphicsitem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QML_DEFINE_TYPE(Qt.VisualTest, 4,6, VisualTest, QmlGraphicsVisualTest);
+QML_DEFINE_TYPE(Qt.VisualTest, 4,6, Frame, QmlGraphicsVisualTestFrame);
+QML_DEFINE_TYPE(Qt.VisualTest, 4,6, Mouse, QmlGraphicsVisualTestMouse);
+QML_DEFINE_TYPE(Qt.VisualTest, 4,6, Key, QmlGraphicsVisualTestKey);
+
+QmlGraphicsTester::QmlGraphicsTester(const QString &script, QmlViewer::ScriptOptions opts,
+ QmlView *parent)
+: QAbstractAnimation(parent), m_script(script), m_view(parent), filterEvents(true), options(opts),
+ testscript(0), hasCompleted(false), hasFailed(false)
+{
+ parent->viewport()->installEventFilter(this);
+ parent->installEventFilter(this);
+ QUnifiedTimer::instance()->setConsistentTiming(true);
+ if (options & QmlViewer::Play)
+ this->run();
+ start();
+}
+
+QmlGraphicsTester::~QmlGraphicsTester()
+{
+ if (!hasFailed &&
+ options & QmlViewer::Record &&
+ options & QmlViewer::SaveOnExit)
+ save();
+}
+
+int QmlGraphicsTester::duration() const
+{
+ return -1;
+}
+
+void QmlGraphicsTester::addMouseEvent(Destination dest, QMouseEvent *me)
+{
+ MouseEvent e(me);
+ e.destination = dest;
+ m_mouseEvents << e;
+}
+
+void QmlGraphicsTester::addKeyEvent(Destination dest, QKeyEvent *ke)
+{
+ KeyEvent e(ke);
+ e.destination = dest;
+ m_keyEvents << e;
+}
+
+bool QmlGraphicsTester::eventFilter(QObject *o, QEvent *e)
+{
+ if (!filterEvents)
+ return false;
+
+ Destination destination;
+ if (o == m_view) {
+ destination = View;
+ } else if (o == m_view->viewport()) {
+ destination = ViewPort;
+ } else {
+ return false;
+ }
+
+ switch (e->type()) {
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ addKeyEvent(destination, (QKeyEvent *)e);
+ return true;
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseMove:
+ case QEvent::MouseButtonDblClick:
+ addMouseEvent(destination, (QMouseEvent *)e);
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+void QmlGraphicsTester::executefailure()
+{
+ hasFailed = true;
+
+ if (options & QmlViewer::ExitOnFailure)
+ exit(-1);
+}
+
+void QmlGraphicsTester::imagefailure()
+{
+ hasFailed = true;
+
+ if (options & QmlViewer::ExitOnFailure)
+ exit(-1);
+}
+
+void QmlGraphicsTester::complete()
+{
+ if ((options & QmlViewer::TestErrorProperty) && !hasFailed) {
+ QString e = m_view->root()->property("error").toString();
+ if (!e.isEmpty()) {
+ qWarning() << "Test failed:" << e;
+ hasFailed = true;
+ }
+ }
+ if (options & QmlViewer::ExitOnComplete)
+ QApplication::exit(hasFailed?-1:0);
+
+ if (hasCompleted)
+ return;
+ hasCompleted = true;
+
+ if (options & QmlViewer::Play)
+ qWarning("Script playback complete");
+}
+
+void QmlGraphicsTester::run()
+{
+ QmlComponent c(m_view->engine(), m_script + QLatin1String(".qml"));
+
+ testscript = qobject_cast<QmlGraphicsVisualTest *>(c.create());
+ if (testscript) testscript->setParent(this);
+ else executefailure();
+ testscriptidx = 0;
+}
+
+void QmlGraphicsTester::save()
+{
+ QString filename = m_script + QLatin1String(".qml");
+ QFileInfo filenameInfo(filename);
+ QDir saveDir = filenameInfo.absoluteDir();
+ saveDir.mkpath(".");
+
+ QFile file(filename);
+ file.open(QIODevice::WriteOnly);
+ QTextStream ts(&file);
+
+ ts << "import Qt.VisualTest 4.6\n\n";
+ ts << "VisualTest {\n";
+
+ int imgCount = 0;
+ QList<KeyEvent> keyevents = m_savedKeyEvents;
+ QList<MouseEvent> mouseevents = m_savedMouseEvents;
+ for (int ii = 0; ii < m_savedFrameEvents.count(); ++ii) {
+ const FrameEvent &fe = m_savedFrameEvents.at(ii);
+ ts << " Frame {\n";
+ ts << " msec: " << fe.msec << "\n";
+ if (!fe.hash.isEmpty()) {
+ ts << " hash: \"" << fe.hash.toHex() << "\"\n";
+ } else if (!fe.image.isNull()) {
+ QString filename = filenameInfo.baseName() + "." + QString::number(imgCount) + ".png";
+ fe.image.save(m_script + "." + QString::number(imgCount) + ".png");
+ imgCount++;
+ ts << " image: \"" << filename << "\"\n";
+ }
+ ts << " }\n";
+
+ while (!mouseevents.isEmpty() &&
+ mouseevents.first().msec == fe.msec) {
+ MouseEvent me = mouseevents.takeFirst();
+
+ ts << " Mouse {\n";
+ ts << " type: " << me.type << "\n";
+ ts << " button: " << me.button << "\n";
+ ts << " buttons: " << me.buttons << "\n";
+ ts << " x: " << me.pos.x() << "; y: " << me.pos.y() << "\n";
+ ts << " modifiers: " << me.modifiers << "\n";
+ if (me.destination == ViewPort)
+ ts << " sendToViewport: true\n";
+ ts << " }\n";
+ }
+
+ while (!keyevents.isEmpty() &&
+ keyevents.first().msec == fe.msec) {
+ KeyEvent ke = keyevents.takeFirst();
+
+ ts << " Key {\n";
+ ts << " type: " << ke.type << "\n";
+ ts << " key: " << ke.key << "\n";
+ ts << " modifiers: " << ke.modifiers << "\n";
+ ts << " text: \"" << ke.text.toUtf8().toHex() << "\"\n";
+ ts << " autorep: " << (ke.autorep?"true":"false") << "\n";
+ ts << " count: " << ke.count << "\n";
+ if (ke.destination == ViewPort)
+ ts << " sendToViewport: true\n";
+ ts << " }\n";
+ }
+ }
+
+ ts << "}\n";
+ file.close();
+}
+
+void QmlGraphicsTester::updateCurrentTime(int msec)
+{
+ QmlGraphicsItemPrivate::setConsistentTime(msec);
+
+ QImage img(m_view->width(), m_view->height(), QImage::Format_RGB32);
+
+ if (options & QmlViewer::TestImages) {
+ img.fill(qRgb(255,255,255));
+ QPainter p(&img);
+ m_view->render(&p);
+ }
+
+ FrameEvent fe;
+ fe.msec = msec;
+ if (msec == 0 || !(options & QmlViewer::TestImages)) {
+ // Skip first frame, skip if not doing images
+ } else if (0 == (m_savedFrameEvents.count() % 60)) {
+ fe.image = img;
+ } else {
+ QCryptographicHash hash(QCryptographicHash::Md5);
+ hash.addData((const char *)img.bits(), img.bytesPerLine() * img.height());
+ fe.hash = hash.result();
+ }
+ m_savedFrameEvents.append(fe);
+
+ // Deliver mouse events
+ filterEvents = false;
+
+ if (!testscript) {
+ for (int ii = 0; ii < m_mouseEvents.count(); ++ii) {
+ MouseEvent &me = m_mouseEvents[ii];
+ me.msec = msec;
+ QMouseEvent event(me.type, me.pos, me.button, me.buttons, me.modifiers);
+
+ if (me.destination == View) {
+ QCoreApplication::sendEvent(m_view, &event);
+ } else {
+ QCoreApplication::sendEvent(m_view->viewport(), &event);
+ }
+ }
+
+ for (int ii = 0; ii < m_keyEvents.count(); ++ii) {
+ KeyEvent &ke = m_keyEvents[ii];
+ ke.msec = msec;
+ QKeyEvent event(ke.type, ke.key, ke.modifiers, ke.text, ke.autorep, ke.count);
+
+ if (ke.destination == View) {
+ QCoreApplication::sendEvent(m_view, &event);
+ } else {
+ QCoreApplication::sendEvent(m_view->viewport(), &event);
+ }
+ }
+ m_savedMouseEvents.append(m_mouseEvents);
+ m_savedKeyEvents.append(m_keyEvents);
+ }
+
+ m_mouseEvents.clear();
+ m_keyEvents.clear();
+
+ // Advance test script
+ static int imgCount = 0;
+ while (testscript && testscript->count() > testscriptidx) {
+
+ QObject *event = testscript->event(testscriptidx);
+
+ if (QmlGraphicsVisualTestFrame *frame = qobject_cast<QmlGraphicsVisualTestFrame *>(event)) {
+ if (frame->msec() < msec) {
+ if (options & QmlViewer::TestImages && !(options & QmlViewer::Record)) {
+ qWarning() << "QmlGraphicsTester: Extra frame. Seen:"
+ << msec << "Expected:" << frame->msec();
+ imagefailure();
+ }
+ } else if (frame->msec() == msec) {
+ if (!frame->hash().isEmpty() && frame->hash().toUtf8() != fe.hash.toHex()) {
+ if (options & QmlViewer::TestImages && !(options & QmlViewer::Record)) {
+ qWarning() << "QmlGraphicsTester: Mismatched frame hash. Seen:"
+ << fe.hash.toHex() << "Expected:"
+ << frame->hash().toUtf8();
+ imagefailure();
+ }
+ }
+ } else if (frame->msec() > msec) {
+ break;
+ }
+
+ if (options & QmlViewer::TestImages && !(options & QmlViewer::Record) && !frame->image().isEmpty()) {
+ QImage goodImage(frame->image().toLocalFile());
+ if (goodImage != img) {
+ QString reject(frame->image().toLocalFile() + ".reject.png");
+ qWarning() << "QmlGraphicsTester: Image mismatch. Reject saved to:"
+ << reject;
+ img.save(reject);
+ imagefailure();
+ }
+ }
+ } else if (QmlGraphicsVisualTestMouse *mouse = qobject_cast<QmlGraphicsVisualTestMouse *>(event)) {
+ QPoint pos(mouse->x(), mouse->y());
+ QPoint globalPos = m_view->mapToGlobal(QPoint(0, 0)) + pos;
+ QMouseEvent event((QEvent::Type)mouse->type(), pos, globalPos, (Qt::MouseButton)mouse->button(), (Qt::MouseButtons)mouse->buttons(), (Qt::KeyboardModifiers)mouse->modifiers());
+
+ MouseEvent me(&event);
+ me.msec = msec;
+ if (!mouse->sendToViewport()) {
+ QCoreApplication::sendEvent(m_view, &event);
+ me.destination = View;
+ } else {
+ QCoreApplication::sendEvent(m_view->viewport(), &event);
+ me.destination = ViewPort;
+ }
+ m_savedMouseEvents.append(me);
+ } else if (QmlGraphicsVisualTestKey *key = qobject_cast<QmlGraphicsVisualTestKey *>(event)) {
+
+ QKeyEvent event((QEvent::Type)key->type(), key->key(), (Qt::KeyboardModifiers)key->modifiers(), QString::fromUtf8(QByteArray::fromHex(key->text().toUtf8())), key->autorep(), key->count());
+
+ KeyEvent ke(&event);
+ ke.msec = msec;
+ if (!key->sendToViewport()) {
+ QCoreApplication::sendEvent(m_view, &event);
+ ke.destination = View;
+ } else {
+ QCoreApplication::sendEvent(m_view->viewport(), &event);
+ ke.destination = ViewPort;
+ }
+ m_savedKeyEvents.append(ke);
+ }
+ testscriptidx++;
+ }
+
+ filterEvents = true;
+
+ if (testscript && testscript->count() <= testscriptidx)
+ complete();
+}
+
+QT_END_NAMESPACE
diff --git a/tools/qmlviewer/qfxtester.h b/tools/qmlviewer/qfxtester.h
new file mode 100644
index 0000000..303ac3a
--- /dev/null
+++ b/tools/qmlviewer/qfxtester.h
@@ -0,0 +1,262 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the tools applications 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXTESTER_H
+#define QFXTESTER_H
+
+#include <QEvent>
+#include <QMouseEvent>
+#include <QKeyEvent>
+#include <qmlviewer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QmlGraphicsVisualTest : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QList<QObject *>* events READ events CONSTANT)
+ Q_CLASSINFO("DefaultProperty", "events")
+public:
+ QmlGraphicsVisualTest() {}
+
+ QList<QObject *> *events() { return &m_events; }
+
+ int count() const { return m_events.count(); }
+ QObject *event(int idx) { return m_events.at(idx); }
+
+private:
+ QList<QObject *> m_events;
+};
+QML_DECLARE_TYPE(QmlGraphicsVisualTest)
+
+class QmlGraphicsVisualTestFrame : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int msec READ msec WRITE setMsec)
+ Q_PROPERTY(QString hash READ hash WRITE setHash)
+ Q_PROPERTY(QUrl image READ image WRITE setImage)
+public:
+ QmlGraphicsVisualTestFrame() : m_msec(-1) {}
+
+ int msec() const { return m_msec; }
+ void setMsec(int m) { m_msec = m; }
+
+ QString hash() const { return m_hash; }
+ void setHash(const QString &hash) { m_hash = hash; }
+
+ QUrl image() const { return m_image; }
+ void setImage(const QUrl &image) { m_image = image; }
+
+private:
+ int m_msec;
+ QString m_hash;
+ QUrl m_image;
+};
+QML_DECLARE_TYPE(QmlGraphicsVisualTestFrame)
+
+class QmlGraphicsVisualTestMouse : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int type READ type WRITE setType)
+ Q_PROPERTY(int button READ button WRITE setButton)
+ Q_PROPERTY(int buttons READ buttons WRITE setButtons)
+ Q_PROPERTY(int x READ x WRITE setX)
+ Q_PROPERTY(int y READ y WRITE setY)
+ Q_PROPERTY(int modifiers READ modifiers WRITE setModifiers)
+ Q_PROPERTY(bool sendToViewport READ sendToViewport WRITE setSendToViewport)
+public:
+ QmlGraphicsVisualTestMouse() : m_type(0), m_button(0), m_buttons(0), m_x(0), m_y(0), m_modifiers(0), m_viewport(false) {}
+
+ int type() const { return m_type; }
+ void setType(int t) { m_type = t; }
+
+ int button() const { return m_button; }
+ void setButton(int b) { m_button = b; }
+
+ int buttons() const { return m_buttons; }
+ void setButtons(int b) { m_buttons = b; }
+
+ int x() const { return m_x; }
+ void setX(int x) { m_x = x; }
+
+ int y() const { return m_y; }
+ void setY(int y) { m_y = y; }
+
+ int modifiers() const { return m_modifiers; }
+ void setModifiers(int modifiers) { m_modifiers = modifiers; }
+
+ bool sendToViewport() const { return m_viewport; }
+ void setSendToViewport(bool v) { m_viewport = v; }
+private:
+ int m_type;
+ int m_button;
+ int m_buttons;
+ int m_x;
+ int m_y;
+ int m_modifiers;
+ bool m_viewport;
+};
+QML_DECLARE_TYPE(QmlGraphicsVisualTestMouse)
+
+class QmlGraphicsVisualTestKey : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int type READ type WRITE setType)
+ Q_PROPERTY(int key READ key WRITE setKey)
+ Q_PROPERTY(int modifiers READ modifiers WRITE setModifiers)
+ Q_PROPERTY(QString text READ text WRITE setText)
+ Q_PROPERTY(bool autorep READ autorep WRITE setAutorep)
+ Q_PROPERTY(int count READ count WRITE setCount)
+ Q_PROPERTY(bool sendToViewport READ sendToViewport WRITE setSendToViewport)
+public:
+ QmlGraphicsVisualTestKey() : m_type(0), m_key(0), m_modifiers(0), m_autorep(false), m_count(0), m_viewport(false) {}
+
+ int type() const { return m_type; }
+ void setType(int t) { m_type = t; }
+
+ int key() const { return m_key; }
+ void setKey(int k) { m_key = k; }
+
+ int modifiers() const { return m_modifiers; }
+ void setModifiers(int m) { m_modifiers = m; }
+
+ QString text() const { return m_text; }
+ void setText(const QString &t) { m_text = t; }
+
+ bool autorep() const { return m_autorep; }
+ void setAutorep(bool a) { m_autorep = a; }
+
+ int count() const { return m_count; }
+ void setCount(int c) { m_count = c; }
+
+ bool sendToViewport() const { return m_viewport; }
+ void setSendToViewport(bool v) { m_viewport = v; }
+private:
+ int m_type;
+ int m_key;
+ int m_modifiers;
+ QString m_text;
+ bool m_autorep;
+ int m_count;
+ bool m_viewport;
+};
+QML_DECLARE_TYPE(QmlGraphicsVisualTestKey)
+
+class QmlGraphicsTester : public QAbstractAnimation
+{
+public:
+ QmlGraphicsTester(const QString &script, QmlViewer::ScriptOptions options, QmlView *parent);
+ ~QmlGraphicsTester();
+
+ virtual int duration() const;
+
+ void run();
+ void save();
+
+ void executefailure();
+protected:
+ virtual void updateCurrentTime(int msecs);
+ virtual bool eventFilter(QObject *, QEvent *);
+
+private:
+ QString m_script;
+
+ void imagefailure();
+ void complete();
+
+ enum Destination { View, ViewPort };
+ void addKeyEvent(Destination, QKeyEvent *);
+ void addMouseEvent(Destination, QMouseEvent *);
+ QmlView *m_view;
+
+ struct MouseEvent {
+ MouseEvent(QMouseEvent *e)
+ : type(e->type()), button(e->button()), buttons(e->buttons()),
+ pos(e->pos()), modifiers(e->modifiers()), destination(View) {}
+
+ QEvent::Type type;
+ Qt::MouseButton button;
+ Qt::MouseButtons buttons;
+ QPoint pos;
+ Qt::KeyboardModifiers modifiers;
+ Destination destination;
+
+ int msec;
+ };
+ struct KeyEvent {
+ KeyEvent(QKeyEvent *e)
+ : type(e->type()), key(e->key()), modifiers(e->modifiers()), text(e->text()),
+ autorep(e->isAutoRepeat()), count(e->count()), destination(View) {}
+ QEvent::Type type;
+ int key;
+ Qt::KeyboardModifiers modifiers;
+ QString text;
+ bool autorep;
+ ushort count;
+ Destination destination;
+
+ int msec;
+ };
+ struct FrameEvent {
+ QImage image;
+ QByteArray hash;
+ int msec;
+ };
+ QList<MouseEvent> m_mouseEvents;
+ QList<KeyEvent> m_keyEvents;
+
+ QList<MouseEvent> m_savedMouseEvents;
+ QList<KeyEvent> m_savedKeyEvents;
+ QList<FrameEvent> m_savedFrameEvents;
+ bool filterEvents;
+
+ QmlViewer::ScriptOptions options;
+ int testscriptidx;
+ QmlGraphicsVisualTest *testscript;
+
+ bool hasCompleted;
+ bool hasFailed;
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QFXTESTER_H
diff --git a/tools/qmlviewer/qmlviewer.cpp b/tools/qmlviewer/qmlviewer.cpp
new file mode 100644
index 0000000..ea0936b
--- /dev/null
+++ b/tools/qmlviewer/qmlviewer.cpp
@@ -0,0 +1,1160 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the tools applications 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qmlview.h>
+#include "ui_recopts.h"
+
+#include "qmlviewer.h"
+#include <QtDeclarative/qmlcontext.h>
+#include <QtDeclarative/qmlengine.h>
+#include "qml.h"
+#include <private/qperformancelog_p_p.h>
+#include <private/qabstractanimation_p.h>
+#include <QAbstractAnimation>
+#include "deviceskin.h"
+
+#include <QSettings>
+#include <QNetworkCookieJar>
+#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"
+
+#ifdef GL_SUPPORTED
+#include <QGLWidget>
+#endif
+
+#include <qfxtester.h>
+
+QT_BEGIN_NAMESPACE
+
+
+class SizedMenuBar : public QMenuBar
+{
+ Q_OBJECT
+public:
+ SizedMenuBar(QWidget *parent, QWidget *referenceWidget)
+ : QMenuBar(parent), refWidget(referenceWidget)
+ {
+ }
+
+ virtual QSize sizeHint() const
+ {
+ return QSize(refWidget->sizeHint().width(), QMenuBar::sizeHint().height());
+ }
+
+private:
+ QWidget *refWidget;
+};
+
+
+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(QObject *parent) : QNetworkAccessManager(parent) { }
+
+ 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);
+ }
+};
+
+class PersistentCookieJar : public QNetworkCookieJar {
+public:
+ PersistentCookieJar(QObject *parent) : QNetworkCookieJar(parent) { load(); }
+ ~PersistentCookieJar() { save(); }
+
+private:
+ void save()
+ {
+ QList<QNetworkCookie> list = allCookies();
+ QByteArray data;
+ foreach (QNetworkCookie cookie, list) {
+ if (!cookie.isSessionCookie()) {
+ data.append(cookie.toRawForm());
+ data.append("\n");
+ }
+ }
+ QSettings settings("Nokia", "QtQmlViewer");
+ settings.setValue("Cookies",data);
+ }
+
+ void load()
+ {
+ QSettings settings("Nokia", "QtQmlViewer");
+ QByteArray data = settings.value("Cookies").toByteArray();
+ setAllCookies(QNetworkCookie::parseCookies(data));
+ }
+};
+
+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), m_scriptOptions(0),
+ tester(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();
+ }
+
+ canvas = new QmlView(this);
+ canvas->setAttribute(Qt::WA_OpaquePaintEvent);
+ canvas->setAttribute(Qt::WA_NoSystemBackground);
+ canvas->setContentResizable(!skin || !scaleSkin);
+ canvas->engine()->setNetworkAccessManager(new ConfiguredNetworkAccessManager(canvas->engine()));
+ canvas->setFocus();
+
+ QObject::connect(canvas, SIGNAL(sceneResized(QSize)), this, SLOT(sceneResized(QSize)));
+ QObject::connect(canvas, SIGNAL(initialSize(QSize)), this, SLOT(adjustSizeSlot()));
+ QObject::connect(canvas, SIGNAL(errors(QList<QmlError>)), this, SLOT(executeErrors()));
+
+ if (!(flags & Qt::FramelessWindowHint))
+ createMenu(menuBar(),0);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->setMargin(0);
+ layout->setSpacing(0);
+ setLayout(layout);
+ if (mb)
+ layout->addWidget(mb);
+ layout->addWidget(canvas);
+
+ setupProxy();
+ canvas->engine()->networkAccessManager()->setCookieJar(new PersistentCookieJar(this));
+
+ 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);
+}
+
+void QmlViewer::adjustSizeSlot()
+{
+ resize(sizeHint());
+}
+
+QMenuBar *QmlViewer::menuBar() const
+{
+ if (!mb)
+ mb = new SizedMenuBar((QWidget*)this, canvas);
+
+ 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 Snapshot\tF3"), parent);
+ connect(snapshotAction, SIGNAL(triggered()), this, SLOT(takeSnapShot()));
+ recordMenu->addAction(snapshotAction);
+
+ recordAction = new QAction(tr("Start Recording &Video\tF9"), 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 *debugMenu = flatmenu ? flatmenu->addMenu(tr("&Debugging")) : menu->addMenu(tr("&Debugging"));
+
+ QAction *slowAction = new QAction(tr("&Slow Down Animations"), parent);
+ slowAction->setShortcut(QKeySequence("Ctrl+."));
+ slowAction->setCheckable(true);
+ connect(slowAction, SIGNAL(triggered(bool)), this, SLOT(setSlowMode(bool)));
+ debugMenu->addAction(slowAction);
+
+ 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\tF9") : tr("&Start Recording Video\tF9"));
+ setRecording(recording);
+}
+
+void QmlViewer::setSlowMode(bool enable)
+{
+ QUnifiedTimer::instance()->setSlowModeEnabled(enable);
+}
+
+void QmlViewer::addLibraryPath(const QString& lib)
+{
+ canvas->engine()->addImportPath(lib);
+}
+
+void QmlViewer::reload()
+{
+ openQml(currentFileOrUrl);
+}
+
+void QmlViewer::open()
+{
+ QString cur = canvas->url().toLocalFile();
+ QString fileName = QFileDialog::getOpenFileName(this, tr("Open QML file"), cur, tr("QML Files (*.qml)"));
+ if (!fileName.isEmpty()) {
+ QFileInfo fi(fileName);
+ openQml(fi.absoluteFilePath());
+ }
+}
+
+void QmlViewer::executeErrors()
+{
+ if (tester) tester->executefailure();
+}
+
+void QmlViewer::openQml(const QString& file_or_url)
+{
+ currentFileOrUrl = file_or_url;
+
+ QUrl url;
+ QFileInfo fi(file_or_url);
+ if (fi.exists())
+ url = QUrl::fromLocalFile(fi.absoluteFilePath());
+ else
+ url = QUrl(file_or_url);
+ setWindowTitle(tr("%1 - Qt Declarative UI Viewer").arg(file_or_url));
+
+ if (!m_script.isEmpty())
+ tester = new QmlGraphicsTester(m_script, m_scriptOptions, canvas);
+
+ canvas->reset();
+
+ QString fileName = url.toLocalFile();
+ if (!fileName.isEmpty()) {
+ QFileInfo fi(fileName);
+ if (fi.exists()) {
+ if (fi.suffix().toLower() != QLatin1String("qml")) {
+ qWarning() << "qmlviewer cannot open non-QML file" << fileName;
+ return;
+ }
+
+ 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 (tester) tester->executefailure();
+ }
+
+ if (dummyData) {
+ qWarning() << "Loaded dummy data:" << dir.filePath(qml);
+ qml.truncate(qml.length()-4);
+ ctxt->setContextProperty(qml, dummyData);
+ dummyData->setParent(this);
+ }
+ }
+ } else {
+ qWarning() << "qmlviewer cannot find file:" << fileName;
+ return;
+ }
+ }
+
+ canvas->setUrl(url);
+
+ QTime t;
+ t.start();
+ canvas->execute();
+ qWarning() << "Wall startup time:" << t.elapsed();
+
+ if (!skin) {
+ canvas->updateGeometry();
+ if (mb)
+ mb->updateGeometry();
+ 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 - save test script\n"
+ << "F3 - take PNG snapshot\n"
+ << "F4 - show items and state\n"
+ << "F5 - reload QML\n"
+ << "F6 - show object tree\n"
+ << "F7 - show timing\n"
+ << "F8 - show performance (if available)\n"
+ << "F9 - toggle video recording\n"
+ << "device keys: 0=quit, 1..8=F1..F8"
+ ;
+ } else if (event->key() == Qt::Key_F2 || (event->key() == Qt::Key_2 && devicemode)) {
+ if (tester && m_scriptOptions & Record)
+ tester->save();
+ } 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();
+ } else if (event->key() == Qt::Key_F9 || (event->key() == Qt::Key_9 && devicemode)) {
+ toggleRecording();
+ }
+
+ 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);
+ }
+}
+
+void QmlViewer::setUseGL(bool useGL)
+{
+#ifdef GL_SUPPORTED
+ if (useGL) {
+ QGLFormat format = QGLFormat::defaultFormat();
+ format.setSampleBuffers(false);
+
+ QGLWidget *glWidget = new QGLWidget(format);
+ glWidget->setAutoFillBackground(false);
+ canvas->setViewport(glWidget);
+ }
+#endif
+}
+QT_END_NAMESPACE
+
+#include "qmlviewer.moc"
diff --git a/tools/qmlviewer/qmlviewer.h b/tools/qmlviewer/qmlviewer.h
new file mode 100644
index 0000000..78512a9
--- /dev/null
+++ b/tools/qmlviewer/qmlviewer.h
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the tools applications 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMLVIEWER_H
+#define QMLVIEWER_H
+
+#include <QMenuBar>
+#include <private/qmltimer_p.h>
+#include <QTime>
+#include <QList>
+
+QT_BEGIN_NAMESPACE
+
+class QmlView;
+class PreviewDeviceSkin;
+class QmlGraphicsTestEngine;
+class QProcess;
+class RecordingDialog;
+class QmlGraphicsTester;
+
+class QmlViewer : public QWidget
+{
+Q_OBJECT
+public:
+ QmlViewer(QWidget *parent=0, Qt::WindowFlags flags=0);
+
+ enum ScriptOption {
+ Play = 0x00000001,
+ Record = 0x00000002,
+ TestImages = 0x00000004,
+ TestErrorProperty = 0x00000008,
+ SaveOnExit = 0x00000010,
+ ExitOnComplete = 0x00000020,
+ ExitOnFailure = 0x00000040
+ };
+ Q_DECLARE_FLAGS(ScriptOptions, ScriptOption)
+ void setScript(const QString &s) { m_script = s; }
+ void setScriptOptions(ScriptOptions opt) { m_scriptOptions = opt; }
+ void setRecordDither(const QString& s) { record_dither = s; }
+ void setRecordRate(int fps);
+ void setRecordFile(const QString&);
+ 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);
+ void setUseGL(bool use);
+
+ QStringList builtinSkins() const;
+
+ QMenuBar *menuBar() const;
+
+public slots:
+ void sceneResized(QSize size);
+ void openQml(const QString&);
+ 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();
+ void executeErrors();
+ void setSlowMode(bool);
+
+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();
+ void adjustSizeSlot();
+
+private:
+ void setupProxy();
+ QString getVideoFileName();
+
+ PreviewDeviceSkin *skin;
+ QSize skinscreensize;
+ QmlView *canvas;
+ QString currentFileOrUrl;
+ 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;
+
+ QString m_script;
+ ScriptOptions m_scriptOptions;
+ QmlGraphicsTester *tester;
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QmlViewer::ScriptOptions)
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/tools/qmlviewer/qmlviewer.pro b/tools/qmlviewer/qmlviewer.pro
new file mode 100644
index 0000000..899a3ab
--- /dev/null
+++ b/tools/qmlviewer/qmlviewer.pro
@@ -0,0 +1,35 @@
+TEMPLATE = app
+CONFIG += qt \
+ uic
+DESTDIR = ../../bin
+QT += declarative \
+ script \
+ network \
+ sql
+
+contains(QT_CONFIG, opengl) {
+ QT += opengl
+ DEFINES += GL_SUPPORTED
+}
+
+# Input
+HEADERS += qmlviewer.h \
+ proxysettings.h \
+ qfxtester.h
+SOURCES += main.cpp \
+ qmlviewer.cpp \
+ proxysettings.cpp \
+ qfxtester.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>