diff options
Diffstat (limited to 'src/qml/types')
-rw-r--r-- | src/qml/types/qqmldelegatemodel.cpp | 192 | ||||
-rw-r--r-- | src/qml/types/qqmldelegatemodel_p.h | 8 | ||||
-rw-r--r-- | src/qml/types/qqmldelegatemodel_p_p.h | 16 | ||||
-rw-r--r-- | src/qml/types/qqmllistmodel.cpp | 151 | ||||
-rw-r--r-- | src/qml/types/qqmllistmodel_p.h | 4 | ||||
-rw-r--r-- | src/qml/types/qqmllistmodel_p_p.h | 35 | ||||
-rw-r--r-- | src/qml/types/qqmllistmodelworkeragent_p.h | 2 | ||||
-rw-r--r-- | src/qml/types/qqmlmodelsmodule.cpp | 5 | ||||
-rw-r--r-- | src/qml/types/qqmltimer_p.h | 2 | ||||
-rw-r--r-- | src/qml/types/qquickworkerscript.cpp | 12 | ||||
-rw-r--r-- | src/qml/types/types.pri | 18 |
11 files changed, 348 insertions, 97 deletions
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index 7a12813f0c..62ccf0d66c 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -93,7 +93,7 @@ struct DelegateModelGroupFunction : QV4::FunctionObject static Heap::DelegateModelGroupFunction *create(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg)) { - return scope->engine()->memoryManager->allocObject<DelegateModelGroupFunction>(scope, flag, code); + return scope->engine()->memoryManager->allocate<DelegateModelGroupFunction>(scope, flag, code); } static ReturnedValue call(const QV4::FunctionObject *that, const Value *thisObject, const Value *argv, int argc) @@ -200,8 +200,7 @@ QQmlDelegateModelParts::QQmlDelegateModelParts(QQmlDelegateModel *parent) */ QQmlDelegateModelPrivate::QQmlDelegateModelPrivate(QQmlContext *ctxt) - : m_delegate(nullptr) - , m_cacheMetaType(nullptr) + : m_cacheMetaType(nullptr) , m_context(ctxt) , m_parts(nullptr) , m_filterGroup(QStringLiteral("items")) @@ -214,6 +213,7 @@ QQmlDelegateModelPrivate::QQmlDelegateModelPrivate(QQmlContext *ctxt) , m_transaction(false) , m_incubatorCleanupScheduled(false) , m_waitingToFetchMore(false) + , m_useFirstColumnOnly(true) , m_cacheItems(nullptr) , m_items(nullptr) , m_persistedItems(nullptr) @@ -228,6 +228,11 @@ QQmlDelegateModelPrivate::~QQmlDelegateModelPrivate() m_cacheMetaType->release(); } +int QQmlDelegateModelPrivate::adaptorModelCount() const +{ + return m_useFirstColumnOnly ? m_adaptorModel.rowCount() : m_adaptorModel.count(); +} + void QQmlDelegateModelPrivate::requestMoreIfNecessary() { Q_Q(QQmlDelegateModel); @@ -263,6 +268,7 @@ QQmlDelegateModel::QQmlDelegateModel(QQmlContext *ctxt, QObject *parent) QQmlDelegateModel::~QQmlDelegateModel() { Q_D(QQmlDelegateModel); + d->m_adaptorModel.setObject(nullptr, this); for (QQmlDelegateModelItem *cacheItem : qAsConst(d->m_cache)) { if (cacheItem->object) { @@ -336,7 +342,7 @@ void QQmlDelegateModel::componentComplete() static_cast<QQmlPartsModel *>(d->m_pendingParts.first())->updateFilterGroup(); QVector<Compositor::Insert> inserts; - d->m_count = d->m_adaptorModel.count(); + d->m_count = d->adaptorModelCount(); d->m_compositor.append( &d->m_adaptorModel, 0, @@ -383,7 +389,7 @@ void QQmlDelegateModel::setModel(const QVariant &model) } if (d->m_complete) { - _q_itemsInserted(0, d->m_adaptorModel.count()); + _q_itemsInserted(0, d->adaptorModelCount()); d->requestMoreIfNecessary(); } } @@ -409,7 +415,7 @@ void QQmlDelegateModel::setDelegate(QQmlComponent *delegate) return; } bool wasValid = d->m_delegate != nullptr; - d->m_delegate = delegate; + d->m_delegate.setObject(delegate, this); d->m_delegateValidated = false; if (wasValid && d->m_complete) { for (int i = 1; i < d->m_groupCount; ++i) { @@ -475,7 +481,7 @@ void QQmlDelegateModel::setRootIndex(const QVariant &root) if (d->m_adaptorModel.canFetchMore()) d->m_adaptorModel.fetchMore(); if (d->m_complete) { - const int newCount = d->m_adaptorModel.count(); + const int newCount = d->adaptorModelCount(); if (oldCount) _q_itemsRemoved(0, oldCount); if (newCount) @@ -487,6 +493,35 @@ void QQmlDelegateModel::setRootIndex(const QVariant &root) } /*! + \qmlproperty int QtQml.Models::DelegateModel::rows + + Contains the number of rows in the model. If the model + is a list of items, it will be equal to the number of items + in the list. + + \since QtQml.Models 2.12 +*/ +int QQmlDelegateModel::rows() const +{ + Q_D(const QQmlDelegateModel); + return d->m_adaptorModel.rowCount(); +} + +/*! + \qmlproperty int QtQml.Models::DelegateModel::columns + + Contains the number of columns in the model. If the model + is a list of items, it will be equal to \c 1. + + \since QtQml.Models 2.12 +*/ +int QQmlDelegateModel::columns() const +{ + Q_D(const QQmlDelegateModel); + return d->m_adaptorModel.columnCount(); +} + +/*! \qmlmethod QModelIndex QtQml.Models::DelegateModel::modelIndex(int index) QAbstractItemModel provides a hierarchical tree of data, whereas @@ -536,25 +571,24 @@ int QQmlDelegateModel::count() const QQmlDelegateModel::ReleaseFlags QQmlDelegateModelPrivate::release(QObject *object) { - QQmlDelegateModel::ReleaseFlags stat = nullptr; if (!object) - return stat; - - if (QQmlDelegateModelItem *cacheItem = QQmlDelegateModelItem::dataForObject(object)) { - if (cacheItem->releaseObject()) { - cacheItem->destroyObject(); - emitDestroyingItem(object); - if (cacheItem->incubationTask) { - releaseIncubator(cacheItem->incubationTask); - cacheItem->incubationTask = nullptr; - } - cacheItem->Dispose(); - stat |= QQmlInstanceModel::Destroyed; - } else { - stat |= QQmlDelegateModel::Referenced; - } + return QQmlDelegateModel::ReleaseFlags(0); + + QQmlDelegateModelItem *cacheItem = QQmlDelegateModelItem::dataForObject(object); + if (!cacheItem) + return QQmlDelegateModel::ReleaseFlags(0); + + if (!cacheItem->releaseObject()) + return QQmlDelegateModel::Referenced; + + cacheItem->destroyObject(); + emitDestroyingItem(object); + if (cacheItem->incubationTask) { + releaseIncubator(cacheItem->incubationTask); + cacheItem->incubationTask = nullptr; } - return stat; + cacheItem->Dispose(); + return QQmlInstanceModel::Destroyed; } /* @@ -862,6 +896,13 @@ void QQmlDelegateModelPrivate::releaseIncubator(QQDMIncubationTask *incubationTa } } +void QQmlDelegateModelPrivate::addCacheItem(QQmlDelegateModelItem *item, Compositor::iterator it) +{ + m_cache.insert(it.cacheIndex, item); + m_compositor.setFlags(it, 1, Compositor::CacheFlag); + Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache)); +} + void QQmlDelegateModelPrivate::removeCacheItem(QQmlDelegateModelItem *cacheItem) { int cidx = m_cache.lastIndexOf(cacheItem); @@ -951,10 +992,7 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ return nullptr; cacheItem->groups = it->flags; - - m_cache.insert(it.cacheIndex, cacheItem); - m_compositor.setFlags(it, 1, Compositor::CacheFlag); - Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache)); + addCacheItem(cacheItem, it); } // Bump the reference counts temporarily so neither the content data or the delegate object @@ -1046,7 +1084,10 @@ QQmlIncubator::Status QQmlDelegateModel::incubationStatus(int index) if (!it->inCache()) return QQmlIncubator::Null; - return d->m_cache.at(it.cacheIndex)->incubationTask->status(); + if (auto incubationTask = d->m_cache.at(it.cacheIndex)->incubationTask) + return incubationTask->status(); + + return QQmlIncubator::Ready; } QString QQmlDelegateModelPrivate::stringValue(Compositor::Group group, int index, const QString &name) @@ -1510,7 +1551,7 @@ void QQmlDelegateModel::_q_modelReset() d->m_adaptorModel.rootIndex = QModelIndex(); if (d->m_complete) { - d->m_count = d->m_adaptorModel.count(); + d->m_count = d->adaptorModelCount(); const QList<QQmlDelegateModelItem *> cache = d->m_cache; for (int i = 0, c = cache.count(); i < c; ++i) { @@ -1588,8 +1629,15 @@ void QQmlDelegateModel::_q_rowsMoved( void QQmlDelegateModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end, const QVector<int> &roles) { Q_D(QQmlDelegateModel); - if (begin.parent() == d->m_adaptorModel.rootIndex) - _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, roles); + if (begin.parent() != d->m_adaptorModel.rootIndex) + return; + + int rowCount = end.row() - begin.row() + 1; + + for (int col = begin.column(); col <= end.column(); ++col) { + int startIndex = d->m_adaptorModel.indexAt(begin.row(), col); + _q_itemsChanged(startIndex, rowCount, roles); + } } bool QQmlDelegateModel::isDescendantOf(const QPersistentModelIndex& desc, const QList< QPersistentModelIndex >& parents) const @@ -1918,6 +1966,8 @@ QQmlDelegateModelItem::QQmlDelegateModelItem( , scriptRef(0) , groups(0) , index(modelIndex) + , row(QQmlDelegateModelPrivate::get(metaType->model)->m_adaptorModel.rowAt(modelIndex)) + , column(QQmlDelegateModelPrivate::get(metaType->model)->m_adaptorModel.columnAt(modelIndex)) { metaType->addref(); } @@ -1952,6 +2002,27 @@ void QQmlDelegateModelItem::Dispose() delete this; } +void QQmlDelegateModelItem::setModelIndex(int idx) +{ + if (idx == index) + return; + + const int prevRow = row; + const int prevColumn = column; + const QQmlAdaptorModel &adaptorModel = QQmlDelegateModelPrivate::get(metaType->model)->m_adaptorModel; + + index = idx; + row = adaptorModel.rowAt(idx); + column = adaptorModel.columnAt(idx); + + Q_EMIT modelIndexChanged(); + + if (row != prevRow) + emit rowChanged(); + if (column != prevColumn) + emit columnChanged(); +} + void QQmlDelegateModelItem::destroyObject() { Q_ASSERT(object); @@ -2080,22 +2151,29 @@ QQmlDelegateModelAttached::QQmlDelegateModelAttached( , m_previousGroups(cacheItem->groups) { QQml_setParent_noEvent(this, parent); + resetCurrentIndex(); + // Let m_previousIndex be equal to m_currentIndex + std::copy(std::begin(m_currentIndex), std::end(m_currentIndex), std::begin(m_previousIndex)); + + if (!cacheItem->metaType->metaObject) + cacheItem->metaType->initializeMetaObject(); + + QObjectPrivate::get(this)->metaObject = cacheItem->metaType->metaObject; + cacheItem->metaType->metaObject->addref(); +} + +void QQmlDelegateModelAttached::resetCurrentIndex() +{ if (QQDMIncubationTask *incubationTask = m_cacheItem->incubationTask) { for (int i = 1; i < qMin<int>(m_cacheItem->metaType->groupCount, Compositor::MaximumGroupCount); ++i) - m_currentIndex[i] = m_previousIndex[i] = incubationTask->index[i]; + m_currentIndex[i] = incubationTask->index[i]; } else { QQmlDelegateModelPrivate * const model = QQmlDelegateModelPrivate::get(m_cacheItem->metaType->model); Compositor::iterator it = model->m_compositor.find( Compositor::Cache, model->m_cache.indexOf(m_cacheItem)); for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) - m_currentIndex[i] = m_previousIndex[i] = it.index[i]; + m_currentIndex[i] = it.index[i]; } - - if (!cacheItem->metaType->metaObject) - cacheItem->metaType->initializeMetaObject(); - - QObjectPrivate::get(this)->metaObject = cacheItem->metaType->metaObject; - cacheItem->metaType->metaObject->addref(); } /*! @@ -2483,7 +2561,7 @@ QQmlV4Handle QQmlDelegateModelGroup::get(int index) model->m_cacheMetaType->initializePrototype(); QV4::ExecutionEngine *v4 = model->m_cacheMetaType->v4Engine; QV4::Scope scope(v4); - QV4::ScopedObject o(scope, v4->memoryManager->allocObject<QQmlDelegateModelItemObject>(cacheItem)); + QV4::ScopedObject o(scope, v4->memoryManager->allocate<QQmlDelegateModelItemObject>(cacheItem)); QV4::ScopedObject p(scope, model->m_cacheMetaType->modelItemProto.value()); o->setPrototype(p); ++cacheItem->scriptRef; @@ -3194,7 +3272,10 @@ QQmlIncubator::Status QQmlPartsModel::incubationStatus(int index) if (!it->inCache()) return QQmlIncubator::Null; - return model->m_cache.at(it.cacheIndex)->incubationTask->status(); + if (auto incubationTask = model->m_cache.at(it.cacheIndex)->incubationTask) + return incubationTask->status(); + + return QQmlIncubator::Ready; } int QQmlPartsModel::indexOf(QObject *item, QObject *) const @@ -3214,7 +3295,10 @@ void QQmlPartsModel::createdPackage(int index, QQuickPackage *package) void QQmlPartsModel::initPackage(int index, QQuickPackage *package) { - emit initItem(index, package->part(m_part)); + if (m_modelUpdatePending) + m_pendingPackageInitializations << index; + else + emit initItem(index, package->part(m_part)); } void QQmlPartsModel::destroyingPackage(QQuickPackage *package) @@ -3226,9 +3310,22 @@ void QQmlPartsModel::destroyingPackage(QQuickPackage *package) void QQmlPartsModel::emitModelUpdated(const QQmlChangeSet &changeSet, bool reset) { + m_modelUpdatePending = false; emit modelUpdated(changeSet, reset); if (changeSet.difference() != 0) emit countChanged(); + + QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_model); + QVector<int> pendingPackageInitializations; + qSwap(pendingPackageInitializations, m_pendingPackageInitializations); + for (int index : pendingPackageInitializations) { + if (!model->m_delegate || index < 0 || index >= model->m_compositor.count(m_compositorGroup)) + continue; + QObject *object = model->object(m_compositorGroup, index, QQmlIncubator::Asynchronous); + if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object)) + emit initItem(index, package->part(m_part)); + model->release(object); + } } //============================================================================ @@ -3238,7 +3335,7 @@ struct QQmlDelegateModelGroupChange : QV4::Object V4_OBJECT2(QQmlDelegateModelGroupChange, QV4::Object) static QV4::Heap::QQmlDelegateModelGroupChange *create(QV4::ExecutionEngine *e) { - return e->memoryManager->allocObject<QQmlDelegateModelGroupChange>(); + return e->memoryManager->allocate<QQmlDelegateModelGroupChange>(); } static QV4::ReturnedValue method_get_index(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) { @@ -3275,7 +3372,7 @@ struct QQmlDelegateModelGroupChangeArray : public QV4::Object public: static QV4::Heap::QQmlDelegateModelGroupChangeArray *create(QV4::ExecutionEngine *engine, const QVector<QQmlChangeSet::Change> &changes) { - return engine->memoryManager->allocObject<QQmlDelegateModelGroupChangeArray>(changes); + return engine->memoryManager->allocate<QQmlDelegateModelGroupChangeArray>(changes); } quint32 count() const { return d()->changes->count(); } @@ -3306,12 +3403,13 @@ public: return object.asReturnedValue(); } - static QV4::ReturnedValue get(const QV4::Managed *m, QV4::String *name, bool *hasProperty) + static QV4::ReturnedValue get(const QV4::Managed *m, QV4::StringOrSymbol *name, bool *hasProperty) { Q_ASSERT(m->as<QQmlDelegateModelGroupChangeArray>()); const QQmlDelegateModelGroupChangeArray *array = static_cast<const QQmlDelegateModelGroupChangeArray *>(m); - if (name->equals(array->engine()->id_length())) { + name->makeIdentifier(); + if (name->identifier() == array->engine()->id_length()->identifier()) { if (hasProperty) *hasProperty = true; return QV4::Encode(array->count()); diff --git a/src/qml/types/qqmldelegatemodel_p.h b/src/qml/types/qqmldelegatemodel_p.h index b0786cd088..232a40798c 100644 --- a/src/qml/types/qqmldelegatemodel_p.h +++ b/src/qml/types/qqmldelegatemodel_p.h @@ -88,6 +88,8 @@ class Q_QML_PRIVATE_EXPORT QQmlDelegateModel : public QQmlInstanceModel, public Q_PROPERTY(QQmlListProperty<QQmlDelegateModelGroup> groups READ groups CONSTANT) Q_PROPERTY(QObject *parts READ parts CONSTANT) Q_PROPERTY(QVariant rootIndex READ rootIndex WRITE setRootIndex NOTIFY rootIndexChanged) + Q_PROPERTY(int rows READ rows NOTIFY rowsChanged REVISION 12) + Q_PROPERTY(int columns READ columns NOTIFY columnsChanged REVISION 12) Q_CLASSINFO("DefaultProperty", "delegate") Q_INTERFACES(QQmlParserStatus) public: @@ -107,6 +109,9 @@ public: QVariant rootIndex() const; void setRootIndex(const QVariant &root); + int rows() const; + int columns() const; + Q_INVOKABLE QVariant modelIndex(int idx) const; Q_INVOKABLE QVariant parentModelIndex() const; @@ -138,6 +143,8 @@ Q_SIGNALS: void filterGroupChanged(); void defaultGroupsChanged(); void rootIndexChanged(); + Q_REVISION(12) void rowsChanged(); + Q_REVISION(12) void columnsChanged(); private Q_SLOTS: void _q_itemsChanged(int index, int count, const QVector<int> &roles); @@ -212,6 +219,7 @@ public: QQmlDelegateModelAttached(QQmlDelegateModelItem *cacheItem, QObject *parent); ~QQmlDelegateModelAttached() {} + void resetCurrentIndex(); void setCacheItem(QQmlDelegateModelItem *item); QQmlDelegateModel *model() const; diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h index 18980cfd7c..a0c1f6aa12 100644 --- a/src/qml/types/qqmldelegatemodel_p_p.h +++ b/src/qml/types/qqmldelegatemodel_p_p.h @@ -95,6 +95,8 @@ class QQmlDelegateModelItem : public QObject { Q_OBJECT Q_PROPERTY(int index READ modelIndex NOTIFY modelIndexChanged) + Q_PROPERTY(int row MEMBER row NOTIFY rowChanged) + Q_PROPERTY(int column MEMBER column NOTIFY columnChanged) Q_PROPERTY(QObject *model READ modelObject CONSTANT) public: QQmlDelegateModelItem(QQmlDelegateModelItemMetaType *metaType, int modelIndex); @@ -121,7 +123,7 @@ public: int groupIndex(Compositor::Group group); int modelIndex() const { return index; } - void setModelIndex(int idx) { index = idx; Q_EMIT modelIndexChanged(); } + virtual void setModelIndex(int idx); virtual QV4::ReturnedValue get() { return QV4::QObjectWrapper::wrap(v4, this); } @@ -148,9 +150,13 @@ public: Q_SIGNALS: void modelIndexChanged(); + void rowChanged(); + void columnChanged(); protected: void objectDestroyed(QObject *); + int row; + int column; }; namespace QV4 { @@ -269,6 +275,7 @@ public: Q_EMIT q_func()->initItem(incubationTask->index[m_compositorGroup], item); } void emitDestroyingPackage(QQuickPackage *package); void emitDestroyingItem(QObject *item) { Q_EMIT q_func()->destroyingItem(item); } + void addCacheItem(QQmlDelegateModelItem *item, Compositor::iterator it); void removeCacheItem(QQmlDelegateModelItem *cacheItem); void updateFilterGroup(); @@ -295,6 +302,8 @@ public: bool insert(Compositor::insert_iterator &before, const QV4::Value &object, int groups); + int adaptorModelCount() const; + static void group_append(QQmlListProperty<QQmlDelegateModelGroup> *property, QQmlDelegateModelGroup *group); static int group_count(QQmlListProperty<QQmlDelegateModelGroup> *property); static QQmlDelegateModelGroup *group_at(QQmlListProperty<QQmlDelegateModelGroup> *property, int index); @@ -305,7 +314,7 @@ public: QQmlAdaptorModel m_adaptorModel; QQmlListCompositor m_compositor; - QQmlComponent *m_delegate; + QQmlStrongJSQObjectReference<QQmlComponent> m_delegate; QQmlDelegateModelItemMetaType *m_cacheMetaType; QPointer<QQmlContext> m_context; QQmlDelegateModelParts *m_parts; @@ -327,6 +336,7 @@ public: bool m_transaction : 1; bool m_incubatorCleanupScheduled : 1; bool m_waitingToFetchMore : 1; + bool m_useFirstColumnOnly : 1; union { struct { @@ -378,8 +388,10 @@ private: QString m_part; QString m_filterGroup; QList<QByteArray> m_watchedRoles; + QVector<int> m_pendingPackageInitializations; // vector holds model indices Compositor::Group m_compositorGroup; bool m_inheritGroup; + bool m_modelUpdatePending = true; }; class QMetaPropertyBuilder; diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp index 830c2bef5a..0a9540bf4b 100644 --- a/src/qml/types/qqmllistmodel.cpp +++ b/src/qml/types/qqmllistmodel.cpp @@ -62,6 +62,8 @@ #include <QtCore/qdatetime.h> #include <QScopedValueRollback> +Q_DECLARE_METATYPE(const QV4::CompiledData::Binding*); + QT_BEGIN_NAMESPACE // Set to 1024 as a debugging aid - easier to distinguish uids from indices of elements/models. @@ -124,8 +126,8 @@ const ListLayout::Role &ListLayout::getRoleOrCreate(QV4::String *key, Role::Data const ListLayout::Role &ListLayout::createRole(const QString &key, ListLayout::Role::DataType type) { - const int dataSizes[] = { sizeof(QString), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QPointer<QObject>), sizeof(QVariantMap), sizeof(QDateTime), sizeof(QJSValue) }; - const int dataAlignments[] = { sizeof(QString), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QObject *), sizeof(QVariantMap), sizeof(QDateTime), sizeof(QJSValue) }; + const int dataSizes[] = { sizeof(StringOrTranslation), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QPointer<QObject>), sizeof(QVariantMap), sizeof(QDateTime), sizeof(QJSValue) }; + const int dataAlignments[] = { sizeof(StringOrTranslation), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QObject *), sizeof(QVariantMap), sizeof(QDateTime), sizeof(QJSValue) }; Role *r = new Role; r->name = key; @@ -227,6 +229,10 @@ const ListLayout::Role *ListLayout::getRoleOrCreate(const QString &key, const QV data.value<QJSValue>().isCallable()) { type = Role::Function; break; + } else if (data.userType() == qMetaTypeId<const QV4::CompiledData::Binding*>() + && data.value<const QV4::CompiledData::Binding*>()->containsTranslations()) { + type = Role::String; + break; } else { type = Role::List; break; @@ -261,6 +267,75 @@ const ListLayout::Role *ListLayout::getExistingRole(QV4::String *key) const return r; } +StringOrTranslation::StringOrTranslation(const QString &s) +{ + d.setFlag(); + setString(s); +} + +StringOrTranslation::StringOrTranslation(const QV4::CompiledData::Binding *binding) +{ + d.setFlag(); + clear(); + d = binding; +} + +StringOrTranslation::~StringOrTranslation() +{ + clear(); +} + +void StringOrTranslation::setString(const QString &s) +{ + d.setFlag(); + clear(); + QStringData *stringData = const_cast<QString &>(s).data_ptr(); + d = stringData; + if (stringData) + stringData->ref.ref(); +} + +void StringOrTranslation::setTranslation(const QV4::CompiledData::Binding *binding) +{ + d.setFlag(); + clear(); + d = binding; +} + +QString StringOrTranslation::toString(const QQmlListModel *owner) const +{ + if (d.isNull()) + return QString(); + if (d.isT1()) { + QStringDataPtr holder = { d.asT1() }; + holder.ptr->ref.ref(); + return QString(holder); + } + if (!owner) + return QString(); + return d.asT2()->valueAsString(owner->m_compilationUnit->data); +} + +QString StringOrTranslation::asString() const +{ + if (d.isNull()) + return QString(); + if (!d.isT1()) + return QString(); + QStringDataPtr holder = { d.asT1() }; + holder.ptr->ref.ref(); + return QString(holder); +} + +void StringOrTranslation::clear() +{ + if (QStringData *strData = d.isT1() ? d.asT1() : nullptr) { + if (!strData->ref.deref()) + QStringData::deallocate(strData); + } + d = static_cast<QStringData *>(nullptr); +} + QObject *ListModel::getOrCreateModelObject(QQmlListModel *model, int elementIndex) { ListElement *e = elements[elementIndex]; @@ -717,11 +792,11 @@ ModelNodeMetaObject *ListElement::objectCache() return ModelNodeMetaObject::get(m_objectCache); } -QString *ListElement::getStringProperty(const ListLayout::Role &role) +StringOrTranslation *ListElement::getStringProperty(const ListLayout::Role &role) { char *mem = getPropertyMemory(role); - QString *s = reinterpret_cast<QString *>(mem); - return s->data_ptr() ? s : nullptr; + StringOrTranslation *s = reinterpret_cast<StringOrTranslation *>(mem); + return s; } QObject *ListElement::getQObjectProperty(const ListLayout::Role &role) @@ -806,9 +881,9 @@ QVariant ListElement::getProperty(const ListLayout::Role &role, const QQmlListMo break; case ListLayout::Role::String: { - QString *value = reinterpret_cast<QString *>(mem); - if (value->data_ptr() != nullptr) - data = *value; + StringOrTranslation *value = reinterpret_cast<StringOrTranslation *>(mem); + if (value->isSet()) + data = value->toString(owner); } break; case ListLayout::Role::Bool: @@ -878,15 +953,13 @@ int ListElement::setStringProperty(const ListLayout::Role &role, const QString & if (role.type == ListLayout::Role::String) { char *mem = getPropertyMemory(role); - QString *c = reinterpret_cast<QString *>(mem); + StringOrTranslation *c = reinterpret_cast<StringOrTranslation *>(mem); bool changed; - if (c->data_ptr() == nullptr) { - new (mem) QString(s); + if (!c->isSet() || c->isTranslation()) changed = true; - } else { - changed = c->compare(s) != 0; - *c = s; - } + else + changed = c->asString().compare(s) != 0; + c->setString(s); if (changed) roleIndex = role.index; } @@ -1048,11 +1121,25 @@ int ListElement::setFunctionProperty(const ListLayout::Role &role, const QJSValu return roleIndex; } +int ListElement::setTranslationProperty(const ListLayout::Role &role, const QV4::CompiledData::Binding *b) +{ + int roleIndex = -1; + + if (role.type == ListLayout::Role::String) { + char *mem = getPropertyMemory(role); + StringOrTranslation *s = reinterpret_cast<StringOrTranslation *>(mem); + s->setTranslation(b); + roleIndex = role.index; + } + + return roleIndex; +} + void ListElement::setStringPropertyFast(const ListLayout::Role &role, const QString &s) { char *mem = getPropertyMemory(role); - new (mem) QString(s); + new (mem) StringOrTranslation(s); } void ListElement::setDoublePropertyFast(const ListLayout::Role &role, double d) @@ -1219,9 +1306,9 @@ void ListElement::destroy(ListLayout *layout) switch (r.type) { case ListLayout::Role::String: { - QString *string = getStringProperty(r); + StringOrTranslation *string = getStringProperty(r); if (string) - string->~QString(); + string->~StringOrTranslation(); } break; case ListLayout::Role::List: @@ -1284,7 +1371,10 @@ int ListElement::setVariantProperty(const ListLayout::Role &role, const QVariant roleIndex = setDoubleProperty(role, d.toDouble()); break; case ListLayout::Role::String: - roleIndex = setStringProperty(role, d.toString()); + if (d.userType() == qMetaTypeId<const QV4::CompiledData::Binding *>()) + roleIndex = setTranslationProperty(role, d.value<const QV4::CompiledData::Binding*>()); + else + roleIndex = setStringProperty(role, d.toString()); break; case ListLayout::Role::Bool: roleIndex = setBoolProperty(role, d.toBool()); @@ -1446,7 +1536,7 @@ void ModelNodeMetaObject::propertyWritten(int index) return; QString propName = QString::fromUtf8(name(index)); - QVariant value = operator[](index); + const QVariant value = this->value(index); QV4::Scope scope(m_model->engine()); QV4::ScopedValue v(scope, scope.engine->fromVariant(value)); @@ -1474,8 +1564,12 @@ void ModelNodeMetaObject::emitDirectNotifies(const int *changedRoles, int roleCo namespace QV4 { -bool ModelObject::put(Managed *m, String *name, const Value &value) +bool ModelObject::put(Managed *m, StringOrSymbol *n, const Value &value) { + if (n->isSymbol()) + return Object::put(m, n, value); + String *name = static_cast<String *>(n); + ModelObject *that = static_cast<ModelObject*>(m); ExecutionEngine *eng = that->engine(); @@ -1491,8 +1585,12 @@ bool ModelObject::put(Managed *m, String *name, const Value &value) return true; } -ReturnedValue ModelObject::get(const Managed *m, String *name, bool *hasProperty) +ReturnedValue ModelObject::get(const Managed *m, StringOrSymbol *n, bool *hasProperty) { + if (n->isSymbol()) + return Object::get(m, n, hasProperty); + String *name = static_cast<String *>(n); + const ModelObject *that = static_cast<const ModelObject*>(m); const ListLayout::Role *role = that->d()->m_model->m_listModel->getExistingRole(name); if (!role) @@ -1809,6 +1907,7 @@ QQmlListModel::QQmlListModel(const QQmlListModel *owner, ListModel *data, QV4::E m_listModel = data; m_engine = engine; + m_compilationUnit = owner->m_compilationUnit; } QQmlListModel::QQmlListModel(QQmlListModel *orig, QQmlListModelWorkerAgent *agent) @@ -1828,6 +1927,7 @@ QQmlListModel::QQmlListModel(QQmlListModel *orig, QQmlListModelWorkerAgent *agen ListModel::sync(orig->m_listModel, m_listModel); m_engine = nullptr; + m_compilationUnit = orig->m_compilationUnit; } QQmlListModel::~QQmlListModel() @@ -2434,7 +2534,7 @@ QQmlV4Handle QQmlListModel::get(int index) const QObject *object = m_listModel->getOrCreateModelObject(const_cast<QQmlListModel *>(this), index); QQmlData *ddata = QQmlData::get(object); if (ddata->jsWrapper.isNullOrUndefined()) { - result = scope.engine->memoryManager->allocObject<QV4::ModelObject>(object, const_cast<QQmlListModel *>(this)); + result = scope.engine->memoryManager->allocate<QV4::ModelObject>(object, const_cast<QQmlListModel *>(this)); // Keep track of the QObjectWrapper in persistent value storage ddata->jsWrapper.set(scope.engine, result); } else { @@ -2631,7 +2731,9 @@ bool QQmlListModelParser::applyProperty(QV4::CompiledData::CompilationUnit *comp } else { QVariant value; - if (binding->evaluatesToString()) { + if (binding->containsTranslations()) { + value = QVariant::fromValue<const QV4::CompiledData::Binding*>(binding); + } else if (binding->evaluatesToString()) { value = binding->valueAsString(qmlUnit); } else if (binding->type == QV4::CompiledData::Binding::Type_Number) { value = binding->valueAsNumber(); @@ -2693,6 +2795,7 @@ void QQmlListModelParser::applyBindings(QObject *obj, QV4::CompiledData::Compila QQmlListModel *rv = static_cast<QQmlListModel *>(obj); rv->m_engine = qmlEngine(rv)->handle(); + rv->m_compilationUnit = compilationUnit; const QV4::CompiledData::Unit *qmlUnit = compilationUnit->data; diff --git a/src/qml/types/qqmllistmodel_p.h b/src/qml/types/qqmllistmodel_p.h index 0c0859dc80..56a1a95a02 100644 --- a/src/qml/types/qqmllistmodel_p.h +++ b/src/qml/types/qqmllistmodel_p.h @@ -64,6 +64,8 @@ #include <private/qv4engine_p.h> #include <private/qpodvector_p.h> +QT_REQUIRE_CONFIG(qml_list_model); + QT_BEGIN_NAMESPACE @@ -122,6 +124,7 @@ private: friend class ListElement; friend class DynamicRoleModelNode; friend class DynamicRoleModelNodeMetaObject; + friend struct StringOrTranslation; // Constructs a flat list model for a worker agent QQmlListModel(QQmlListModel *orig, QQmlListModelWorkerAgent *agent); @@ -133,6 +136,7 @@ private: QQmlListModelWorkerAgent *m_agent; mutable QV4::ExecutionEngine *m_engine; + QQmlRefPointer<QV4::CompiledData::CompilationUnit> m_compilationUnit; bool m_mainThread; bool m_primary; diff --git a/src/qml/types/qqmllistmodel_p_p.h b/src/qml/types/qqmllistmodel_p_p.h index ad5e94c909..75eeaeed0c 100644 --- a/src/qml/types/qqmllistmodel_p_p.h +++ b/src/qml/types/qqmllistmodel_p_p.h @@ -57,6 +57,8 @@ #include <private/qv4qobjectwrapper_p.h> #include <qqml.h> +QT_REQUIRE_CONFIG(qml_list_model); + QT_BEGIN_NAMESPACE @@ -142,16 +144,6 @@ protected: private: using QQmlOpenMetaObject::setValue; - void setValue(const QByteArray &name, const QVariant &val, bool force) - { - if (force) { - QVariant existingValue = value(name); - if (existingValue.isValid()) { - (*this)[name] = QVariant(); - } - } - setValue(name, val); - } void emitDirectNotifies(const int *changedRoles, int roleCount); @@ -181,8 +173,8 @@ struct ModelObject : public QObjectWrapper { struct ModelObject : public QObjectWrapper { - static bool put(Managed *m, String *name, const Value& value); - static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); + static bool put(Managed *m, StringOrSymbol *name, const Value& value); + static ReturnedValue get(const Managed *m, StringOrSymbol *name, bool *hasProperty); static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); V4_OBJECT2(ModelObject, QObjectWrapper) @@ -252,6 +244,22 @@ private: QStringHash<Role *> roleHash; }; +struct StringOrTranslation +{ + explicit StringOrTranslation(const QString &s); + explicit StringOrTranslation(const QV4::CompiledData::Binding *binding); + ~StringOrTranslation(); + bool isSet() const { return d.flag(); } + bool isTranslation() const { return d.isT2(); } + void setString(const QString &s); + void setTranslation(const QV4::CompiledData::Binding *binding); + QString toString(const QQmlListModel *owner) const; + QString asString() const; +private: + void clear(); + QBiPointer<QStringData, const QV4::CompiledData::Binding> d; +}; + /*! \internal */ @@ -287,6 +295,7 @@ private: int setVariantMapProperty(const ListLayout::Role &role, QVariantMap *m); int setDateTimeProperty(const ListLayout::Role &role, const QDateTime &dt); int setFunctionProperty(const ListLayout::Role &role, const QJSValue &f); + int setTranslationProperty(const ListLayout::Role &role, const QV4::CompiledData::Binding *b); void setStringPropertyFast(const ListLayout::Role &role, const QString &s); void setDoublePropertyFast(const ListLayout::Role &role, double n); @@ -301,7 +310,7 @@ private: QVariant getProperty(const ListLayout::Role &role, const QQmlListModel *owner, QV4::ExecutionEngine *eng); ListModel *getListProperty(const ListLayout::Role &role); - QString *getStringProperty(const ListLayout::Role &role); + StringOrTranslation *getStringProperty(const ListLayout::Role &role); QObject *getQObjectProperty(const ListLayout::Role &role); QPointer<QObject> *getGuardProperty(const ListLayout::Role &role); QVariantMap *getVariantMapProperty(const ListLayout::Role &role); diff --git a/src/qml/types/qqmllistmodelworkeragent_p.h b/src/qml/types/qqmllistmodelworkeragent_p.h index 2120f25744..ae2d4b11e0 100644 --- a/src/qml/types/qqmllistmodelworkeragent_p.h +++ b/src/qml/types/qqmllistmodelworkeragent_p.h @@ -59,6 +59,8 @@ #include <private/qv8engine_p.h> +QT_REQUIRE_CONFIG(qml_list_model); + QT_BEGIN_NAMESPACE diff --git a/src/qml/types/qqmlmodelsmodule.cpp b/src/qml/types/qqmlmodelsmodule.cpp index e217b63c6f..d9756704d1 100644 --- a/src/qml/types/qqmlmodelsmodule.cpp +++ b/src/qml/types/qqmlmodelsmodule.cpp @@ -39,7 +39,9 @@ #include "qqmlmodelsmodule_p.h" #include <QtCore/qitemselectionmodel.h> +#if QT_CONFIG(qml_list_model) #include <private/qqmllistmodel_p.h> +#endif #if QT_CONFIG(qml_delegate_model) #include <private/qqmldelegatemodel_p.h> #endif @@ -51,10 +53,13 @@ void QQmlModelsModule::defineModule() { const char uri[] = "QtQml.Models"; +#if QT_CONFIG(qml_list_model) qmlRegisterType<QQmlListElement>(uri, 2, 1, "ListElement"); qmlRegisterCustomType<QQmlListModel>(uri, 2, 1, "ListModel", new QQmlListModelParser); +#endif #if QT_CONFIG(qml_delegate_model) qmlRegisterType<QQmlDelegateModel>(uri, 2, 1, "DelegateModel"); + qmlRegisterType<QQmlDelegateModel,12>(uri, 2, 9, "DelegateModel"); qmlRegisterType<QQmlDelegateModelGroup>(uri, 2, 1, "DelegateModelGroup"); #endif qmlRegisterType<QQmlObjectModel>(uri, 2, 1, "ObjectModel"); diff --git a/src/qml/types/qqmltimer_p.h b/src/qml/types/qqmltimer_p.h index d597869994..0160e97a2f 100644 --- a/src/qml/types/qqmltimer_p.h +++ b/src/qml/types/qqmltimer_p.h @@ -57,6 +57,8 @@ #include <private/qtqmlglobal_p.h> +QT_REQUIRE_CONFIG(qml_animation); + QT_BEGIN_NAMESPACE class QQmlTimerPrivate; diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp index 98f819337b..f8879160b2 100644 --- a/src/qml/types/qquickworkerscript.cpp +++ b/src/qml/types/qquickworkerscript.cpp @@ -37,9 +37,12 @@ ** ****************************************************************************/ +#include "qtqmlglobal_p.h" #include "qquickworkerscript_p.h" +#if QT_CONFIG(qml_list_model) #include "qqmllistmodel_p.h" #include "qqmllistmodelworkeragent_p.h" +#endif #include <private/qqmlengine_p.h> #include <private/qqmlexpression_p.h> @@ -201,7 +204,7 @@ private: }; QQuickWorkerScriptEnginePrivate::WorkerEngine::WorkerEngine(QQuickWorkerScriptEnginePrivate *parent) - : QV8Engine(nullptr, new QV4::ExecutionEngine), p(parent) + : QV8Engine(new QV4::ExecutionEngine), p(parent) #if QT_CONFIG(qml_network) , accessManager(nullptr) #endif @@ -241,14 +244,13 @@ void QQuickWorkerScriptEnginePrivate::WorkerEngine::init() QV4::Scope scope(m_v4Engine); QV4::ExecutionContext *globalContext = scope.engine->rootContext(); - onmessage.set(scope.engine, QV4::Script(globalContext, QV4::Compiler::GlobalCode, QString::fromUtf8(CALL_ONMESSAGE_SCRIPT)).run()); // do not use QStringLiteral here, MSVC2012 cannot apply this cleanly to the macro + onmessage.set(scope.engine, QV4::Script(globalContext, QV4::Compiler::ContextType::Global, QString::fromUtf8(CALL_ONMESSAGE_SCRIPT)).run()); // do not use QStringLiteral here, MSVC2012 cannot apply this cleanly to the macro Q_ASSERT(!scope.engine->hasException); - QV4::Script createsendscript(globalContext, QV4::Compiler::GlobalCode, QString::fromUtf8(SEND_MESSAGE_CREATE_SCRIPT)); // do not use QStringLiteral here, MSVC2012 cannot apply this cleanly to the macro + QV4::Script createsendscript(globalContext, QV4::Compiler::ContextType::Global, QString::fromUtf8(SEND_MESSAGE_CREATE_SCRIPT)); // do not use QStringLiteral here, MSVC2012 cannot apply this cleanly to the macro QV4::ScopedFunctionObject createsendconstructor(scope, createsendscript.run()); Q_ASSERT(!scope.engine->hasException); QV4::ScopedString name(scope, m_v4Engine->newString(QStringLiteral("sendMessage"))); - QV4::ScopedValue function(scope, QV4::FunctionObject::createBuiltinFunction(globalContext, name, - QQuickWorkerScriptEnginePrivate::method_sendMessage)); + QV4::ScopedValue function(scope, QV4::FunctionObject::createBuiltinFunction(m_v4Engine, name, method_sendMessage, 1)); QV4::JSCallData jsCallData(scope, 1); jsCallData->args[0] = function; *jsCallData->thisObject = m_v4Engine->global(); diff --git a/src/qml/types/types.pri b/src/qml/types/types.pri index 8bcbd6e544..5d75759281 100644 --- a/src/qml/types/types.pri +++ b/src/qml/types/types.pri @@ -1,8 +1,6 @@ SOURCES += \ $$PWD/qqmlbind.cpp \ $$PWD/qqmlconnections.cpp \ - $$PWD/qqmllistmodel.cpp \ - $$PWD/qqmllistmodelworkeragent.cpp \ $$PWD/qqmlmodelsmodule.cpp \ $$PWD/qqmlmodelindexvaluetype.cpp \ $$PWD/qqmlobjectmodel.cpp \ @@ -13,9 +11,6 @@ SOURCES += \ HEADERS += \ $$PWD/qqmlbind_p.h \ $$PWD/qqmlconnections_p.h \ - $$PWD/qqmllistmodel_p.h \ - $$PWD/qqmllistmodel_p_p.h \ - $$PWD/qqmllistmodelworkeragent_p.h \ $$PWD/qqmlmodelsmodule_p.h \ $$PWD/qqmlmodelindexvaluetype_p.h \ $$PWD/qqmlobjectmodel_p.h \ @@ -24,6 +19,17 @@ HEADERS += \ $$PWD/qqmlinstantiator_p.h \ $$PWD/qqmlinstantiator_p_p.h +qtConfig(qml-list-model) { + SOURCES += \ + $$PWD/qqmllistmodel.cpp \ + $$PWD/qqmllistmodelworkeragent.cpp + + HEADERS += \ + $$PWD/qqmllistmodel_p.h \ + $$PWD/qqmllistmodel_p_p.h \ + $$PWD/qqmllistmodelworkeragent_p.h +} + qtConfig(qml-delegate-model) { SOURCES += \ $$PWD/qqmldelegatemodel.cpp @@ -33,7 +39,7 @@ qtConfig(qml-delegate-model) { $$PWD/qqmldelegatemodel_p_p.h } -qtConfig(animation) { +qtConfig(qml-animation) { SOURCES += \ $$PWD/qqmltimer.cpp |