diff options
Diffstat (limited to 'src/declarative')
-rw-r--r-- | src/declarative/debugger/qmldebugger.cpp | 153 | ||||
-rw-r--r-- | src/declarative/debugger/qmldebugger.h | 12 | ||||
-rw-r--r-- | src/declarative/qml/qmlengine.cpp | 36 | ||||
-rw-r--r-- | src/declarative/qml/qmlengine_p.h | 11 | ||||
-rw-r--r-- | src/declarative/qml/qmlmetaproperty.cpp | 12 | ||||
-rw-r--r-- | src/declarative/qml/qmlmetaproperty.h | 1 |
6 files changed, 185 insertions, 40 deletions
diff --git a/src/declarative/debugger/qmldebugger.cpp b/src/declarative/debugger/qmldebugger.cpp index 033a15f..9b84b9e 100644 --- a/src/declarative/debugger/qmldebugger.cpp +++ b/src/declarative/debugger/qmldebugger.cpp @@ -43,6 +43,8 @@ #include <QtGui/qtreewidget.h> #include <QtGui/qboxlayout.h> #include <QtGui/qplaintextedit.h> +#include <QTextBlock> +#include <QtGui/qtabwidget.h> #include <QtDeclarative/qmlbindablevalue.h> #include <private/qmlboundsignal_p.h> #include <private/qmlcontext_p.h> @@ -52,10 +54,11 @@ #include <QtCore/qurl.h> #include <QtGui/qsplitter.h> #include <QtGui/qpushbutton.h> +#include <QtGui/qtablewidget.h> #include <QtGui/qevent.h> QmlDebugger::QmlDebugger(QWidget *parent) -: QWidget(parent), m_tree(0) +: QWidget(parent), m_tree(0), m_warnings(0), m_watchers(0), m_text(0) { QHBoxLayout *layout = new QHBoxLayout; setLayout(layout); @@ -69,18 +72,33 @@ QmlDebugger::QmlDebugger(QWidget *parent) splitter->addWidget(treeWid); m_tree = new QTreeWidget(treeWid); + m_tree->setSelectionMode(QTreeWidget::NoSelection); m_tree->setHeaderHidden(true); - QObject::connect(m_tree, SIGNAL(itemPressed(QTreeWidgetItem *, int)), this, SLOT(itemPressed(QTreeWidgetItem *))); + QObject::connect(m_tree, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(itemClicked(QTreeWidgetItem *))); + QObject::connect(m_tree, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(itemDoubleClicked(QTreeWidgetItem *))); vlayout->addWidget(m_tree); QPushButton *pb = new QPushButton("Refresh", treeWid); QObject::connect(pb, SIGNAL(clicked()), this, SLOT(refresh())); vlayout->addWidget(pb); + QTabWidget *tabs = new QTabWidget(this); + m_text = new QPlainTextEdit(this); m_text->setReadOnly(true); - splitter->addWidget(m_text); + tabs->addTab(m_text, "File"); + + m_warnings = new QTreeWidget(this); + m_warnings->setHeaderHidden(true); + tabs->addTab(m_warnings, "Warnings"); + + m_watchers = new QTableWidget(this); + tabs->addTab(m_watchers, "Watchers"); + + splitter->addWidget(tabs); splitter->setStretchFactor(1, 2); + + setGeometry(0, 100, 800, 600); } class QmlDebuggerItem : public QTreeWidgetItem @@ -103,31 +121,29 @@ public: QPointer<QmlBindableValue> bindableValue; }; -void QmlDebugger::itemPressed(QTreeWidgetItem *i) +void QmlDebugger::itemDoubleClicked(QTreeWidgetItem *i) { QmlDebuggerItem *item = static_cast<QmlDebuggerItem *>(i); if(item->bindableValue) { - QString str; - QmlExpressionPrivate *p = item->bindableValue->d; - if(p->log) { - QString str; - QDebug d(&str); - for(int ii = 0; ii < p->log->count(); ++ii) { - d << p->log->at(ii).result() << "\n"; - QStringList warnings = p->log->at(ii).warnings(); - foreach(const QString &warning, warnings) - d << " " << warning << "\n"; - } - m_text->setPlainText(str); + if(m_watchedIds.contains(p->id)) { + m_watchedIds.remove(p->id); + item->setForeground(0, Qt::green); } else { - m_text->setPlainText("No history"); + m_watchedIds.insert(p->id); + item->setForeground(0, QColor("purple")); } - } else if(item->url.scheme() == QLatin1String("file")) { + } +} + +void QmlDebugger::itemClicked(QTreeWidgetItem *i) +{ + QmlDebuggerItem *item = static_cast<QmlDebuggerItem *>(i); + if(item->url.scheme() == QLatin1String("file")) { QString f = item->url.toLocalFile(); QFile file(f); file.open(QIODevice::ReadOnly); @@ -141,17 +157,11 @@ void QmlDebugger::itemPressed(QTreeWidgetItem *i) QTextDocument *document = m_text->document(); QTextCharFormat format; format.setForeground(Qt::lightGray); - { - QTextCursor cursor(document); - cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor); - cursor.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor, item->startLine - 1); - cursor.setCharFormat(format); - } { QTextCursor cursor(document); cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor); - cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, item->endLine); + cursor.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor, item->endLine); cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); cursor.setCharFormat(format); } @@ -159,31 +169,87 @@ void QmlDebugger::itemPressed(QTreeWidgetItem *i) { QTextCursor cursor(document); cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor); - cursor.setCharFormat(QTextCharFormat()); + cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor, item->startLine - 1); + cursor.setCharFormat(format); } { QTextCursor cursor(document); cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor); - cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, item->startLine - 1); + cursor.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor, item->startLine - 1); m_text->setTextCursor(cursor); m_text->centerCursor(); } + + } } } -static bool makeItem(QObject *obj, QmlDebuggerItem *item) +bool QmlDebugger::makeItem(QObject *obj, QmlDebuggerItem *item) { bool rv = true; QString text; if(QmlBindableValue *bv = qobject_cast<QmlBindableValue *>(obj)) { + QmlExpressionPrivate *p = bv->d; + text = bv->property().name() + ": " + bv->expression(); - item->setForeground(0, Qt::green); + bool watched = m_watchedIds.contains(p->id); + if(watched) + item->setForeground(0, QColor("purple")); + else + item->setForeground(0, Qt::green); item->bindableValue = bv; + + if(p->log) { + QTreeWidgetItem *warningItem = 0; + + int column = m_watchers->columnCount(); + + if(watched) { + m_watchers->insertColumn(column); + QTableWidgetItem *tableheader = new QTableWidgetItem; + tableheader->setText(bv->expression()); + tableheader->setToolTip(bv->expression()); + m_watchers->setHorizontalHeaderItem(column, tableheader); + } + + for(int ii = 0; ii < p->log->count(); ++ii) { + const QmlExpressionLog &log = p->log->at(ii); + + QString variant; QDebug d(&variant); d << log.result(); + if(watched) { + QString str = log.result().toString(); + if(str.isEmpty()) + str = variant; + m_expressions << qMakePair(log.time(), qMakePair(column, str)); + } + + if(!log.warnings().isEmpty()) { + + if(!warningItem) { + warningItem = new QTreeWidgetItem(m_warnings); + warningItem->setText(0, bv->expression()); + } + + QTreeWidgetItem *entry = new QTreeWidgetItem(warningItem); + entry->setExpanded(true); + + entry->setText(0, variant); + + foreach(const QString &warning, log.warnings()) { + QTreeWidgetItem *w = new QTreeWidgetItem(entry); + w->setText(0, warning); + } + } + + } + + } + } else if(QmlBoundSignal *bs = qobject_cast<QmlBoundSignal *>(obj)) { QMetaMethod method = obj->parent()->metaObject()->method(bs->index()); QByteArray sig = method.signature(); @@ -237,7 +303,7 @@ static bool makeItem(QObject *obj, QmlDebuggerItem *item) return rv; } -static void buildTree(QObject *obj, QmlDebuggerItem *parent) +void QmlDebugger::buildTree(QObject *obj, QmlDebuggerItem *parent) { QObjectList children = obj->children(); @@ -253,9 +319,20 @@ void QmlDebugger::refresh() setDebugObject(m_object); } +bool operator<(const QPair<quint32, QPair<int, QString> > &lhs, + const QPair<quint32, QPair<int, QString> > &rhs) +{ + return lhs.first < rhs.first; +} + void QmlDebugger::setDebugObject(QObject *obj) { m_tree->clear(); + m_warnings->clear(); + m_watchers->clear(); + m_watchers->setColumnCount(0); + m_watchers->setRowCount(0); + m_expressions.clear(); m_object = obj; if(!obj) @@ -265,6 +342,20 @@ void QmlDebugger::setDebugObject(QObject *obj) makeItem(obj, item); buildTree(obj, item); item->setExpanded(true); - setGeometry(0, 100, 800, 600); + + m_watchers->setRowCount(m_expressions.count()); + + qSort(m_expressions.begin(), m_expressions.end()); + + for(int ii = 0; ii < m_expressions.count(); ++ii) { + + const QPair<quint32, QPair<int, QString> > &expr = m_expressions.at(ii); + QTableWidgetItem *item = new QTableWidgetItem; + item->setText(expr.second.second); + m_watchers->setItem(ii, expr.second.first, item); + + } + + } diff --git a/src/declarative/debugger/qmldebugger.h b/src/declarative/debugger/qmldebugger.h index 943abef..e04eb2e 100644 --- a/src/declarative/debugger/qmldebugger.h +++ b/src/declarative/debugger/qmldebugger.h @@ -43,6 +43,7 @@ #define QMLDEBUGGER_H #include <QtCore/qpointer.h> +#include <QtCore/qset.h> #include <QtGui/qwidget.h> QT_BEGIN_HEADER @@ -54,6 +55,8 @@ QT_MODULE(Declarative) class QTreeWidget; class QTreeWidgetItem; class QPlainTextEdit; +class QmlDebuggerItem; +class QTableWidget; class QmlDebugger : public QWidget { Q_OBJECT @@ -66,12 +69,19 @@ public slots: void refresh(); private slots: - void itemPressed(QTreeWidgetItem *); + void itemClicked(QTreeWidgetItem *); + void itemDoubleClicked(QTreeWidgetItem *); private: + void buildTree(QObject *obj, QmlDebuggerItem *parent); + bool makeItem(QObject *obj, QmlDebuggerItem *item); QTreeWidget *m_tree; + QTreeWidget *m_warnings; + QTableWidget *m_watchers; QPlainTextEdit *m_text; QPointer<QObject> m_object; + QList<QPair<quint32, QPair<int, QString> > > m_expressions; + QSet<quint32> m_watchedIds; }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index be5226e..15b5879 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -139,7 +139,7 @@ QStack<QmlEngine *> *QmlEngineStack::engines() QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) : rootContext(0), currentBindContext(0), currentExpression(0), q(e), - rootComponent(0), networkAccessManager(0), typeManager(e) + rootComponent(0), networkAccessManager(0), typeManager(e), uniqueId(1) { QScriptValue proto = scriptEngine.newObject(); proto.setProperty(QLatin1String("emit"), @@ -720,17 +720,17 @@ QmlEngine *QmlEngine::activeEngine() QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b) -: q(b), ctxt(0), sseData(0), proxy(0), me(0), trackChange(false), log(0) +: q(b), ctxt(0), sseData(0), proxy(0), me(0), trackChange(false), id(0), log(0) { } QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, void *expr, QmlRefCount *rc) -: q(b), ctxt(0), sse((const char *)expr, rc), sseData(0), proxy(0), me(0), trackChange(true), log(0) +: q(b), ctxt(0), sse((const char *)expr, rc), sseData(0), proxy(0), me(0), trackChange(true), id(0), log(0) { } QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, const QString &expr, bool ssecompile) -: q(b), ctxt(0), expression(expr), sseData(0), proxy(0), me(0), trackChange(true), log(0) +: q(b), ctxt(0), expression(expr), sseData(0), proxy(0), me(0), trackChange(true), id(0), log(0) { if (ssecompile) { #ifdef Q_ENABLE_PERFORMANCE_LOG @@ -765,6 +765,8 @@ QmlExpression::QmlExpression(QmlContext *ctxt, void *expr, : d(new QmlExpressionPrivate(this, expr, rc)) { d->ctxt = ctxt; + if(ctxt && ctxt->engine()) + d->id = ctxt->engine()->d_func()->getUniqueId(); d->me = me; } @@ -774,6 +776,8 @@ QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expr, : d(new QmlExpressionPrivate(this, expr, ssecompile)) { d->ctxt = ctxt; + if(ctxt && ctxt->engine()) + d->id = ctxt->engine()->d_func()->getUniqueId(); d->me = me; } @@ -789,6 +793,8 @@ QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression, : d(new QmlExpressionPrivate(this, expression, true)) { d->ctxt = ctxt; + if(ctxt && ctxt->engine()) + d->id = ctxt->engine()->d_func()->getUniqueId(); d->me = scope; } @@ -810,7 +816,7 @@ QmlEngine *QmlExpression::engine() const } /*! - Returns teh QmlContext this expression is associated with, or 0 if there + Returns the QmlContext this expression is associated with, or 0 if there is no association or the QmlContext has been destroyed. */ QmlContext *QmlExpression::context() const @@ -988,6 +994,7 @@ QVariant QmlExpression::value() if(qmlDebugger()) { QmlExpressionLog log; + log.setTime(engine()->d_func()->getUniqueId()); log.setExpression(expression()); log.setResult(rv); @@ -997,8 +1004,8 @@ QVariant QmlExpression::value() if (prop.hasChangedNotifier()) { prop.connectNotifier(d->proxy, changedIndex); - } else { - QString warn = QLatin1String("Expression depends on property without a NOTIFY signal: ") + QLatin1String(prop.object()->metaObject()->className()) + QLatin1String(".") + prop.name(); + } else if (prop.needsChangedNotifier()) { + QString warn = QLatin1String("Expression depends on property without a NOTIFY signal: [") + QLatin1String(prop.object()->metaObject()->className()) + QLatin1String("].") + prop.name(); log.addWarning(warn); } } @@ -1015,6 +1022,7 @@ QVariant QmlExpression::value() } } else { QmlExpressionLog log; + log.setTime(engine()->d_func()->getUniqueId()); log.setExpression(expression()); log.setResult(rv); d->addLog(log); @@ -1023,6 +1031,7 @@ QVariant QmlExpression::value() } else { if(qmlDebugger()) { QmlExpressionLog log; + log.setTime(engine()->d_func()->getUniqueId()); log.setExpression(expression()); log.setResult(rv); d->addLog(log); @@ -1421,7 +1430,8 @@ QmlExpressionLog::QmlExpressionLog() } QmlExpressionLog::QmlExpressionLog(const QmlExpressionLog &o) -: m_expression(o.m_expression), +: m_time(o.m_time), + m_expression(o.m_expression), m_result(o.m_result), m_warnings(o.m_warnings) { @@ -1433,12 +1443,22 @@ QmlExpressionLog::~QmlExpressionLog() QmlExpressionLog &QmlExpressionLog::operator=(const QmlExpressionLog &o) { + m_time = o.m_time; m_expression = o.m_expression; m_result = o.m_result; m_warnings = o.m_warnings; return *this; } +void QmlExpressionLog::setTime(quint32 time) +{ + m_time = time; +} + +quint32 QmlExpressionLog::time() const +{ + return m_time; +} QString QmlExpressionLog::expression() const { diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 7d5176e..63df0ba 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -114,6 +114,11 @@ public: QmlCompositeTypeManager typeManager; QMap<QString,QString> nameSpacePaths; + + mutable quint32 uniqueId; + quint32 getUniqueId() const { + return uniqueId++; + } }; @@ -201,6 +206,9 @@ public: QmlExpressionLog &operator=(const QmlExpressionLog &); + void setTime(quint32); + quint32 time() const; + QString expression() const; void setExpression(const QString &); @@ -211,6 +219,7 @@ public: void setResult(const QVariant &); private: + quint32 m_time; QString m_expression; QVariant m_result; QStringList m_warnings; @@ -233,6 +242,8 @@ public: QObject *me; bool trackChange; + quint32 id; + void addLog(const QmlExpressionLog &); QList<QmlExpressionLog> *log; }; diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index 40c9b0e..59d6b38 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -988,6 +988,18 @@ bool QmlMetaProperty::hasChangedNotifier() const } /*! + Returns true if the property needs a change notifier signal for bindings + to remain upto date, false otherwise. + + Some properties, such as attached properties or those whose value never + changes, do not require a change notifier. +*/ +bool QmlMetaProperty::needsChangedNotifier() const +{ + return type() & Property && !(type() & Attached); +} + +/*! Connects the property's change notifier signal to the specified \a method of the \a dest object and returns true. Returns false if this metaproperty does not diff --git a/src/declarative/qml/qmlmetaproperty.h b/src/declarative/qml/qmlmetaproperty.h index 4836038..68b06e5 100644 --- a/src/declarative/qml/qmlmetaproperty.h +++ b/src/declarative/qml/qmlmetaproperty.h @@ -89,6 +89,7 @@ public: void emitSignal(); bool hasChangedNotifier() const; + bool needsChangedNotifier() const; bool connectNotifier(QObject *dest, const char *slot) const; bool connectNotifier(QObject *dest, int method) const; |