diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/declarative/debugger/qmldebugger.cpp | 154 | ||||
-rw-r--r-- | src/declarative/debugger/qmldebugger.h | 12 | ||||
-rw-r--r-- | src/declarative/fx/qfximage.cpp | 106 | ||||
-rw-r--r-- | src/declarative/fx/qfximage.h | 5 | ||||
-rw-r--r-- | src/declarative/fx/qfximage_p.h | 12 | ||||
-rw-r--r-- | src/declarative/fx/qfxpixmap.cpp | 8 | ||||
-rw-r--r-- | src/declarative/fx/qfxpixmap.h | 3 | ||||
-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 | ||||
-rw-r--r-- | src/declarative/util/qmlanimation.cpp | 3 | ||||
-rw-r--r-- | src/declarative/util/qmlanimation_p.h | 14 | ||||
-rw-r--r-- | src/declarative/util/qmllistmodel.cpp | 68 |
14 files changed, 368 insertions, 77 deletions
diff --git a/src/declarative/debugger/qmldebugger.cpp b/src/declarative/debugger/qmldebugger.cpp index 033a15f..a1956f9 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,34 @@ 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); + m_watchers->setSelectionMode(QTableWidget::NoSelection); + tabs->addTab(m_watchers, "Watchers"); + + splitter->addWidget(tabs); splitter->setStretchFactor(1, 2); + + setGeometry(0, 100, 800, 600); } class QmlDebuggerItem : public QTreeWidgetItem @@ -103,31 +122,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 +158,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 +170,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 +304,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 +320,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 +343,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/fx/qfximage.cpp b/src/declarative/fx/qfximage.cpp index 106d551..d66846d 100644 --- a/src/declarative/fx/qfximage.cpp +++ b/src/declarative/fx/qfximage.cpp @@ -125,8 +125,8 @@ QFxImage::QFxImage(QFxImagePrivate &dd, QFxItem *parent) QFxImage::~QFxImage() { Q_D(const QFxImage); - if (d->reply) - d->reply->deleteLater(); + if (d->sciReply) + d->sciReply->deleteLater(); } /*! @@ -783,6 +783,19 @@ QString QFxImage::propertyInfo() const return d->url.toString(); } +/*! + \qmlproperty enum Image::status + + This property holds the status of image loading. It can be one of: + \list + \o Idle - no image has been set, or the image has been loaded + \o Loading - the images is currently being loaded + \o Error - an error occurred while loading the image + \endlist + + \sa progress +*/ + QFxImage::Status QFxImage::status() const { Q_D(const QFxImage); @@ -790,6 +803,21 @@ QFxImage::Status QFxImage::status() const } /*! + \qmlproperty real Image::progress + + This property holds the progress of image loading, from 0.0 (nothing loaded) + to 1.0 (finished). + + \sa status +*/ + +qreal QFxImage::progress() const +{ + Q_D(const QFxImage); + return d->progress; +} + +/*! \qmlproperty string Image::source Image can handle any image format supported by Qt, loaded from any URL scheme supported by Qt. @@ -831,9 +859,9 @@ void QFxImage::setSource(const QString &url) if (url == d->source) return; - if (d->reply) { - d->reply->deleteLater(); - d->reply = 0; + if (d->sciReply) { + d->sciReply->deleteLater(); + d->sciReply = 0; } if (!d->url.isEmpty()) @@ -844,10 +872,25 @@ void QFxImage::setSource(const QString &url) d->source = url; d->url = qmlContext(this)->resolvedUrl(url); d->sciurl = QUrl(); + if (d->progress != 0.0) { + d->progress = 0.0; + emit progressChanged(d->progress); + } if (url.isEmpty()) { setPixmap(QPixmap()); d->status = Idle; + d->progress = 1.0; + setImplicitWidth(0); + setImplicitHeight(0); +#if defined(QFX_RENDER_OPENGL) + d->_texDirty = true; + d->_tex.clear(); +#endif + emit statusChanged(d->status); + emit sourceChanged(d->source); + emit progressChanged(1.0); + update(); } else { d->status = Loading; if (d->url.path().endsWith(QLatin1String(".sci"))) { @@ -861,12 +904,19 @@ void QFxImage::setSource(const QString &url) { QNetworkRequest req(d->url); req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); - d->reply = qmlEngine(this)->networkAccessManager()->get(req); - QObject::connect(d->reply, SIGNAL(finished()), + d->sciReply = qmlEngine(this)->networkAccessManager()->get(req); + QObject::connect(d->sciReply, SIGNAL(finished()), this, SLOT(sciRequestFinished())); } } else { - QFxPixmap::get(qmlEngine(this), d->url, this, SLOT(requestFinished())); + d->reply = QFxPixmap::get(qmlEngine(this), d->url, this, SLOT(requestFinished())); + if (d->reply) { + connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), + this, SLOT(requestProgress(qint64,qint64))); + } else { + d->progress = 1.0; + emit progressChanged(d->progress); + } } } @@ -879,6 +929,12 @@ void QFxImage::requestFinished() if (d->url.path().endsWith(QLatin1String(".sci"))) { d->_pix = QFxPixmap(d->sciurl); } else { + if (d->reply) { + disconnect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), + this, SLOT(requestProgress(qint64,qint64))); + if (d->reply->error() != QNetworkReply::NoError) + d->status = Error; + } d->_pix = QFxPixmap(d->url); d->_pix.setOpaque(d->_opaque); setOptions(QFxImage::SimpleItem, true); @@ -886,32 +942,43 @@ void QFxImage::requestFinished() setImplicitWidth(d->_pix.width()); setImplicitHeight(d->_pix.height()); - d->status = Idle; + if (d->status == Loading) + d->status = Idle; + d->progress = 1.0; #if defined(QFX_RENDER_OPENGL) d->_texDirty = true; d->_tex.clear(); #endif emit statusChanged(d->status); emit sourceChanged(d->source); + emit progressChanged(1.0); update(); } void QFxImage::sciRequestFinished() { Q_D(QFxImage); - if (d->reply->error() != QNetworkReply::NoError) { + if (d->sciReply->error() != QNetworkReply::NoError) { d->status = Error; - d->reply->deleteLater(); - d->reply = 0; + d->sciReply->deleteLater(); + d->sciReply = 0; emit statusChanged(d->status); } else { - QFxGridScaledImage sci(d->reply); - d->reply->deleteLater(); - d->reply = 0; + QFxGridScaledImage sci(d->sciReply); + d->sciReply->deleteLater(); + d->sciReply = 0; setGridScaledImage(sci); } } +void QFxImage::requestProgress(qint64 received, qint64 total) +{ + Q_D(QFxImage); + if (d->status == Loading && total > 0) { + d->progress = qreal(received)/total; + emit progressChanged(d->progress); + } +} void QFxImage::setGridScaledImage(const QFxGridScaledImage& sci) { @@ -921,7 +988,14 @@ void QFxImage::setGridScaledImage(const QFxGridScaledImage& sci) emit statusChanged(d->status); } else { d->sciurl = d->url.resolved(QUrl(sci.pixmapUrl())); - QFxPixmap::get(qmlEngine(this), d->sciurl, this, SLOT(requestFinished())); + d->reply = QFxPixmap::get(qmlEngine(this), d->sciurl, this, SLOT(requestFinished())); + if (d->reply) { + connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), + this, SLOT(requestProgress(qint64,qint64))); + } else { + d->progress = 1.0; + emit progressChanged(d->progress); + } QFxScaleGrid *sg = scaleGrid(); sg->setTop(sci.gridTop()); sg->setBottom(sci.gridBottom()); diff --git a/src/declarative/fx/qfximage.h b/src/declarative/fx/qfximage.h index 37fe5be..dc13a97 100644 --- a/src/declarative/fx/qfximage.h +++ b/src/declarative/fx/qfximage.h @@ -43,6 +43,7 @@ #define QFXIMAGE_H #include <qfxitem.h> +#include <QtNetwork/qnetworkreply.h> QT_BEGIN_HEADER @@ -58,6 +59,7 @@ class Q_DECLARATIVE_EXPORT QFxImage : public QFxItem Q_PROPERTY(Status status READ status NOTIFY statusChanged) Q_PROPERTY(QString source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged) Q_PROPERTY(QFxScaleGrid *scaleGrid READ scaleGrid) Q_PROPERTY(bool tile READ isTiled WRITE setTiled) @@ -84,6 +86,7 @@ public: enum Status { Idle, Loading, Error }; Status status() const; + qreal progress() const; QString source() const; virtual void setSource(const QString &url); @@ -101,6 +104,7 @@ public: Q_SIGNALS: void sourceChanged(const QString &); void statusChanged(Status); + void progressChanged(qreal progress); protected: QFxImage(QFxImagePrivate &dd, QFxItem *parent); @@ -109,6 +113,7 @@ protected: private Q_SLOTS: void requestFinished(); void sciRequestFinished(); + void requestProgress(qint64,qint64); private: Q_DISABLE_COPY(QFxImage) diff --git a/src/declarative/fx/qfximage_p.h b/src/declarative/fx/qfximage_p.h index fbb4c44..8227ce4 100644 --- a/src/declarative/fx/qfximage_p.h +++ b/src/declarative/fx/qfximage_p.h @@ -76,7 +76,7 @@ public: #if defined(QFX_RENDER_OPENGL) _texDirty(true), #endif - status(QFxImage::Idle), reply(0) + status(QFxImage::Idle), sciReply(0), progress(0.0) { } @@ -95,10 +95,10 @@ public: } QFxScaleGrid *_scaleGrid; - bool _tiled; QFxPixmap _pix; - bool _smooth; - bool _opaque; + bool _tiled : 1; + bool _smooth : 1; + bool _opaque : 1; #if defined(QFX_RENDER_OPENGL) void checkDirty(); bool _texDirty; @@ -109,7 +109,9 @@ public: QString source; QUrl url; QUrl sciurl; - QNetworkReply *reply; + QNetworkReply *sciReply; + QPointer<QNetworkReply> reply; + qreal progress; }; QT_END_NAMESPACE diff --git a/src/declarative/fx/qfxpixmap.cpp b/src/declarative/fx/qfxpixmap.cpp index 0d456c6..3fdd8e5 100644 --- a/src/declarative/fx/qfxpixmap.cpp +++ b/src/declarative/fx/qfxpixmap.cpp @@ -233,8 +233,11 @@ QFxPixmap::operator const QSimpleCanvasConfig::Image &() const Starts a network request to load \a url. When the URL is loaded, the given slot is invoked. Note that if the image is already cached, the slot may be invoked immediately. + + Returns a QNetworkReply if the image is not immediately available, otherwise + returns 0. The QNetworkReply must not be stored - it may be destroyed at any time. */ -void QFxPixmap::get(QmlEngine *engine, const QUrl& url, QObject* obj, const char* slot) +QNetworkReply *QFxPixmap::get(QmlEngine *engine, const QUrl& url, QObject* obj, const char* slot) { QString key = url.toString(); QFxPixmapCache::Iterator iter = qfxPixmapCache.find(key); @@ -259,11 +262,14 @@ void QFxPixmap::get(QmlEngine *engine, const QUrl& url, QObject* obj, const char if ((*iter)->reply) { // still loading QObject::connect((*iter)->reply, SIGNAL(finished()), obj, slot); + return (*iter)->reply; } else { // already loaded QObject dummy; QObject::connect(&dummy, SIGNAL(destroyed()), obj, slot); } + + return 0; } /*! diff --git a/src/declarative/fx/qfxpixmap.h b/src/declarative/fx/qfxpixmap.h index 9a3ba4e..748991e 100644 --- a/src/declarative/fx/qfxpixmap.h +++ b/src/declarative/fx/qfxpixmap.h @@ -54,6 +54,7 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) class QmlEngine; +class QNetworkReply; class QFxPixmapPrivate; class Q_DECLARATIVE_EXPORT QFxPixmap { @@ -65,7 +66,7 @@ public: QFxPixmap &operator=(const QFxPixmap &); - static void get(QmlEngine *, const QUrl& url, QObject*, const char* slot); + static QNetworkReply *get(QmlEngine *, const QUrl& url, QObject*, const char* slot); static void cancelGet(const QUrl& url, QObject* obj, const char* slot); bool isNull() const; 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; diff --git a/src/declarative/util/qmlanimation.cpp b/src/declarative/util/qmlanimation.cpp index 08a7a28..dd4e1eb 100644 --- a/src/declarative/util/qmlanimation.cpp +++ b/src/declarative/util/qmlanimation.cpp @@ -791,6 +791,7 @@ void QmlColorAnimation::prepare(QmlMetaProperty &p) d->fromSourced = false; d->value.QmlTimeLineValue::setValue(0.); d->ca->setAnimValue(&d->value, QAbstractAnimation::KeepWhenStopped); + d->ca->setFromSourcedValue(&d->fromSourced); } QAbstractAnimation *QmlColorAnimation::qtAnimation() @@ -1595,6 +1596,7 @@ void QmlNumericAnimation::prepare(QmlMetaProperty &p) d->fromSourced = false; d->value.QmlTimeLineValue::setValue(0.); d->na->setAnimValue(&d->value, QAbstractAnimation::KeepWhenStopped); + d->na->setFromSourcedValue(&d->fromSourced); } QAbstractAnimation *QmlNumericAnimation::qtAnimation() @@ -2152,6 +2154,7 @@ void QmlVariantAnimation::prepare(QmlMetaProperty &p) d->fromSourced = false; d->value.QmlTimeLineValue::setValue(0.); d->va->setAnimValue(&d->value, QAbstractAnimation::KeepWhenStopped); + d->va->setFromSourcedValue(&d->fromSourced); } void QmlVariantAnimation::transition(QmlStateActions &actions, diff --git a/src/declarative/util/qmlanimation_p.h b/src/declarative/util/qmlanimation_p.h index 06b7c08..00937a6 100644 --- a/src/declarative/util/qmlanimation_p.h +++ b/src/declarative/util/qmlanimation_p.h @@ -116,8 +116,7 @@ private: class QmlTimeLineValueAnimator : public QVariantAnimation { public: - QmlTimeLineValueAnimator(QObject *parent = 0) : QVariantAnimation(parent), animValue(0), policy(KeepWhenStopped) {} - QmlTimeLineValueAnimator(QmlTimeLineValue *value, QObject *parent = 0) : QVariantAnimation(parent), animValue(value), policy(KeepWhenStopped) {} + QmlTimeLineValueAnimator(QObject *parent = 0) : QVariantAnimation(parent), animValue(0), fromSourced(0), policy(KeepWhenStopped) {} void setAnimValue(QmlTimeLineValue *value, DeletionPolicy p) { if (state() == Running) @@ -125,6 +124,10 @@ public: animValue = value; policy = p; } + void setFromSourcedValue(bool *value) + { + fromSourced = value; + } protected: virtual void updateCurrentValue(const QVariant &value) { @@ -134,7 +137,11 @@ protected: virtual void updateState(State oldState, State newState) { QVariantAnimation::updateState(oldState, newState); - if (newState == Stopped && policy == DeleteWhenStopped) { + if (newState == Running) { + //check for new from every loop + if (fromSourced) + *fromSourced = false; + } else if (newState == Stopped && policy == DeleteWhenStopped) { delete animValue; animValue = 0; } @@ -142,6 +149,7 @@ protected: private: QmlTimeLineValue *animValue; + bool *fromSourced; DeletionPolicy policy; }; diff --git a/src/declarative/util/qmllistmodel.cpp b/src/declarative/util/qmllistmodel.cpp index 1cd2f69..8184bda 100644 --- a/src/declarative/util/qmllistmodel.cpp +++ b/src/declarative/util/qmllistmodel.cpp @@ -93,8 +93,7 @@ Q_DECLARE_METATYPE(QListModelInterface *); } \endcode - Elements beginning with a capital are items. Elements beginning - with lower-case are the data roles. The above example defines a + Item roles (properties) must begin with a lower-case letter. The above example defines a ListModel containing three items, with the roles "name" and "cost". The defined model can be used in views such as ListView: @@ -102,15 +101,9 @@ Q_DECLARE_METATYPE(QListModelInterface *); Component { id: FruitDelegate Item { - width: 200 - height: 50 - Text { - text: name - } - Text { - text: '$'+cost - anchors.right: parent.right - } + width: 200; height: 50 + Text { text: name } + Text { text: '$'+cost; anchors.right: parent.right } } } @@ -120,6 +113,59 @@ Q_DECLARE_METATYPE(QListModelInterface *); anchors.fill: parent } \endcode + + It is possible for roles to contain list data. In the example below we create a list of fruit attributes: + + \code + ListModel { + id: FruitModel + ListElement { + name: "Apple" + cost: 2.45 + attributes: [ + ListElement { description: "Core" }, + ListElement { description: "Deciduous" } + ] + } + ListElement { + name: "Orange" + cost: 3.25 + attributes: [ + ListElement { description: "Citrus" } + ] + } + ListElement { + name: "Banana" + cost: 1.95 + attributes: [ + ListElement { description: "Tropical" } + ListElement { description: "Seedless" } + ] + } + } + \endcode + + The delegate below will list all the fruit attributes: + \code + Component { + id: FruitDelegate + Item { + width: 200; height: 50 + Text { id: Name; text: name } + Text { text: '$'+cost; anchors.right: parent.right } + HorizontalLayout { + anchors.top: Name.bottom + spacing: 5 + Text { text: "Attributes:" } + Repeater { + dataSource: attributes + Component { Text { text: description } } + } + } + } + } + \endcode + */ struct ModelNode; |