From fb5d5ce1cd1e2714343c3e26338601aa5dd79a54 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Thu, 15 Oct 2009 10:13:55 +1000 Subject: Give more information about the value of a property when the variant toString() is empty. --- src/declarative/qml/qmlenginedebug.cpp | 12 +++++++++--- tools/qmldebugger/objectpropertiesview.cpp | 16 +++++++++++++--- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/declarative/qml/qmlenginedebug.cpp b/src/declarative/qml/qmlenginedebug.cpp index e20616a..1c7450a 100644 --- a/src/declarative/qml/qmlenginedebug.cpp +++ b/src/declarative/qml/qmlenginedebug.cpp @@ -318,7 +318,7 @@ void QmlEngineDebugServer::propertyChanged(int id, int objectId, const QByteArra QByteArray reply; QVariant v; QDataStream rs(&reply, QIODevice::WriteOnly); - + if (value.type() == QVariant::UserType || QmlMetaType::isObject(value.userType())) { QObject *o = QmlMetaType::toQObject(value); if (o) { @@ -327,9 +327,15 @@ void QmlEngineDebugServer::propertyChanged(int id, int objectId, const QByteArra objectName = QLatin1String(""); v = QString::fromUtf8(o->metaObject()->className()) + QLatin1String(": ") + objectName; + } else { + v = QString::fromUtf8(value.typeName()); + } + if (v.isNull()) { + QString s = value.toString(); + if (s.isEmpty()) + s = QLatin1String(""); + v = s; } - if (v.isNull()) - v = value.toString(); } else { v = value; } diff --git a/tools/qmldebugger/objectpropertiesview.cpp b/tools/qmldebugger/objectpropertiesview.cpp index f725194..864468c 100644 --- a/tools/qmldebugger/objectpropertiesview.cpp +++ b/tools/qmldebugger/objectpropertiesview.cpp @@ -109,7 +109,7 @@ void ObjectPropertiesView::setObject(const QmlDebugObjectReference &object) item->setText(0, p.name()); item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); if (!p.hasNotifySignal()) - item->setForeground(0, Qt::lightGray); + item->setForeground(0, Qt::gray); if (!p.binding().isEmpty()) { PropertiesViewItem *binding = new PropertiesViewItem(item); @@ -159,8 +159,18 @@ void ObjectPropertiesView::valueChanged(const QByteArray &name, const QVariant & { for (int i=0; itopLevelItemCount(); i++) { PropertiesViewItem *item = static_cast(m_tree->topLevelItem(i)); - if (item->property.name() == name) - item->setText(1, value.toString()); + if (item->property.name() == name) { + if (value.isNull()) { + item->setText(1, QLatin1String("null")); + item->setForeground(1, Qt::gray); + } else { + QString s = value.toString(); + if (s.isEmpty()) + s = QString::fromUtf8(value.typeName()); + item->setText(1, s); + item->setForeground(1, QBrush()); + } + } } } -- cgit v0.12 From b5702e57ff6ab2e6fda63d760198ea417d312e89 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Fri, 16 Oct 2009 16:02:56 +1000 Subject: Don't try to open non-qml files. --- tools/qmlviewer/qmlviewer.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/qmlviewer/qmlviewer.cpp b/tools/qmlviewer/qmlviewer.cpp index 07b68ea..a8034cf 100644 --- a/tools/qmlviewer/qmlviewer.cpp +++ b/tools/qmlviewer/qmlviewer.cpp @@ -630,6 +630,11 @@ void QmlViewer::openQml(const QString& fileName) QUrl url(fileName); QFileInfo fi(fileName); if (fi.exists()) { + if (fi.suffix().toLower() != QLatin1String("qml")) { + qWarning() << "qmlviewer cannot open non-QML file" << fileName; + return; + } + url = QUrl::fromLocalFile(fi.absoluteFilePath()); QmlContext *ctxt = canvas->rootContext(); QDir dir(fi.path()+"/dummydata", "*.qml"); @@ -658,6 +663,9 @@ void QmlViewer::openQml(const QString& fileName) dummyData->setParent(this); } } + } else { + qWarning() << "qmlviewer cannot find file:" << fileName; + return; } canvas->setUrl(url); -- cgit v0.12 From 0ae3e10fecfe9f6241e8752bdd4deab8663988b7 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Tue, 20 Oct 2009 09:28:12 +1000 Subject: Add bool* argument to QmlExpression::value() to help debugger. --- src/declarative/qml/qmlexpression.cpp | 16 +++++++++++----- src/declarative/qml/qmlexpression.h | 2 +- src/declarative/qml/qmlexpression_p.h | 4 ++-- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index 76ca2c1..e158621 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -275,7 +275,7 @@ void QmlExpressionPrivate::printException(QScriptEngine *scriptEngine) } } -QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) +QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope, bool *isUndefined) { #ifdef Q_ENABLE_PERFORMANCE_LOG QFxPerfTimer perfqt; @@ -312,6 +312,9 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) QScriptValue svalue = data->expressionFunction.call(); + if (isUndefined) + *isUndefined = svalue.isUndefined(); + if (scriptEngine->hasUncaughtException()) printException(scriptEngine); @@ -352,7 +355,7 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) return rv; } -QVariant QmlExpressionPrivate::value(QObject *secondaryScope) +QVariant QmlExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined) { Q_Q(QmlExpression); @@ -379,7 +382,7 @@ QVariant QmlExpressionPrivate::value(QObject *secondaryScope) if (data->sse.isValid()) { rv = evalSSE(); } else { - rv = evalQtScript(secondaryScope); + rv = evalQtScript(secondaryScope, isUndefined); } ep->currentExpression = lastCurrentExpression; @@ -403,11 +406,14 @@ QVariant QmlExpressionPrivate::value(QObject *secondaryScope) /*! Returns the value of the expression, or an invalid QVariant if the expression is invalid or has an error. + + \a isUndefined is set to true if the expression resulted in an + undefined value. */ -QVariant QmlExpression::value() +QVariant QmlExpression::value(bool *isUndefined) { Q_D(QmlExpression); - return d->value(); + return d->value(0, isUndefined); } /*! diff --git a/src/declarative/qml/qmlexpression.h b/src/declarative/qml/qmlexpression.h index b85e0a7..169d096 100644 --- a/src/declarative/qml/qmlexpression.h +++ b/src/declarative/qml/qmlexpression.h @@ -81,7 +81,7 @@ public: QObject *scopeObject() const; public Q_SLOTS: - QVariant value(); + QVariant value(bool *isUndefined = 0); Q_SIGNALS: virtual void valueChanged(); diff --git a/src/declarative/qml/qmlexpression_p.h b/src/declarative/qml/qmlexpression_p.h index d9bb27b..3ec8d1c 100644 --- a/src/declarative/qml/qmlexpression_p.h +++ b/src/declarative/qml/qmlexpression_p.h @@ -140,9 +140,9 @@ public: QmlExpressionData *data; - QVariant value(QObject *secondaryScope = 0); + QVariant value(QObject *secondaryScope = 0, bool *isUndefined = 0); QVariant evalSSE(); - QVariant evalQtScript(QObject *secondaryScope); + QVariant evalQtScript(QObject *secondaryScope, bool *isUndefined = 0); void updateGuards(const QPODVector &properties); void clearGuards(); -- cgit v0.12 From 515cb0f40654e54384fd75c7042b9fa25d3df193 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Tue, 20 Oct 2009 09:54:57 +1000 Subject: Add EVAL_EXPRESSION so clients can evaluate an expression within the current object's context. --- src/declarative/debugger/qmldebug.cpp | 66 +++++++++++++++++++++++++++- src/declarative/debugger/qmldebug.h | 22 ++++++++++ src/declarative/qml/qmlenginedebug.cpp | 78 ++++++++++++++++++++++++---------- src/declarative/qml/qmlenginedebug_p.h | 1 + 4 files changed, 144 insertions(+), 23 deletions(-) diff --git a/src/declarative/debugger/qmldebug.cpp b/src/declarative/debugger/qmldebug.cpp index 1ef7503..75418e8 100644 --- a/src/declarative/debugger/qmldebug.cpp +++ b/src/declarative/debugger/qmldebug.cpp @@ -32,10 +32,12 @@ public: static void remove(QmlEngineDebug *, QmlDebugEnginesQuery *); static void remove(QmlEngineDebug *, QmlDebugRootContextQuery *); static void remove(QmlEngineDebug *, QmlDebugObjectQuery *); + static void remove(QmlEngineDebug *, QmlDebugExpressionQuery *); QHash enginesQuery; QHash rootContextQuery; QHash objectQuery; + QHash expressionQuery; QHash watched; }; @@ -81,6 +83,12 @@ void QmlEngineDebugPrivate::remove(QmlEngineDebug *c, QmlDebugObjectQuery *q) p->objectQuery.remove(q->m_queryId); } +void QmlEngineDebugPrivate::remove(QmlEngineDebug *c, QmlDebugExpressionQuery *q) +{ + QmlEngineDebugPrivate *p = (QmlEngineDebugPrivate *)QObjectPrivate::get(c); + p->expressionQuery.remove(q->m_queryId); +} + Q_DECLARE_METATYPE(QmlDebugObjectReference); void QmlEngineDebugPrivate::decode(QDataStream &ds, QmlDebugObjectReference &o, bool simple) @@ -212,6 +220,19 @@ void QmlEngineDebugPrivate::message(const QByteArray &data) query->m_client = 0; query->setState(QmlDebugQuery::Completed); + } else if (type == "EVAL_EXPRESSION_R") { + int queryId; + QVariant result; + ds >> queryId >> result; + + QmlDebugExpressionQuery *query = expressionQuery.value(queryId); + if (!query) + return; + expressionQuery.remove(queryId); + + query->m_result = result; + query->m_client = 0; + query->setState(QmlDebugQuery::Completed); } else if (type == "WATCH_PROPERTY_R") { int queryId; bool ok; @@ -267,7 +288,6 @@ QmlDebugPropertyWatch *QmlEngineDebug::addWatch(const QmlDebugPropertyReference QmlDebugPropertyWatch *watch = new QmlDebugPropertyWatch(parent); if (d->client->isConnected()) { - //query->m_client = this; int queryId = d->getId(); watch->m_queryId = queryId; watch->m_objectDebugId = property.objectDebugId(); @@ -445,6 +465,29 @@ QmlDebugObjectQuery *QmlEngineDebug::queryObjectRecursive(const QmlDebugObjectRe return query; } +QmlDebugExpressionQuery *QmlEngineDebug::queryExpressionResult(int objectDebugId, const QString &expr, QObject *parent) +{ + Q_D(QmlEngineDebug); + + QmlDebugExpressionQuery *query = new QmlDebugExpressionQuery(parent); + if (d->client->isConnected() && objectDebugId != -1) { + query->m_client = this; + query->m_expr = expr; + int queryId = d->getId(); + query->m_queryId = queryId; + d->expressionQuery.insert(queryId, query); + + QByteArray message; + QDataStream ds(&message, QIODevice::WriteOnly); + ds << QByteArray("EVAL_EXPRESSION") << queryId << objectDebugId << expr; + d->client->sendMessage(message); + } else { + query->m_state = QmlDebugQuery::Error; + } + + return query; +} + QmlDebugWatch::QmlDebugWatch(QObject *parent) : QObject(parent), m_state(Waiting), m_queryId(-1), m_objectDebugId(-1) { @@ -566,6 +609,27 @@ QmlDebugObjectReference QmlDebugObjectQuery::object() const return m_object; } +QmlDebugExpressionQuery::QmlDebugExpressionQuery(QObject *parent) +: QmlDebugQuery(parent), m_client(0), m_queryId(-1) +{ +} + +QmlDebugExpressionQuery::~QmlDebugExpressionQuery() +{ + if (m_client && m_queryId != -1) + QmlEngineDebugPrivate::remove(m_client, this); +} + +QString QmlDebugExpressionQuery::expression() const +{ + return m_expr; +} + +QVariant QmlDebugExpressionQuery::result() const +{ + return m_result; +} + QmlDebugEngineReference::QmlDebugEngineReference() : m_debugId(-1) { diff --git a/src/declarative/debugger/qmldebug.h b/src/declarative/debugger/qmldebug.h index 681ee08..153a10f 100644 --- a/src/declarative/debugger/qmldebug.h +++ b/src/declarative/debugger/qmldebug.h @@ -12,6 +12,7 @@ class QmlDebugObjectExpressionWatch; class QmlDebugEnginesQuery; class QmlDebugRootContextQuery; class QmlDebugObjectQuery; +class QmlDebugExpressionQuery; class QmlDebugPropertyReference; class QmlDebugContextReference; class QmlDebugObjectReference; @@ -44,6 +45,9 @@ public: QObject *parent = 0); QmlDebugObjectQuery *queryObjectRecursive(const QmlDebugObjectReference &, QObject *parent = 0); + QmlDebugExpressionQuery *queryExpressionResult(int objectDebugId, + const QString &expr, + QObject *parent = 0); private: Q_DECLARE_PRIVATE(QmlEngineDebug) @@ -287,4 +291,22 @@ private: }; +class Q_DECLARATIVE_EXPORT QmlDebugExpressionQuery : public QmlDebugQuery +{ +Q_OBJECT +public: + virtual ~QmlDebugExpressionQuery(); + QString expression() const; + QVariant result() const; +private: + friend class QmlEngineDebug; + friend class QmlEngineDebugPrivate; + QmlDebugExpressionQuery(QObject *); + QmlEngineDebug *m_client; + int m_queryId; + QString m_expr; + QVariant m_result; + +}; + #endif // QMLDEBUG_H diff --git a/src/declarative/qml/qmlenginedebug.cpp b/src/declarative/qml/qmlenginedebug.cpp index 1c7450a..bbe6f77 100644 --- a/src/declarative/qml/qmlenginedebug.cpp +++ b/src/declarative/qml/qmlenginedebug.cpp @@ -184,6 +184,33 @@ void QmlEngineDebugServer::buildObjectList(QDataStream &message, } } +QVariant QmlEngineDebugServer::serializableVariant(const QVariant &value) +{ + QVariant v; + if (value.type() == QVariant::UserType || QmlMetaType::isObject(value.userType())) { + QObject *o = QmlMetaType::toQObject(value); + if (o) { + QString objectName = o->objectName(); + if (objectName.isEmpty()) + objectName = QLatin1String(""); + v = QString::fromUtf8(o->metaObject()->className()) + + QLatin1String(": ") + objectName; + } else { + v = QString::fromUtf8(value.typeName()); + } + if (v.isNull()) { + QString s = value.toString(); + if (s.isEmpty()) + s = QLatin1String(""); + v = s; + } + } else { + v = value; + } + + return v; +} + QmlEngineDebugServer::QmlObjectData QmlEngineDebugServer::objectData(QObject *object) { @@ -310,36 +337,43 @@ void QmlEngineDebugServer::messageReceived(const QByteArray &message) ds >> queryId; m_watch->removeWatch(queryId); + } else if (type == "EVAL_EXPRESSION") { + int queryId; + int objectId; + QString expr; + + ds >> queryId >> objectId >> expr; + + QObject *object = QmlDebugService::objectForId(objectId); + QmlContext *context = qmlContext(object); + QVariant result; + if (object && context) { + QmlExpression *exprObj = new QmlExpression(context, expr, object); + bool undefined = false; + QVariant value = exprObj->value(&undefined); + if (undefined) + result = QLatin1String(""); + else + result = serializableVariant(value); + delete exprObj; + } else { + result = QLatin1String(""); + } + + QByteArray reply; + QDataStream rs(&reply, QIODevice::WriteOnly); + rs << QByteArray("EVAL_EXPRESSION_R") << queryId << result; + + sendMessage(reply); } } void QmlEngineDebugServer::propertyChanged(int id, int objectId, const QByteArray &property, const QVariant &value) { QByteArray reply; - QVariant v; + QVariant v = serializableVariant(value); QDataStream rs(&reply, QIODevice::WriteOnly); - if (value.type() == QVariant::UserType || QmlMetaType::isObject(value.userType())) { - QObject *o = QmlMetaType::toQObject(value); - if (o) { - QString objectName = o->objectName(); - if (objectName.isEmpty()) - objectName = QLatin1String(""); - v = QString::fromUtf8(o->metaObject()->className()) + - QLatin1String(": ") + objectName; - } else { - v = QString::fromUtf8(value.typeName()); - } - if (v.isNull()) { - QString s = value.toString(); - if (s.isEmpty()) - s = QLatin1String(""); - v = s; - } - } else { - v = value; - } - rs << QByteArray("UPDATE_WATCH") << id << objectId << property << v; sendMessage(reply); diff --git a/src/declarative/qml/qmlenginedebug_p.h b/src/declarative/qml/qmlenginedebug_p.h index e2f903c..9ad198a 100644 --- a/src/declarative/qml/qmlenginedebug_p.h +++ b/src/declarative/qml/qmlenginedebug_p.h @@ -103,6 +103,7 @@ private: void buildObjectDump(QDataStream &, QObject *, bool); QmlObjectData objectData(QObject *); QmlObjectProperty propertyData(QObject *, int); + QVariant serializableVariant(const QVariant &value); static QList m_engines; QmlWatcher *m_watch; -- cgit v0.12 From 85fe2b6ece1e590199bcf7960c1a40e816e81105 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Tue, 20 Oct 2009 09:57:41 +1000 Subject: Add ExpressionQueryWidget and do some clean up. --- tools/qmldebugger/expressionquerywidget.cpp | 181 ++++++++++++++++++++++++++++ tools/qmldebugger/expressionquerywidget.h | 58 +++++++++ tools/qmldebugger/objectpropertiesview.cpp | 2 +- tools/qmldebugger/objecttree.cpp | 10 +- tools/qmldebugger/objecttree.h | 6 +- tools/qmldebugger/qmldebugger.cpp | 4 + tools/qmldebugger/qmldebugger.pri | 6 +- tools/qmldebugger/watchtable.cpp | 3 + 8 files changed, 259 insertions(+), 11 deletions(-) create mode 100644 tools/qmldebugger/expressionquerywidget.cpp create mode 100644 tools/qmldebugger/expressionquerywidget.h diff --git a/tools/qmldebugger/expressionquerywidget.cpp b/tools/qmldebugger/expressionquerywidget.cpp new file mode 100644 index 0000000..90ab8ee --- /dev/null +++ b/tools/qmldebugger/expressionquerywidget.cpp @@ -0,0 +1,181 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "expressionquerywidget.h" + +ExpressionQueryWidget::ExpressionQueryWidget(QmlEngineDebug *client, QWidget *parent) + : QWidget(parent), + m_style(Compact), + m_client(client), + m_query(0), + m_groupBox(0), + m_textEdit(new QTextEdit), + m_lineEdit(0) +{ + m_prompt = QLatin1String(">> "); + + m_groupBox = new QGroupBox; + QVBoxLayout *vbox = new QVBoxLayout(m_groupBox); + vbox->addWidget(m_textEdit); + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->addWidget(m_groupBox); + + updateTitle(); + + if (m_style == Compact) { + QHBoxLayout *hbox = new QHBoxLayout; + QPushButton *button = new QPushButton(tr("Execute")); + connect(button, SIGNAL(clicked()), SLOT(executeExpression())); + m_lineEdit = new QLineEdit; + connect(m_lineEdit, SIGNAL(returnPressed()), SLOT(executeExpression())); + hbox->addWidget(new QLabel(tr("Expression:"))); + hbox->addWidget(m_lineEdit); + hbox->addWidget(button); + vbox->addLayout(hbox); + + m_textEdit->setReadOnly(true); + } else { + m_textEdit->installEventFilter(this); + } +} + +void ExpressionQueryWidget::updateTitle() +{ + if (m_currObject.debugId() < 0) { + m_groupBox->setTitle(tr("Expression queries")); + } else { + QString desc = QLatin1String("<") + + m_currObject.className() + QLatin1String(": ") + + (m_currObject.name().isEmpty() ? QLatin1String("") : m_currObject.name()) + + QLatin1String(">"); + m_groupBox->setTitle(tr("Expression queries (current context: %1)" + , "Selected object").arg(desc)); + } +} + +void ExpressionQueryWidget::appendPrompt() +{ + m_textEdit->moveCursor(QTextCursor::End); + + if (m_style == Compact) { + 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() +{ + m_textEdit->moveCursor(QTextCursor::End); + m_textEdit->setTextColor(Qt::darkGreen); + m_textEdit->append(m_currObject.className() + + QLatin1String(": ") + + (m_currObject.name().isEmpty() ? QLatin1String("") : m_currObject.name())); + appendPrompt(); +} + +void ExpressionQueryWidget::executeExpression() +{ + if (m_style == Compact) + m_expr = m_lineEdit->text().trimmed(); + + if (!m_expr.trimmed().isEmpty() && m_currObject.debugId() != -1) { + checkCurrentContext(); + if (m_query) + delete m_query; + m_query = m_client->queryExpressionResult(m_currObject.debugId(), m_expr.trimmed(), this); + if (!m_query->isWaiting()) + showResult(); + else + QObject::connect(m_query, SIGNAL(stateChanged(State)), + this, SLOT(showResult())); + + if (m_lineEdit) + m_lineEdit->clear(); + } +} + +void ExpressionQueryWidget::showResult() +{ + if (m_query) { + m_textEdit->moveCursor(QTextCursor::End); + QString result = m_query->result().toString(); + if (result.isEmpty()) + result = QLatin1String(""); + + if (m_style == Compact) { + 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->append(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(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; + } + } + return QWidget::eventFilter(obj, event); +} diff --git a/tools/qmldebugger/expressionquerywidget.h b/tools/qmldebugger/expressionquerywidget.h new file mode 100644 index 0000000..3ea95ac --- /dev/null +++ b/tools/qmldebugger/expressionquerywidget.h @@ -0,0 +1,58 @@ +#ifndef EXPRESSIONQUERYWIDGET_H +#define EXPRESSIONQUERYWIDGET_H + +#include + +#include + +QT_BEGIN_NAMESPACE + +class QGroupBox; +class QTextEdit; +class QLineEdit; + +class ExpressionQueryWidget : public QWidget +{ + Q_OBJECT +public: + enum Style { + Compact, + Shell + }; + + ExpressionQueryWidget(QmlEngineDebug *client, QWidget *parent = 0); + +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(); + + Style m_style; + + QmlEngineDebug *m_client; + QmlDebugExpressionQuery *m_query; + QGroupBox *m_groupBox; + QTextEdit *m_textEdit; + QLineEdit *m_lineEdit; + QString m_prompt; + QString m_expr; + + QmlDebugObjectReference m_currObject; + QmlDebugObjectReference m_objectAtLastFocus; +}; + +QT_END_NAMESPACE + +#endif + diff --git a/tools/qmldebugger/objectpropertiesview.cpp b/tools/qmldebugger/objectpropertiesview.cpp index 864468c..4a2f97d 100644 --- a/tools/qmldebugger/objectpropertiesview.cpp +++ b/tools/qmldebugger/objectpropertiesview.cpp @@ -177,7 +177,7 @@ void ObjectPropertiesView::valueChanged(const QByteArray &name, const QVariant & void ObjectPropertiesView::itemActivated(QTreeWidgetItem *i) { PropertiesViewItem *item = static_cast(i); - if (!item->property.name().isEmpty() && item->property.hasNotifySignal()) + if (!item->property.name().isEmpty()) emit activated(m_object, item->property); } diff --git a/tools/qmldebugger/objecttree.cpp b/tools/qmldebugger/objecttree.cpp index f68e7f1..0b92ceb 100644 --- a/tools/qmldebugger/objecttree.cpp +++ b/tools/qmldebugger/objecttree.cpp @@ -19,8 +19,8 @@ ObjectTree::ObjectTree(QmlEngineDebug *client, QWidget *parent) { setHeaderHidden(true); - connect(this, SIGNAL(itemClicked(QTreeWidgetItem *, int)), - this, SLOT(handleItemClicked(QTreeWidgetItem *))); + connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), + this, SLOT(currentItemChanged(QTreeWidgetItem *))); } void ObjectTree::reload(int objectDebugId) @@ -38,7 +38,7 @@ void ObjectTree::reload(int objectDebugId) this, SLOT(objectFetched())); } -void ObjectTree::selectObject(int debugId) +void ObjectTree::setCurrentObject(int debugId) { QTreeWidgetItem *item = findItemByObjectId(debugId); if (item) { @@ -57,14 +57,14 @@ void ObjectTree::objectFetched() m_query = 0; } -void ObjectTree::handleItemClicked(QTreeWidgetItem *item) +void ObjectTree::currentItemChanged(QTreeWidgetItem *item) { QmlDebugObjectReference obj = item->data(0, Qt::UserRole).value(); if (obj.debugId() < 0) { qWarning("QML Object Tree: bad object id"); return; } - emit objectSelected(obj); + emit currentObjectChanged(obj); } void ObjectTree::buildTree(const QmlDebugObjectReference &obj, QTreeWidgetItem *parent) diff --git a/tools/qmldebugger/objecttree.h b/tools/qmldebugger/objecttree.h index bba6c08..3c0a5c6 100644 --- a/tools/qmldebugger/objecttree.h +++ b/tools/qmldebugger/objecttree.h @@ -20,19 +20,19 @@ public: ObjectTree(QmlEngineDebug *client, QWidget *parent = 0); signals: - void objectSelected(const QmlDebugObjectReference &); + void currentObjectChanged(const QmlDebugObjectReference &); void expressionWatchRequested(const QmlDebugObjectReference &, const QString &); public slots: void reload(int objectDebugId); - void selectObject(int debugId); + void setCurrentObject(int debugId); protected: virtual void mousePressEvent(QMouseEvent *); private slots: void objectFetched(); - void handleItemClicked(QTreeWidgetItem *); + void currentItemChanged(QTreeWidgetItem *); private: QTreeWidgetItem *findItemByObjectId(int debugId) const; diff --git a/tools/qmldebugger/qmldebugger.cpp b/tools/qmldebugger/qmldebugger.cpp index 0f0fc03..e0a76b6 100644 --- a/tools/qmldebugger/qmldebugger.cpp +++ b/tools/qmldebugger/qmldebugger.cpp @@ -57,6 +57,10 @@ QmlDebugger::QmlDebugger(QWidget *parent) QObject::connect(&client, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(connectionError(QAbstractSocket::SocketError))); + + + m_tabs->setCurrentIndex(1); + connectToHost(); } void QmlDebugger::setHost(const QString &host) diff --git a/tools/qmldebugger/qmldebugger.pri b/tools/qmldebugger/qmldebugger.pri index ce36381..c49d334 100644 --- a/tools/qmldebugger/qmldebugger.pri +++ b/tools/qmldebugger/qmldebugger.pri @@ -7,7 +7,8 @@ HEADERS += $$PWD/qmldebugger.h \ $$PWD/watchtable.h \ $$PWD/engine.h \ $$PWD/objecttree.h \ - $$PWD/objectpropertiesview.h + $$PWD/objectpropertiesview.h \ + $$PWD/expressionquerywidget.h SOURCES += $$PWD/qmldebugger.cpp \ $$PWD/main.cpp \ @@ -15,7 +16,8 @@ SOURCES += $$PWD/qmldebugger.cpp \ $$PWD/watchtable.cpp \ $$PWD/engine.cpp \ $$PWD/objecttree.cpp \ - $$PWD/objectpropertiesview.cpp + $$PWD/objectpropertiesview.cpp \ + $$PWD/expressionquerywidget.cpp RESOURCES += $$PWD/qmldebugger.qrc diff --git a/tools/qmldebugger/watchtable.cpp b/tools/qmldebugger/watchtable.cpp index e4163dc..512bfb2 100644 --- a/tools/qmldebugger/watchtable.cpp +++ b/tools/qmldebugger/watchtable.cpp @@ -193,6 +193,9 @@ void WatchTableModel::addValue(int column, const QVariant &value) void WatchTableModel::togglePropertyWatch(const QmlDebugObjectReference &object, const QmlDebugPropertyReference &property) { + if (!property.hasNotifySignal()) + return; + QmlDebugWatch *watch = findWatch(object.debugId(), property.name()); if (watch) { // watch will be deleted in watchStateChanged() -- cgit v0.12 From a0c0e0b584b107375a8a348af45da6ad681d4a8c Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 20 Oct 2009 11:43:49 +1000 Subject: Make ParentChange work when target has a transformOrigin set. --- src/declarative/util/qmlstateoperations.cpp | 47 ++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/src/declarative/util/qmlstateoperations.cpp b/src/declarative/util/qmlstateoperations.cpp index 60fd421..053cdc3 100644 --- a/src/declarative/util/qmlstateoperations.cpp +++ b/src/declarative/util/qmlstateoperations.cpp @@ -70,10 +70,11 @@ public: void QmlParentChangePrivate::doChange(QFxItem *targetParent, QFxItem *stackBefore) { if (targetParent && target && target->parentItem()) { - //### for backwards direction, we can just restore original x, y, scale, rotation + //### for backwards direction, can we just restore original x, y, scale, rotation Q_Q(QmlParentChange); - const QTransform &transform = target->itemTransform(targetParent); - if (transform.type() >= QTransform::TxShear) { + bool ok; + const QTransform &transform = target->itemTransform(targetParent, &ok); + if (transform.type() >= QTransform::TxShear || !ok) { qmlInfo(QObject::tr("Unable to preserve appearance under complex transform"), q); } @@ -82,25 +83,49 @@ void QmlParentChangePrivate::doChange(QFxItem *targetParent, QFxItem *stackBefor if (transform.type() != QTransform::TxRotate) { if (transform.m11() == transform.m22()) scale = transform.m11(); - else + else { qmlInfo(QObject::tr("Unable to preserve appearance under non-uniform scale"), q); + ok = false; + } } else if (transform.type() == QTransform::TxRotate) { if (transform.m11() == transform.m22()) scale = qSqrt(transform.m11()*transform.m11() + transform.m12()*transform.m12()); - else + else { qmlInfo(QObject::tr("Unable to preserve appearance under non-uniform scale"), q); + ok = false; + } if (scale != 0) rotation = atan2(transform.m12()/scale, transform.m11()/scale) * 180/M_PI; - else + else { qmlInfo(QObject::tr("Unable to preserve appearance under scale of 0"), q); + ok = false; + } } + + qreal xt = transform.dx(); + qreal yt = transform.dy(); + if (target->transformOrigin() != QFxItem::TopLeft) { + qreal tempxt = target->transformOriginPoint().x(); + qreal tempyt = target->transformOriginPoint().y(); + QTransform t; + t.translate(-tempxt, -tempyt); + t.rotate(rotation); + t.scale(scale, scale); + t.translate(tempxt, tempyt); + QPointF offset = t.map(QPointF(0,0)); + xt += offset.x(); + yt += offset.y(); + } + target->setParentItem(targetParent); - //qDebug() << transform.dx() << transform.dy() << rotation << scale; - target->setX(transform.dx()); - target->setY(transform.dy()); - target->setRotation(rotation); - target->setScale(scale); + if (ok) { + //qDebug() << xt << yt << rotation << scale; + target->setX(xt); + target->setY(yt); + target->setRotation(rotation); + target->setScale(scale); + } } else if (target) { target->setParentItem(targetParent); } -- cgit v0.12 From dea5af3305ea0b4c7481d0b8f5bad4613a1fb6bc Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 20 Oct 2009 13:38:15 +1000 Subject: Temporary fix for animation bug. --- src/corelib/animation/qabstractanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index c775a00..f23ad3c 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -328,7 +328,7 @@ int QUnifiedTimer::closestPauseAnimationTimeToFinish() int timeToFinish; if (animation->direction() == QAbstractAnimation::Forward) - timeToFinish = animation->totalDuration() - QAbstractAnimationPrivate::get(animation)->totalCurrentTime; + timeToFinish = animation->duration() - QAbstractAnimationPrivate::get(animation)->currentTime; else timeToFinish = QAbstractAnimationPrivate::get(animation)->totalCurrentTime; -- cgit v0.12 From 3f7d4b985847d49cb47b666535218f2b9b08e0a5 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 20 Oct 2009 13:41:10 +1000 Subject: Don't accidently override originals. --- src/declarative/util/qmlstate.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/declarative/util/qmlstate.cpp b/src/declarative/util/qmlstate.cpp index 98facd9..7e4e992 100644 --- a/src/declarative/util/qmlstate.cpp +++ b/src/declarative/util/qmlstate.cpp @@ -350,7 +350,6 @@ void QmlState::apply(QmlStateGroup *group, QmlTransition *trans, QmlState *rever if (action.event) { if (!action.event->isReversable()) continue; - action.event->saveOriginals(); for (jj = 0; jj < d->revertList.count(); ++jj) { ActionEvent *event = d->revertList.at(jj).event; if (event && event->typeName() == action.event->typeName()) { @@ -360,6 +359,8 @@ void QmlState::apply(QmlStateGroup *group, QmlTransition *trans, QmlState *rever } } } + if (!found || action.event != d->revertList.at(jj).event) + action.event->saveOriginals(); } else { action.fromBinding = action.property.binding(); -- cgit v0.12 From 6dfbe4f4c57985c0767d152fd056ee5aad326d55 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Tue, 20 Oct 2009 13:45:24 +1000 Subject: Remove references to KeyActions in focus docs. --- doc/src/declarative/focus.qdoc | 88 ++++++++++++++++++++++++++++-------------- 1 file changed, 60 insertions(+), 28 deletions(-) diff --git a/doc/src/declarative/focus.qdoc b/doc/src/declarative/focus.qdoc index 8733b2d..ec6a02f 100644 --- a/doc/src/declarative/focus.qdoc +++ b/doc/src/declarative/focus.qdoc @@ -58,12 +58,14 @@ When the user presses or releases a key, the following occurs: \o The key event is delivered by the scene to the QML \l Item with \e {active focus}. If no \l Item has \e {active focus}, the key event is \l {QEvent::ignore()}{ignored} and regular Qt key handling continues. \o If the QML \l Item with \e {active focus} accepts the key event, propagation stops. Otherwise the event is "bubbled up", by recursively passing it to each \l Item's parent until either the event is accepted, or the root \l Item is reached. -If the \c {Rectangle} element in the following example has active focus and the \e A key is pressed, it will bubble up to the \c {KeyActions}. However, pressing the \e B key will bubble up to the root item and thus subsequently be \l {QEvent::ignore()}{ignored}. +If the \c {Rectangle} element in the following example has active focus and the \e A key is pressed, +it will bubble up to its parent. However, pressing the \e B key will bubble up to the root +item and thus subsequently be \l {QEvent::ignore()}{ignored}. \code Item { - KeyActions { - keyA: "print('Key A was pressed')" + Item { + Keys.onPressed: if (event.key == Qt.Key_A) { print('Key A was pressed'); event.accepted = true } Rectangle {} } } @@ -91,8 +93,8 @@ An \l Item requests focus by setting the \c {Item::focus} property to true. For very simple cases simply setting the \c {Item::focus} property is sometimes sufficient. If we run the following example in the \c qmlviewer, we see that -the \c {KeyActions} element has \e {active focus} and pressing the -\e A, \e B, or \e C keys modifies the text appropriately. +the \c {keyHandler} element has \e {active focus} and pressing the 'A', 'B' +or 'C' keys modifies the text appropriately. \table \row @@ -100,11 +102,17 @@ the \c {KeyActions} element has \e {active focus} and pressing the Rectangle { color: "lightsteelblue"; width: 240; height: 25 Text { id: myText } - KeyActions { + Item { + id: keyHandler focus: true - keyA: "myText.text = 'Key A was pressed'" - keyB: "myText.text = 'Key B was pressed'" - keyC: "myText.text = 'Key C was pressed'" + Keys.onPressed: { + if (event.key == Qt.Key_A) + myText.text = 'Key A was pressed' + else if (event.key == Qt.Key_B) + myText.text = 'Key B was pressed' + else if (event.key == Qt.Key_C) + myText.text = 'Key C was pressed' + } } } \endcode @@ -134,22 +142,34 @@ Rectangle { Rectangle { color: "lightsteelblue"; width: 240; height: 25 Text { id: myText } - KeyActions { + Item { + id: keyHandler focus: true - keyA: "myText.text = 'Key A was pressed'" - keyB: "myText.text = 'Key B was pressed'" - keyC: "myText.text = 'Key C was pressed'" + Keys.onPressed: { + if (event.key == Qt.Key_A) + myText.text = 'Key A was pressed' + else if (event.key == Qt.Key_B) + myText.text = 'Key B was pressed' + else if (event.key == Qt.Key_C) + myText.text = 'Key C was pressed' + } } } Rectangle { y: 30; focus: true color: "lightsteelblue"; width: 240; height: 25 Text { id: myText } - KeyActions { + Item { + id: keyHandler focus: true - keyA: "myText.text = 'Key A was pressed'" - keyB: "myText.text = 'Key B was pressed'" - keyC: "myText.text = 'Key C was pressed'" + Keys.onPressed: { + if (event.key == Qt.Key_A) + myText.text = 'Key A was pressed' + else if (event.key == Qt.Key_B) + myText.text = 'Key B was pressed' + else if (event.key == Qt.Key_C) + myText.text = 'Key C was pressed' + } } } } @@ -166,9 +186,9 @@ of \c {Item::focus} in the other two instances is reverted back to false. This is exactly the opposite of what was wanted! This problem is fundamentally one of visibility. The \c {MyWidget} -components each set their \c {KeyActions} as focused as that is all they can +components each set their \c {keyHandler} Items as focused as that is all they can do - they don't know how they are going to be used, but they do know that when -they're in use their \c {KeyActions} element is what needs focus. Likewise +they're in use their \c {keyHandler} element is what needs focus. Likewise the code that uses the \c {MyWidget}'s sets the second \c {MyWidget} as focused because, while it doesn't know exactly how the \c {MyWidget} is implemented, it knows that it wants the second one to be focused. No one piece @@ -191,11 +211,17 @@ FocusScope { Rectangle { color: "lightsteelblue"; width: 240; height: 25 Text { id: myText } - KeyActions { + Item { + id: keyHandler focus: true - keyA: "myText.text = 'Key A was pressed'" - keyB: "myText.text = 'Key B was pressed'" - keyC: "myText.text = 'Key C was pressed'" + Keys.onPressed: { + if (event.key == Qt.Key_A) + myText.text = 'Key A was pressed' + else if (event.key == Qt.Key_B) + myText.text = 'Key B was pressed' + else if (event.key == Qt.Key_C) + myText.text = 'Key C was pressed' + } } } } @@ -205,8 +231,11 @@ FocusScope { Conceptually \e {focus scopes} are quite simple. \list -\o Within each \e {focus scope} one element may have \c {Item::focus} set to true. If more than one \l Item has the \c {Item::focus} property set, the first is selected and the others are unset, just like when there are no \e {focus scopes}. -\o When a \e {focus scope} receives \e {active focus}, the contained element with \c {Item::focus} set (if any) also gets \e {active focus}. If this element is +\o Within each \e {focus scope} one element may have \c {Item::focus} set to true. +If more than one \l Item has the \c {Item::focus} property set, the first is selected +and the others are unset, just like when there are no \e {focus scopes}. +\o When a \e {focus scope} receives \e {active focus}, the contained element with +\c {Item::focus} set (if any) also gets \e {active focus}. If this element is also a \l FocusScope, the proxying behaviour continues. Both the \e {focus scope} and the sub-focused item will have \c {Item::focus} set. \endlist @@ -270,8 +299,11 @@ Rectangle { } delegate: FocusScope { width: contents.width; height: contents.height - Text { text: name } - KeyActions { return: "print(name)"; focus: true } + Text { + focus: true + text: name + Keys.onReturnPressed: print(name) + } } } } @@ -285,7 +317,7 @@ property. As the \l ListView is a \e {focus scope}, this doesn't effect the rest of the application. However, if the \l ListView itself has \e {active focus} this causes the delegate itself to receive \e {active focus}. In this example, the root element of the delegate is also a \e {focus scope}, -which in turn gives \e {active focus} to the \c {KeyActions} element that +which in turn gives \e {active focus} to the \c {Text} element that actually performs the work of handling the \e {Return} key. All of the QML view classes, such as \l PathView and \l GridView, behave -- cgit v0.12 From 04eae20d3b86cc61ab3b3bdded74caa370a84c43 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 20 Oct 2009 14:07:43 +1000 Subject: Additional temporary fix for animation bug. --- src/corelib/animation/qabstractanimation.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index f23ad3c..8d34a98 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -228,11 +228,7 @@ void QUnifiedTimer::updateAnimationsTime() void QUnifiedTimer::restartAnimationTimer() { - if (runningLeafAnimations == 0 && !runningPauseAnimations.isEmpty()) { - int closestTimeToFinish = closestPauseAnimationTimeToFinish(); - animationTimer.start(closestTimeToFinish, this); - isPauseTimerActive = true; - } else if (!animationTimer.isActive() || isPauseTimerActive) { + if (!animationTimer.isActive()) { animationTimer.start(timingInterval, this); isPauseTimerActive = false; } -- cgit v0.12 From c878a18a65b8c6ce4845179babb34f9732f485c9 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 20 Oct 2009 14:34:08 +1000 Subject: Doc --- doc/src/declarative/pics/qml-scope.png | Bin 34888 -> 47564 bytes doc/src/declarative/scope.qdoc | 206 +++++++++++++++++++++++++++++++-- 2 files changed, 198 insertions(+), 8 deletions(-) diff --git a/doc/src/declarative/pics/qml-scope.png b/doc/src/declarative/pics/qml-scope.png index 05403db..be025c8 100644 Binary files a/doc/src/declarative/pics/qml-scope.png and b/doc/src/declarative/pics/qml-scope.png differ diff --git a/doc/src/declarative/scope.qdoc b/doc/src/declarative/scope.qdoc index 4c613df..df7a215 100644 --- a/doc/src/declarative/scope.qdoc +++ b/doc/src/declarative/scope.qdoc @@ -50,31 +50,221 @@ dramatically different scope chains. \image qml-scope.png -\section1 Variable object +\section1 ECMAScript Variable object -Where local variables are stored. Not really applicable to bindings. +Each binding and script block has its own distinct ECMAScript variable object where local +variables are stored. That is, local variables from different bindings and script blocks never +conflict. -\section1 QML Scope object +\section1 Element Type Names -Principally for the \c parent property. +Bindings or script blocks use element type names when accessing \l {Attached Properties} or +enumeration values. The set of available element names is defined by the import list of the +\l {QML Documents}{QML Document} in which the the binding or script block is defined. + +These two examples show how to access attached properties and enumeration values with different +types of import statements. +\table +\row +\o +\code +import Qt 4.6 + +Text { + id: root + scale: root.PathView.scale + horizontalAlignment: Text.AlignLeft +} +\endcode +\o +\code +import Qt 4.6 as MyQt + +Text { + id: root + scale: root.MyQt.PathView.scale + horizontalAlignment: MyQt.Text.AlignLeft +} +\endcode +\endtable + +\section1 QML Local Scope + +Most variables references are resolved in the local scope. The local scope is controlled by the +QML component in which the binding or script block was declarated. The following example shows +three different bindings, and the component that dictates their local scope. + +\table +\row +\o +\code +// main.qml +import Qt 4.6 + +Rectangle { // Local scope component for binding 1 + id: root + property string text + + Button { + text: root.text // binding 1 + } + + ListView { + delegate: Component { // Local scope component for binding 2 + Rectangle { + width: ListView.view.width // binding 2 + } + } + } + +} +\endcode +\o +\code +// Button.qml +import Qt 4.6 + +Rectangle { // Local scope component for binding 3 + id: root + property string text + + Text { + text: root.text // binding 3 + } +} +\endcode +\endtable + +Inside the local scope, four "sub-scopes" exist. Each "sub-scope" is searched in order when +resolving a name - names in a higher "sub-scopes" shadow those in lower sub-scopes. + +\section2 IDs + +IDs present in the component take precendence over other names. The QML engine enforces +uniqueness of IDs within a component, so their names cannot conflict with one another. + +This is an example of using IDs within bindings. \code Item { - anchors.fill: parent + id: root + width: nested.width + Item { + id: nested + height: root.height + } } \endcode -vs +\section2 Script Methods + +Methods declared in script blocks are searched immediately after IDs. In the case of multiple +script blocks in the one component, the blocks are searched in the order in which they were +declared - the nesting of script blocks within a component is not significant for name +resolution. + +In the following example, \c {Method 1} shadows \c {Method 2} for the bindings, but not for +\c {Method 3}. \code Item { - anchors.fill: this.parent + Script { + function getValue() { return 10; } // Method 1 + } + + Rectangle { + Script { + function getValue() { return 11; } // Method 2 + function getValue2() { return getValue(); } // Method 3 + } + + x: getValue() // Resolves to Method 1, set to 10 + y: getValue2() // Resolves to Method 3, set to 11 + } +} +\endcode + +\section2 Scope Object + +A scope object is associated with each binding and script block. Properties and methods of the +scope object appear in the scope chain, immediately after \l {Script Methods}. + +In bindings and script blocks established explicitly in \l {QML Documents}, the scope object is +always the element containing the binding or script block. The following example shows two +bindings, one using grouped properties, and the corresponding scope object. These two bindings +use the scope object to resolve variable references - \c height is a property on \l Rectangle, +and \c parent is a property on \l Text. + +\code +Item { + Rectangle { // Scope object for Binding 1 + width: height * 2 // Binding 1 + } + + Text { // Scope object for Binding 2 + font.pixelSize: parent.height * 0.7 // binding 2 + } +} +\endcode + +One notable characteristic of the scope object is its interaction with \l {Attached Properties}. +As attached properties exist on all object, an attached property reference that is not +explicitly prefixed by an id will \e always resolve to the attached property on the scope +object. + +In the following example, \c {Binding 1} will resolve to the attached properties of the +\l Rectangle element, as intended. However, due to the property search of the scope object, +\c {Binding 2} will resolve to the attached properties of the \l Text element, which +is probably not what was intended. This code can be corrected, by replacing \c {Binding 2} +with this explicit element reference \c {root.ListView.view.width}. + +\code +import Qt 4.6 + +ListView { + delegate: Rectangle { + id: root + width: ListView.view.width // Binding 1 + Text { + text: contactName + width: ListView.view.width // Binding 2 + } + } +} +\endcode + +\e TODO + +\list +\o scope object for Script {} +\o scope object for PropertyChanges +\endlist + +\section2 Root Object + +Properties and methods on the local scope component's root object appear in the scope chain +immediately after the \l {Scope Object}. If the scope object and root object are the same, +this step has no effect. + +This example uses the root object to easily propagate data throughout the component. + +\code +Item { + property string description + property int fontSize + + Text { + text: description + font.pixelSize: fontSize + } } \endcode \section1 QML Component chain -Principally for propogating properties around the component. +\section2 IDs +\section2 Script Methods +\section2 Root Object \section1 QmlContext chain -- cgit v0.12 From 7fe26e119685dfc694dcf5bd1dceeeb1226f3dfd Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 20 Oct 2009 14:34:14 +1000 Subject: Don't search non-local context types --- src/declarative/qml/qmlcontextscriptclass.cpp | 9 ++++++--- src/declarative/qml/qmlcontextscriptclass_p.h | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/declarative/qml/qmlcontextscriptclass.cpp b/src/declarative/qml/qmlcontextscriptclass.cpp index ae86fb1..4df23f0 100644 --- a/src/declarative/qml/qmlcontextscriptclass.cpp +++ b/src/declarative/qml/qmlcontextscriptclass.cpp @@ -99,10 +99,12 @@ QmlContextScriptClass::queryProperty(Object *object, const Identifier &name, if (!bindContext) return 0; + bool includeTypes = true; while (bindContext) { QScriptClass::QueryFlags rv = - queryProperty(bindContext, scopeObject, name, flags); + queryProperty(bindContext, scopeObject, name, flags, includeTypes); scopeObject = 0; // Only applies to the first context + includeTypes = false; // Only applies to the first context if (rv) return rv; bindContext = bindContext->parentContext(); } @@ -113,7 +115,8 @@ QmlContextScriptClass::queryProperty(Object *object, const Identifier &name, QScriptClass::QueryFlags QmlContextScriptClass::queryProperty(QmlContext *bindContext, QObject *scopeObject, const Identifier &name, - QScriptClass::QueryFlags flags) + QScriptClass::QueryFlags flags, + bool includeTypes) { QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); QmlContextPrivate *cp = QmlContextPrivate::get(bindContext); @@ -124,7 +127,7 @@ QmlContextScriptClass::queryProperty(QmlContext *bindContext, QObject *scopeObje return QScriptClass::HandlesReadAccess; } - if (cp->imports) { + if (includeTypes && cp->imports) { QmlTypeNameCache::Data *data = cp->imports->data(name); if (data) { diff --git a/src/declarative/qml/qmlcontextscriptclass_p.h b/src/declarative/qml/qmlcontextscriptclass_p.h index 126c8fe..95dff5b 100644 --- a/src/declarative/qml/qmlcontextscriptclass_p.h +++ b/src/declarative/qml/qmlcontextscriptclass_p.h @@ -80,7 +80,8 @@ protected: private: QScriptClass::QueryFlags queryProperty(QmlContext *, QObject *scopeObject, const Identifier &, - QScriptClass::QueryFlags flags); + QScriptClass::QueryFlags flags, + bool includeTypes); QmlEngine *engine; -- cgit v0.12 From 61b287e14d75a86c44f99f1110848c9036f63ded Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 20 Oct 2009 15:14:01 +1000 Subject: Doc --- doc/src/declarative/scope.qdoc | 108 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 102 insertions(+), 6 deletions(-) diff --git a/doc/src/declarative/scope.qdoc b/doc/src/declarative/scope.qdoc index df7a215..7dbbefc 100644 --- a/doc/src/declarative/scope.qdoc +++ b/doc/src/declarative/scope.qdoc @@ -46,7 +46,7 @@ \l {Property Binding}s and \l {ECMAScript Blocks} are executed in a scope chain automatically established by QML when constructing a component instance. QML is a \e {dynamically scoped} language. Different object instances instantiated from the same component can exist in -dramatically different scope chains. +different scope chains. \image qml-scope.png @@ -262,15 +262,111 @@ Item { \section1 QML Component chain -\section2 IDs -\section2 Script Methods -\section2 Root Object +When a QML component is instantiated it is given a parent component instance. The parent +component instance is immutable - it is not effected, for example, by changes in the instance's +visual parent (in the case of visual elements). Should name resolution fail within the +\l {QML Local Scope}, this parent chain is searched. + +For each component instance in the chain, the following are examined: + +\list 1 +\o IDs +\o Script Methods +\o Root Object +\endlist + +This list is a sub-set of that in the \l {QML Local Scope}. + +Sub-components used within a component have their parent component instance set to the component +instance that created them. In the following example, the two \c Button instances have the +\c main.qml instance as their parent component instance. If the \c Button type was used from +within another QML file, it may have a difference parent component instance, and consequently +the \c buttonClicked() method may resolve differently. + +\table +\row +\o +\code +// main.qml +Item { + function buttonClicked(var data) { + print(data + " clicked"); + } + + Button { text: "Button1" } + Button { text: "Button2" } +} +\endcode +\o +\code +// Button.qml +Rectangle { + id: root + property string text + width: 80 + height: 30 + Text { + anchors.centerIn: parent + text: root.text + } + MouseRegion { + anchors.fill: parent + onClicked: buttonClicked(text) + } +} +\endcode +\endtable + +The code above discourages the re-use of the \c Button component, as it has a hard dependency +on the environment in which it is used. Tightly coupling two types together like this should +only be used when the components are within the same module, and the author controls the +implementations of both. + +In the following example, the \l ListView sets the parent component instance of each of its +delegates to its own component instance. In this way, the main component can easily pass data +into the \l ListView delegates. + +\code +Item { + property color delegateColor: "red" + + ListView { + delegate: Component { + Rectangle { + color: delegateColor + } + } + } +} +\endcode \section1 QmlContext chain -App provided data. +The \l QmlContext chain allows C++ applications to pass data into QML applications. +\l QmlComponent object instances created from C++ are passed a \l QmlContext in which they +are created. Variables defined in this context appear in the scope chain. Each QmlContext +also defines a parent context. Variables in child QmlContext's shadow those in its parent. + +Consider the following QmlContext tree. + +\image qml-context-tree.png + +The value of \c background in \c {Context 1} would be used if it was instantiated in +\c {Context 1}, where as the value of the \c background in the root context would be used if +the component instance was instantiated in \c {Context 2}. + +\code +import Qt 4.6 + +Rectangle { + id: myRect + width: 100; height: 100 + color: background +} +\endcode \section1 QML Global Object -Contains all the properties ECMAScript defines, plus some QML ones. Documented \l {QML Global Object}. +The \l {QML Global Object} contains all the properties of the ECMAScript global object, plus some +QML specific extensions. */ -- cgit v0.12 From d61c87a4d54bc5745f26b4d67978b5e3881fc85f Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 20 Oct 2009 15:27:31 +1000 Subject: Doc --- doc/src/declarative/scope.qdoc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/doc/src/declarative/scope.qdoc b/doc/src/declarative/scope.qdoc index 7dbbefc..14efa59 100644 --- a/doc/src/declarative/scope.qdoc +++ b/doc/src/declarative/scope.qdoc @@ -196,8 +196,15 @@ use the scope object to resolve variable references - \c height is a property on and \c parent is a property on \l Text. \code -Item { - Rectangle { // Scope object for Binding 1 +Item { // Scope object for Script block 1 + Script { // Script block 1 + function calculateValue() { ... } + } + + Rectangle { // Scope object for Binding 1 and Script block 2 + Script { // Script block 2 + function calculateColor() { ... } + } width: height * 2 // Binding 1 } @@ -236,7 +243,6 @@ ListView { \e TODO \list -\o scope object for Script {} \o scope object for PropertyChanges \endlist -- cgit v0.12 From 526ee93af932613ae8e7553bcbc26b8978cabc79 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 20 Oct 2009 18:11:01 +1000 Subject: Doc --- doc/src/declarative/modules.qdoc | 1 - doc/src/declarative/qtdeclarative.qdoc | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/src/declarative/modules.qdoc b/doc/src/declarative/modules.qdoc index 3a6495d..2f7cb57 100644 --- a/doc/src/declarative/modules.qdoc +++ b/doc/src/declarative/modules.qdoc @@ -40,7 +40,6 @@ ****************************************************************************/ /*! -\target qmlmodules \page qmlmodules.html \title Modules diff --git a/doc/src/declarative/qtdeclarative.qdoc b/doc/src/declarative/qtdeclarative.qdoc index 45f9347..c687bff 100644 --- a/doc/src/declarative/qtdeclarative.qdoc +++ b/doc/src/declarative/qtdeclarative.qdoc @@ -89,7 +89,7 @@ completely new applications. QML is fully \l {Extending QML}{extensible from C+ \o \l {qmlmodels}{Data Models} \o \l {anchor-layout}{Anchor-based Layout} \o \l {qmlanimation}{Animation} -\o \l {qmlmodules}{Modules} +\o \l {qmlmodules.html}{Modules} \o \l {qmlfocus}{Keyboard Focus} \o \l {Extending types from QML} \endlist -- cgit v0.12 From 626d9966e2675127fb28072c7f775edb1ae40721 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 20 Oct 2009 18:14:55 +1000 Subject: Doc --- doc/src/declarative/qtdeclarative.qdoc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/src/declarative/qtdeclarative.qdoc b/doc/src/declarative/qtdeclarative.qdoc index c687bff..ebf7880 100644 --- a/doc/src/declarative/qtdeclarative.qdoc +++ b/doc/src/declarative/qtdeclarative.qdoc @@ -74,8 +74,7 @@ completely new applications. QML is fully \l {Extending QML}{extensible from C+ \list \o \l {Introduction to the QML language} \o \l {Tutorial}{Tutorial: 'Hello World'} -\o \l {tutorials-declarative-contacts.html}{Tutorial: 'Introduction to QML'} -\o \l {advtutorial.html}{Advanced Tutorial: 'Same Game'} +\o \l {advtutorial.html}{Tutorial: 'Same Game'} \o \l {QML Examples and Walkthroughs} \o \l {Using QML in C++ Applications} \endlist @@ -105,4 +104,9 @@ completely new applications. QML is fully \l {Extending QML}{extensible from C+ \o \l {Extending QML} \o \l {qtbinding}{QML/C++ Data Binding} \endlist + +\section1 Deprecated + +\o \l {tutorials-declarative-contacts.html}{Tutorial: 'Introduction to QML'} + */ -- cgit v0.12 From 7bd7f5ec6eb520b7d9940a24817b17132d9ed6a2 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 20 Oct 2009 19:05:40 +1000 Subject: Doc --- doc/src/declarative/qtbinding.qdoc | 79 +++++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/doc/src/declarative/qtbinding.qdoc b/doc/src/declarative/qtbinding.qdoc index f6fe069..1831cf8 100644 --- a/doc/src/declarative/qtbinding.qdoc +++ b/doc/src/declarative/qtbinding.qdoc @@ -44,15 +44,93 @@ \target qtbinding \title Using QML in C++ Applications +The QML API is split into three main classes - QmlEngine, QmlComponent and QmlContext. +QmlEngine provides the environment in which QML is run, QmlComponent encapsulates +\l {QML Documents}, and QmlContext allows applications to expose data to QML component instances. + +\section1 Basic Usage + +Every application requires at least one QmlEngine. A QmlEngine allows the configuration of +global settings that apply to all the QML component instances - such as the QNetworkAccessManager +that is used for network communications, and the path used for persistent storage. +Multiple QmlEngine's are only needed if the application requires these settings to differ +between QML component instances. + +\l {QML Documents} are loaded using the QmlComponent class. Each QmlComponent instance +represents a single QML document. A QmlComponent can be passed a document URL, or raw text +representing the content of the document. The document URL can be a local filesystem URL, or +any network URL supported by QNetworkAccessManager. + +QML component instances can then be created by calling the QmlComponent::create() method. Here's +an example of loading a QML document, and creating an object from it. + +\code +QmlEngine *engine = new QmlEngine(parent); +QmlComponent component(engine, QUrl("main.qml")); +QObject *myObject = component.create(); +\endcode + +\section1 Exposing Data + +QML components are instantiated in a QmlContext. A context allows the application to expose data +to the QML component instance. A single QmlContext can be used to instantiate all the objects +used by an application, or several QmlContext can be created for more fine grained control over +the data exposed to each instance. If a context is not passed to the QmlComponent::create() +method, the QmlEngine's \l {QmlEngine::rootContext()}{root context} is used. + +To expose data to a QML component instance, applications set \l {QmlContext::setContextProperty()}{context properties} which are then accessible by name from QML \l {Property Binding}s and +\l {ECMAScript Blocks}. + +\section1 Network Components + +If the URL passed to QmlComponent is a network resource, or if the QML document references a +network resource, the QmlComponent has to fetch the network data before it is able to create +objects. In this case, the QmlComponent will have a \l {QmlComponent::Loading}{Loading} +\l {QmlComponent::status()}{status}. An application will have to wait until the component +is \l {QmlComponent::Ready}{Ready} before calling \l {QmlComponent::create()}. + +The following example shows how to load a QML file from a network resource. After creating +the QmlComponent, it tests whether the component is loading. If it is, it connects to the +QmlComponent::statusChanged() signal and otherwise calls the \c {continueLoading()} method +directly. This test is necessary, even for URLs that are known to be remote, just in case +the component has been cached and is ready immediately. + +\code +MyApplication::MyApplication() +{ + // ... + component = new QmlComponent(engine, QUrl("http://www.example.com/main.qml")); + if (component->isLoading()) + QObject::connect(component, SIGNAL(statusChanged(QmlComponent::Status)), + this, SLOT(continueLoading())); + else + continueLoading(); +} + +void MyApplication::continueLoading() +{ + if (component->isError()) { + qWarning() << component->errors(); + } else { + QObject *myObject = component->create(); + } +} +\endcode + \section1 TODO \list \o QmlEngine and QmlComponent \o QmlContext and data \o QBindableMap \o QAbstractItemModel Data models +\o QmlView \endlist +*/ + +/* \section1 Overview + The QML mechanisms of data binding can also be used to bind Qt C++ objects. The data binding framework is based on Qt's property system (see the Qt documentation for more details on this system). If a binding is meant to be dynamic (where changes in one object are reflected in another object), \c NOTIFY must be specified for the property being tracked. If \c NOTIFY is not specified, any binding to that property will be an 'intialization' binding (the tracking object will be updated only once with the initial value of the tracked object). @@ -60,7 +138,6 @@ The data binding framework is based on Qt's property system (see the Qt document Relevant items can also be bound to the contents of a Qt model. For example, ListView can make use of data from a QAbstractItemModel-derived model. - \section1 Passing Data Between C++ and QML Data binding provides one method of data transfer between C++ and QML. -- cgit v0.12 From 110c58a20f3158143d83ebea4f2ece4f7925f913 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Wed, 21 Oct 2009 10:20:57 +1000 Subject: Give more info about whether a value is null and its value type. --- src/declarative/debugger/qmldebug.cpp | 15 ++++++-- src/declarative/debugger/qmldebug.h | 2 ++ src/declarative/qml/qmlenginedebug.cpp | 29 ++++++++------- src/declarative/qml/qmlenginedebug_p.h | 1 + tools/qmldebugger/expressionquerywidget.cpp | 55 +++++++++++++++++++++++------ tools/qmldebugger/expressionquerywidget.h | 4 +++ tools/qmldebugger/objectpropertiesview.cpp | 19 +++++----- 7 files changed, 89 insertions(+), 36 deletions(-) diff --git a/src/declarative/debugger/qmldebug.cpp b/src/declarative/debugger/qmldebug.cpp index 75418e8..2537ec0 100644 --- a/src/declarative/debugger/qmldebug.cpp +++ b/src/declarative/debugger/qmldebug.cpp @@ -117,6 +117,7 @@ void QmlEngineDebugPrivate::decode(QDataStream &ds, QmlDebugObjectReference &o, prop.m_name = data.name; prop.m_binding = data.binding; prop.m_hasNotifySignal = data.hasNotifySignal; + prop.m_valueTypeName = data.valueTypeName; if (data.type == QmlEngineDebugServer::QmlObjectProperty::Basic) prop.m_value = data.value; else if (data.type == QmlEngineDebugServer::QmlObjectProperty::Object) { @@ -124,7 +125,6 @@ void QmlEngineDebugPrivate::decode(QDataStream &ds, QmlDebugObjectReference &o, obj.m_debugId = prop.m_value.toInt(); prop.m_value = qVariantFromValue(obj); } - o.m_properties << prop; } @@ -812,13 +812,17 @@ QmlDebugPropertyReference::QmlDebugPropertyReference() } QmlDebugPropertyReference::QmlDebugPropertyReference(const QmlDebugPropertyReference &o) -: m_objectDebugId(o.m_objectDebugId), m_name(o.m_name), m_value(o.m_value), m_binding(o.m_binding), m_hasNotifySignal(o.m_hasNotifySignal) +: m_objectDebugId(o.m_objectDebugId), m_name(o.m_name), m_value(o.m_value), + m_valueTypeName(o.m_valueTypeName), m_binding(o.m_binding), + m_hasNotifySignal(o.m_hasNotifySignal) { } QmlDebugPropertyReference &QmlDebugPropertyReference::operator=(const QmlDebugPropertyReference &o) { - m_objectDebugId = o.m_objectDebugId; m_name = o.m_name; m_value = o.m_value; m_binding = o.m_binding; m_hasNotifySignal = o.m_hasNotifySignal; + m_objectDebugId = o.m_objectDebugId; m_name = o.m_name; m_value = o.m_value; + m_valueTypeName = o.m_valueTypeName; m_binding = o.m_binding; + m_hasNotifySignal = o.m_hasNotifySignal; return *this; } @@ -832,6 +836,11 @@ QString QmlDebugPropertyReference::name() const return m_name; } +QString QmlDebugPropertyReference::valueTypeName() const +{ + return m_valueTypeName; +} + QVariant QmlDebugPropertyReference::value() const { return m_value; diff --git a/src/declarative/debugger/qmldebug.h b/src/declarative/debugger/qmldebug.h index 153a10f..bd076ff 100644 --- a/src/declarative/debugger/qmldebug.h +++ b/src/declarative/debugger/qmldebug.h @@ -232,6 +232,7 @@ public: int objectDebugId() const; QString name() const; QVariant value() const; + QString valueTypeName() const; QString binding() const; bool hasNotifySignal() const; @@ -240,6 +241,7 @@ private: int m_objectDebugId; QString m_name; QVariant m_value; + QString m_valueTypeName; QString m_binding; bool m_hasNotifySignal; }; diff --git a/src/declarative/qml/qmlenginedebug.cpp b/src/declarative/qml/qmlenginedebug.cpp index bbe6f77..7178e6c 100644 --- a/src/declarative/qml/qmlenginedebug.cpp +++ b/src/declarative/qml/qmlenginedebug.cpp @@ -80,7 +80,8 @@ QDataStream &operator>>(QDataStream &ds, QDataStream &operator<<(QDataStream &ds, const QmlEngineDebugServer::QmlObjectProperty &data) { - ds << (int)data.type << data.name << data.value << data.binding << data.hasNotifySignal; + ds << (int)data.type << data.name << data.value << data.valueTypeName + << data.binding << data.hasNotifySignal; return ds; } @@ -88,7 +89,8 @@ QDataStream &operator>>(QDataStream &ds, QmlEngineDebugServer::QmlObjectProperty &data) { int type; - ds >> type >> data.name >> data.value >> data.binding >> data.hasNotifySignal; + ds >> type >> data.name >> data.value >> data.valueTypeName + >> data.binding >> data.hasNotifySignal; data.type = (QmlEngineDebugServer::QmlObjectProperty::Type)type; return ds; } @@ -101,6 +103,7 @@ QmlEngineDebugServer::propertyData(QObject *obj, int propIdx) QMetaProperty prop = obj->metaObject()->property(propIdx); rv.type = QmlObjectProperty::Unknown; + rv.valueTypeName = QString::fromUtf8(prop.typeName()); rv.name = prop.name(); rv.hasNotifySignal = prop.hasNotifySignal(); QmlAbstractBinding *binding = QmlMetaProperty(obj, rv.name).binding(); @@ -116,6 +119,7 @@ QmlEngineDebugServer::propertyData(QObject *obj, int propIdx) QmlMetaType::isQmlList(prop.userType())) { rv.type = QmlObjectProperty::List; } + return rv; } @@ -149,7 +153,7 @@ void QmlEngineDebugServer::buildObjectList(QDataStream &message, int ctxtId = QmlDebugService::idForObject(ctxt); message << ctxtName << ctxtId; - + int count = 0; for (QSet::ConstIterator iter = p->childContexts.begin(); @@ -186,6 +190,12 @@ void QmlEngineDebugServer::buildObjectList(QDataStream &message, QVariant QmlEngineDebugServer::serializableVariant(const QVariant &value) { + if (value.type() < QVariant::UserType) + return value; + + if (!value.toString().isEmpty()) + return value.toString(); + QVariant v; if (value.type() == QVariant::UserType || QmlMetaType::isObject(value.userType())) { QObject *o = QmlMetaType::toQObject(value); @@ -195,19 +205,12 @@ QVariant QmlEngineDebugServer::serializableVariant(const QVariant &value) objectName = QLatin1String(""); v = QString::fromUtf8(o->metaObject()->className()) + QLatin1String(": ") + objectName; - } else { - v = QString::fromUtf8(value.typeName()); - } - if (v.isNull()) { - QString s = value.toString(); - if (s.isEmpty()) - s = QLatin1String(""); - v = s; } - } else { - v = value; } + if (v.isNull()) + v = QString::fromUtf8(value.typeName()); + return v; } diff --git a/src/declarative/qml/qmlenginedebug_p.h b/src/declarative/qml/qmlenginedebug_p.h index 9ad198a..075a711 100644 --- a/src/declarative/qml/qmlenginedebug_p.h +++ b/src/declarative/qml/qmlenginedebug_p.h @@ -85,6 +85,7 @@ public: Type type; QString name; QVariant value; + QString valueTypeName; QString binding; bool hasNotifySignal; }; diff --git a/tools/qmldebugger/expressionquerywidget.cpp b/tools/qmldebugger/expressionquerywidget.cpp index 90ab8ee..b29b465 100644 --- a/tools/qmldebugger/expressionquerywidget.cpp +++ b/tools/qmldebugger/expressionquerywidget.cpp @@ -16,7 +16,8 @@ ExpressionQueryWidget::ExpressionQueryWidget(QmlEngineDebug *client, QWidget *pa m_query(0), m_groupBox(0), m_textEdit(new QTextEdit), - m_lineEdit(0) + m_lineEdit(0), + m_button(0) { m_prompt = QLatin1String(">> "); @@ -31,16 +32,19 @@ ExpressionQueryWidget::ExpressionQueryWidget(QmlEngineDebug *client, QWidget *pa if (m_style == Compact) { QHBoxLayout *hbox = new QHBoxLayout; - QPushButton *button = new QPushButton(tr("Execute")); - connect(button, SIGNAL(clicked()), SLOT(executeExpression())); + m_button = new QPushButton(tr("Execute")); + m_button->setEnabled(false); + connect(m_button, SIGNAL(clicked()), SLOT(executeExpression())); m_lineEdit = new QLineEdit; connect(m_lineEdit, SIGNAL(returnPressed()), SLOT(executeExpression())); + connect(m_lineEdit, SIGNAL(textChanged(QString)), SLOT(lineEditTextChanged(QString))); hbox->addWidget(new QLabel(tr("Expression:"))); hbox->addWidget(m_lineEdit); - hbox->addWidget(button); + hbox->addWidget(m_button); vbox->addLayout(hbox); m_textEdit->setReadOnly(true); + m_lineEdit->installEventFilter(this); } else { m_textEdit->installEventFilter(this); } @@ -55,7 +59,7 @@ void ExpressionQueryWidget::updateTitle() + m_currObject.className() + QLatin1String(": ") + (m_currObject.name().isEmpty() ? QLatin1String("") : m_currObject.name()) + QLatin1String(">"); - m_groupBox->setTitle(tr("Expression queries (current context: %1)" + m_groupBox->setTitle(tr("Expression queries (using context for %1)" , "Selected object").arg(desc)); } } @@ -101,18 +105,20 @@ void ExpressionQueryWidget::executeExpression() { if (m_style == Compact) m_expr = m_lineEdit->text().trimmed(); + else + m_expr = m_expr.trimmed(); - if (!m_expr.trimmed().isEmpty() && m_currObject.debugId() != -1) { - checkCurrentContext(); + if (!m_expr.isEmpty() && m_currObject.debugId() != -1) { if (m_query) delete m_query; - m_query = m_client->queryExpressionResult(m_currObject.debugId(), m_expr.trimmed(), this); + m_query = m_client->queryExpressionResult(m_currObject.debugId(), m_expr, this); if (!m_query->isWaiting()) showResult(); else QObject::connect(m_query, SIGNAL(stateChanged(State)), this, SLOT(showResult())); + m_lastExpr = m_expr; if (m_lineEdit) m_lineEdit->clear(); } @@ -122,9 +128,11 @@ void ExpressionQueryWidget::showResult() { if (m_query) { m_textEdit->moveCursor(QTextCursor::End); - QString result = m_query->result().toString(); - if (result.isEmpty()) + QString result; + if (m_query->result().isNull()) result = QLatin1String(""); + else + result = m_query->result().toString(); if (m_style == Compact) { m_textEdit->setTextColor(Qt::black); @@ -140,6 +148,12 @@ void ExpressionQueryWidget::showResult() } } +void ExpressionQueryWidget::lineEditTextChanged(const QString &s) +{ + if (m_button) + m_button->setEnabled(!s.isEmpty()); +} + bool ExpressionQueryWidget::eventFilter(QObject *obj, QEvent *event) { if (obj == m_textEdit) { @@ -176,6 +190,27 @@ bool ExpressionQueryWidget::eventFilter(QObject *obj, QEvent *event) default: break; } + } else if (obj == m_lineEdit) { + switch (event->type()) { + case QEvent::KeyPress: + { + QKeyEvent *keyEvent = static_cast(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/expressionquerywidget.h b/tools/qmldebugger/expressionquerywidget.h index 3ea95ac..8db8f9f 100644 --- a/tools/qmldebugger/expressionquerywidget.h +++ b/tools/qmldebugger/expressionquerywidget.h @@ -10,6 +10,7 @@ QT_BEGIN_NAMESPACE class QGroupBox; class QTextEdit; class QLineEdit; +class QPushButton; class ExpressionQueryWidget : public QWidget { @@ -31,6 +32,7 @@ public slots: private slots: void executeExpression(); void showResult(); + void lineEditTextChanged(const QString &s); private: void appendPrompt(); @@ -45,8 +47,10 @@ private: QGroupBox *m_groupBox; QTextEdit *m_textEdit; QLineEdit *m_lineEdit; + QPushButton *m_button; QString m_prompt; QString m_expr; + QString m_lastExpr; QmlDebugObjectReference m_currObject; QmlDebugObjectReference m_objectAtLastFocus; diff --git a/tools/qmldebugger/objectpropertiesview.cpp b/tools/qmldebugger/objectpropertiesview.cpp index 4a2f97d..61afe3f 100644 --- a/tools/qmldebugger/objectpropertiesview.cpp +++ b/tools/qmldebugger/objectpropertiesview.cpp @@ -22,12 +22,12 @@ public: }; PropertiesViewItem::PropertiesViewItem(QTreeWidget *widget) -: QTreeWidgetItem(widget) + : QTreeWidgetItem(widget) { } PropertiesViewItem::PropertiesViewItem(QTreeWidgetItem *parent) -: QTreeWidgetItem(parent) + : QTreeWidgetItem(parent) { } @@ -108,8 +108,10 @@ void ObjectPropertiesView::setObject(const QmlDebugObjectReference &object) item->setText(0, p.name()); item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); - if (!p.hasNotifySignal()) + if (!p.hasNotifySignal()) { item->setForeground(0, Qt::gray); + item->setForeground(1, Qt::gray); + } if (!p.binding().isEmpty()) { PropertiesViewItem *binding = new PropertiesViewItem(item); @@ -161,14 +163,11 @@ void ObjectPropertiesView::valueChanged(const QByteArray &name, const QVariant & PropertiesViewItem *item = static_cast(m_tree->topLevelItem(i)); if (item->property.name() == name) { if (value.isNull()) { - item->setText(1, QLatin1String("null")); - item->setForeground(1, Qt::gray); + item->setText(1, QLatin1String("") + + QLatin1String(" : ") + + item->property.valueTypeName()); } else { - QString s = value.toString(); - if (s.isEmpty()) - s = QString::fromUtf8(value.typeName()); - item->setText(1, s); - item->setForeground(1, QBrush()); + item->setText(1, value.toString()); } } } -- cgit v0.12 From 1de91381a125c7d31b4aed7e97d57fb78df665a2 Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Wed, 21 Oct 2009 10:48:44 +1000 Subject: better easing example --- examples/declarative/easing/easing.qml | 162 +++++++++++++++++---------------- 1 file changed, 84 insertions(+), 78 deletions(-) diff --git a/examples/declarative/easing/easing.qml b/examples/declarative/easing/easing.qml index 23d7b29..100d5d2 100644 --- a/examples/declarative/easing/easing.qml +++ b/examples/declarative/easing/easing.qml @@ -2,92 +2,98 @@ import Qt 4.6 Rectangle { id: window - width: 640 - height: layout.height - color: "white" + width: 600; height: 460; color: "#232323" ListModel { id: easingTypes - ListElement { type: "easeLinear" } - ListElement { type: "easeInQuad" } - ListElement { type: "easeOutQuad" } - ListElement { type: "easeInOutQuad" } - ListElement { type: "easeOutInQuad" } - ListElement { type: "easeInCubic" } - ListElement { type: "easeOutCubic" } - ListElement { type: "easeInOutCubic" } - ListElement { type: "easeOutInCubic" } - ListElement { type: "easeInQuart" } - ListElement { type: "easeOutQuart" } - ListElement { type: "easeInOutQuart" } - ListElement { type: "easeOutInQuart" } - ListElement { type: "easeInQuint" } - ListElement { type: "easeOutQuint" } - ListElement { type: "easeInOutQuint" } - ListElement { type: "easeOutInQuint" } - ListElement { type: "easeInSine" } - ListElement { type: "easeOutSine" } - ListElement { type: "easeInOutSine" } - ListElement { type: "easeOutInSine" } - ListElement { type: "easeInExpo" } - ListElement { type: "easeOutExpo" } - ListElement { type: "easeInOutExpo" } - ListElement { type: "easeOutInExpo" } - ListElement { type: "easeInCirc" } - ListElement { type: "easeOutCirc" } - ListElement { type: "easeInOutCirc" } - ListElement { type: "easeOutInCirc" } - ListElement { type: "easeInElastic" } - ListElement { type: "easeOutElastic" } - ListElement { type: "easeInOutElastic" } - ListElement { type: "easeOutInElastic" } - ListElement { type: "easeInBack" } - ListElement { type: "easeOutBack" } - ListElement { type: "easeInOutBack" } - ListElement { type: "easeOutInBack" } - ListElement { type: "easeOutBounce" } - ListElement { type: "easeInBounce" } - ListElement { type: "easeInOutBounce" } - ListElement { type: "easeOutInBounce" } + ListElement { type: "easeLinear"; ballColor: "DarkRed" } + ListElement { type: "easeInQuad"; ballColor: "IndianRed" } + ListElement { type: "easeOutQuad"; ballColor: "Salmon" } + ListElement { type: "easeInOutQuad"; ballColor: "Tomato" } + ListElement { type: "easeOutInQuad"; ballColor: "DarkOrange" } + ListElement { type: "easeInCubic"; ballColor: "Gold" } + ListElement { type: "easeOutCubic"; ballColor: "Yellow" } + ListElement { type: "easeInOutCubic"; ballColor: "PeachPuff" } + ListElement { type: "easeOutInCubic"; ballColor: "Thistle" } + ListElement { type: "easeInQuart"; ballColor: "Orchid" } + ListElement { type: "easeOutQuart"; ballColor: "Purple" } + ListElement { type: "easeInOutQuart"; ballColor: "SlateBlue" } + ListElement { type: "easeOutInQuart"; ballColor: "Chartreuse" } + ListElement { type: "easeInQuint"; ballColor: "LimeGreen" } + ListElement { type: "easeOutQuint"; ballColor: "SeaGreen" } + ListElement { type: "easeInOutQuint"; ballColor: "DarkGreen" } + ListElement { type: "easeOutInQuint"; ballColor: "Olive" } + ListElement { type: "easeInSine"; ballColor: "DarkSeaGreen" } + ListElement { type: "easeOutSine"; ballColor: "Teal" } + ListElement { type: "easeInOutSine"; ballColor: "Turquoise" } + ListElement { type: "easeOutInSine"; ballColor: "SteelBlue" } + ListElement { type: "easeInExpo"; ballColor: "SkyBlue" } + ListElement { type: "easeOutExpo"; ballColor: "RoyalBlue" } + ListElement { type: "easeInOutExpo"; ballColor: "MediumBlue" } + ListElement { type: "easeOutInExpo"; ballColor: "MidnightBlue" } + ListElement { type: "easeInCirc"; ballColor: "CornSilk" } + ListElement { type: "easeOutCirc"; ballColor: "Bisque" } + ListElement { type: "easeInOutCirc"; ballColor: "RosyBrown" } + ListElement { type: "easeOutInCirc"; ballColor: "SandyBrown" } + ListElement { type: "easeInElastic"; ballColor: "DarkGoldenRod" } + ListElement { type: "easeOutElastic"; ballColor: "Chocolate" } + ListElement { type: "easeInOutElastic"; ballColor: "SaddleBrown" } + ListElement { type: "easeOutInElastic"; ballColor: "Brown" } + ListElement { type: "easeInBack"; ballColor: "Maroon" } + ListElement { type: "easeOutBack"; ballColor: "LavenderBlush" } + ListElement { type: "easeInOutBack"; ballColor: "MistyRose" } + ListElement { type: "easeOutInBack"; ballColor: "Gainsboro" } + ListElement { type: "easeOutBounce"; ballColor: "Silver" } + ListElement { type: "easeInBounce"; ballColor: "DimGray" } + ListElement { type: "easeInOutBounce"; ballColor: "SlateGray" } + ListElement { type: "easeOutInBounce"; ballColor: "DarkSlateGray" } } - Column { - id: layout - anchors.left: window.left - anchors.right: window.right - Repeater { - model: easingTypes - Component { - Text { - text: type - height: 18 - font.italic: true - x: SequentialAnimation { - id: anim - NumberAnimation { - from: 0 - to: window.width / 2 - easing: type - duration: 1000 - } - PauseAnimation { - duration: 300 - } - NumberAnimation { - to: 0 - from: window.width / 2 - easing: type - duration: 1000 - } + Component { + id: delegate + + Item { + height: 42; width: window.width + Text { text: type; anchors.centerIn: parent; color: "White" } + Rectangle { + id: slot1; color: "#121212"; x: 10; height: 32; width: 32 + border.color: "#343434"; border.width: 1; radius: 8; anchors.verticalCenter: parent.verticalCenter + } + Rectangle { + id: slot2; color: "#121212"; x: window.width - 42; height: 32; width: 32 + border.color: "#343434"; border.width: 1; radius: 8; anchors.verticalCenter: parent.verticalCenter + } + Rectangle { + id: rect; x: 10; color: "#454545" + border.color: "White"; border.width: 2 + height: 32; width: 32; radius: 8; anchors.verticalCenter: parent.verticalCenter + + MouseRegion { + onClicked: if (rect.state == '') rect.state = "right"; else rect.state = '' + anchors.fill: parent + } + + states : State { + name: "right" + PropertyChanges { target: rect; x: window.width - 42; color: ballColor } + } + + transitions: Transition { + ParallelAnimation { + NumberAnimation { properties: "x"; easing: type; duration: 1000 } + ColorAnimation { properties: "color"; easing: type; duration: 1000 } } - children: [ - MouseRegion { - onClicked: { anim.running=true } - anchors.fill: parent - } - ] } } } } + + Flickable { + anchors.fill: parent; viewportHeight: layout.height + Column { + id: layout + anchors.left: window.left; anchors.right: window.right + Repeater { model: easingTypes; delegate: delegate } + } + } } -- cgit v0.12