summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Alpert <alan.alpert@nokia.com>2010-01-19 07:54:46 (GMT)
committerAlan Alpert <alan.alpert@nokia.com>2010-01-19 07:54:46 (GMT)
commit630114a8c65e492b7b9008e056895302865ba528 (patch)
tree50bb56cd3d5cd45626bb2d9a40c7cf21f14a4a20
parent98a8be614d410a153cd9c314465f4c49d4ad096d (diff)
parent8eb1bf3ea506ec1f9636cab684695b91d846a3cd (diff)
downloadQt-630114a8c65e492b7b9008e056895302865ba528.zip
Qt-630114a8c65e492b7b9008e056895302865ba528.tar.gz
Qt-630114a8c65e492b7b9008e056895302865ba528.tar.bz2
Merge branch 'kinetic-declarativeui' of scm.dev.nokia.troll.no:qt/kinetic into kinetic-declarativeui
-rw-r--r--src/declarative/graphicsitems/qmlgraphicspathview.cpp34
-rw-r--r--src/declarative/graphicsitems/qmlgraphicstext.cpp4
-rw-r--r--src/declarative/qml/qmlworkerscript.cpp505
-rw-r--r--src/declarative/qml/qmlworkerscript_p.h45
-rw-r--r--src/declarative/util/qmllistmodel.cpp45
-rw-r--r--tests/auto/declarative/qmllistmodel/tst_qmllistmodel.cpp5
-rw-r--r--tools/qmlviewer/main.cpp3
7 files changed, 608 insertions, 33 deletions
diff --git a/src/declarative/graphicsitems/qmlgraphicspathview.cpp b/src/declarative/graphicsitems/qmlgraphicspathview.cpp
index 2fc0dfb..112eda2 100644
--- a/src/declarative/graphicsitems/qmlgraphicspathview.cpp
+++ b/src/declarative/graphicsitems/qmlgraphicspathview.cpp
@@ -56,6 +56,18 @@ QT_BEGIN_NAMESPACE
QML_DEFINE_TYPE(Qt,4,6,PathView,QmlGraphicsPathView)
+
+inline qreal qmlMod(qreal x, qreal y)
+{
+#ifdef QT_USE_MATH_H_FLOATS
+ if(sizeof(qreal) == sizeof(float))
+ return fmodf(float(x), float(y));
+ else
+#endif
+ return fmod(x, y);
+}
+
+
class QmlGraphicsPathViewAttached : public QObject
{
Q_OBJECT
@@ -250,7 +262,7 @@ void QmlGraphicsPathViewPrivate::setOffset(qreal o)
{
Q_Q(QmlGraphicsPathView);
if (_offset != o) {
- _offset = fmod(o, qreal(100.0));
+ _offset = qmlMod(o, qreal(100.0));
if (_offset < 0)
_offset = 100.0 + _offset;
q->refill();
@@ -450,8 +462,8 @@ void QmlGraphicsPathView::mouseReleaseEvent(QGraphicsSceneMouseEvent *)
velocity = 100;
else if (velocity < -100)
velocity = -100;
- qreal inc = fmod(d->_offset - d->snapPos, qreal(100.0 / d->model->count()));
- qreal dist = qAbs(velocity/2 - fmod(velocity/2, qreal(100.0 / d->model->count()) - inc));
+ qreal inc = qmlMod(d->_offset - d->snapPos, qreal(100.0 / d->model->count()));
+ qreal dist = qAbs(velocity/2 - qmlMod(velocity/2, qreal(100.0 / d->model->count()) - inc));
d->moveOffset.setValue(d->_offset);
d->tl.accel(d->moveOffset, velocity, 10, dist);
d->tl.execute(d->fixupOffsetEvent);
@@ -542,7 +554,7 @@ void QmlGraphicsPathView::componentComplete()
itemIndex += d->pathOffset;
itemIndex %= d->items.count();
- qreal targetOffset = fmod(100 + (d->snapPos*100) - 100.0 * itemIndex / d->items.count(), qreal(100.0));
+ qreal targetOffset = qmlMod(100 + (d->snapPos*100) - 100.0 * itemIndex / d->items.count(), qreal(100.0));
if (targetOffset < 0)
targetOffset = 100.0 + targetOffset;
@@ -609,7 +621,7 @@ void QmlGraphicsPathView::refill()
for (int i=0; i<d->items.count(); i++){
qreal percent = i * (100. / d->items.count());
percent = percent + d->_offset;
- percent = fmod(percent, qreal(100.0));
+ percent = qmlMod(percent, qreal(100.0));
positions << qAbs(percent/100.0);
}
@@ -696,7 +708,7 @@ void QmlGraphicsPathView::itemsInserted(int modelIndex, int count)
int itemIndex = (d->currentIndex - d->firstIndex + d->model->count())%d->model->count();
itemIndex += d->pathOffset;
itemIndex %= d->items.count();
- qreal targetOffset = fmod(100 + (d->snapPos*100) - 100.0 * itemIndex / d->items.count(), qreal(100.0));
+ qreal targetOffset = qmlMod(100 + (d->snapPos*100) - 100.0 * itemIndex / d->items.count(), qreal(100.0));
if (targetOffset < 0)
targetOffset = 100.0 + targetOffset;
@@ -733,7 +745,7 @@ void QmlGraphicsPathView::itemsRemoved(int modelIndex, int count)
int itemIndex = (d->currentIndex - d->firstIndex + d->model->count())%d->model->count();
itemIndex += d->pathOffset;
itemIndex %= d->items.count();
- qreal targetOffset = fmod(100 + (d->snapPos*100) - 100.0 * itemIndex / d->items.count(), qreal(100.0));
+ qreal targetOffset = qmlMod(100 + (d->snapPos*100) - 100.0 * itemIndex / d->items.count(), qreal(100.0));
if (targetOffset < 0)
targetOffset = 100.0 + targetOffset;
@@ -766,12 +778,12 @@ int QmlGraphicsPathViewPrivate::calcCurrentIndex()
{
int current = -1;
if (model && items.count()) {
- _offset = fmod(_offset, qreal(100.0));
+ _offset = qmlMod(_offset, qreal(100.0));
if (_offset < 0)
_offset += 100.0;
if (pathItems == -1) {
- qreal delta = fmod(_offset - snapPos, qreal(100.0));
+ qreal delta = qmlMod(_offset - snapPos, qreal(100.0));
if (delta < 0)
delta = 100.0 + delta;
int ii = model->count() - qRound(delta * model->count() / 100);
@@ -784,7 +796,7 @@ int QmlGraphicsPathViewPrivate::calcCurrentIndex()
for (int i=0; i<items.count(); i++){
qreal percent = i * (100. / items.count());
percent = percent + _offset;
- percent = fmod(percent, qreal(100.0));
+ percent = qmlMod(percent, qreal(100.0));
qreal diff = qAbs(snapPos - (percent/100.0));
if (diff < bestDiff){
bestDiff = diff;
@@ -843,7 +855,7 @@ void QmlGraphicsPathViewPrivate::snapToCurrent()
itemIndex += pathOffset;
itemIndex %= items.count();
- qreal targetOffset = fmod(100 + (snapPos*100) - 100.0 * itemIndex / items.count(), qreal(100.0));
+ qreal targetOffset = qmlMod(100 + (snapPos*100) - 100.0 * itemIndex / items.count(), qreal(100.0));
if (targetOffset < 0)
targetOffset = 100.0 + targetOffset;
diff --git a/src/declarative/graphicsitems/qmlgraphicstext.cpp b/src/declarative/graphicsitems/qmlgraphicstext.cpp
index 84f925d..bfb928a 100644
--- a/src/declarative/graphicsitems/qmlgraphicstext.cpp
+++ b/src/declarative/graphicsitems/qmlgraphicstext.cpp
@@ -368,7 +368,7 @@ void QmlGraphicsText::setWrap(bool w)
will automatically determine whether the text should be treated as
rich text. This determination is made using Qt::mightBeRichText().
- StyledText is an optimized format able supporting some basic text
+ StyledText is an optimized format supporting some basic text
styling markup, in the style of html 3.2:
\code
@@ -379,6 +379,8 @@ void QmlGraphicsText::setWrap(bool w)
&gt; &lt; &amp;
\endcode
+ \c StyledText parser is strict, requiring tags to be correctly nested.
+
\table
\row
\o
diff --git a/src/declarative/qml/qmlworkerscript.cpp b/src/declarative/qml/qmlworkerscript.cpp
index a0d6ef0..75c5179 100644
--- a/src/declarative/qml/qmlworkerscript.cpp
+++ b/src/declarative/qml/qmlworkerscript.cpp
@@ -51,6 +51,9 @@
#include <QtCore/qwaitcondition.h>
#include <QtScript/qscriptvalueiterator.h>
#include <QtCore/qfile.h>
+#include <QtDeclarative/qmlinfo.h>
+
+QT_BEGIN_NAMESPACE
class WorkerDataEvent : public QEvent
{
@@ -144,6 +147,82 @@ private:
void processLoad(int, const QUrl &);
};
+// Currently this will leak as no-one releases it in the worker thread
+class QmlWorkerListModelAgent : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int count READ count);
+
+public:
+ QmlWorkerListModelAgent(QmlWorkerListModel *);
+ ~QmlWorkerListModelAgent();
+
+ void addref();
+ void release();
+
+ int count() const;
+
+ Q_INVOKABLE void clear();
+ Q_INVOKABLE void remove(int index);
+ Q_INVOKABLE void append(const QScriptValue &);
+ Q_INVOKABLE void insert(int index, const QScriptValue&);
+ Q_INVOKABLE QScriptValue get(int index) const;
+ Q_INVOKABLE void set(int index, const QScriptValue &);
+ Q_INVOKABLE void sync();
+
+ struct VariantRef
+ {
+ VariantRef() : a(0) {}
+ VariantRef(const VariantRef &r) : a(r.a) { if (a) a->addref(); }
+ VariantRef(QmlWorkerListModelAgent *_a) : a(_a) { if (a) a->addref(); }
+ ~VariantRef() { if (a) a->release(); }
+
+ VariantRef &operator=(const VariantRef &o) {
+ if (o.a) o.a->addref();
+ if (a) a->release(); a = o.a;
+ return *this;
+ }
+
+ QmlWorkerListModelAgent *a;
+ };
+protected:
+ virtual bool event(QEvent *);
+
+private:
+ friend class QmlWorkerScriptEnginePrivate;
+ friend class QmlWorkerListModel;
+ QScriptEngine *m_engine;
+
+ struct Change {
+ enum { Inserted, Removed, Moved, Changed } type;
+ int index; // Inserted/Removed/Moved/Changed
+ int count; // Inserted/Removed/Moved/Changed
+ int to; // Moved
+ };
+
+ struct Data {
+ QHash<int, QString> roles;
+ QHash<QString, int> strings;
+ QList<QHash<int, QVariant> > values;
+ QList<Change> changes;
+
+ void clearChange();
+ void insertChange(int index, int count);
+ void removeChange(int index, int count);
+ void changedChange(int index, int count);
+ };
+ Data data;
+
+ struct Sync : public QEvent {
+ Sync() : QEvent(QEvent::User) {}
+ Data data;
+ };
+
+ QAtomicInt m_ref;
+ QmlWorkerListModel *m_model;
+};
+Q_DECLARE_METATYPE(QmlWorkerListModelAgent::VariantRef);
+
QmlWorkerScriptEnginePrivate::QmlWorkerScriptEnginePrivate()
: workerEngine(0), m_nextId(0)
{
@@ -285,6 +364,15 @@ QVariant QmlWorkerScriptEnginePrivate::scriptValueToVariant(const QScriptValue &
}
return QVariant(list);
+ } else if (value.isQObject()) {
+ QmlWorkerListModel *lm = qobject_cast<QmlWorkerListModel *>(value.toQObject());
+ if (lm) {
+ QmlWorkerListModelAgent::VariantRef v(lm->agent());
+ return qVariantFromValue(v);
+ } else {
+ // No other QObject's are allowed to be sent
+ return QVariant();
+ }
} else if (value.isObject()) {
QVariantHash hash;
@@ -310,6 +398,15 @@ QScriptValue QmlWorkerScriptEnginePrivate::variantToScriptValue(const QVariant &
return QScriptValue(value.toString());
} else if (value.userType() == QMetaType::QReal) {
return QScriptValue(value.toReal());
+ } else if (value.userType() == qMetaTypeId<QmlWorkerListModelAgent::VariantRef>()) {
+ QmlWorkerListModelAgent::VariantRef vr = qvariant_cast<QmlWorkerListModelAgent::VariantRef>(value);
+ if (vr.a->m_engine == 0)
+ vr.a->m_engine = engine;
+ else if (vr.a->m_engine != engine)
+ return engine->nullValue();
+ QScriptValue o = engine->newQObject(vr.a);
+ o.setData(engine->newVariant(value)); // Keeps the agent ref so that it is cleaned up on gc
+ return o;
} else if (value.userType() == QMetaType::QVariantList) {
QVariantList list = qvariant_cast<QVariantList>(value);
QScriptValue rv = engine->newArray(list.count());
@@ -513,5 +610,411 @@ bool QmlWorkerScript::event(QEvent *event)
}
}
-
QML_DEFINE_TYPE(Qt, 4, 6, WorkerScript, QmlWorkerScript);
+
+void QmlWorkerListModelAgent::Data::clearChange()
+{
+ changes.clear();
+}
+
+void QmlWorkerListModelAgent::Data::insertChange(int index, int count)
+{
+ Change c = { Change::Inserted, index, count, 0 };
+ changes << c;
+}
+
+void QmlWorkerListModelAgent::Data::removeChange(int index, int count)
+{
+ Change c = { Change::Removed, index, count, 0 };
+ changes << c;
+}
+
+void QmlWorkerListModelAgent::Data::changedChange(int index, int count)
+{
+ Change c = { Change::Changed, index, count, 0 };
+ changes << c;
+}
+
+QmlWorkerListModelAgent::QmlWorkerListModelAgent(QmlWorkerListModel *m)
+: m_engine(0), m_ref(1), m_model(m)
+{
+ data.roles = m_model->m_roles;
+ data.strings = m_model->m_strings;
+ data.values = m_model->m_values;
+}
+
+QmlWorkerListModelAgent::~QmlWorkerListModelAgent()
+{
+}
+
+void QmlWorkerListModelAgent::addref()
+{
+ m_ref.ref();
+}
+
+void QmlWorkerListModelAgent::release()
+{
+ bool del = !m_ref.deref();
+
+ if (del)
+ delete this;
+}
+
+int QmlWorkerListModelAgent::count() const
+{
+ return data.values.count();
+}
+
+void QmlWorkerListModelAgent::clear()
+{
+ data.clearChange();
+ data.removeChange(0, data.values.count());
+ data.values.clear();
+}
+
+void QmlWorkerListModelAgent::remove(int index)
+{
+ if (data.values.count() <= index)
+ return;
+
+ data.values.removeAt(index);
+ data.removeChange(index, 1);
+}
+
+void QmlWorkerListModelAgent::append(const QScriptValue &value)
+{
+ QHash<int, QVariant> row;
+
+ QScriptValueIterator it(value);
+ while (it.hasNext()) {
+ it.next();
+ QString name = it.name();
+ QVariant v = it.value().toVariant();
+
+ QHash<QString, int>::Iterator iter = data.strings.find(name);
+ if (iter == data.strings.end()) {
+ int role = data.roles.count();
+ data.roles.insert(role, name);
+ iter = data.strings.insert(name, role);
+ }
+ row.insert(*iter, v);
+ }
+
+ data.values.append(row);
+ data.insertChange(data.values.count() - 1, 1);
+}
+
+void QmlWorkerListModelAgent::insert(int index, const QScriptValue &value)
+{
+ if (index > data.values.count())
+ return;
+
+ QHash<int, QVariant> row;
+
+ QScriptValueIterator it(value);
+ while (it.hasNext()) {
+ it.next();
+ QString name = it.name();
+ QVariant v = it.value().toVariant();
+
+ QHash<QString, int>::Iterator iter = data.strings.find(name);
+ if (iter == data.strings.end()) {
+ int role = data.roles.count();
+ data.roles.insert(role, name);
+ iter = data.strings.insert(name, role);
+ }
+ row.insert(*iter, v);
+ }
+
+ data.values.insert(index, row);
+ data.insertChange(index, 1);
+}
+
+void QmlWorkerListModelAgent::set(int index, const QScriptValue &value)
+{
+ if (data.values.count() <= index)
+ return;
+
+ QHash<int, QVariant> row;
+
+ QScriptValueIterator it(value);
+ while (it.hasNext()) {
+ it.next();
+ QString name = it.name();
+ QVariant v = it.value().toVariant();
+
+ QHash<QString, int>::Iterator iter = data.strings.find(name);
+ if (iter == data.strings.end()) {
+ int role = data.roles.count();
+ data.roles.insert(role, name);
+ iter = data.strings.insert(name, role);
+ }
+ row.insert(*iter, v);
+ }
+
+ if (data.values.at(index) != row) {
+ data.values[index] = row;
+ data.changedChange(index, 1);
+ }
+}
+
+QScriptValue QmlWorkerListModelAgent::get(int index) const
+{
+ if (data.values.count() <= index)
+ return m_engine->undefinedValue();
+
+ QScriptValue rv = m_engine->newObject();
+
+ QHash<int, QVariant> row = data.values.at(index);
+ for (QHash<int, QVariant>::ConstIterator iter = row.begin(); iter != row.end(); ++iter)
+ rv.setProperty(data.roles.value(iter.key()), qScriptValueFromValue(m_engine, iter.value()));
+
+ return rv;
+}
+
+void QmlWorkerListModelAgent::sync()
+{
+ Sync *s = new Sync;
+ s->data = data;
+ data.changes.clear();
+ QCoreApplication::postEvent(this, s);
+}
+
+bool QmlWorkerListModelAgent::event(QEvent *e)
+{
+ if (e->type() == QEvent::User) {
+ Sync *s = static_cast<Sync *>(e);
+
+ const QList<Change> &changes = s->data.changes;
+
+ if (m_model) {
+ bool cc = m_model->m_values.count() != s->data.values.count();
+
+ m_model->m_roles = s->data.roles;
+ m_model->m_strings = s->data.strings;
+ m_model->m_values = s->data.values;
+
+ for (int ii = 0; ii < changes.count(); ++ii) {
+ const Change &change = changes.at(ii);
+ switch (change.type) {
+ case Change::Inserted:
+ emit m_model->itemsInserted(change.index, change.count);
+ break;
+ case Change::Removed:
+ emit m_model->itemsRemoved(change.index, change.count);
+ break;
+ case Change::Moved:
+ emit m_model->itemsMoved(change.index, change.to, change.count);
+ break;
+ case Change::Changed:
+ emit m_model->itemsMoved(change.index, change.to, change.count);
+ break;
+ }
+ }
+
+ if (cc)
+ emit m_model->countChanged();
+ }
+ }
+
+ return QObject::event(e);
+}
+
+QmlWorkerListModel::QmlWorkerListModel(QObject *parent)
+: QListModelInterface(parent), m_agent(0)
+{
+}
+
+QmlWorkerListModel::~QmlWorkerListModel()
+{
+ if (m_agent) {
+ m_agent->m_model = 0;
+ m_agent->release();
+ }
+}
+
+void QmlWorkerListModel::clear()
+{
+ if (m_agent) {
+ qmlInfo(this) << "List can only be modified from a WorkerScript";
+ return;
+ }
+
+ int count = m_values.count();
+ m_values.clear();
+ if (count) {
+ emit itemsRemoved(0, count);
+ emit countChanged();
+ }
+}
+
+void QmlWorkerListModel::remove(int index)
+{
+ if (m_agent) {
+ qmlInfo(this) << "List can only be modified from a WorkerScript";
+ return;
+ }
+
+ if (m_values.count() <= index)
+ return;
+
+ m_values.removeAt(index);
+ emit itemsRemoved(index, 1);
+ emit countChanged();
+}
+
+void QmlWorkerListModel::append(const QScriptValue &value)
+{
+ if (m_agent) {
+ qmlInfo(this) << "List can only be modified from a WorkerScript";
+ return;
+ }
+
+ QHash<int, QVariant> data;
+
+ QScriptValueIterator it(value);
+ while (it.hasNext()) {
+ it.next();
+ QString name = it.name();
+ QVariant v = it.value().toVariant();
+
+ QHash<QString, int>::Iterator iter = m_strings.find(name);
+ if (iter == m_strings.end()) {
+ int role = m_roles.count();
+ m_roles.insert(role, name);
+ iter = m_strings.insert(name, role);
+ }
+ data.insert(*iter, v);
+ }
+
+ m_values.append(data);
+
+ emit itemsInserted(m_values.count() - 1, 1);
+ emit countChanged();
+}
+
+void QmlWorkerListModel::insert(int index, const QScriptValue &value)
+{
+ if (m_agent) {
+ qmlInfo(this) << "List can only be modified from a WorkerScript";
+ return;
+ }
+
+ if (index > m_values.count())
+ return;
+
+ QHash<int, QVariant> data;
+
+ QScriptValueIterator it(value);
+ while (it.hasNext()) {
+ it.next();
+ QString name = it.name();
+ QVariant v = it.value().toVariant();
+
+ QHash<QString, int>::Iterator iter = m_strings.find(name);
+ if (iter == m_strings.end()) {
+ int role = m_roles.count();
+ m_roles.insert(role, name);
+ iter = m_strings.insert(name, role);
+ }
+ data.insert(*iter, v);
+ }
+
+ m_values.insert(index, data);
+ emit itemsInserted(index, 1);
+ emit countChanged();
+}
+
+QScriptValue QmlWorkerListModel::get(int index) const
+{
+ QmlEngine *engine = qmlEngine(this);
+ if (!engine || m_values.count() <= index)
+ return QScriptValue();
+
+ QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine);
+ QScriptValue rv = scriptEngine->newObject();
+
+ QHash<int, QVariant> data = m_values.at(index);
+ for (QHash<int, QVariant>::ConstIterator iter = data.begin(); iter != data.end(); ++iter)
+ rv.setProperty(m_roles.value(iter.key()), qScriptValueFromValue(scriptEngine, iter.value()));
+
+ return rv;
+}
+
+void QmlWorkerListModel::set(int index, const QScriptValue &value)
+{
+ if (m_agent) {
+ qmlInfo(this) << "List can only be modified from a WorkerScript";
+ return;
+ }
+
+ if (m_values.count() <= index)
+ return;
+
+ QHash<int, QVariant> data;
+
+ QScriptValueIterator it(value);
+ while (it.hasNext()) {
+ it.next();
+ QString name = it.name();
+ QVariant v = it.value().toVariant();
+
+ QHash<QString, int>::Iterator iter = m_strings.find(name);
+ if (iter == m_strings.end()) {
+ int role = m_roles.count();
+ m_roles.insert(role, name);
+ iter = m_strings.insert(name, role);
+ }
+ data.insert(*iter, v);
+ }
+
+ if (m_values.at(index) != data) {
+ m_values[index] = data;
+ emit itemsChanged(index, 1, m_roles.keys());
+ }
+}
+
+QmlWorkerListModelAgent *QmlWorkerListModel::agent()
+{
+ if (!m_agent)
+ m_agent = new QmlWorkerListModelAgent(this);
+
+ return m_agent;
+}
+
+QList<int> QmlWorkerListModel::roles() const
+{
+ return m_roles.keys();
+}
+
+QString QmlWorkerListModel::toString(int role) const
+{
+ return m_roles.value(role);
+}
+
+int QmlWorkerListModel::count() const
+{
+ return m_values.count();
+}
+
+QHash<int,QVariant> QmlWorkerListModel::data(int index, const QList<int> &) const
+{
+ if (m_values.count() <= index)
+ return QHash<int, QVariant>();
+ else
+ return m_values.at(index);
+}
+
+QVariant QmlWorkerListModel::data(int index, int role) const
+{
+ if (m_values.count() <= index)
+ return QVariant();
+ else
+ return m_values.at(index).value(role);
+}
+
+QML_DEFINE_TYPE(Qt,4,6,WorkerListModel,QmlWorkerListModel)
+
+#include "qmlworkerscript.moc"
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmlworkerscript_p.h b/src/declarative/qml/qmlworkerscript_p.h
index 1ec7af3..1c70f2d 100644
--- a/src/declarative/qml/qmlworkerscript_p.h
+++ b/src/declarative/qml/qmlworkerscript_p.h
@@ -55,11 +55,14 @@
#include "qml.h"
#include "qmlparserstatus.h"
+#include <private/qlistmodelinterface_p.h>
#include <QtCore/qthread.h>
#include <QtScript/qscriptvalue.h>
#include <QtCore/qurl.h>
+QT_BEGIN_NAMESPACE
+
class QmlWorkerScript;
class QmlWorkerScriptEnginePrivate;
class QmlWorkerScriptEngine : public QThread
@@ -110,6 +113,48 @@ private:
int m_scriptId;
QUrl m_source;
};
+
+class QmlWorkerListModelAgent;
+class QmlWorkerListModel : public QListModelInterface
+{
+ Q_OBJECT
+ Q_PROPERTY(int count READ count NOTIFY countChanged);
+
+public:
+ QmlWorkerListModel(QObject * = 0);
+ virtual ~QmlWorkerListModel();
+
+ Q_INVOKABLE void clear();
+ Q_INVOKABLE void remove(int index);
+ Q_INVOKABLE void append(const QScriptValue &);
+ Q_INVOKABLE void insert(int index, const QScriptValue&);
+ Q_INVOKABLE QScriptValue get(int index) const;
+ Q_INVOKABLE void set(int index, const QScriptValue &);
+
+ QmlWorkerListModelAgent *agent();
+
+ virtual QList<int> roles() const;
+ virtual QString toString(int role) const;
+ virtual int count() const;
+ virtual QHash<int,QVariant> data(int index, const QList<int> &roles = (QList<int>())) const;
+ virtual QVariant data(int index, int role) const;
+
+Q_SIGNALS:
+ void countChanged();
+
+private:
+ friend class QmlWorkerListModelAgent;
+
+ QHash<int, QString> m_roles;
+ QHash<QString, int> m_strings;
+ QList<QHash<int, QVariant> > m_values;
+
+ QmlWorkerListModelAgent *m_agent;
+};
+
+QT_END_NAMESPACE
+
QML_DECLARE_TYPE(QmlWorkerScript);
+QML_DECLARE_TYPE(QmlWorkerListModel);
#endif // QMLWORKERSCRIPT_P_H
diff --git a/src/declarative/util/qmllistmodel.cpp b/src/declarative/util/qmllistmodel.cpp
index de6ee2e..cd4a120 100644
--- a/src/declarative/util/qmllistmodel.cpp
+++ b/src/declarative/util/qmllistmodel.cpp
@@ -265,6 +265,7 @@ struct ModelNode
QmlListModel *modelCache;
ModelObject *objectCache;
+ bool isArray;
};
QT_END_NAMESPACE
@@ -280,6 +281,7 @@ void ModelNode::setObjectValue(const QScriptValue& valuemap) {
ModelNode *value = new ModelNode;
QScriptValue v = it.value();
if (v.isArray()) {
+ value->isArray = true;
value->setListValue(v);
} else {
value->values << v.toVariant();
@@ -296,6 +298,7 @@ void ModelNode::setListValue(const QScriptValue& valuelist) {
ModelNode *value = new ModelNode;
QScriptValue v = it.value();
if (v.isArray()) {
+ value->isArray = true;
value->setListValue(v);
} else if (v.isObject()) {
value->setObjectValue(v);
@@ -367,27 +370,29 @@ QVariant QmlListModel::valueForNode(ModelNode *node) const
{
QObject *rv = 0;
- if (!node->properties.isEmpty()) {
- // Object
- rv = node->object(this);
- } else if (node->values.count() == 0) {
- // Invalid
- return QVariant();
- } else if (node->values.count() == 1) {
- // Value
- QVariant &var = node->values[0];
- ModelNode *valueNode = qvariant_cast<ModelNode *>(var);
- if (valueNode) {
- if (!valueNode->properties.isEmpty())
- rv = valueNode->object(this);
- else
- rv = valueNode->model(this);
- } else {
- return var;
- }
- } else if (node->values.count() > 1) {
+ if (node->isArray) {
// List
rv = node->model(this);
+ } else {
+ if (!node->properties.isEmpty()) {
+ // Object
+ rv = node->object(this);
+ } else if (node->values.count() == 0) {
+ // Invalid
+ return QVariant();
+ } else if (node->values.count() == 1) {
+ // Value
+ QVariant &var = node->values[0];
+ ModelNode *valueNode = qvariant_cast<ModelNode *>(var);
+ if (valueNode) {
+ if (!valueNode->properties.isEmpty())
+ rv = valueNode->object(this);
+ else
+ rv = valueNode->model(this);
+ } else {
+ return var;
+ }
+ }
}
if (rv)
@@ -933,7 +938,7 @@ static void dump(ModelNode *node, int ind)
}
ModelNode::ModelNode()
-: modelCache(0), objectCache(0)
+: modelCache(0), objectCache(0), isArray(false)
{
}
diff --git a/tests/auto/declarative/qmllistmodel/tst_qmllistmodel.cpp b/tests/auto/declarative/qmllistmodel/tst_qmllistmodel.cpp
index 0986d20..b43b699 100644
--- a/tests/auto/declarative/qmllistmodel/tst_qmllistmodel.cpp
+++ b/tests/auto/declarative/qmllistmodel/tst_qmllistmodel.cpp
@@ -150,7 +150,12 @@ void tst_QmlListModel::dynamic_data()
QTest::newRow("listprop1a") << "{append({'foo':123,'bars':[{'a':1},{'a':2},{'a':3}]});count}" << 1 << "";
QTest::newRow("listprop1b") << "{append({'foo':123,'bars':[{'a':1},{'a':2},{'a':3}]});get(0).bars.get(1).a}" << 2 << "";
+ QTest::newRow("listprop1c") << "{append({'foo':123,'bars':[{'a':1},{'a':2},{'a':3}]});get(0).bars.count}" << 3 << "";
QTest::newRow("listprop2a") << "{append({'foo':123,'bars':[{'a':1},{'a':2},{'a':3}]});get(0).bars.append({'a':4});get(0).bars.get(3).a}" << 4 << "";
+
+ QTest::newRow("list-0-items") << "{append({'foo':[]});get(0).foo.count}" << 0 << "";
+ QTest::newRow("list-1-item") << "{append({'foo':[1]});get(0).foo.count}" << 1 << "";
+ QTest::newRow("list-multi-items") << "{append({'foo':[1,2,3]});get(0).foo.count}" << 3 << "";
}
void tst_QmlListModel::dynamic()
diff --git a/tools/qmlviewer/main.cpp b/tools/qmlviewer/main.cpp
index f11c7c9..b7a3f1a 100644
--- a/tools/qmlviewer/main.cpp
+++ b/tools/qmlviewer/main.cpp
@@ -83,6 +83,7 @@ void usage()
qWarning(" -skin <qvfbskindir> ...................... run with a skin window frame");
qWarning(" \"list\" for a list of built-ins");
qWarning(" -resizeview .............................. resize the view, not the skin");
+ qWarning(" -qmlbrowser .............................. use a QML-based file browser");
qWarning(" -recordfile <output> ..................... set video recording file");
qWarning(" - ImageMagick 'convert' for GIF)");
qWarning(" - png file for raw frames");
@@ -222,6 +223,8 @@ int main(int argc, char ** argv)
translationFile = argv[++i];
} else if (arg == "-opengl") {
useGL = true;
+ } else if (arg == "-qmlbrowser") {
+ useNativeFileBrowser = false;
} else if (arg == "-L") {
if (lastArg) usage();
libraries << QString(argv[++i]);