diff options
author | Martin Jones <martin.jones@nokia.com> | 2009-10-22 01:59:33 (GMT) |
---|---|---|
committer | Martin Jones <martin.jones@nokia.com> | 2009-10-22 01:59:33 (GMT) |
commit | 6c9ac788a60fcd2f946787a5297d7c2f71ad1968 (patch) | |
tree | af53424d7d2adfcbb324624ab93d31845d3db80d /src | |
parent | 2391cf5d127882ce8811e058115d5c2605328079 (diff) | |
parent | fa85d539decf7bdcb16fa8f52858b13479cea659 (diff) | |
download | Qt-6c9ac788a60fcd2f946787a5297d7c2f71ad1968.zip Qt-6c9ac788a60fcd2f946787a5297d7c2f71ad1968.tar.gz Qt-6c9ac788a60fcd2f946787a5297d7c2f71ad1968.tar.bz2 |
Merge branch 'kinetic-declarativeui' of scm.dev.nokia.troll.no:qt/kinetic into kinetic-declarativeui
Diffstat (limited to 'src')
33 files changed, 927 insertions, 797 deletions
diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index 8d34a98..0d5f278 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -228,7 +228,11 @@ void QUnifiedTimer::updateAnimationsTime() void QUnifiedTimer::restartAnimationTimer() { - if (!animationTimer.isActive()) { + if (runningLeafAnimations == 0 && !runningPauseAnimations.isEmpty()) { + int closestTimeToFinish = closestPauseAnimationTimeToFinish(); + animationTimer.start(closestTimeToFinish, this); + isPauseTimerActive = true; + } else if (!animationTimer.isActive() || isPauseTimerActive) { animationTimer.start(timingInterval, this); isPauseTimerActive = false; } @@ -274,11 +278,11 @@ void QUnifiedTimer::registerAnimation(QAbstractAnimation *animation, bool isTopL void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation) { - unregisterRunningAnimation(animation); - if (!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer) return; + unregisterRunningAnimation(animation); + int idx = animations.indexOf(animation); if (idx != -1) { animations.removeAt(idx); @@ -314,6 +318,7 @@ void QUnifiedTimer::unregisterRunningAnimation(QAbstractAnimation *animation) runningPauseAnimations.removeOne(animation); else runningLeafAnimations--; + Q_ASSERT(runningLeafAnimations >= 0); } int QUnifiedTimer::closestPauseAnimationTimeToFinish() @@ -324,9 +329,9 @@ int QUnifiedTimer::closestPauseAnimationTimeToFinish() int timeToFinish; if (animation->direction() == QAbstractAnimation::Forward) - timeToFinish = animation->duration() - QAbstractAnimationPrivate::get(animation)->currentTime; + timeToFinish = animation->duration() - animation->currentTime(); else - timeToFinish = QAbstractAnimationPrivate::get(animation)->totalCurrentTime; + timeToFinish = animation->currentTime(); if (timeToFinish < closestTimeToFinish) closestTimeToFinish = timeToFinish; @@ -644,13 +649,13 @@ int QAbstractAnimation::currentLoop() const */ int QAbstractAnimation::totalDuration() const { - Q_D(const QAbstractAnimation); - if (d->loopCount < 0) - return -1; int dura = duration(); - if (dura == -1) + if (dura <= 0) + return dura; + int loopcount = loopCount(); + if (loopcount < 0) return -1; - return dura * d->loopCount; + return dura * loopcount; } /*! @@ -681,7 +686,7 @@ void QAbstractAnimation::setCurrentTime(int msecs) // Calculate new time and loop. int dura = duration(); - int totalDura = (d->loopCount < 0 || dura == -1) ? -1 : dura * d->loopCount; + int totalDura = dura <= 0 ? dura : ((d->loopCount < 0) ? -1 : dura * d->loopCount); if (totalDura != -1) msecs = qMin(totalDura, msecs); d->totalCurrentTime = msecs; diff --git a/src/declarative/debugger/qmldebug.cpp b/src/declarative/debugger/qmldebug.cpp index 1ef7503..2537ec0 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<int, QmlDebugEnginesQuery *> enginesQuery; QHash<int, QmlDebugRootContextQuery *> rootContextQuery; QHash<int, QmlDebugObjectQuery *> objectQuery; + QHash<int, QmlDebugExpressionQuery *> expressionQuery; QHash<int, QmlDebugWatch *> 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) @@ -109,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) { @@ -116,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; } @@ -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) { @@ -748,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; } @@ -768,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 681ee08..bd076ff 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) @@ -228,6 +232,7 @@ public: int objectDebugId() const; QString name() const; QVariant value() const; + QString valueTypeName() const; QString binding() const; bool hasNotifySignal() const; @@ -236,6 +241,7 @@ private: int m_objectDebugId; QString m_name; QVariant m_value; + QString m_valueTypeName; QString m_binding; bool m_hasNotifySignal; }; @@ -287,4 +293,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/extra/extra.pri b/src/declarative/extra/extra.pri index 6730550..502504a 100644 --- a/src/declarative/extra/extra.pri +++ b/src/declarative/extra/extra.pri @@ -3,11 +3,9 @@ SOURCES += \ extra/qmlnumberformatter.cpp \ extra/qmldatetimeformatter.cpp \ extra/qfxintegermodel.cpp \ - extra/qmlfolderlistmodel.cpp \ extra/qfxanimatedimageitem.cpp \ extra/qfxparticles.cpp \ extra/qmlbehavior.cpp \ - extra/qbindablemap.cpp \ extra/qmlfontloader.cpp HEADERS += \ @@ -15,12 +13,10 @@ HEADERS += \ extra/qmlnumberformatter.h \ extra/qmldatetimeformatter.h \ extra/qfxintegermodel.h \ - extra/qmlfolderlistmodel.h \ extra/qfxanimatedimageitem.h \ extra/qfxanimatedimageitem_p.h \ extra/qfxparticles.h \ extra/qmlbehavior.h \ - extra/qbindablemap.h \ extra/qmlfontloader.h contains(QT_CONFIG, xmlpatterns) { diff --git a/src/declarative/extra/qbindablemap.cpp b/src/declarative/extra/qbindablemap.cpp deleted file mode 100644 index 5254e2a..0000000 --- a/src/declarative/extra/qbindablemap.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qbindablemap.h" -#include <qmlopenmetaobject.h> -#include <QDebug> - -QT_BEGIN_NAMESPACE - -//QBindableMapMetaObject lets us listen for changes coming from QML -//so we can emit the changed signal. -class QBindableMapMetaObject : public QmlOpenMetaObject -{ -public: - QBindableMapMetaObject(QBindableMap *obj) : QmlOpenMetaObject(obj) - { - map = obj; - } - -protected: - virtual void propertyWrite(int index) - { - map->emitChanged(QString::fromUtf8(name(index))); - } - -private: - QBindableMap *map; -}; - -/*! - \class QBindableMap - \brief The QBindableMap class allows you to set key-value pairs that can be used in bindings. - - QBindableMap provides a convenient way to expose domain data to the UI layer. - The following example shows how you might declare data in C++ and then - access it in QML. - - Setup in C++: - \code - //create our data - QBindableMap ownerData; - ownerData.setValue("name", QVariant(QString("John Smith"))); - ownerData.setValue("phone", QVariant(QString("555-5555"))); - - //expose it to the UI layer - QmlContext *ctxt = view->bindContext(); - ctxt->setProperty("owner", &data); - \endcode - - Then, in QML: - \code - Text { text: owner.name } - Text { text: owner.phone } - \endcode - - The binding is dynamic - whenever a key's value is updated, anything bound to that - key will be updated as well. - - To detect value changes made in the UI layer you can connect to the changed() signal. - However, note that changed() is \b NOT emitted when changes are made by calling setValue() - or clearValue() - it is only emitted when a value is updated from QML. -*/ - -// is there a more efficient way to store/return keys? -// (or should we just provide an iterator or something else instead?) -// can we provide a way to clear keys? -// do we want to make any claims regarding key ordering? -// should we have signals for insertion and and deletion -- becoming more model like -// should we emit change for our own changes as well? -// Bug or Feature?: values can be created in QML (owner.somethingElse = "Hello") will create somethingElse property. (need to verify if this is actually the case) -// Bug or Feature?: all values are read-write (there are no read-only values) - -/*! - Constructs a bindable map with parent object \a parent. -*/ -QBindableMap::QBindableMap(QObject *parent) -: QObject(parent) -{ - m_mo = new QBindableMapMetaObject(this); -} - -/*! - Destroys the bindable map. -*/ -QBindableMap::~QBindableMap() -{ -} - -/*! - Clears the value (if any) associated with \a key. -*/ -void QBindableMap::clearValue(const QString &key) -{ - //m_keys.remove(); //### - m_mo->setValue(key.toUtf8(), QVariant()); - //emit changed(key); -} - -/*! - Returns the value associated with \a key. - - If no value has been set for this key (or if the value has been cleared), - an invalid QVariant is returned. -*/ -QVariant QBindableMap::value(const QString &key) const -{ - return m_mo->value(key.toUtf8()); -} - -/*! - Sets the value associated with \a key to \a value. - - If the key doesn't exist, it is automatically created. -*/ -void QBindableMap::setValue(const QString &key, QVariant value) -{ - if (!m_keys.contains(key)) - m_keys.append(key); - m_mo->setValue(key.toUtf8(), value); - //emit changed(key); -} - -/*! - Returns the list of keys. - - Keys that have been cleared will still appear in this list, even though their - associated values are invalid QVariants. -*/ -QStringList QBindableMap::keys() const -{ - return m_keys; -} - -/*! - \fn void QBindableMap::changed(const QString &key) - This signal is emitted whenever one of the values in the map is changed. \a key - is the key corresponding to the value that was changed. - */ - -void QBindableMap::emitChanged(const QString &key) -{ - emit changed(key); -} -QT_END_NAMESPACE diff --git a/src/declarative/extra/qmlfolderlistmodel.cpp b/src/declarative/extra/qmlfolderlistmodel.cpp deleted file mode 100644 index 0e5c275..0000000 --- a/src/declarative/extra/qmlfolderlistmodel.cpp +++ /dev/null @@ -1,413 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "private/qobject_p.h" -#include <QDirModel> -#include <qdebug.h> -#include "qmlfolderlistmodel.h" -#include <QtDeclarative/qmlcontext.h> - -QT_BEGIN_NAMESPACE - -class QmlFolderListModelPrivate : public QObjectPrivate -{ -public: - QmlFolderListModelPrivate() - : sortField(QmlFolderListModel::Name), sortReversed(false), count(0) { - nameFilters << QLatin1String("*"); - } - - void updateSorting() { - QDir::SortFlags flags = 0; - switch(sortField) { - case QmlFolderListModel::Unsorted: - flags |= QDir::Unsorted; - break; - case QmlFolderListModel::Name: - flags |= QDir::Name; - break; - case QmlFolderListModel::Time: - flags |= QDir::Time; - break; - case QmlFolderListModel::Size: - flags |= QDir::Size; - break; - case QmlFolderListModel::Type: - flags |= QDir::Type; - break; - } - - if (sortReversed) - flags |= QDir::Reversed; - - model.setSorting(flags); - } - - QDirModel model; - QUrl folder; - QStringList nameFilters; - QModelIndex folderIndex; - QmlFolderListModel::SortField sortField; - bool sortReversed; - int count; -}; - -/*! - \qmlclass FolderListModel - \brief The FolderListModel provides a model of the contents of a folder in a filesystem. - - FolderListModel provides access to the local filesystem. The \e folder property - specifies the folder to list. - - Qt uses "/" as a universal directory separator in the same way that "/" is - used as a path separator in URLs. If you always use "/" as a directory - separator, Qt will translate your paths to conform to the underlying - operating system. - - The roles available are: - \list - \o fileName - \o filePath - \endlist - - Additionally a file entry can be differentiated from a folder entry - via the \l isFolder() method. -*/ - -QmlFolderListModel::QmlFolderListModel(QObject *parent) - : QListModelInterface(*(new QmlFolderListModelPrivate), parent) -{ - Q_D(QmlFolderListModel); - d->model.setFilter(QDir::AllDirs | QDir::Files | QDir::Drives | QDir::NoDotAndDotDot); - connect(&d->model, SIGNAL(rowsInserted(const QModelIndex&,int,int)) - , this, SLOT(inserted(const QModelIndex&,int,int))); - connect(&d->model, SIGNAL(rowsRemoved(const QModelIndex&,int,int)) - , this, SLOT(removed(const QModelIndex&,int,int))); - connect(&d->model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)) - , this, SLOT(dataChanged(const QModelIndex&,const QModelIndex&))); - connect(&d->model, SIGNAL(modelReset()), this, SLOT(refresh())); - connect(&d->model, SIGNAL(layoutChanged()), this, SLOT(refresh())); -} - -QmlFolderListModel::~QmlFolderListModel() -{ -} - -QHash<int,QVariant> QmlFolderListModel::data(int index, const QList<int> &roles) const -{ - Q_UNUSED(roles); - Q_D(const QmlFolderListModel); - QHash<int,QVariant> folderData; - QModelIndex modelIndex = d->model.index(index, 0, d->folderIndex); - if (modelIndex.isValid()) { - folderData[QDirModel::FileNameRole] = d->model.data(modelIndex, QDirModel::FileNameRole); - folderData[QDirModel::FilePathRole] = QUrl::fromLocalFile(d->model.data(modelIndex, QDirModel::FilePathRole).toString()); - } - - return folderData; -} - -int QmlFolderListModel::count() const -{ - Q_D(const QmlFolderListModel); - return d->count; -} - -QList<int> QmlFolderListModel::roles() const -{ - QList<int> r; - r << QDirModel::FileNameRole; - r << QDirModel::FilePathRole; - return r; -} - -QString QmlFolderListModel::toString(int role) const -{ - switch (role) { - case QDirModel::FileNameRole: - return QLatin1String("fileName"); - case QDirModel::FilePathRole: - return QLatin1String("filePath"); - } - - return QString(); -} - -/*! - \qmlproperty string FolderListModel::folder - - The \a folder property holds the folder the model is currently providing. - - It is a URL, but must be a file: or qrc: URL (or relative to such a URL). -*/ -QUrl QmlFolderListModel::folder() const -{ - Q_D(const QmlFolderListModel); - return d->folder; -} - -void QmlFolderListModel::setFolder(const QUrl &folder) -{ - Q_D(QmlFolderListModel); - if (folder == d->folder) - return; - QModelIndex index = d->model.index(folder.toLocalFile()); - if (index.isValid() && d->model.isDir(index)) { - d->folder = folder; - QMetaObject::invokeMethod(this, "refresh", Qt::QueuedConnection); - emit folderChanged(); - } -} - -QUrl QmlFolderListModel::parentFolder() const -{ - Q_D(const QmlFolderListModel); - int pos = d->folder.path().lastIndexOf(QLatin1Char('/')); - if (pos == -1) - return QUrl(); - QUrl r = d->folder; - r.setPath(d->folder.path().left(pos)); - return r; -} - -/*! - \qmlproperty list<string> FolderListModel::nameFilters - - The \a nameFilters property contains a list of filename filters. - The filters may include the ? and * wildcards. - - The example below filters on PNG and JPEG files: - - \code - FolderListModel { - nameFilters: [ "*.png", "*.jpg" ] - } - \endcode -*/ -QStringList QmlFolderListModel::nameFilters() const -{ - Q_D(const QmlFolderListModel); - return d->nameFilters; -} - -void QmlFolderListModel::setNameFilters(const QStringList &filters) -{ - Q_D(QmlFolderListModel); - d->nameFilters = filters; - d->model.setNameFilters(d->nameFilters); -} - -void QmlFolderListModel::componentComplete() -{ - Q_D(QmlFolderListModel); - if (!d->folder.isValid() || !QDir().exists(d->folder.toLocalFile())) - setFolder(QUrl(QLatin1String("file://")+QDir::currentPath())); - - if (!d->folderIndex.isValid()) - QMetaObject::invokeMethod(this, "refresh", Qt::QueuedConnection); -} - -QmlFolderListModel::SortField QmlFolderListModel::sortField() const -{ - Q_D(const QmlFolderListModel); - return d->sortField; -} - -void QmlFolderListModel::setSortField(SortField field) -{ - Q_D(QmlFolderListModel); - if (field != d->sortField) { - d->sortField = field; - d->updateSorting(); - } -} - -bool QmlFolderListModel::sortReversed() const -{ - Q_D(const QmlFolderListModel); - return d->sortReversed; -} - -void QmlFolderListModel::setSortReversed(bool rev) -{ - Q_D(QmlFolderListModel); - if (rev != d->sortReversed) { - d->sortReversed = rev; - d->updateSorting(); - } -} - -/*! - \qmlmethod bool FolderListModel::isFolder(int index) - - Returns true if the entry \a index is a folder; otherwise - returns false. -*/ -bool QmlFolderListModel::isFolder(int index) const -{ - Q_D(const QmlFolderListModel); - if (index != -1) { - QModelIndex idx = d->model.index(index, 0, d->folderIndex); - if (idx.isValid()) - return d->model.isDir(idx); - } - return false; -} - -void QmlFolderListModel::refresh() -{ - Q_D(QmlFolderListModel); - d->folderIndex = QModelIndex(); - if (d->count) { - int tmpCount = d->count; - d->count = 0; - emit itemsRemoved(0, tmpCount); - } - d->folderIndex = d->model.index(d->folder.toLocalFile()); - d->count = d->model.rowCount(d->folderIndex); - if (d->count) { - emit itemsInserted(0, d->count); - } -} - -void QmlFolderListModel::inserted(const QModelIndex &index, int start, int end) -{ - Q_D(QmlFolderListModel); - if (index == d->folderIndex) { - d->count = d->model.rowCount(d->folderIndex); - emit itemsInserted(start, end - start + 1); - } -} - -void QmlFolderListModel::removed(const QModelIndex &index, int start, int end) -{ - Q_D(QmlFolderListModel); - if (index == d->folderIndex) { - d->count = d->model.rowCount(d->folderIndex); - emit itemsRemoved(start, end - start + 1); - } -} - -void QmlFolderListModel::dataChanged(const QModelIndex &start, const QModelIndex &end) -{ - Q_D(QmlFolderListModel); - qDebug() << "data changed"; - if (start.parent() == d->folderIndex) - emit itemsChanged(start.row(), end.row() - start.row() + 1, roles()); -} - -/*! - \qmlproperty bool FolderListModel::showDirs - - If true (the default), directories are included in the model. - - Note that the nameFilters are ignored for directories. -*/ -bool QmlFolderListModel::showDirs() const -{ - Q_D(const QmlFolderListModel); - return d->model.filter() & QDir::AllDirs; -} - -void QmlFolderListModel::setShowDirs(bool on) -{ - Q_D(QmlFolderListModel); - if (!(d->model.filter() & QDir::AllDirs) == !on) - return; - if (on) - d->model.setFilter(d->model.filter() | QDir::AllDirs | QDir::Drives); - else - d->model.setFilter(d->model.filter() & ~(QDir::AllDirs | QDir::Drives)); -} - -/*! - \qmlproperty bool FolderListModel::showDotAndDotDot - - If true, the "." and ".." directories are included in the model. - - The default is false. -*/ -bool QmlFolderListModel::showDotAndDotDot() const -{ - Q_D(const QmlFolderListModel); - return !(d->model.filter() & QDir::NoDotAndDotDot); -} - -void QmlFolderListModel::setShowDotAndDotDot(bool on) -{ - Q_D(QmlFolderListModel); - if (!(d->model.filter() & QDir::NoDotAndDotDot) == on) - return; - if (on) - d->model.setFilter(d->model.filter() & ~QDir::NoDotAndDotDot); - else - d->model.setFilter(d->model.filter() | QDir::NoDotAndDotDot); -} - -/*! - \qmlproperty bool FolderListModel::showOnlyReadable - - If true, only readable files and directories are shown. - - The default is false. -*/ -bool QmlFolderListModel::showOnlyReadable() const -{ - Q_D(const QmlFolderListModel); - return d->model.filter() & QDir::Readable; -} - -void QmlFolderListModel::setShowOnlyReadable(bool on) -{ - Q_D(QmlFolderListModel); - if (!(d->model.filter() & QDir::Readable) == !on) - return; - if (on) - d->model.setFilter(d->model.filter() | QDir::Readable); - else - d->model.setFilter(d->model.filter() & ~QDir::Readable); -} - - -QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,FolderListModel,QmlFolderListModel) - -QT_END_NAMESPACE - diff --git a/src/declarative/extra/qmlfolderlistmodel.h b/src/declarative/extra/qmlfolderlistmodel.h deleted file mode 100644 index 66e600b..0000000 --- a/src/declarative/extra/qmlfolderlistmodel.h +++ /dev/null @@ -1,128 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QMLFOLDERLISTMODEL_H -#define QMLFOLDERLISTMODEL_H - -#include <QtDeclarative/qml.h> -#include <QtDeclarative/QListModelInterface> - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) - -class QmlContext; -class QModelIndex; - -class QmlFolderListModelPrivate; -class Q_DECLARATIVE_EXPORT QmlFolderListModel : public QListModelInterface, public QmlParserStatus -{ - Q_OBJECT - Q_INTERFACES(QmlParserStatus) - - Q_PROPERTY(QUrl folder READ folder WRITE setFolder NOTIFY folderChanged) - Q_PROPERTY(QUrl parentFolder READ parentFolder NOTIFY folderChanged) - Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters) - Q_PROPERTY(SortField sortField READ sortField WRITE setSortField) - Q_PROPERTY(bool sortReversed READ sortReversed WRITE setSortReversed) - Q_PROPERTY(bool showDirs READ showDirs WRITE setShowDirs) - Q_PROPERTY(bool showDotAndDotDot READ showDotAndDotDot WRITE setShowDotAndDotDot) - Q_PROPERTY(bool showOnlyReadable READ showOnlyReadable WRITE setShowOnlyReadable) - -public: - QmlFolderListModel(QObject *parent = 0); - ~QmlFolderListModel(); - - virtual QHash<int,QVariant> data(int index, const QList<int> &roles = (QList<int>())) const; - virtual int count() const; - virtual QList<int> roles() const; - virtual QString toString(int role) const; - - QUrl folder() const; - void setFolder(const QUrl &folder); - - QUrl parentFolder() const; - - QStringList nameFilters() const; - void setNameFilters(const QStringList &filters); - - virtual void componentComplete(); - - Q_INVOKABLE bool isFolder(int index) const; - - enum SortField { Unsorted, Name, Time, Size, Type }; - SortField sortField() const; - void setSortField(SortField field); - Q_ENUMS(SortField) - - bool sortReversed() const; - void setSortReversed(bool rev); - - bool showDirs() const; - void setShowDirs(bool); - bool showDotAndDotDot() const; - void setShowDotAndDotDot(bool); - bool showOnlyReadable() const; - void setShowOnlyReadable(bool); - -Q_SIGNALS: - void folderChanged(); - -private Q_SLOTS: - void refresh(); - void inserted(const QModelIndex &index, int start, int end); - void removed(const QModelIndex &index, int start, int end); - void dataChanged(const QModelIndex &start, const QModelIndex &end); - -private: - Q_DECLARE_PRIVATE(QmlFolderListModel) - Q_DISABLE_COPY(QmlFolderListModel) -}; - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QmlFolderListModel) - -QT_END_HEADER - -#endif // QMLFOLDERLISTMODEL_H diff --git a/src/declarative/fx/qfxlistview.cpp b/src/declarative/fx/qfxlistview.cpp index 4fb0ec1..2ea1cb7 100644 --- a/src/declarative/fx/qfxlistview.cpp +++ b/src/declarative/fx/qfxlistview.cpp @@ -864,6 +864,52 @@ QFxListView::~QFxListView() } /*! + \qmlattachedproperty bool ListView::isCurrentItem + This attched property is true if this delegate is the current item; otherwise false. + + It is attached to each instance of the delegate. + + This property may be used to adjust the appearance of the current item, for example: + + \snippet doc/src/snippets/declarative/listview/highlight.qml 0 +*/ + +/*! + \qmlattachedproperty ListView ListView::view + This attached property holds the view that manages this delegate instance. + + It is attached to each instance of the delegate. +*/ + +/*! + \qmlattachedproperty string ListView::prevSection + This attached property holds the section of the previous element. + + It is attached to each instance of the delegate. + + The section is evaluated using the \l {ListView::sectionExpression}{sectionExpression} property. +*/ + +/*! + \qmlattachedproperty string ListView::section + This attached property holds the section of this element. + + It is attached to each instance of the delegate. + + The section is evaluated using the \l {ListView::sectionExpression}{sectionExpression} property. +*/ + +/*! + \qmlattachedproperty bool ListView::delayRemove + This attached property holds whether the delegate may be destroyed. + + It is attached to each instance of the delegate. + + It is sometimes necessary to delay the destruction of an item + until an animation completes. +*/ + +/*! \qmlproperty model ListView::model This property holds the model providing data for the list. diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index 58a18a2..b6e86a8 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -40,6 +40,7 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlpropertycache.cpp \ qml/qmlintegercache.cpp \ qml/qmltypenamecache.cpp \ + qml/qmlscriptstring.cpp \ qml/qmlobjectscriptclass.cpp \ qml/qmlcontextscriptclass.cpp \ qml/qmlglobalscriptclass.cpp \ @@ -102,6 +103,7 @@ HEADERS += qml/qmlparser_p.h \ qml/qmlpropertycache_p.h \ qml/qmlintegercache_p.h \ qml/qmltypenamecache_p.h \ + qml/qmlscriptstring.h \ qml/qmlobjectscriptclass_p.h \ qml/qmlcontextscriptclass_p.h \ qml/qmlglobalscriptclass_p.h \ diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index e2fd7cb..726051e 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -69,6 +69,7 @@ #include <private/qmlexpression_p.h> #include "qmlmetaproperty_p.h" #include "qmlrewrite_p.h" +#include <QtDeclarative/qmlscriptstring.h> #include "qmlscriptparser_p.h" @@ -860,6 +861,17 @@ void QmlCompiler::genObject(QmlParser::Object *obj) void QmlCompiler::genObjectBody(QmlParser::Object *obj) { + typedef QPair<Property *, int> PropPair; + foreach(const PropPair &prop, obj->scriptStringProperties) { + QmlInstruction ss; + ss.type = QmlInstruction::StoreScriptString; + ss.storeScriptString.propertyIndex = prop.first->index; + ss.storeScriptString.value = + output->indexForString(prop.first->values.at(0)->value.asScript()); + ss.storeScriptString.scope = prop.second; + output->bytecode << ss; + } + bool seenDefer = false; foreach(Property *prop, obj->valueProperties) { if (prop->isDeferred) { @@ -1371,6 +1383,10 @@ bool QmlCompiler::buildProperty(QmlParser::Property *prop, COMPILE_CHECK(buildListProperty(prop, obj, ctxt)); + } else if (prop->type == qMetaTypeId<QmlScriptString>()) { + + COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt)); + } else { COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt)); @@ -1823,6 +1839,22 @@ bool QmlCompiler::buildListProperty(QmlParser::Property *prop, return true; } +// Compiles an assignment to a QmlScriptString property +bool QmlCompiler::buildScriptStringProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) +{ + if (prop->values.count() > 1) + COMPILE_EXCEPTION(prop->values.at(1), qApp->translate("QmlCompiler", "Cannot assign multiple values to a script property")); + + if (prop->values.at(0)->object || !prop->values.at(0)->value.isScript()) + COMPILE_EXCEPTION(prop->values.at(0), qApp->translate("QmlCompiler", "Invalid property assignment: script expected")); + + obj->addScriptStringProperty(prop, ctxt.stack); + + return true; +} + // Compile regular property assignments of the form "property: <value>" // // ### The following problems exist diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index cff4937..8a9ca9c 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -197,6 +197,9 @@ private: bool buildListProperty(QmlParser::Property *prop, QmlParser::Object *obj, const BindingContext &ctxt); + bool buildScriptStringProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt); bool buildPropertyAssignment(QmlParser::Property *prop, QmlParser::Object *obj, const BindingContext &ctxt); diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 528e8c9..9fad80b 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -76,9 +76,10 @@ #include <QtCore/qdir.h> #include <QtGui/qcolor.h> #include <QtGui/qvector3d.h> +#include <QtGui/qsound.h> #include <qmlcomponent.h> -#include "private/qmlcomponentjs_p.h" -#include "private/qmlmetaproperty_p.h" +#include <private/qmlcomponentjs_p.h> +#include <private/qmlmetaproperty_p.h> #include <private/qmlbinding_p.h> #include <private/qmlvme_p.h> #include <private/qmlenginedebug_p.h> @@ -87,6 +88,7 @@ #include <private/qmlsqldatabase_p.h> #include <private/qmltypenamescriptclass_p.h> #include <private/qmllistscriptclass_p.h> +#include <QtDeclarative/qmlscriptstring.h> #ifdef Q_OS_WIN // for %APPDATA% #include "qt_windows.h" @@ -153,12 +155,14 @@ QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) qtObject.setProperty(QLatin1String("darker"), scriptEngine.newFunction(QmlEnginePrivate::darker, 1)); qtObject.setProperty(QLatin1String("tint"), scriptEngine.newFunction(QmlEnginePrivate::tint, 2)); + //misc methods + qtObject.setProperty(QLatin1String("playSound"), scriptEngine.newFunction(QmlEnginePrivate::playSound, 1)); + scriptEngine.globalObject().setProperty(QLatin1String("createQmlObject"), scriptEngine.newFunction(QmlEnginePrivate::createQmlObject, 1)); scriptEngine.globalObject().setProperty(QLatin1String("createComponent"), scriptEngine.newFunction(QmlEnginePrivate::createComponent, 1)); - //scriptEngine.globalObject().setScriptClass(new QmlGlobalScriptClass(&scriptEngine)); globalClass = new QmlGlobalScriptClass(&scriptEngine); } @@ -216,6 +220,9 @@ Q_GLOBAL_STATIC(QmlEngineDebugServer, qmlEngineDebugServer); void QmlEnginePrivate::init() { Q_Q(QmlEngine); + qRegisterMetaType<QVariant>("QVariant"); + qRegisterMetaType<QmlScriptString>("QmlScriptString"); + scriptEngine.installTranslatorFunctions(); contextClass = new QmlContextScriptClass(q); objectClass = new QmlObjectScriptClass(q); @@ -281,8 +288,6 @@ QmlEngine::QmlEngine(QObject *parent) { Q_D(QmlEngine); d->init(); - - qRegisterMetaType<QVariant>("QVariant"); } /*! @@ -401,7 +406,12 @@ QmlContext *QmlEngine::contextForObject(const QObject *object) QmlDeclarativeData *data = static_cast<QmlDeclarativeData *>(priv->declarativeData); - return data?data->context:0; + if (!data) + return 0; + else if (data->outerContext) + return data->outerContext; + else + return data->context; } /*! @@ -565,6 +575,17 @@ QScriptValue QmlEnginePrivate::qmlScriptObject(QObject* object, } /*! + Returns the QmlContext for the executing QScript \a ctxt. +*/ +QmlContext *QmlEnginePrivate::getContext(QScriptContext *ctxt) +{ + QScriptValue scopeNode = QScriptDeclarativeClass::scopeChainValue(ctxt, -3); + Q_ASSERT(scopeNode.isValid()); + Q_ASSERT(QScriptDeclarativeClass::scriptClass(scopeNode) == contextClass); + return contextClass->contextFromValue(scopeNode); +} + +/*! This function is intended for use inside QML only. In C++ just create a component object as usual. @@ -626,7 +647,7 @@ QScriptValue QmlEnginePrivate::createComponent(QScriptContext *ctxt, static_cast<QmlScriptEngine*>(engine)->p; QmlEngine* activeEngine = activeEnginePriv->q_func(); - QmlContext* context = activeEnginePriv->currentExpression->context(); + QmlContext* context = activeEnginePriv->getContext(ctxt); if(ctxt->argumentCount() != 1) { c = new QmlComponentJS(activeEngine); }else{ @@ -647,7 +668,7 @@ QScriptValue QmlEnginePrivate::createComponent(QScriptContext *ctxt, Example (where targetItem is the id of an existing QML item): \code - newObject = createQmlObject('Rectangle {color: "red"; width: 20; height: 20}', + newObject = createQmlObject('import Qt 4.6; Rectangle {color: "red"; width: 20; height: 20}', targetItem, "dynamicSnippet1"); \endcode @@ -677,9 +698,16 @@ QScriptValue QmlEnginePrivate::createQmlObject(QScriptContext *ctxt, QScriptEngi QUrl url; if(ctxt->argumentCount() > 2) url = QUrl(ctxt->argument(2).toString()); + else + url = QUrl(QLatin1String("DynamicQML")); QObject *parentArg = activeEnginePriv->objectClass->toQObject(ctxt->argument(1)); QmlContext *qmlCtxt = qmlContext(parentArg); - url = qmlCtxt->resolvedUrl(url); + if (url.isEmpty()) { + url = qmlCtxt->resolvedUrl(QUrl(QLatin1String("<Unknown File>"))); + } else { + url = qmlCtxt->resolvedUrl(url); + } + QmlComponent component(activeEngine, qml.toUtf8(), url); if(component.isError()) { QList<QmlError> errors = component.errors(); @@ -836,6 +864,30 @@ QScriptValue QmlEnginePrivate::darker(QScriptContext *ctxt, QScriptEngine *engin return qScriptValueFromValue(engine, qVariantFromValue(color)); } +QScriptValue QmlEnginePrivate::playSound(QScriptContext *ctxt, QScriptEngine *engine) +{ + if (ctxt->argumentCount() < 1) + return engine->undefinedValue(); + + QUrl url(ctxt->argument(0).toString()); + + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + if (url.isRelative()) { + QmlContext *context = enginePriv->getContext(ctxt); + if (!context) + return engine->undefinedValue(); + + url = context->resolvedUrl(url); + } + + if (url.scheme() == QLatin1String("file")) { + + QSound::play(url.toLocalFile()); + + } + return engine->undefinedValue(); +} + /*! This function allows tinting one color with another. diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index a85ac55..a74854d 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -259,10 +259,13 @@ public: static QScriptValue darker(QScriptContext*, QScriptEngine*); static QScriptValue tint(QScriptContext*, QScriptEngine*); + static QScriptValue playSound(QScriptContext*, QScriptEngine*); + static QScriptEngine *getScriptEngine(QmlEngine *e) { return &e->d_func()->scriptEngine; } static QmlEngine *getEngine(QScriptEngine *e) { return static_cast<QmlScriptEngine*>(e)->p->q_func(); } static QmlEnginePrivate *get(QmlEngine *e) { return e->d_func(); } static QmlEnginePrivate *get(QScriptEngine *e) { return static_cast<QmlScriptEngine*>(e)->p; } + QmlContext *getContext(QScriptContext *); }; diff --git a/src/declarative/qml/qmlenginedebug.cpp b/src/declarative/qml/qmlenginedebug.cpp index e20616a..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<QmlContext *>::ConstIterator iter = p->childContexts.begin(); @@ -184,6 +188,32 @@ 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); + if (o) { + QString objectName = o->objectName(); + if (objectName.isEmpty()) + objectName = QLatin1String("<unnamed>"); + v = QString::fromUtf8(o->metaObject()->className()) + + QLatin1String(": ") + objectName; + } + } + + if (v.isNull()) + v = QString::fromUtf8(value.typeName()); + + return v; +} + QmlEngineDebugServer::QmlObjectData QmlEngineDebugServer::objectData(QObject *object) { @@ -310,29 +340,42 @@ 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("<undefined>"); + else + result = serializableVariant(value); + delete exprObj; + } else { + result = QLatin1String("<unknown context>"); + } + + 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("<unnamed>"); - v = QString::fromUtf8(o->metaObject()->className()) + - QLatin1String(": ") + objectName; - } - if (v.isNull()) - v = value.toString(); - } else { - v = value; - } rs << QByteArray("UPDATE_WATCH") << id << objectId << property << v; diff --git a/src/declarative/qml/qmlenginedebug_p.h b/src/declarative/qml/qmlenginedebug_p.h index e2f903c..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; }; @@ -103,6 +104,7 @@ private: void buildObjectDump(QDataStream &, QObject *, bool); QmlObjectData objectData(QObject *); QmlObjectProperty propertyData(QObject *, int); + QVariant serializableVariant(const QVariant &value); static QList<QmlEngine *> m_engines; QmlWatcher *m_watch; diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index cfa9469..d2bf4a8 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -281,7 +281,7 @@ void QmlExpressionPrivate::printException(QScriptEngine *scriptEngine) } } -QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) +QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope, bool *isUndefined) { #ifdef Q_ENABLE_PERFORMANCE_LOG QFxPerfTimer<QFxPerf::BindValueQt> perfqt; @@ -318,6 +318,9 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) QScriptValue svalue = data->expressionFunction.call(); + if (isUndefined) + *isUndefined = svalue.isUndefined(); + if (scriptEngine->hasUncaughtException()) printException(scriptEngine); @@ -355,7 +358,7 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) return rv; } -QVariant QmlExpressionPrivate::value(QObject *secondaryScope) +QVariant QmlExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined) { Q_Q(QmlExpression); @@ -382,7 +385,7 @@ QVariant QmlExpressionPrivate::value(QObject *secondaryScope) if (data->sse.isValid()) { rv = evalSSE(); } else { - rv = evalQtScript(secondaryScope); + rv = evalQtScript(secondaryScope, isUndefined); } ep->currentExpression = lastCurrentExpression; @@ -406,11 +409,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 73682f1..96694d6 100644 --- a/src/declarative/qml/qmlexpression.h +++ b/src/declarative/qml/qmlexpression.h @@ -83,7 +83,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<QmlEnginePrivate::CapturedProperty> &properties); void clearGuards(); diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index 5265d42..dc18b05 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -119,6 +119,7 @@ public: StoreSignal, /* storeSignal */ StoreScript, /* storeScript */ + StoreScriptString, /* storeScriptString */ // // Unresolved single assignment @@ -245,6 +246,11 @@ public: int value; } storeString; struct { + int propertyIndex; + int value; + int scope; + } storeScriptString; + struct { int value; int fileName; int lineNumber; diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp index bae263a..f9e3c50 100644 --- a/src/declarative/qml/qmlparser.cpp +++ b/src/declarative/qml/qmlparser.cpp @@ -80,6 +80,9 @@ QmlParser::Object::~Object() prop->release(); foreach(Property *prop, valueTypeProperties) prop->release(); + typedef QPair<Property *, int> PropPair; + foreach(const PropPair &prop, scriptStringProperties) + prop.first->release(); foreach(const DynamicProperty &prop, dynamicProperties) if (prop.defaultValue) prop.defaultValue->release(); foreach(Object *obj, scriptBlockObjects) @@ -142,6 +145,13 @@ void QmlParser::Object::addValueTypeProperty(Property *p) valueTypeProperties << p; } +void QmlParser::Object::addScriptStringProperty(Property *p, int stack) +{ + p->addref(); + scriptStringProperties << qMakePair(p, stack); +} + + Property *QmlParser::Object::getProperty(const QByteArray &name, bool create) { if (!properties.contains(name)) { diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h index 88d7d77..f0867ea 100644 --- a/src/declarative/qml/qmlparser_p.h +++ b/src/declarative/qml/qmlparser_p.h @@ -160,11 +160,13 @@ namespace QmlParser void addAttachedProperty(Property *); void addGroupedProperty(Property *); void addValueTypeProperty(Property *); + void addScriptStringProperty(Property *, int = 0); QList<Property *> valueProperties; QList<Property *> signalProperties; QList<Property *> attachedProperties; QList<Property *> groupedProperties; QList<Property *> valueTypeProperties; + QList<QPair<Property *, int> > scriptStringProperties; // Script blocks that were nested under this object QStringList scriptBlocks; diff --git a/src/declarative/qml/qmlscriptstring.cpp b/src/declarative/qml/qmlscriptstring.cpp new file mode 100644 index 0000000..8a6afcc --- /dev/null +++ b/src/declarative/qml/qmlscriptstring.cpp @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlscriptstring.h" + +QT_BEGIN_NAMESPACE + +class QmlScriptStringPrivate : public QSharedData +{ +public: + QmlScriptStringPrivate() : context(0), scope(0) {} + + QmlContext *context; + QObject *scope; + QString script; +}; + +/*! +\class QmlScriptString +\brief The QmlScriptString class encapsulates a script and its context. + +The QmlScriptString is used by properties that want to accept a script "assignment" from QML. + +Normally, the following code would result in a binding being established for the \c script +property. If the property had a type of QmlScriptString, the script - \e {print(1921)} - itself +would be passed to the property and it could choose how to handle it. + +\code +MyType { + script: print(1921) +} +\endcode +*/ + +/*! +Construct an empty instance. +*/ +QmlScriptString::QmlScriptString() +: d(new QmlScriptStringPrivate) +{ +} + +/*! +Copy \a other. +*/ +QmlScriptString::QmlScriptString(const QmlScriptString &other) +: d(other.d) +{ +} + +/*! +\internal +*/ +QmlScriptString::~QmlScriptString() +{ +} + +/*! +Assign \a other to this. +*/ +QmlScriptString &QmlScriptString::operator=(const QmlScriptString &other) +{ + d = other.d; + return *this; +} + +/*! +Return the context for the script. +*/ +QmlContext *QmlScriptString::context() const +{ + return d->context; +} + +/*! +Sets the \a context for the script. +*/ +void QmlScriptString::setContext(QmlContext *context) +{ + d->context = context; +} + +/*! +Returns the scope object for the script. +*/ +QObject *QmlScriptString::scopeObject() const +{ + return d->scope; +} + +/*! +Sets the scope \a object for the script. +*/ +void QmlScriptString::setScopeObject(QObject *object) +{ + d->scope = object; +} + +/*! +Returns the script text. +*/ +QString QmlScriptString::script() const +{ + return d->script; +} + +/*! +Sets the \a script text. +*/ +void QmlScriptString::setScript(const QString &script) +{ + d->script = script; +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qmlscriptstring.h b/src/declarative/qml/qmlscriptstring.h new file mode 100644 index 0000000..c6067ce --- /dev/null +++ b/src/declarative/qml/qmlscriptstring.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLSCRIPTSTRING_H +#define QMLSCRIPTSTRING_H + +#include <QtCore/qstring.h> +#include <QtCore/qshareddata.h> +#include <QtCore/qmetatype.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QObject; +class QmlContext; +class QmlScriptStringPrivate; +class Q_DECLARATIVE_EXPORT QmlScriptString +{ +public: + QmlScriptString(); + QmlScriptString(const QmlScriptString &); + ~QmlScriptString(); + + QmlScriptString &operator=(const QmlScriptString &); + + QmlContext *context() const; + void setContext(QmlContext *); + + QObject *scopeObject() const; + void setScopeObject(QObject *); + + QString script() const; + void setScript(const QString &); + +private: + QSharedDataPointer<QmlScriptStringPrivate> d; +}; + +Q_DECLARE_METATYPE(QmlScriptString); + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLSCRIPTSTRING_H + diff --git a/src/declarative/qml/qmlsqldatabase.cpp b/src/declarative/qml/qmlsqldatabase.cpp index 4a5983d..9e39ffc 100644 --- a/src/declarative/qml/qmlsqldatabase.cpp +++ b/src/declarative/qml/qmlsqldatabase.cpp @@ -340,7 +340,7 @@ static QScriptValue qmlsqldatabase_open(QScriptContext *context, QScriptEngine * QString basename = QmlEnginePrivate::get(engine)->offlineStoragePath + QLatin1String("/Databases/"); QDir().mkpath(basename); basename += dbid; - database.setDatabaseName(basename+QLatin1String(".sqllite")); + database.setDatabaseName(basename+QLatin1String(".sqlite")); QSettings ini(basename+QLatin1String(".ini"),QSettings::IniFormat); ini.setValue(QLatin1String("Name"), dbname); ini.setValue(QLatin1String("Version"), dbversion); diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index 1f3903d..7f673a2 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -67,6 +67,7 @@ #include <private/qmlbinding_p.h> #include <private/qmlcontext_p.h> #include <private/qmlbindingoptimizations_p.h> +#include <QtDeclarative/qmlscriptstring.h> QT_BEGIN_NAMESPACE @@ -552,6 +553,21 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, } break; + case QmlInstruction::StoreScriptString: + { + QObject *target = stack.top(); + QObject *scope = stack.at(stack.count() - 1 - instr.storeScriptString.scope); + QmlScriptString ss; + ss.setContext(ctxt); + ss.setScopeObject(scope); + ss.setScript(primitives.at(instr.storeScriptString.value)); + + void *a[] = { &ss, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeScriptString.propertyIndex, a); + } + break; + case QmlInstruction::BeginObject: { QObject *target = stack.top(); diff --git a/src/declarative/qml/qmlvmemetaobject.cpp b/src/declarative/qml/qmlvmemetaobject.cpp index e5acc51..62a2a6b 100644 --- a/src/declarative/qml/qmlvmemetaobject.cpp +++ b/src/declarative/qml/qmlvmemetaobject.cpp @@ -55,7 +55,7 @@ QmlVMEMetaObject::QmlVMEMetaObject(QObject *obj, const QMetaObject *other, const QmlVMEMetaData *meta, QmlRefCount *rc) -: object(obj), ref(rc), metaData(meta), parent(0) +: object(obj), ref(rc), ctxt(qmlContext(obj)), metaData(meta), parent(0) { if (ref) ref->addref(); @@ -251,7 +251,6 @@ int QmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) (const QChar *)(((const char*)metaData) + data->bodyOffset); QString code = QString::fromRawData(body, data->bodyLength); - QmlContext *ctxt = qmlContext(object); if (0 == (metaData->methodData() + id)->parameterCount) { QmlExpression expr(ctxt, code, object); diff --git a/src/declarative/qml/qmlvmemetaobject_p.h b/src/declarative/qml/qmlvmemetaobject_p.h index d376f4c..de46853 100644 --- a/src/declarative/qml/qmlvmemetaobject_p.h +++ b/src/declarative/qml/qmlvmemetaobject_p.h @@ -112,6 +112,7 @@ protected: private: QObject *object; QmlRefCount *ref; + QGuard<QmlContext> ctxt; const QmlVMEMetaData *metaData; int propOffset; diff --git a/src/declarative/util/qmlanimation_p.h b/src/declarative/util/qmlanimation_p.h index 4f6edb7..22c4e2d 100644 --- a/src/declarative/util/qmlanimation_p.h +++ b/src/declarative/util/qmlanimation_p.h @@ -92,6 +92,7 @@ private: //performs an action of type QAbstractAnimationAction class QActionAnimation : public QAbstractAnimation { + Q_OBJECT public: QActionAnimation(QObject *parent = 0) : QAbstractAnimation(parent), animAction(0), policy(KeepWhenStopped) {} QActionAnimation(QAbstractAnimationAction *action, QObject *parent = 0) @@ -126,6 +127,7 @@ private: //animates QmlTimeLineValue (assumes start and end values will be reals or compatible) class QmlTimeLineValueAnimator : public QVariantAnimation { + Q_OBJECT public: QmlTimeLineValueAnimator(QObject *parent = 0) : QVariantAnimation(parent), animValue(0), fromSourced(0), policy(KeepWhenStopped) {} void setAnimValue(QmlTimeLineValue *value, DeletionPolicy p) diff --git a/src/declarative/util/qmlopenmetaobject.cpp b/src/declarative/util/qmlopenmetaobject.cpp index 7305362..11648f6 100644 --- a/src/declarative/util/qmlopenmetaobject.cpp +++ b/src/declarative/util/qmlopenmetaobject.cpp @@ -136,6 +136,14 @@ QVariant QmlOpenMetaObject::value(const QByteArray &name) const return d->data.at(*iter); } +QVariant &QmlOpenMetaObject::operator[](const QByteArray &name) +{ + QHash<QByteArray, int>::ConstIterator iter = d->names.find(name); + Q_ASSERT(iter != d->names.end()); + + return d->data[*iter]; +} + void QmlOpenMetaObject::setValue(const QByteArray &name, const QVariant &val) { QHash<QByteArray, int>::ConstIterator iter = d->names.find(name); diff --git a/src/declarative/util/qmlopenmetaobject.h b/src/declarative/util/qmlopenmetaobject.h index f65660d..be0490d 100644 --- a/src/declarative/util/qmlopenmetaobject.h +++ b/src/declarative/util/qmlopenmetaobject.h @@ -64,6 +64,7 @@ public: void setValue(const QByteArray &, const QVariant &); QVariant value(int) const; void setValue(int, const QVariant &); + QVariant &operator[](const QByteArray &); int count() const; QByteArray name(int) const; diff --git a/src/declarative/util/qmlpropertymap.cpp b/src/declarative/util/qmlpropertymap.cpp new file mode 100644 index 0000000..a587af3 --- /dev/null +++ b/src/declarative/util/qmlpropertymap.cpp @@ -0,0 +1,273 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlpropertymap.h" +#include <qmlopenmetaobject.h> +#include <QDebug> + +QT_BEGIN_NAMESPACE + +//QmlPropertyMapMetaObject lets us listen for changes coming from QML +//so we can emit the changed signal. +class QmlPropertyMapMetaObject : public QmlOpenMetaObject +{ +public: + QmlPropertyMapMetaObject(QmlPropertyMap *obj, QmlPropertyMapPrivate *objPriv); + +protected: + virtual void propertyWrite(int index); + +private: + QmlPropertyMap *map; + QmlPropertyMapPrivate *priv; +}; + +class QmlPropertyMapPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QmlPropertyMap) +public: + QmlPropertyMapMetaObject *mo; + QStringList keys; + void emitChanged(const QString &key); +}; + +void QmlPropertyMapPrivate::emitChanged(const QString &key) +{ + Q_Q(QmlPropertyMap); + emit q->valueChanged(key); +} + +QmlPropertyMapMetaObject::QmlPropertyMapMetaObject(QmlPropertyMap *obj, QmlPropertyMapPrivate *objPriv) : QmlOpenMetaObject(obj) +{ + map = obj; + priv = objPriv; +} + +void QmlPropertyMapMetaObject::propertyWrite(int index) +{ + priv->emitChanged(QString::fromUtf8(name(index))); +} + +/*! + \class QmlPropertyMap + \brief The QmlPropertyMap class allows you to set key-value pairs that can be used in bindings. + + QmlPropertyMap provides a convenient way to expose domain data to the UI layer. + The following example shows how you might declare data in C++ and then + access it in QML. + + Setup in C++: + \code + //create our data + QmlPropertyMap ownerData; + ownerData.insert("name", QVariant(QString("John Smith"))); + ownerData.insert("phone", QVariant(QString("555-5555"))); + + //expose it to the UI layer + QmlContext *ctxt = view->bindContext(); + ctxt->setProperty("owner", &data); + \endcode + + Then, in QML: + \code + Text { text: owner.name } + Text { text: owner.phone } + \endcode + + The binding is dynamic - whenever a key's value is updated, anything bound to that + key will be updated as well. + + To detect value changes made in the UI layer you can connect to the valueChanged() signal. + However, note that valueChanged() is \b NOT emitted when changes are made by calling insert() + or clear() - it is only emitted when a value is updated from QML. + + \note It is not possible to remove keys from the map; once a key has been added, you can only + modify or clear its associated value. +*/ + +/*! + Constructs a bindable map with parent object \a parent. +*/ +QmlPropertyMap::QmlPropertyMap(QObject *parent) +: QObject(*(new QmlPropertyMapPrivate), parent) +{ + Q_D(QmlPropertyMap); + d->mo = new QmlPropertyMapMetaObject(this, d); +} + +/*! + Destroys the bindable map. +*/ +QmlPropertyMap::~QmlPropertyMap() +{ +} + +/*! + Clears the value (if any) associated with \a key. +*/ +void QmlPropertyMap::clear(const QString &key) +{ + Q_D(QmlPropertyMap); + d->mo->setValue(key.toUtf8(), QVariant()); +} + +/*! + Returns the value associated with \a key. + + If no value has been set for this key (or if the value has been cleared), + an invalid QVariant is returned. +*/ +QVariant QmlPropertyMap::value(const QString &key) const +{ + Q_D(const QmlPropertyMap); + return d->mo->value(key.toUtf8()); +} + +/*! + Sets the value associated with \a key to \a value. + + If the key doesn't exist, it is automatically created. +*/ +void QmlPropertyMap::insert(const QString &key, const QVariant &value) +{ + Q_D(QmlPropertyMap); + if (!d->keys.contains(key)) + d->keys.append(key); + d->mo->setValue(key.toUtf8(), value); +} + +/*! + Returns the list of keys. + + Keys that have been cleared will still appear in this list, even though their + associated values are invalid QVariants. +*/ +QStringList QmlPropertyMap::keys() const +{ + Q_D(const QmlPropertyMap); + return d->keys; +} + +/*! + \overload + + Same as size(). +*/ +int QmlPropertyMap::count() const +{ + Q_D(const QmlPropertyMap); + return d->keys.count(); +} + +/*! + Returns the number of keys in the map. + + \sa isEmpty(), count() +*/ +int QmlPropertyMap::size() const +{ + Q_D(const QmlPropertyMap); + return d->keys.size(); +} + +/*! + Returns true if the map contains no keys; otherwise returns + false. + + \sa size() +*/ +bool QmlPropertyMap::isEmpty() const +{ + Q_D(const QmlPropertyMap); + return d->keys.isEmpty(); +} + +/*! + Returns true if the map contains \a key. + + \sa size() +*/ +bool QmlPropertyMap::contains(const QString &key) const +{ + Q_D(const QmlPropertyMap); + return d->keys.contains(key); +} + +/*! + Returns the value associated with the key \a key as a modifiable + reference. + + If the map contains no item with key \a key, the function inserts + an invalid QVariant into the map with key \a key, and + returns a reference to it. + + \sa insert(), value() +*/ +QVariant &QmlPropertyMap::operator[](const QString &key) +{ + //### optimize + Q_D(QmlPropertyMap); + QByteArray utf8key = key.toUtf8(); + if (!d->keys.contains(key)) { + d->keys.append(key); + d->mo->setValue(utf8key, QVariant()); //force creation -- needed below + } + + return (*(d->mo))[utf8key]; +} + +/*! + \overload + + Same as value(). +*/ +const QVariant QmlPropertyMap::operator[](const QString &key) const +{ + return value(key); +} + +/*! + \fn void QmlPropertyMap::valueChanged(const QString &key) + This signal is emitted whenever one of the values in the map is changed. \a key + is the key corresponding to the value that was changed. +*/ + +QT_END_NAMESPACE diff --git a/src/declarative/extra/qbindablemap.h b/src/declarative/util/qmlpropertymap.h index aa1908e..24b4395 100644 --- a/src/declarative/extra/qbindablemap.h +++ b/src/declarative/util/qmlpropertymap.h @@ -39,8 +39,8 @@ ** ****************************************************************************/ -#ifndef QBINDABLEMAP_H -#define QBINDABLEMAP_H +#ifndef QMLPROPERTYMAP_H +#define QMLPROPERTYMAP_H #include <QtDeclarative/qfxglobal.h> #include <QtCore/QObject> @@ -54,29 +54,34 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) -class QBindableMapMetaObject; -class Q_DECLARATIVE_EXPORT QBindableMap : public QObject +class QmlPropertyMapPrivate; +class Q_DECLARATIVE_EXPORT QmlPropertyMap : public QObject { Q_OBJECT public: - QBindableMap(QObject *parent = 0); - virtual ~QBindableMap(); + QmlPropertyMap(QObject *parent = 0); + virtual ~QmlPropertyMap(); QVariant value(const QString &key) const; - void setValue(const QString &key, QVariant value); - void clearValue(const QString &key); + void insert(const QString &key, const QVariant &value); + void clear(const QString &key); Q_INVOKABLE QStringList keys() const; + int count() const; + int size() const; + bool isEmpty() const; + bool contains(const QString &key) const; + + QVariant &operator[](const QString &key); + const QVariant operator[](const QString &key) const; + Q_SIGNALS: - void changed(const QString &key); + void valueChanged(const QString &key); private: - Q_DISABLE_COPY(QBindableMap) - void emitChanged(const QString &key); - QBindableMapMetaObject *m_mo; - QStringList m_keys; - friend class QBindableMapMetaObject; + Q_DECLARE_PRIVATE(QmlPropertyMap) + Q_DISABLE_COPY(QmlPropertyMap) }; QT_END_NAMESPACE diff --git a/src/declarative/util/util.pri b/src/declarative/util/util.pri index ec9967c..01ad898 100644 --- a/src/declarative/util/util.pri +++ b/src/declarative/util/util.pri @@ -19,7 +19,8 @@ SOURCES += \ util/qmlopenmetaobject.cpp \ util/qmltimeline.cpp \ util/qmltimer.cpp \ - util/qmlbind.cpp + util/qmlbind.cpp \ + util/qmlpropertymap.cpp HEADERS += \ util/qmlview.h \ @@ -46,4 +47,5 @@ HEADERS += \ util/qmlnullablevalue_p.h \ util/qmltimeline_p.h \ util/qmltimer.h \ - util/qmlbind.h + util/qmlbind.h \ + util/qmlpropertymap.h |