diff options
Diffstat (limited to 'src/declarative/qml')
43 files changed, 1205 insertions, 1237 deletions
diff --git a/src/declarative/qml/parser/qdeclarativejslexer.cpp b/src/declarative/qml/parser/qdeclarativejslexer.cpp index 34163a4..6404be3 100644 --- a/src/declarative/qml/parser/qdeclarativejslexer.cpp +++ b/src/declarative/qml/parser/qdeclarativejslexer.cpp @@ -56,9 +56,11 @@ #include <stdio.h> #include <string.h> -QT_QML_BEGIN_NAMESPACE - +QT_BEGIN_NAMESPACE extern double qstrtod(const char *s00, char const **se, bool *ok); +QT_END_NAMESPACE + +QT_QML_BEGIN_NAMESPACE #define shiftWindowsLineBreak() \ do { \ diff --git a/src/declarative/qml/qdeclarative.h b/src/declarative/qml/qdeclarative.h index 77b7484..dfdef11 100644 --- a/src/declarative/qml/qdeclarative.h +++ b/src/declarative/qml/qdeclarative.h @@ -99,7 +99,7 @@ int qmlRegisterType() qRegisterMetaType<T *>(pointerName.constData()), qRegisterMetaType<QDeclarativeListProperty<T> >(listName.constData()), - 0, + 0, 0, 0, 0, 0, 0, &T::staticMetaObject, @@ -131,7 +131,7 @@ int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const c qRegisterMetaType<T *>(pointerName.constData()), qRegisterMetaType<QDeclarativeListProperty<T> >(listName.constData()), - QDeclarativePrivate::create<T>, + sizeof(T), QDeclarativePrivate::createInto<T>, uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, @@ -163,7 +163,7 @@ int qmlRegisterExtendedType() qRegisterMetaType<T *>(pointerName.constData()), qRegisterMetaType<QDeclarativeListProperty<T> >(listName.constData()), - 0, + 0, 0, 0, 0, 0, 0, &T::staticMetaObject, @@ -203,7 +203,7 @@ int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor, qRegisterMetaType<T *>(pointerName.constData()), qRegisterMetaType<QDeclarativeListProperty<T> >(listName.constData()), - QDeclarativePrivate::create<T>, + sizeof(T), QDeclarativePrivate::createInto<T>, uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, @@ -256,7 +256,7 @@ int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor, qRegisterMetaType<T *>(pointerName.constData()), qRegisterMetaType<QDeclarativeListProperty<T> >(listName.constData()), - QDeclarativePrivate::create<T>, + sizeof(T), QDeclarativePrivate::createInto<T>, uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, @@ -275,18 +275,6 @@ int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor, return QDeclarativePrivate::registerType(type); } -#define QML_REGISTER_INTERFACE(INTERFACE) \ - qmlRegisterInterface<INTERFACE>(#INTERFACE) - -#define QML_REGISTER_EXTENDED_TYPE(URI, VERSION_MAJ, VERSION_MIN, NAME, CLASS, EXTENSION) \ - qmlRegisterExtendedType<CLASS,EXTENSION>(#URI, VERSION_MAJ, VERSION_MIN, #NAME) - -#define QML_REGISTER_TYPE(URI,VMAJ,VMIN,NAME,CLASS) \ - qmlRegisterType<CLASS>(#URI, VMAJ, VMIN, #NAME) - -#define QML_REGISTER_NOCREATE_TYPE(CLASS) \ - qmlRegisterType<CLASS>() - class QDeclarativeContext; class QDeclarativeEngine; Q_DECLARATIVE_EXPORT void qmlExecuteDeferred(QObject *); diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp index 88ca5cd..bc78b5b 100644 --- a/src/declarative/qml/qdeclarativebinding.cpp +++ b/src/declarative/qml/qdeclarativebinding.cpp @@ -223,7 +223,7 @@ void QDeclarativeBinding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteF int QDeclarativeBinding::propertyIndex() { Q_D(QDeclarativeBinding); - return d->bindingData()->property.index(); + return QDeclarativePropertyPrivate::bindingIndex(d->bindingData()->property); } bool QDeclarativeBinding::enabled() const @@ -259,23 +259,57 @@ void QDeclarativeAbstractBinding::addToObject(QObject *object) { Q_ASSERT(object); + if (m_object == object) + return; + + int index = propertyIndex(); + removeFromObject(); Q_ASSERT(!m_prevBinding); - QDeclarativeDeclarativeData *data = QDeclarativeDeclarativeData::get(object, true); - m_nextBinding = data->bindings; - if (m_nextBinding) m_nextBinding->m_prevBinding = &m_nextBinding; - m_prevBinding = &data->bindings; - data->bindings = this; m_object = object; + QDeclarativeDeclarativeData *data = QDeclarativeDeclarativeData::get(object, true); + + if (index & 0xFF000000) { + // Value type - data->setBindingBit(m_object, propertyIndex()); + int coreIndex = index & 0xFFFFFF; + + // Find the value type proxy (if there is one) + QDeclarativeValueTypeProxyBinding *proxy = 0; + if (data->hasBindingBit(coreIndex)) { + QDeclarativeAbstractBinding *b = data->bindings; + while (b && b->propertyIndex() != coreIndex) + b = b->m_nextBinding; + Q_ASSERT(b && b->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy); + proxy = static_cast<QDeclarativeValueTypeProxyBinding *>(b); + } + + if (!proxy) + proxy = new QDeclarativeValueTypeProxyBinding(object, coreIndex); + proxy->addToObject(object); + + m_nextBinding = proxy->m_bindings; + if (m_nextBinding) m_nextBinding->m_prevBinding = &m_nextBinding; + m_prevBinding = &proxy->m_bindings; + proxy->m_bindings = this; + + } else { + m_nextBinding = data->bindings; + if (m_nextBinding) m_nextBinding->m_prevBinding = &m_nextBinding; + m_prevBinding = &data->bindings; + data->bindings = this; + + data->setBindingBit(m_object, index); + } } void QDeclarativeAbstractBinding::removeFromObject() { if (m_prevBinding) { + int index = propertyIndex(); + Q_ASSERT(m_object); *m_prevBinding = m_nextBinding; @@ -283,8 +317,14 @@ void QDeclarativeAbstractBinding::removeFromObject() m_prevBinding = 0; m_nextBinding = 0; - QDeclarativeDeclarativeData *data = QDeclarativeDeclarativeData::get(m_object, false); - if (data) data->clearBindingBit(propertyIndex()); + if (index & 0xFF000000) { + // Value type - we don't remove the proxy from the object. It will sit their happily + // doing nothing for ever more. + } else { + QDeclarativeDeclarativeData *data = QDeclarativeDeclarativeData::get(m_object, false); + if (data) data->clearBindingBit(index); + } + m_object = 0; } } @@ -305,4 +345,88 @@ void QDeclarativeAbstractBinding::setEnabled(bool e, QDeclarativePropertyPrivate if (e) m_mePtr = 0; } +QDeclarativeValueTypeProxyBinding::QDeclarativeValueTypeProxyBinding(QObject *o, int index) +: m_object(o), m_index(index), m_bindings(0) +{ +} + +QDeclarativeValueTypeProxyBinding::~QDeclarativeValueTypeProxyBinding() +{ + while (m_bindings) { + QDeclarativeAbstractBinding *binding = m_bindings; + binding->setEnabled(false, 0); + binding->destroy(); + } +} + +void QDeclarativeValueTypeProxyBinding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags) +{ + if (e) { + addToObject(m_object); + + QDeclarativeAbstractBinding *bindings = m_bindings; + m_bindings = 0; + recursiveEnable(bindings, flags); + } else { + removeFromObject(); + + QDeclarativeAbstractBinding *bindings = m_bindings; + m_bindings = 0; + recursiveDisable(bindings); + } +} + +void QDeclarativeValueTypeProxyBinding::recursiveEnable(QDeclarativeAbstractBinding *b, QDeclarativePropertyPrivate::WriteFlags flags) +{ + if (!b) + return; + + QDeclarativeAbstractBinding *next = b->m_nextBinding; + b->m_prevBinding = 0; + b->m_nextBinding = 0; + Q_ASSERT(b->m_mePtr == 0); + b->m_mePtr = &b; + + recursiveEnable(next, flags); + + if (b) + b->setEnabled(true, flags); +} + +void QDeclarativeValueTypeProxyBinding::recursiveDisable(QDeclarativeAbstractBinding *b) +{ + if (!b) + return; + + recursiveDisable(b->m_nextBinding); + + b->setEnabled(false, 0); + + Q_ASSERT(b->m_prevBinding == 0); + Q_ASSERT(b->m_nextBinding == 0); + b->m_nextBinding = m_bindings; + if (b->m_nextBinding) b->m_nextBinding->m_prevBinding = &b->m_nextBinding; + b->m_prevBinding = &m_bindings; + m_bindings = b; +} + +int QDeclarativeValueTypeProxyBinding::propertyIndex() +{ + return m_index; +} + +void QDeclarativeValueTypeProxyBinding::update(QDeclarativePropertyPrivate::WriteFlags) +{ +} + +QDeclarativeAbstractBinding *QDeclarativeValueTypeProxyBinding::binding(int propertyIndex) +{ + QDeclarativeAbstractBinding *binding = m_bindings; + + while (binding && binding->propertyIndex() != propertyIndex) + binding = binding->m_nextBinding; + + return binding; +} + QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativebinding_p.h b/src/declarative/qml/qdeclarativebinding_p.h index 1a714f0..21e3248 100644 --- a/src/declarative/qml/qdeclarativebinding_p.h +++ b/src/declarative/qml/qdeclarativebinding_p.h @@ -74,6 +74,9 @@ public: virtual QString expression() const; + enum Type { PropertyBinding, ValueTypeProxy }; + virtual Type bindingType() const { return PropertyBinding; } + void setEnabled(bool e) { setEnabled(e, QDeclarativePropertyPrivate::DontRemoveBinding); } virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags) = 0; virtual int propertyIndex() = 0; @@ -92,6 +95,7 @@ private: friend class QDeclarativeProperty; friend class QDeclarativePropertyPrivate; friend class QDeclarativeVME; + friend class QDeclarativeValueTypeProxyBinding; QObject *m_object; QDeclarativeAbstractBinding **m_mePtr; @@ -99,6 +103,30 @@ private: QDeclarativeAbstractBinding *m_nextBinding; }; +class QDeclarativeValueTypeProxyBinding : public QDeclarativeAbstractBinding +{ +public: + QDeclarativeValueTypeProxyBinding(QObject *o, int coreIndex); + virtual ~QDeclarativeValueTypeProxyBinding(); + + virtual Type bindingType() const { return ValueTypeProxy; } + + virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags); + virtual int propertyIndex(); + virtual void update(QDeclarativePropertyPrivate::WriteFlags); + + QDeclarativeAbstractBinding *binding(int propertyIndex); + +private: + void recursiveEnable(QDeclarativeAbstractBinding *, QDeclarativePropertyPrivate::WriteFlags); + void recursiveDisable(QDeclarativeAbstractBinding *); + + friend class QDeclarativeAbstractBinding; + QObject *m_object; + int m_index; + QDeclarativeAbstractBinding *m_bindings; +}; + class QDeclarativeContext; class QDeclarativeBindingPrivate; class Q_DECLARATIVE_EXPORT QDeclarativeBinding : public QDeclarativeExpression, public QDeclarativeAbstractBinding diff --git a/src/declarative/qml/qdeclarativecompiledbindings.cpp b/src/declarative/qml/qdeclarativecompiledbindings.cpp index 17937fd..aa549a9 100644 --- a/src/declarative/qml/qdeclarativecompiledbindings.cpp +++ b/src/declarative/qml/qdeclarativecompiledbindings.cpp @@ -48,12 +48,17 @@ #include <private/qdeclarativejsast_p.h> #include <private/qdeclarativejsengine_p.h> #include <private/qdeclarativeexpression_p.h> +#include <QtCore/qcoreapplication.h> #include <QtCore/qdebug.h> #include <QtCore/qnumeric.h> #include <private/qdeclarativeanchors_p_p.h> +#include <private/qdeclarativeglobal_p.h> QT_BEGIN_NAMESPACE +DEFINE_BOOL_CONFIG_OPTION(qmlExperimental, QML_EXPERIMENTAL); +DEFINE_BOOL_CONFIG_OPTION(qmlDisableOptimizer, QML_DISABLE_OPTIMIZER); + using namespace QDeclarativeJS; namespace { @@ -124,24 +129,7 @@ public: QDeclarativeCompiledBindingsPrivate *parent; }; - struct Subscription { - struct Signal { - QDeclarativeGuard<QObject> source; - int notifyIndex; - }; - - enum { InvalidType, SignalType, IdType } type; - inline Subscription(); - inline ~Subscription(); - bool isSignal() const { return type == SignalType; } - bool isId() const { return type == IdType; } - inline Signal *signal(); - inline QDeclarativeContextPrivate::IdNotifier *id(); - union { - char signalData[sizeof(Signal)]; - char idData[sizeof(QDeclarativeContextPrivate::IdNotifier)]; - }; - }; + typedef QDeclarativeNotifierEndpoint Subscription; Subscription *subscriptions; QScriptDeclarativeClass::PersistentIdentifier *identifiers; @@ -190,18 +178,6 @@ QDeclarativeCompiledBindingsPrivate::~QDeclarativeCompiledBindingsPrivate() delete [] identifiers; identifiers = 0; } -QDeclarativeCompiledBindingsPrivate::Subscription::Subscription() -: type(InvalidType) -{ -} - -QDeclarativeCompiledBindingsPrivate::Subscription::~Subscription() -{ - if (type == SignalType) ((Signal *)signalData)->~Signal(); - else if (type == IdType) ((QDeclarativeContextPrivate::IdNotifier *)idData)->~IdNotifier(); -} - - int QDeclarativeCompiledBindingsPrivate::methodCount = -1; QDeclarativeCompiledBindings::QDeclarativeCompiledBindings(const char *program, QDeclarativeContext *context) @@ -248,7 +224,6 @@ void QDeclarativeCompiledBindingsPrivate::Binding::setEnabled(bool e, QDeclarati { if (e) { addToObject(target); - update(flags); } else { removeFromObject(); } @@ -303,8 +278,6 @@ void QDeclarativeCompiledBindingsPrivate::run(Binding *binding) if (!binding->enabled) return; - if (binding->updating) - qWarning("ERROR: Circular binding"); QDeclarativeContext *context = q->QDeclarativeAbstractExpression::context(); if (!context) { @@ -313,6 +286,25 @@ void QDeclarativeCompiledBindingsPrivate::run(Binding *binding) } QDeclarativeContextPrivate *cp = QDeclarativeContextPrivate::get(context); + if (binding->updating) { + QString name; + if (binding->property & 0xFFFF0000) { + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(cp->engine); + + QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF]; + Q_ASSERT(vt); + + name = QLatin1String(binding->target->metaObject()->property(binding->property & 0xFFFF).name()); + name.append(QLatin1String(".")); + name.append(QLatin1String(vt->metaObject()->property(binding->property >> 24).name())); + } else { + name = binding->target->metaObject()->property(binding->property).name(); + } + qmlInfo(binding->target) << QCoreApplication::translate("QDeclarativeCompiledBindings", "Binding loop detected for property \"%1\"").arg(name); + return; + } + + binding->updating = true; if (binding->property & 0xFFFF0000) { QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(cp->engine); @@ -328,22 +320,7 @@ void QDeclarativeCompiledBindingsPrivate::run(Binding *binding) } else { run(binding->index, cp, binding, binding->scope, binding->target); } -} - -QDeclarativeCompiledBindingsPrivate::Subscription::Signal *QDeclarativeCompiledBindingsPrivate::Subscription::signal() -{ - if (type == IdType) ((QDeclarativeContextPrivate::IdNotifier *)idData)->~IdNotifier(); - if (type != SignalType) new (signalData) Signal; - type = SignalType; - return (Signal *)signalData; -} - -QDeclarativeContextPrivate::IdNotifier *QDeclarativeCompiledBindingsPrivate::Subscription::id() -{ - if (type == SignalType) ((Signal *)signalData)->~Signal(); - if (type != IdType) new (idData) QDeclarativeContextPrivate::IdNotifier; - type = IdType; - return (QDeclarativeContextPrivate::IdNotifier *)idData; + binding->updating = false; } namespace { @@ -656,20 +633,7 @@ void QDeclarativeCompiledBindingsPrivate::unsubscribe(int subIndex) Q_Q(QDeclarativeCompiledBindings); QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex); - if (sub->isSignal()) { - QDeclarativeCompiledBindingsPrivate::Subscription::Signal *s = sub->signal(); - if (s->source) -#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 2)) - QMetaObject::disconnectOne(s->source, s->notifyIndex, - q, methodCount + subIndex); -#else - // QTBUG-6781 - QMetaObject::disconnect(s->source, s->notifyIndex, - q, methodCount + subIndex); -#endif - } else if (sub->isId()) { - sub->id()->clear(); - } + sub->disconnect(); } void QDeclarativeCompiledBindingsPrivate::subscribeId(QDeclarativeContextPrivate *p, int idIndex, int subIndex) @@ -680,15 +644,9 @@ void QDeclarativeCompiledBindingsPrivate::subscribeId(QDeclarativeContextPrivate if (p->idValues[idIndex]) { QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex); - QDeclarativeContextPrivate::IdNotifier *i = sub->id(); - - i->next = p->idValues[idIndex].bindings; - i->prev = &p->idValues[idIndex].bindings; - p->idValues[idIndex].bindings = i; - if (i->next) i->next->prev = &i->next; - - i->target = q; - i->methodIndex = methodCount + subIndex; + sub->target = q; + sub->targetMethod = methodCount + subIndex; + sub->connect(&p->idValues[idIndex].bindings); } } @@ -697,27 +655,12 @@ void QDeclarativeCompiledBindingsPrivate::subscribe(QObject *o, int notifyIndex, Q_Q(QDeclarativeCompiledBindings); QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex); - - if (sub->isId()) - unsubscribe(subIndex); - - QDeclarativeCompiledBindingsPrivate::Subscription::Signal *s = sub->signal(); - if (o != s->source || notifyIndex != s->notifyIndex) { - if (s->source) -#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 2)) - QMetaObject::disconnectOne(s->source, s->notifyIndex, - q, methodCount + subIndex); -#else - // QTBUG-6781 - QMetaObject::disconnect(s->source, s->notifyIndex, - q, methodCount + subIndex); -#endif - s->source = o; - s->notifyIndex = notifyIndex; - if (s->source && s->notifyIndex != -1) - QMetaObject::connect(s->source, s->notifyIndex, q, - methodCount + subIndex, Qt::DirectConnection); - } + sub->target = q; + sub->targetMethod = methodCount + subIndex; + if (o) + sub->connect(o, notifyIndex); + else + sub->disconnect(); } // Conversion functions - these MUST match the QtScript expression path @@ -811,9 +754,9 @@ static QObject *variantToQObject(const QVariant &value, bool *ok) } bool QDeclarativeCompiledBindingsPrivate::findproperty(QObject *obj, Register *output, - QDeclarativeEnginePrivate *enginePriv, - int subIdx, const QScriptDeclarativeClass::Identifier &name, - bool isTerminal) + QDeclarativeEnginePrivate *enginePriv, + int subIdx, const QScriptDeclarativeClass::Identifier &name, + bool isTerminal) { if (!obj) { output->setUndefined(); @@ -884,10 +827,10 @@ bool QDeclarativeCompiledBindingsPrivate::findproperty(QObject *obj, Register *o } void QDeclarativeCompiledBindingsPrivate::findgeneric(Register *output, - int subIdx, - QDeclarativeContextPrivate *context, - const QScriptDeclarativeClass::Identifier &name, - bool isTerminal) + int subIdx, + QDeclarativeContextPrivate *context, + const QScriptDeclarativeClass::Identifier &name, + bool isTerminal) { QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(context->engine); @@ -928,7 +871,7 @@ void QDeclarativeCompiledBindingsPrivate::findgeneric(Register *output, } } - if (QObject *root = context->defaultObjects.isEmpty()?0:context->defaultObjects.first()) { + if (QObject *root = context->contextObject) { if (findproperty(root, output, enginePriv, subIdx, name, isTerminal)) return; @@ -1169,7 +1112,7 @@ void QDeclarativeCompiledBindingsPrivate::run(int instrIndex, break; case Instr::LoadRoot: - registers[instr->load.reg].setQObject(context->defaultObjects.at(0)); + registers[instr->load.reg].setQObject(context->contextObject); break; case Instr::LoadAttached: @@ -1612,6 +1555,9 @@ bool QDeclarativeBindingCompilerPrivate::compile(QDeclarativeJS::AST::Node *node return false; if (type.unknownType) { + if (!qmlExperimental()) + return false; + if (destination->type != QMetaType::QReal && destination->type != QVariant::String && destination->type != QMetaType::Bool && @@ -1895,7 +1841,7 @@ bool QDeclarativeBindingCompilerPrivate::parseName(AST::Node *node, Result &type if (!fetch(type, component->metaObject(), reg, d1Idx, subscribeName, nameNodes.at(ii))) return false; - } else { + } else if (qmlExperimental()) { Instr find; if (nameParts.count() == 1) find.common.type = Instr::FindGenericTerminal; @@ -2051,7 +1997,11 @@ bool QDeclarativeBindingCompilerPrivate::numberArith(Result &type, const Result int lhsTmp = -1; int rhsTmp = -1; + if (lhs.unknownType) { + if (!qmlExperimental()) + return false; + lhsTmp = acquireReg(); Instr conv; @@ -2062,6 +2012,9 @@ bool QDeclarativeBindingCompilerPrivate::numberArith(Result &type, const Result } if (rhs.unknownType) { + if (!qmlExperimental()) + return false; + rhsTmp = acquireReg(); Instr conv; @@ -2107,6 +2060,9 @@ bool QDeclarativeBindingCompilerPrivate::stringArith(Result &type, const Result int rhsTmp = -1; if (lhs.unknownType) { + if (!qmlExperimental()) + return false; + lhsTmp = acquireReg(Instr::CleanupString); Instr convert; @@ -2117,6 +2073,9 @@ bool QDeclarativeBindingCompilerPrivate::stringArith(Result &type, const Result } if (rhs.unknownType) { + if (!qmlExperimental()) + return false; + rhsTmp = acquireReg(Instr::CleanupString); Instr convert; @@ -2637,6 +2596,12 @@ int QDeclarativeBindingCompiler::compile(const Expression &expression, QDeclarat { if (!expression.expression.asAST()) return false; + if (!qmlExperimental() && expression.property->isValueTypeSubProperty) + return -1; + + if (qmlDisableOptimizer()) + return -1; + d->context = expression.context; d->component = expression.component; d->destination = expression.property; diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index ef1032b..06ff47c 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -82,7 +82,7 @@ QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP); DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATISTICS_DUMP); -DEFINE_BOOL_CONFIG_OPTION(qmlExperimental, QML_EXPERIMENTAL); +DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP); using namespace QDeclarativeParser; @@ -1850,6 +1850,7 @@ bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type, QMetaProperty p = type->metaObject()->property(idx); prop->index = idx; prop->type = p.userType(); + prop->isValueTypeSubProperty = true; if (prop->value) COMPILE_EXCEPTION(prop, QCoreApplication::translate("QDeclarativeCompiler","Property assignment expected")); @@ -2712,7 +2713,9 @@ bool QDeclarativeCompiler::completeComponentBuild() QDeclarativeBindingCompiler bindingCompiler; - for (QHash<QDeclarativeParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin(); iter != compileState.bindings.end(); ++iter) { + for (QHash<QDeclarativeParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin(); + iter != compileState.bindings.end(); ++iter) { + BindingReference &binding = *iter; expr.context = binding.bindingContext.object; @@ -2720,18 +2723,13 @@ bool QDeclarativeCompiler::completeComponentBuild() expr.expression = binding.expression; expr.imports = unit->imports; - if (qmlExperimental()) { - int index = bindingCompiler.compile(expr, QDeclarativeEnginePrivate::get(engine)); - if (index != -1) { - qWarning() << "Accepted for optimization:" << qPrintable(expr.expression.asScript()); - binding.dataType = BindingReference::Experimental; - binding.compiledIndex = index; - componentStat.optimizedBindings++; - continue; - } else { - qWarning() << "Rejected for optimization:" << qPrintable(expr.expression.asScript()); - } - } + int index = bindingCompiler.compile(expr, QDeclarativeEnginePrivate::get(engine)); + if (index != -1) { + binding.dataType = BindingReference::Experimental; + binding.compiledIndex = index; + componentStat.optimizedBindings++; + continue; + } binding.dataType = BindingReference::QtScript; @@ -2768,7 +2766,8 @@ bool QDeclarativeCompiler::completeComponentBuild() if (bindingCompiler.isValid()) { compileState.compiledBindingData = bindingCompiler.program(); - QDeclarativeBindingCompiler::dump(compileState.compiledBindingData); + if (bindingsDump()) + QDeclarativeBindingCompiler::dump(compileState.compiledBindingData); } saveComponentState(); diff --git a/src/declarative/qml/qdeclarativecomponent.cpp b/src/declarative/qml/qdeclarativecomponent.cpp index d6bb216..d3608c4 100644 --- a/src/declarative/qml/qdeclarativecomponent.cpp +++ b/src/declarative/qml/qdeclarativecomponent.cpp @@ -512,7 +512,6 @@ QDeclarativeComponent::QDeclarativeComponent(QDeclarativeComponentPrivate &dd, Q { } - /*! \internal A version of create which returns a scriptObject, for use in script @@ -526,7 +525,9 @@ QScriptValue QDeclarativeComponent::createObject() return QScriptValue(); } QObject* ret = create(ctxt); - return QDeclarativeEnginePrivate::qmlScriptObject(ret, d->engine); + QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(d->engine); + QDeclarativeDeclarativeData::get(ret, true)->setImplicitDestructible(); + return priv->objectClass->newQObject(ret, QMetaType::QObjectStar); } /*! @@ -541,7 +542,12 @@ QObject *QDeclarativeComponent::create(QDeclarativeContext *context) { Q_D(QDeclarativeComponent); - return d->create(context, QBitField()); + if (!context) + context = d->engine->rootContext(); + + QObject *rv = beginCreate(context); + completeCreate(); + return rv; } QObject *QDeclarativeComponentPrivate::create(QDeclarativeContext *context, @@ -586,7 +592,13 @@ QObject *QDeclarativeComponentPrivate::create(QDeclarativeContext *context, QObject *QDeclarativeComponent::beginCreate(QDeclarativeContext *context) { Q_D(QDeclarativeComponent); - return d->beginCreate(context, QBitField()); + QObject *rv = d->beginCreate(context, QBitField()); + if (rv) { + QDeclarativeDeclarativeData *ddata = QDeclarativeDeclarativeData::get(rv); + Q_ASSERT(ddata); + ddata->indestructible = true; + } + return rv; } QObject * diff --git a/src/declarative/qml/qdeclarativecompositetypemanager.cpp b/src/declarative/qml/qdeclarativecompositetypemanager.cpp index b90a598..e2a6e0c 100644 --- a/src/declarative/qml/qdeclarativecompositetypemanager.cpp +++ b/src/declarative/qml/qdeclarativecompositetypemanager.cpp @@ -154,7 +154,7 @@ QDeclarativeCompositeTypeData::TypeReference::TypeReference() } QDeclarativeCompositeTypeManager::QDeclarativeCompositeTypeManager(QDeclarativeEngine *e) -: engine(e) +: engine(e), redirectCount(0) { } @@ -172,6 +172,10 @@ QDeclarativeCompositeTypeManager::~QDeclarativeCompositeTypeManager() QDeclarativeCompositeTypeData *QDeclarativeCompositeTypeManager::get(const QUrl &url) { + Redirects::Iterator redir = redirects.find(url); + if (redir != redirects.end()) + return get(*redir); + QDeclarativeCompositeTypeData *unit = components.value(url); if (!unit) { @@ -219,6 +223,8 @@ void QDeclarativeCompositeTypeManager::clearCache() } } +#define TYPEMANAGER_MAXIMUM_REDIRECT_RECURSION 16 + void QDeclarativeCompositeTypeManager::replyFinished() { QNetworkReply *reply = static_cast<QNetworkReply *>(sender()); @@ -226,6 +232,26 @@ void QDeclarativeCompositeTypeManager::replyFinished() QDeclarativeCompositeTypeData *unit = components.value(reply->url()); Q_ASSERT(unit); + redirectCount++; + if (redirectCount < TYPEMANAGER_MAXIMUM_REDIRECT_RECURSION) { + QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); + if (redirect.isValid()) { + QUrl url = reply->url().resolved(redirect.toUrl()); + redirects.insert(reply->url(),url); + unit->imports.setBaseUrl(url); + components.remove(reply->url()); + components.insert(url, unit); + reply->deleteLater(); + reply = engine->networkAccessManager()->get(QNetworkRequest(url)); + QObject::connect(reply, SIGNAL(finished()), + this, SLOT(replyFinished())); + QObject::connect(reply, SIGNAL(downloadProgress(qint64,qint64)), + this, SLOT(requestProgress(qint64,qint64))); + return; + } + } + redirectCount = 0; + if (reply->error() != QNetworkReply::NoError) { QString errorDescription; // ### - Fill in error @@ -256,6 +282,24 @@ void QDeclarativeCompositeTypeManager::resourceReplyFinished() QDeclarativeCompositeTypeResource *resource = resources.value(reply->url()); Q_ASSERT(resource); + redirectCount++; + if (redirectCount < TYPEMANAGER_MAXIMUM_REDIRECT_RECURSION) { + QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); + if (redirect.isValid()) { + QUrl url = reply->url().resolved(redirect.toUrl()); + redirects.insert(reply->url(),url); + resource->url = url.toString(); + resources.remove(reply->url()); + resources.insert(url, resource); + reply->deleteLater(); + reply = engine->networkAccessManager()->get(QNetworkRequest(url)); + QObject::connect(reply, SIGNAL(finished()), + this, SLOT(resourceReplyFinished())); + return; + } + } + redirectCount = 0; + if (reply->error() != QNetworkReply::NoError) { resource->status = QDeclarativeCompositeTypeResource::Error; @@ -462,17 +506,18 @@ int QDeclarativeCompositeTypeManager::resolveTypes(QDeclarativeCompositeTypeData int waiting = 0; foreach (QDeclarativeScriptParser::Import imp, unit->data.imports()) { - QString qmldir; + QString qmldircontentnetwork; if (imp.type == QDeclarativeScriptParser::Import::File && imp.qualifier.isEmpty()) { QString importUrl = unit->imports.baseUrl().resolved(QUrl(imp.uri + QLatin1String("/qmldir"))).toString(); for (int ii = 0; ii < unit->resources.count(); ++ii) { if (unit->resources.at(ii)->url == importUrl) { - qmldir = QString::fromUtf8(unit->resources.at(ii)->data); + qmldircontentnetwork = QString::fromUtf8(unit->resources.at(ii)->data); break; } } } + int vmaj = -1; int vmin = -1; if (!imp.version.isEmpty()) { @@ -487,7 +532,7 @@ int QDeclarativeCompositeTypeManager::resolveTypes(QDeclarativeCompositeTypeData } if (!QDeclarativeEnginePrivate::get(engine)-> - addToImport(&unit->imports, qmldir, imp.uri, imp.qualifier, vmaj, vmin, imp.type)) + addToImport(&unit->imports, qmldircontentnetwork, imp.uri, imp.qualifier, vmaj, vmin, imp.type)) { QDeclarativeError error; error.setUrl(unit->imports.baseUrl()); @@ -546,6 +591,10 @@ int QDeclarativeCompositeTypeManager::resolveTypes(QDeclarativeCompositeTypeData continue; } + Redirects::Iterator redir = redirects.find(url); + if (redir != redirects.end()) + url = *redir; + QDeclarativeCompositeTypeData *urlUnit = components.value(url); if (!urlUnit) { diff --git a/src/declarative/qml/qdeclarativecompositetypemanager_p.h b/src/declarative/qml/qdeclarativecompositetypemanager_p.h index 03d16b8..a572e0c 100644 --- a/src/declarative/qml/qdeclarativecompositetypemanager_p.h +++ b/src/declarative/qml/qdeclarativecompositetypemanager_p.h @@ -109,6 +109,9 @@ private: Components components; typedef QHash<QUrl, QDeclarativeCompositeTypeResource *> Resources; Resources resources; + typedef QHash<QUrl, QUrl> Redirects; + Redirects redirects; + int redirectCount; }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativecontext.cpp b/src/declarative/qml/qdeclarativecontext.cpp index f70e143..237cb7e 100644 --- a/src/declarative/qml/qdeclarativecontext.cpp +++ b/src/declarative/qml/qdeclarativecontext.cpp @@ -59,12 +59,14 @@ QT_BEGIN_NAMESPACE QDeclarativeContextPrivate::QDeclarativeContextPrivate() : parent(0), engine(0), isInternal(false), propertyNames(0), - notifyIndex(-1), highPriorityCount(0), imports(0), expressions(0), contextObjects(0), + notifyIndex(-1), contextObject(0), imports(0), childContexts(0), + nextChild(0), prevChild(0), expressions(0), contextObjects(0), idValues(0), idValueCount(0), optimizedBindings(0) { } -void QDeclarativeContextPrivate::addScript(const QDeclarativeParser::Object::ScriptBlock &script, QObject *scopeObject) +void QDeclarativeContextPrivate::addScript(const QDeclarativeParser::Object::ScriptBlock &script, + QObject *scopeObject) { Q_Q(QDeclarativeContext); @@ -109,12 +111,7 @@ void QDeclarativeContextPrivate::destroyed(ContextGuard *guard) if (parent && QObjectPrivate::get(parent)->wasDeleted) return; - while(guard->bindings) { - QObject *o = guard->bindings->target; - int mi = guard->bindings->methodIndex; - guard->bindings->clear(); - if (o) o->qt_metacall(QMetaObject::InvokeMetaMethod, mi, 0); - } + guard->bindings.notify(); for (int ii = 0; ii < idValueCount; ++ii) { if (&idValues[ii] == guard) { @@ -128,8 +125,13 @@ void QDeclarativeContextPrivate::init() { Q_Q(QDeclarativeContext); - if (parent) - parent->d_func()->childContexts.insert(q); + if (parent) { + QDeclarativeContextPrivate *ppriv = parent->d_func(); + nextChild = ppriv->childContexts; + if (nextChild) nextChild->d_func()->prevChild = &nextChild; + prevChild = &ppriv->childContexts; + ppriv->childContexts = q; + } } /*! @@ -177,7 +179,7 @@ void QDeclarativeContextPrivate::init() MyDataSet myDataSet; QDeclarativeEngine engine; QDeclarativeContext context(engine.rootContext()); - context.addDefaultObject(&myDataSet); + context.setContextObject(&myDataSet); QDeclarativeComponent component(&engine, "ListView { model=myModel }"); component.create(&context); @@ -275,15 +277,24 @@ QDeclarativeContext::QDeclarativeContext(QDeclarativeContext *parentContext, QOb QDeclarativeContext::~QDeclarativeContext() { Q_D(QDeclarativeContext); - if (d->parent) - d->parent->d_func()->childContexts.remove(this); - - for (QSet<QDeclarativeContext *>::ConstIterator iter = d->childContexts.begin(); - iter != d->childContexts.end(); - ++iter) { - (*iter)->d_func()->invalidateEngines(); - (*iter)->d_func()->parent = 0; + + if (d->prevChild) { + *d->prevChild = d->nextChild; + if (d->nextChild) d->nextChild->d_func()->prevChild = d->prevChild; + d->nextChild = 0; + d->prevChild = 0; } + + QDeclarativeContext *child = d->childContexts; + while (child) { + QDeclarativeContextPrivate *childpriv = child->d_func(); + childpriv->invalidateEngines(); + childpriv->parent = 0; + child = childpriv->nextChild; + childpriv->nextChild = 0; + childpriv->prevChild = 0; + } + d->childContexts = 0; QDeclarativeAbstractExpression *expression = d->expressions; while (expression) { @@ -322,10 +333,12 @@ void QDeclarativeContextPrivate::invalidateEngines() if (!engine) return; engine = 0; - for (QSet<QDeclarativeContext *>::ConstIterator iter = childContexts.begin(); - iter != childContexts.end(); - ++iter) { - (*iter)->d_func()->invalidateEngines(); + + QDeclarativeContext *child = childContexts; + while (child) { + QDeclarativeContextPrivate *childpriv = child->d_func(); + childpriv->invalidateEngines(); + child = childpriv->nextChild; } } @@ -336,10 +349,11 @@ time the context tree *structure* (not values) changes. */ void QDeclarativeContextPrivate::refreshExpressions() { - for (QSet<QDeclarativeContext *>::ConstIterator iter = childContexts.begin(); - iter != childContexts.end(); - ++iter) { - (*iter)->d_func()->refreshExpressions(); + QDeclarativeContext *child = childContexts; + while (child) { + QDeclarativeContextPrivate *childpriv = child->d_func(); + childpriv->refreshExpressions(); + child = childpriv->nextChild; } QDeclarativeAbstractExpression *expression = expressions; @@ -370,13 +384,21 @@ QDeclarativeContext *QDeclarativeContext::parentContext() const } /*! - Add \a defaultObject to this context. The object will be added after - any existing default objects. + Return the context object, or 0 if there is no context object. */ -void QDeclarativeContext::addDefaultObject(QObject *defaultObject) +QObject *QDeclarativeContext::contextObject() const +{ + Q_D(const QDeclarativeContext); + return d->contextObject; +} + +/*! + Set the context \a object. +*/ +void QDeclarativeContext::setContextObject(QObject *object) { Q_D(QDeclarativeContext); - d->defaultObjects.prepend(defaultObject); + d->contextObject = object; } /*! @@ -471,15 +493,12 @@ QVariant QDeclarativeContext::contextProperty(const QString &name) const if (idx == -1) { QByteArray utf8Name = name.toUtf8(); - for (int ii = d->defaultObjects.count() - 1; ii >= 0; --ii) { - QObject *obj = d->defaultObjects.at(ii); + if (d->contextObject) { + QObject *obj = d->contextObject; QDeclarativePropertyCache::Data local; QDeclarativePropertyCache::Data *property = QDeclarativePropertyCache::property(d->engine, obj, name, local); - if (property) { - value = obj->metaObject()->property(property->coreIndex).read(obj); - break; - } + if (property) value = obj->metaObject()->property(property->coreIndex).read(obj); } if (!value.isValid() && parentContext()) value = parentContext()->contextProperty(name); diff --git a/src/declarative/qml/qdeclarativecontext.h b/src/declarative/qml/qdeclarativecontext.h index 0fb9bee..3ad9863 100644 --- a/src/declarative/qml/qdeclarativecontext.h +++ b/src/declarative/qml/qdeclarativecontext.h @@ -72,11 +72,12 @@ public: QDeclarativeEngine *engine() const; QDeclarativeContext *parentContext() const; - void addDefaultObject(QObject *); - void setContextProperty(const QString &, QObject *); - void setContextProperty(const QString &, const QVariant &); + QObject *contextObject() const; + void setContextObject(QObject *); QVariant contextProperty(const QString &) const; + void setContextProperty(const QString &, QObject *); + void setContextProperty(const QString &, const QVariant &); QUrl resolvedUrl(const QUrl &); diff --git a/src/declarative/qml/qdeclarativecontext_p.h b/src/declarative/qml/qdeclarativecontext_p.h index 8297280..a1056b1 100644 --- a/src/declarative/qml/qdeclarativecontext_p.h +++ b/src/declarative/qml/qdeclarativecontext_p.h @@ -59,6 +59,7 @@ #include "qdeclarativeengine_p.h" #include "qdeclarativeintegercache_p.h" #include "qdeclarativetypenamecache_p.h" +#include "qdeclarativenotifier_p.h" #include <QtCore/qhash.h> #include <QtScript/qscriptvalue.h> @@ -93,8 +94,7 @@ public: QList<QVariant> propertyValues; int notifyIndex; - QObjectList defaultObjects; - int highPriorityCount; + QObject *contextObject; QList<QScriptValue> scripts; void addScript(const QDeclarativeParser::Object::ScriptBlock &, QObject *); @@ -107,25 +107,16 @@ public: void invalidateEngines(); void refreshExpressions(); - QSet<QDeclarativeContext *> childContexts; + + QDeclarativeContext *childContexts; + + QDeclarativeContext *nextChild; + QDeclarativeContext **prevChild; QDeclarativeAbstractExpression *expressions; QDeclarativeDeclarativeData *contextObjects; - struct IdNotifier - { - inline IdNotifier(); - inline ~IdNotifier(); - - inline void clear(); - - IdNotifier *next; - IdNotifier**prev; - QObject *target; - int methodIndex; - }; - struct ContextGuard : public QDeclarativeGuard<QObject> { inline ContextGuard(); @@ -133,7 +124,7 @@ public: inline virtual void objectDestroyed(QObject *); QDeclarativeContextPrivate *priv; - IdNotifier *bindings; + QDeclarativeNotifier bindings; }; ContextGuard *idValues; int idValueCount; @@ -157,26 +148,8 @@ public: static QObject *context_at(QDeclarativeListProperty<QObject> *, int); }; -QDeclarativeContextPrivate::IdNotifier::IdNotifier() -: next(0), prev(0), target(0), methodIndex(-1) -{ -} - -QDeclarativeContextPrivate::IdNotifier::~IdNotifier() -{ - clear(); -} - -void QDeclarativeContextPrivate::IdNotifier::clear() -{ - if (next) next->prev = prev; - if (prev) *prev = next; - next = 0; prev = 0; target = 0; - methodIndex = -1; -} - QDeclarativeContextPrivate::ContextGuard::ContextGuard() -: priv(0), bindings(0) +: priv(0) { } diff --git a/src/declarative/qml/qdeclarativecontextscriptclass.cpp b/src/declarative/qml/qdeclarativecontextscriptclass.cpp index 5fcf4e2..874eeac 100644 --- a/src/declarative/qml/qdeclarativecontextscriptclass.cpp +++ b/src/declarative/qml/qdeclarativecontextscriptclass.cpp @@ -80,7 +80,7 @@ struct ContextData : public QScriptDeclarativeClass::Object { */ QDeclarativeContextScriptClass::QDeclarativeContextScriptClass(QDeclarativeEngine *bindEngine) : QDeclarativeScriptClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine), - lastScopeObject(0), lastContext(0), lastData(0), lastPropertyIndex(-1), lastDefaultObject(-1) + lastScopeObject(0), lastContext(0), lastData(0), lastPropertyIndex(-1) { } @@ -132,7 +132,6 @@ QDeclarativeContextScriptClass::queryProperty(Object *object, const Identifier & lastContext = 0; lastData = 0; lastPropertyIndex = -1; - lastDefaultObject = -1; QDeclarativeContext *bindContext = ((ContextData *)object)->getContext(engine); QObject *scopeObject = ((ContextData *)object)->getScope(engine); @@ -210,13 +209,13 @@ QDeclarativeContextScriptClass::queryProperty(QDeclarativeContext *bindContext, } } - for (int ii = cp->defaultObjects.count() - 1; ii >= 0; --ii) { + if (cp->contextObject) { QScriptClass::QueryFlags rv = - ep->objectClass->queryProperty(cp->defaultObjects.at(ii), name, flags, bindContext, + ep->objectClass->queryProperty(cp->contextObject, name, flags, bindContext, QDeclarativeObjectScriptClass::ImplicitObject | QDeclarativeObjectScriptClass::SkipAttachedProperties); if (rv) { - lastDefaultObject = ii; + lastScopeObject = cp->contextObject; lastContext = bindContext; return rv; } @@ -244,9 +243,9 @@ QDeclarativeContextScriptClass::property(Object *object, const Identifier &name) } else if (lastData) { if (lastData->type) - return Value(scriptEngine, ep->typeNameClass->newObject(cp->defaultObjects.at(0), lastData->type)); + return Value(scriptEngine, ep->typeNameClass->newObject(cp->contextObject, lastData->type)); else - return Value(scriptEngine, ep->typeNameClass->newObject(cp->defaultObjects.at(0), lastData->typeNamespace)); + return Value(scriptEngine, ep->typeNameClass->newObject(cp->contextObject, lastData->typeNamespace)); } else if (lastPropertyIndex != -1) { @@ -267,10 +266,6 @@ QDeclarativeContextScriptClass::property(Object *object, const Identifier &name) return Value(scriptEngine, rv); - } else if(lastDefaultObject != -1) { - - // Default object property - return ep->objectClass->property(cp->defaultObjects.at(lastDefaultObject), name); } else { @@ -283,7 +278,7 @@ void QDeclarativeContextScriptClass::setProperty(Object *object, const Identifie const QScriptValue &value) { Q_UNUSED(object); - Q_ASSERT(lastScopeObject || lastDefaultObject != -1); + Q_ASSERT(lastScopeObject); QDeclarativeContext *bindContext = lastContext; Q_ASSERT(bindContext); @@ -291,12 +286,7 @@ void QDeclarativeContextScriptClass::setProperty(Object *object, const Identifie QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); QDeclarativeContextPrivate *cp = QDeclarativeContextPrivate::get(bindContext); - if (lastScopeObject) { - ep->objectClass->setProperty(lastScopeObject, name, value, bindContext); - } else { - ep->objectClass->setProperty(cp->defaultObjects.at(lastDefaultObject), name, value, - bindContext); - } + ep->objectClass->setProperty(lastScopeObject, name, value, bindContext); } QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativecontextscriptclass_p.h b/src/declarative/qml/qdeclarativecontextscriptclass_p.h index 4b0dca0..32c117c 100644 --- a/src/declarative/qml/qdeclarativecontextscriptclass_p.h +++ b/src/declarative/qml/qdeclarativecontextscriptclass_p.h @@ -90,7 +90,6 @@ private: QDeclarativeContext *lastContext; QDeclarativeTypeNameCache::Data *lastData; int lastPropertyIndex; - int lastDefaultObject; QScriptValue lastFunction; uint m_id; diff --git a/src/declarative/qml/qdeclarativecustomparser_p.h b/src/declarative/qml/qdeclarativecustomparser_p.h index 99587a8..39bd43c 100644 --- a/src/declarative/qml/qdeclarativecustomparser_p.h +++ b/src/declarative/qml/qdeclarativecustomparser_p.h @@ -128,9 +128,10 @@ private: QList<QDeclarativeError> exceptions; }; +#if 0 #define QML_REGISTER_CUSTOM_TYPE(URI, VERSION_MAJ, VERSION_MIN, NAME, TYPE, CUSTOMTYPE) \ qmlRegisterCustomType<TYPE>(#URI, VERSION_MAJ, VERSION_MIN, #NAME, #TYPE, new CUSTOMTYPE) - +#endif QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativedeclarativedata_p.h b/src/declarative/qml/qdeclarativedeclarativedata_p.h index ae40130..ffce9c9 100644 --- a/src/declarative/qml/qdeclarativedeclarativedata_p.h +++ b/src/declarative/qml/qdeclarativedeclarativedata_p.h @@ -67,12 +67,21 @@ class Q_AUTOTEST_EXPORT QDeclarativeDeclarativeData : public QDeclarativeData { public: QDeclarativeDeclarativeData(QDeclarativeContext *ctxt = 0) - : context(ctxt), bindings(0), nextContextObject(0), prevContextObject(0), - bindingBitsSize(0), bindingBits(0), outerContext(0), lineNumber(0), - columnNumber(0), deferredComponent(0), deferredIdx(0), attachedProperties(0), - propertyCache(0), guards(0) {} + : indestructible(true), explicitIndestructibleSet(false), context(ctxt), + bindings(0), nextContextObject(0), prevContextObject(0), bindingBitsSize(0), bindingBits(0), + outerContext(0), lineNumber(0), columnNumber(0), deferredComponent(0), deferredIdx(0), + attachedProperties(0), propertyCache(0), guards(0) {} virtual void destroyed(QObject *); + virtual void parentChanged(QObject *, QObject *); + + void setImplicitDestructible() { + if (!explicitIndestructibleSet) indestructible = false; + } + + quint32 indestructible:1; + quint32 explicitIndestructibleSet:1; + quint32 dummy:29; QDeclarativeContext *context; QDeclarativeAbstractBinding *bindings; diff --git a/src/declarative/qml/qdeclarativedirparser.cpp b/src/declarative/qml/qdeclarativedirparser.cpp index e730b92..b6d2115 100644 --- a/src/declarative/qml/qdeclarativedirparser.cpp +++ b/src/declarative/qml/qdeclarativedirparser.cpp @@ -151,13 +151,16 @@ bool QDeclarativeDirParser::parse() _plugins.append(entry); + } else if (sectionCount == 2) { + // No version specified (should only be used for relative qmldir files) + const Component entry(sections[0], sections[1], -1, -1); + _components.append(entry); } else if (sectionCount == 3) { const QString &version = sections[1]; const int dotIndex = version.indexOf(QLatin1Char('.')); if (dotIndex == -1) { qWarning() << "expected '.'"; // ### use reportError - } else if (version.indexOf(QLatin1Char('.'), dotIndex + 1) != -1) { qWarning() << "unexpected '.'"; // ### use reportError diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index c23b17c..e84e267 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -146,12 +146,11 @@ static bool qt_QmlQtModule_registered = false; void QDeclarativeEnginePrivate::defineModule() { - QML_REGISTER_TYPE(Qt,4,6,Component,QDeclarativeComponent); - QML_REGISTER_TYPE(Qt,4,6,QtObject,QObject); - QML_REGISTER_TYPE(Qt,4,6,WorkerScript,QDeclarativeWorkerScript); - QML_REGISTER_TYPE(Qt,4,6,WorkerListModel,QDeclarativeWorkerListModel); + qmlRegisterType<QDeclarativeComponent>("Qt",4,6,"Component"); + qmlRegisterType<QObject>("Qt",4,6,"QtObject"); + qmlRegisterType<QDeclarativeWorkerScript>("Qt",4,6,"WorkerScript"); - QML_REGISTER_NOCREATE_TYPE(QDeclarativeBinding); + qmlRegisterType<QDeclarativeBinding>(); } QDeclarativeEnginePrivate::QDeclarativeEnginePrivate(QDeclarativeEngine *e) @@ -243,7 +242,6 @@ QDeclarativeScriptEngine::QDeclarativeScriptEngine(QDeclarativeEnginePrivate *pr qtObject.setProperty(QLatin1String("formatDateTime"),newFunction(QDeclarativeEnginePrivate::formatDateTime, 2)); //misc methods - qtObject.setProperty(QLatin1String("closestAngle"), newFunction(QDeclarativeEnginePrivate::closestAngle, 2)); qtObject.setProperty(QLatin1String("openUrlExternally"),newFunction(QDeclarativeEnginePrivate::desktopOpenUrl, 1)); qtObject.setProperty(QLatin1String("md5"),newFunction(QDeclarativeEnginePrivate::md5, 1)); qtObject.setProperty(QLatin1String("btoa"),newFunction(QDeclarativeEnginePrivate::btoa, 1)); @@ -668,6 +666,61 @@ void QDeclarativeEngine::setContextForObject(QObject *object, QDeclarativeContex context->d_func()->contextObjects = data; } +/*! +\enum QDeclarativeEngine::ObjectOwnership + +Ownership controls whether or not QML automatically destroys the QObject when the object +is garbage collected by the JavaScript engine. The two ownership options are: + +\list +\o CppOwnership - The object is owned by C++ code, and will never be deleted by QML. The +JavaScript destroy() method cannot be used on objects with CppOwnership. This option +is similar to QScriptEngine::QtOwnership. + +\o JavaScriptOwnership - The object is owned by JavaScript. When the object is returned to QML +as the return value of a method call or property access, QML will delete the object if there +are no remaining JavaScript references to it and it has no QObject::parent(). This option +is similar to QScriptEngine::ScriptOwnership. +\endlist + +Generally an application doesn't need to set an object's ownership explicitly. QML uses +a heuristic to set the default object ownership. By default, an object that is created by +QML has JavaScriptOwnership. The exception to this are the root objects created by calling +QDeclarativeCompnent::create() or QDeclarativeComponent::beginCreate() which have +CppOwnership by default. The ownership of these root-level objects is considered to have +been transfered to the C++ caller. + +Objects not-created by QML have CppOwnership by default. The exception to this is objects +returned from a C++ method call. The ownership of these objects is passed to JavaScript. + +Calling setObjectOwnership() overrides the default ownership heuristic used by QML. +*/ + +/*! +Sets the \a ownership of \a object. +*/ +void QDeclarativeEngine::setObjectOwnership(QObject *object, ObjectOwnership ownership) +{ + QDeclarativeDeclarativeData *ddata = QDeclarativeDeclarativeData::get(object, true); + if (!ddata) + return; + + ddata->indestructible = (ownership == CppOwnership)?true:false; + ddata->explicitIndestructibleSet = true; +} + +/*! +Returns the ownership of \a object. +*/ +QDeclarativeEngine::ObjectOwnership QDeclarativeEngine::objectOwnership(QObject *object) +{ + QDeclarativeDeclarativeData *ddata = QDeclarativeDeclarativeData::get(object, false); + if (!ddata) + return CppOwnership; + else + return ddata->indestructible?CppOwnership:JavaScriptOwnership; +} + void qmlExecuteDeferred(QObject *object) { QDeclarativeDeclarativeData *data = QDeclarativeDeclarativeData::get(object); @@ -778,6 +831,11 @@ void QDeclarativeDeclarativeData::destroyed(QObject *object) delete this; } +void QDeclarativeDeclarativeData::parentChanged(QObject *, QObject *parent) +{ + if (!parent && scriptValue.isValid()) scriptValue = QScriptValue(); +} + bool QDeclarativeDeclarativeData::hasBindingBit(int bit) const { if (bindingBitsSize > bit) @@ -858,6 +916,7 @@ QScriptValue QDeclarativeEnginePrivate::createComponent(QScriptContext *ctxt, QUrl url = QUrl(context->resolvedUrl(QUrl(arg))); QDeclarativeComponent *c = new QDeclarativeComponent(activeEngine, url, activeEngine); c->setCreationContext(context); + QDeclarativeDeclarativeData::get(c, true)->setImplicitDestructible(); return activeEnginePriv->objectClass->newQObject(c, qMetaTypeId<QDeclarativeComponent*>()); } } @@ -928,7 +987,8 @@ QScriptValue QDeclarativeEnginePrivate::createQmlObject(QScriptContext *ctxt, QS if(gobj && gparent) gobj->setParentItem(gparent); - return qmlScriptObject(obj, activeEngine); + QDeclarativeDeclarativeData::get(obj, true)->setImplicitDestructible(); + return activeEnginePriv->objectClass->newQObject(obj, QMetaType::QObjectStar); } QScriptValue QDeclarativeEnginePrivate::vector(QScriptContext *ctxt, QScriptEngine *engine) @@ -1177,25 +1237,6 @@ QScriptValue QDeclarativeEnginePrivate::quit(QScriptContext * /*ctxt*/, QScriptE return QScriptValue(); } -QScriptValue QDeclarativeEnginePrivate::closestAngle(QScriptContext *ctxt, QScriptEngine *e) -{ - if(ctxt->argumentCount() < 2) - return e->newVariant(QVariant(0.0)); - qreal a = ctxt->argument(0).toNumber(); - qreal b = ctxt->argument(1).toNumber(); - qreal ret = b; - qreal diff = b-a; - while(diff > 180.0){ - ret -= 360.0; - diff -= 360.0; - } - while(diff < -180.0){ - ret += 360.0; - diff += 360.0; - } - return e->newVariant(QVariant(ret)); -} - QScriptValue QDeclarativeEnginePrivate::tint(QScriptContext *ctxt, QScriptEngine *engine) { if(ctxt->argumentCount() != 2) @@ -1301,10 +1342,13 @@ QVariant QDeclarativeScriptClass::toVariant(QDeclarativeEngine *engine, const QS // XXX this beyonds in QUrl::toLocalFile() static QString toLocalFileOrQrc(const QUrl& url) { - QString r = url.toLocalFile(); - if (r.isEmpty() && url.scheme() == QLatin1String("qrc")) - r = QLatin1Char(':') + url.path(); - return r; + if (url.scheme() == QLatin1String("qrc")) { + if (url.authority().isEmpty()) + return QLatin1Char(':') + url.path(); + qWarning() << "Invalid url:" << url.toString() << "authority" << url.authority() << "not known."; + return QString(); + } + return url.toLocalFile(); } ///////////////////////////////////////////////////////////// @@ -1316,7 +1360,7 @@ struct QDeclarativeEnginePrivate::ImportedNamespace { QList<bool> isLibrary; QList<QString> qmlDirContent; - bool find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return, QUrl* url_return) const + bool find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return, QUrl* url_return) { for (int i=0; i<urls.count(); ++i) { int vmaj = majversions.at(i); @@ -1326,14 +1370,10 @@ struct QDeclarativeEnginePrivate::ImportedNamespace { qt += '/'; qt += type; - if (qmlImportTrace()) - qDebug() << "Look in" << qt; QDeclarativeType *t = QDeclarativeMetaType::qmlType(qt,vmaj,vmin); if (t) { if (vmajor) *vmajor = vmaj; if (vminor) *vminor = vmin; - if (qmlImportTrace()) - qDebug() << "Found" << qt; if (type_return) *type_return = t; return true; @@ -1341,14 +1381,8 @@ struct QDeclarativeEnginePrivate::ImportedNamespace { QUrl url = QUrl(urls.at(i) + QLatin1Char('/') + QString::fromUtf8(type) + QLatin1String(".qml")); QString qmldircontent = qmlDirContent.at(i); - if (vmaj>=0 || !qmldircontent.isEmpty()) { - // Check version file - XXX cache these in QDeclarativeEngine! - if (qmldircontent.isEmpty()) { - QFile qmldir(toLocalFileOrQrc(QUrl(urls.at(i)+QLatin1String("/qmldir")))); - if (qmldir.open(QIODevice::ReadOnly)) { - qmldircontent = QString::fromUtf8(qmldir.readAll()); - } - } + + if (!qmldircontent.isEmpty()) { const QString typeName = QString::fromUtf8(type); @@ -1362,7 +1396,6 @@ struct QDeclarativeEnginePrivate::ImportedNamespace { if (c.typeName == typeName) { if (url_return) *url_return = url.resolved(QUrl(c.fileName)); - return true; } } @@ -1396,8 +1429,9 @@ public: QSet<QString> qmlDirFilesForWhichPluginsHaveBeenLoaded; - bool add(const QUrl& base, const QString& qmldircontent, const QString& uri, const QString& prefix, int vmaj, int vmin, QDeclarativeScriptParser::Import::Type importType, const QStringList& importPath, QDeclarativeEngine *engine) + bool add(const QUrl& base, const QString &qmldircontentnetwork, const QString& uri, const QString& prefix, int vmaj, int vmin, QDeclarativeScriptParser::Import::Type importType, const QStringList& importPath, QDeclarativeEngine *engine) { + QString qmldircontent = qmldircontentnetwork; QDeclarativeEnginePrivate::ImportedNamespace *s; if (prefix.isEmpty()) { s = &unqualifiedset; @@ -1410,15 +1444,21 @@ public: if (importType == QDeclarativeScriptParser::Import::Library) { url.replace(QLatin1Char('.'), QLatin1Char('/')); bool found = false; - QString content; QString dir; // user import paths QStringList paths; // base.. - paths += QFileInfo(base.toLocalFile()).path(); + QString localFileOrQrc = toLocalFileOrQrc(base); + QString localFileOrQrcPath = QFileInfo(localFileOrQrc).path(); + paths += localFileOrQrcPath; paths += importPath; + + QString applicationDirPath = QCoreApplication::applicationDirPath(); + if (!applicationDirPath.isEmpty()) + paths += applicationDirPath; + paths += QDeclarativeEnginePrivate::get(engine)->environmentImportPath; #if (QT_VERSION >= QT_VERSION_CHECK(4,7,0)) QString builtinPath = QLibraryInfo::location(QLibraryInfo::ImportsPath); @@ -1430,6 +1470,7 @@ public: foreach (const QString &p, paths) { dir = p+QLatin1Char('/')+url; + QFileInfo fi(dir+QLatin1String("/qmldir")); const QString absoluteFilePath = fi.absoluteFilePath(); @@ -1439,22 +1480,31 @@ public: url = QUrl::fromLocalFile(fi.absolutePath()).toString(); QFile file(absoluteFilePath); - if (file.open(QFile::ReadOnly)) - content = QString::fromUtf8(file.readAll()); + if (file.open(QFile::ReadOnly)) { + qmldircontent = QString::fromUtf8(file.readAll()); + if (qmlImportTrace()) + qDebug() << "QDeclarativeEngine::add: loaded" << absoluteFilePath; + } if (! qmlDirFilesForWhichPluginsHaveBeenLoaded.contains(absoluteFilePath)) { qmlDirFilesForWhichPluginsHaveBeenLoaded.insert(absoluteFilePath); QDeclarativeDirParser qmldirParser; - qmldirParser.setSource(content); + qmldirParser.setSource(qmldircontent); qmldirParser.parse(); foreach (const QDeclarativeDirParser::Plugin &plugin, qmldirParser.plugins()) { - QString resolvedFilePath = QDeclarativeEnginePrivate::get(engine)->resolvePlugin(QDir(dir + QDir::separator() + plugin.path), - plugin.name); - - if (!resolvedFilePath.isEmpty()) + QDir pluginDir(dir + QDir::separator() + plugin.path); + if (p.startsWith(QLatin1Char(':'))) + pluginDir = QDir(QCoreApplication::applicationDirPath()); + QString resolvedFilePath = + QDeclarativeEnginePrivate::get(engine) + ->resolvePlugin(pluginDir, + plugin.name); + + if (!resolvedFilePath.isEmpty()) { engine->importExtension(resolvedFilePath, uri); + } } } @@ -1642,9 +1692,10 @@ QUrl QDeclarativeEnginePrivate::Imports::baseUrl() const type version mapping and possibly declarative extensions plugins. The engine searches in the base directory of the qml file, then - the paths added via addImportPath(), then the paths specified in the - \c QML_IMPORT_PATH environment variable, then the builtin \c ImportsPath from - QLibraryInfo. + the paths added via addImportPath(), then in the directory containing the + application executable (QCoreApplication::applicationDirPath()), + then the paths specified in the \c QML_IMPORT_PATH environment variable, then the + builtin \c ImportsPath from QLibraryInfo. */ void QDeclarativeEngine::addImportPath(const QString& path) @@ -1661,6 +1712,8 @@ void QDeclarativeEngine::addImportPath(const QString& path) */ bool QDeclarativeEngine::importExtension(const QString &fileName, const QString &uri) { + if (qmlImportTrace()) + qDebug() << "QDeclarativeEngine::importExtension" << uri << "from" << fileName; QFileInfo fileInfo(fileName); const QString absoluteFilePath = fileInfo.absoluteFilePath(); QPluginLoader loader(absoluteFilePath); @@ -1784,6 +1837,9 @@ QString QDeclarativeEnginePrivate::resolvePlugin(const QDir &dir, const QString return resolvePlugin(dir, baseName, QStringList() +# ifdef QT_DEBUG + << QLatin1String("_debug.dylib") // try a qmake-style debug build first +# endif << QLatin1String(".dylib") << QLatin1String(".so") << QLatin1String(".bundle"), @@ -1830,12 +1886,12 @@ QString QDeclarativeEnginePrivate::resolvePlugin(const QDir &dir, const QString The base URL must already have been set with Import::setBaseUrl(). */ -bool QDeclarativeEnginePrivate::addToImport(Imports* imports, const QString& qmldircontent, const QString& uri, const QString& prefix, int vmaj, int vmin, QDeclarativeScriptParser::Import::Type importType) const +bool QDeclarativeEnginePrivate::addToImport(Imports* imports, const QString &qmldircontentnetwork, const QString& uri, const QString& prefix, int vmaj, int vmin, QDeclarativeScriptParser::Import::Type importType) const { QDeclarativeEngine *engine = QDeclarativeEnginePrivate::get(const_cast<QDeclarativeEnginePrivate *>(this)); - bool ok = imports->d->add(imports->d->base,qmldircontent,uri,prefix,vmaj,vmin,importType,fileImportPath, engine); if (qmlImportTrace()) - qDebug() << "QDeclarativeEngine::addToImport(" << imports << uri << prefix << vmaj << '.' << vmin << (importType==QDeclarativeScriptParser::Import::Library? "Library" : "File") << ": " << ok; + qDebug() << "QDeclarativeEngine::addToImport(" << imports << uri << prefix << vmaj << '.' << vmin << (importType==QDeclarativeScriptParser::Import::Library? "Library" : "File"); + bool ok = imports->d->add(imports->d->base,qmldircontentnetwork, uri,prefix,vmaj,vmin,importType,fileImportPath, engine); return ok; } @@ -1855,8 +1911,6 @@ bool QDeclarativeEnginePrivate::resolveType(const Imports& imports, const QByteA { ImportedNamespace* ns = imports.d->findNamespace(QString::fromUtf8(type)); if (ns) { - if (qmlImportTrace()) - qDebug() << "QDeclarativeEngine::resolveType" << type << "is namespace for" << ns->urls; if (ns_return) *ns_return = ns; return true; @@ -1864,15 +1918,15 @@ bool QDeclarativeEnginePrivate::resolveType(const Imports& imports, const QByteA if (type_return || url_return) { if (imports.d->find(type,vmaj,vmin,type_return,url_return)) { if (qmlImportTrace()) { + if (type_return && *type_return && url_return && !url_return->isEmpty()) + qDebug() << "QDeclarativeEngine::resolveType" << type << '=' << (*type_return)->typeName() << *url_return; if (type_return && *type_return) qDebug() << "QDeclarativeEngine::resolveType" << type << '=' << (*type_return)->typeName(); - if (url_return) + if (url_return && !url_return->isEmpty()) qDebug() << "QDeclarativeEngine::resolveType" << type << '=' << *url_return; } return true; } - if (qmlImportTrace()) - qDebug() << "QDeclarativeEngine::resolveType" << type << "not found"; } return false; } diff --git a/src/declarative/qml/qdeclarativeengine.h b/src/declarative/qml/qdeclarativeengine.h index fd66358..19e81b6 100644 --- a/src/declarative/qml/qdeclarativeengine.h +++ b/src/declarative/qml/qdeclarativeengine.h @@ -98,6 +98,10 @@ public: static QDeclarativeContext *contextForObject(const QObject *); static void setContextForObject(QObject *, QDeclarativeContext *); + enum ObjectOwnership { CppOwnership, JavaScriptOwnership }; + static void setObjectOwnership(QObject *, ObjectOwnership); + static ObjectOwnership objectOwnership(QObject *); + Q_SIGNALS: void quit (); diff --git a/src/declarative/qml/qdeclarativeengine_p.h b/src/declarative/qml/qdeclarativeengine_p.h index 459a325..c73a758 100644 --- a/src/declarative/qml/qdeclarativeengine_p.h +++ b/src/declarative/qml/qdeclarativeengine_p.h @@ -276,7 +276,7 @@ public: QString resolvePlugin(const QDir &dir, const QString &baseName); - bool addToImport(Imports*, const QString& qmlDirContent,const QString& uri, const QString& prefix, int vmaj, int vmin, QDeclarativeScriptParser::Import::Type importType) const; + bool addToImport(Imports*, const QString& uri, const QString &qmldircontentnetwork, const QString& prefix, int vmaj, int vmin, QDeclarativeScriptParser::Import::Type importType) const; bool resolveType(const Imports&, const QByteArray& type, QDeclarativeType** type_return, QUrl* url_return, int *version_major, int *version_minor, @@ -318,7 +318,6 @@ public: static QScriptValue darker(QScriptContext*, QScriptEngine*); static QScriptValue tint(QScriptContext*, QScriptEngine*); - static QScriptValue closestAngle(QScriptContext*, QScriptEngine*); static QScriptValue desktopOpenUrl(QScriptContext*, QScriptEngine*); static QScriptValue md5(QScriptContext*, QScriptEngine*); static QScriptValue btoa(QScriptContext*, QScriptEngine*); diff --git a/src/declarative/qml/qdeclarativeenginedebug.cpp b/src/declarative/qml/qdeclarativeenginedebug.cpp index 3e4acbe..933683c 100644 --- a/src/declarative/qml/qdeclarativeenginedebug.cpp +++ b/src/declarative/qml/qdeclarativeenginedebug.cpp @@ -230,22 +230,22 @@ void QDeclarativeEngineDebugServer::buildObjectList(QDataStream &message, int count = 0; - for (QSet<QDeclarativeContext *>::ConstIterator iter = p->childContexts.begin(); - iter != p->childContexts.end(); ++iter) { - QDeclarativeContextPrivate *p = (QDeclarativeContextPrivate *)QObjectPrivate::get(*iter); - if (p->isInternal) - continue; - ++count; + QDeclarativeContext *child = p->childContexts; + while (child) { + QDeclarativeContextPrivate *p = QDeclarativeContextPrivate::get(child); + if (!p->isInternal) + ++count; + child = p->nextChild; } message << count; - for (QSet<QDeclarativeContext *>::ConstIterator iter = p->childContexts.begin(); - iter != p->childContexts.end(); ++iter) { - QDeclarativeContextPrivate *p = (QDeclarativeContextPrivate *)QObjectPrivate::get(*iter); - if (p->isInternal) - continue; - buildObjectList(message, *iter); + child = p->childContexts; + while (child) { + QDeclarativeContextPrivate *p = QDeclarativeContextPrivate::get(child); + if (!p->isInternal) + buildObjectList(message, child); + child = p->nextChild; } // Clean deleted objects diff --git a/src/declarative/qml/qdeclarativeexpression.cpp b/src/declarative/qml/qdeclarativeexpression.cpp index 899f402..5ff22f7 100644 --- a/src/declarative/qml/qdeclarativeexpression.cpp +++ b/src/declarative/qml/qdeclarativeexpression.cpp @@ -622,137 +622,74 @@ void QDeclarativeExpression::__q_notify() void QDeclarativeExpressionPrivate::clearGuards() { - Q_Q(QDeclarativeExpression); - - static int notifyIdx = -1; - if (notifyIdx == -1) - notifyIdx = - QDeclarativeExpression::staticMetaObject.indexOfMethod("__q_notify()"); - - for (int ii = 0; ii < data->guardListLength; ++ii) { - if (data->guardList[ii].data()) { -#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 2)) - QMetaObject::disconnectOne(data->guardList[ii].data(), - data->guardList[ii].notifyIndex, - q, notifyIdx); -#else - // QTBUG-6781 - QMetaObject::disconnect(data->guardList[ii].data(), - data->guardList[ii].notifyIndex, - q, notifyIdx); -#endif - } - } - - delete [] data->guardList; data->guardList = 0; + delete [] data->guardList; + data->guardList = 0; data->guardListLength = 0; } void QDeclarativeExpressionPrivate::updateGuards(const QPODVector<QDeclarativeEnginePrivate::CapturedProperty> &properties) { - //clearGuards(); Q_Q(QDeclarativeExpression); static int notifyIdx = -1; if (notifyIdx == -1) - notifyIdx = - QDeclarativeExpression::staticMetaObject.indexOfMethod("__q_notify()"); + notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("__q_notify()"); - QDeclarativeExpressionData::SignalGuard *newGuardList = 0; - - if (properties.count() != data->guardListLength) - newGuardList = new QDeclarativeExpressionData::SignalGuard[properties.count()]; + if (properties.count() != data->guardListLength) { + QDeclarativeNotifierEndpoint *newGuardList = + new QDeclarativeNotifierEndpoint[properties.count()]; + + for (int ii = 0; ii < qMin(data->guardListLength, properties.count()); ++ii) + data->guardList[ii].copyAndClear(newGuardList[ii]); + + delete [] data->guardList; + data->guardList = newGuardList; + data->guardListLength = properties.count(); + } bool outputWarningHeader = false; - int hit = 0; + bool noChanges = true; for (int ii = 0; ii < properties.count(); ++ii) { + QDeclarativeNotifierEndpoint &guard = data->guardList[ii]; const QDeclarativeEnginePrivate::CapturedProperty &property = properties.at(ii); - bool needGuard = true; - if (ii >= data->guardListLength) { - // New guard - } else if(data->guardList[ii].data() == property.object && - data->guardList[ii].notifyIndex == property.notifyIndex) { - // Cache hit - if (!data->guardList[ii].isDuplicate || - (data->guardList[ii].isDuplicate && hit == ii)) { - needGuard = false; - ++hit; - } - } else if(data->guardList[ii].data() && !data->guardList[ii].isDuplicate) { - // Cache miss -#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 2)) - QMetaObject::disconnectOne(data->guardList[ii].data(), - data->guardList[ii].notifyIndex, - q, notifyIdx); -#else - // QTBUG-6781 - QMetaObject::disconnect(data->guardList[ii].data(), - data->guardList[ii].notifyIndex, - q, notifyIdx); -#endif - } - /* else { - // Cache miss, but nothing to do - } */ - - if (needGuard) { - if (!newGuardList) { - newGuardList = new QDeclarativeExpressionData::SignalGuard[properties.count()]; - for (int jj = 0; jj < ii; ++jj) - newGuardList[jj] = data->guardList[jj]; - } + guard.target = q; + guard.targetMethod = notifyIdx; + + if (property.notifyIndex != -1) { + + if (!noChanges && guard.isConnected(property.object, property.notifyIndex)) { + // Nothing to do + + } else { + noChanges = false; - if (property.notifyIndex != -1) { bool existing = false; for (int jj = 0; !existing && jj < ii; ++jj) - existing = newGuardList[jj].data() == property.object && - newGuardList[jj].notifyIndex == property.notifyIndex; - - newGuardList[ii] = property.object; - newGuardList[ii].notifyIndex = property.notifyIndex; - if (existing) - newGuardList[ii].isDuplicate = true; - else - QMetaObject::connect(property.object, property.notifyIndex, - q, notifyIdx); - } else { - if (!outputWarningHeader) { - outputWarningHeader = true; - qWarning() << "QDeclarativeExpression: Expression" << q->expression() - << "depends on non-NOTIFYable properties:"; + if (data->guardList[jj].isConnected(property.object, property.notifyIndex)) + existing = true; + + if (existing) { + // duplicate + guard.disconnect(); + } else { + guard.connect(property.object, property.notifyIndex); } + } - const QMetaObject *metaObj = property.object->metaObject(); - QMetaProperty metaProp = metaObj->property(property.coreIndex); - - qWarning().nospace() << " " << metaObj->className() - << "::" << metaProp.name(); + } else { + if (!outputWarningHeader) { + outputWarningHeader = true; + qWarning() << "QDeclarativeExpression: Expression" << q->expression() + << "depends on non-NOTIFYable properties:"; } - } else if (newGuardList) { - newGuardList[ii] = data->guardList[ii]; - } - } - for (int ii = properties.count(); ii < data->guardListLength; ++ii) { - if (data->guardList[ii].data() && !data->guardList[ii].isDuplicate) { -#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 2)) - QMetaObject::disconnectOne(data->guardList[ii].data(), - data->guardList[ii].notifyIndex, - q, notifyIdx); -#else - // QTBUG-6781 - QMetaObject::disconnect(data->guardList[ii].data(), - data->guardList[ii].notifyIndex, - q, notifyIdx); -#endif - } - } + const QMetaObject *metaObj = property.object->metaObject(); + QMetaProperty metaProp = metaObj->property(property.coreIndex); - if (newGuardList) { - if (data->guardList) delete [] data->guardList; - data->guardList = newGuardList; - data->guardListLength = properties.count(); + qWarning().nospace() << " " << metaObj->className() + << "::" << metaProp.name(); + } } } diff --git a/src/declarative/qml/qdeclarativeexpression_p.h b/src/declarative/qml/qdeclarativeexpression_p.h index cd1729d..d170559 100644 --- a/src/declarative/qml/qdeclarativeexpression_p.h +++ b/src/declarative/qml/qdeclarativeexpression_p.h @@ -129,24 +129,7 @@ public: QString url; // This is a QString for a reason. QUrls are slooooooow... int line; - struct SignalGuard : public QDeclarativeGuard<QObject> { - SignalGuard() : isDuplicate(false), notifyIndex(-1) {} - - SignalGuard &operator=(QObject *obj) { - QDeclarativeGuard<QObject>::operator=(obj); - return *this; - } - SignalGuard &operator=(const SignalGuard &o) { - QDeclarativeGuard<QObject>::operator=(o); - isDuplicate = o.isDuplicate; - notifyIndex = o.notifyIndex; - return *this; - } - - bool isDuplicate:1; - int notifyIndex:31; - }; - SignalGuard *guardList; + QDeclarativeNotifierEndpoint *guardList; int guardListLength; }; diff --git a/src/declarative/qml/qdeclarativeinstruction.cpp b/src/declarative/qml/qdeclarativeinstruction.cpp index cf485fe..a23ff75 100644 --- a/src/declarative/qml/qdeclarativeinstruction.cpp +++ b/src/declarative/qml/qdeclarativeinstruction.cpp @@ -90,7 +90,7 @@ void QDeclarativeCompiledData::dump(QDeclarativeInstruction *instr, int idx) qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_STRING\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value); break; case QDeclarativeInstruction::StoreUrl: - qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_URL\t\t" << instr->storeUrl.propertyIndex << "\t" << instr->storeUrl.value << "\t\t" << primitives.at(instr->storeUrl.value); + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_URL\t\t" << instr->storeUrl.propertyIndex << "\t" << instr->storeUrl.value << "\t\t" << urls.at(instr->storeUrl.value); break; case QDeclarativeInstruction::StoreColor: qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_COLOR\t\t" << instr->storeColor.propertyIndex << "\t\t\t" << QString::number(instr->storeColor.value, 16); diff --git a/src/declarative/qml/qdeclarativemetatype.cpp b/src/declarative/qml/qdeclarativemetatype.cpp index 50ab56b..55c7413 100644 --- a/src/declarative/qml/qdeclarativemetatype.cpp +++ b/src/declarative/qml/qdeclarativemetatype.cpp @@ -124,7 +124,10 @@ public: int m_version_maj; int m_version_min; int m_typeId; int m_listId; - QObject *(*m_newFunc)(); + + int m_allocationSize; + void (*m_newFunc)(void *); + const QMetaObject *m_baseMetaObject; QDeclarativeAttachedPropertiesFunc m_attachedPropertiesFunc; const QMetaObject *m_attachedPropertiesType; @@ -141,7 +144,7 @@ public: QDeclarativeTypePrivate::QDeclarativeTypePrivate() : m_isInterface(false), m_iid(0), m_typeId(0), m_listId(0), - m_newFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0), m_attachedPropertiesType(0), + m_allocationSize(0), m_newFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0), m_attachedPropertiesType(0), m_parserStatusCast(-1), m_propertyValueSourceCast(-1), m_propertyValueInterceptorCast(-1), m_extFunc(0), m_extMetaObject(0), m_index(-1), m_customParser(0), m_isSetup(false) { @@ -174,6 +177,7 @@ QDeclarativeType::QDeclarativeType(int index, const QDeclarativePrivate::Registe d->m_version_min = type.versionMinor; d->m_typeId = type.typeId; d->m_listId = type.listId; + d->m_allocationSize = type.objectSize; d->m_newFunc = type.create; d->m_baseMetaObject = type.metaObject; d->m_attachedPropertiesFunc = type.attachedPropertiesFunction; @@ -274,7 +278,9 @@ QObject *QDeclarativeType::create() const { d->init(); - QObject *rv = d->m_newFunc(); + QObject *rv = (QObject *)operator new(d->m_allocationSize); + d->m_newFunc(rv); + if (rv && !d->m_metaObjects.isEmpty()) (void *)new QDeclarativeProxyMetaObject(rv, &d->m_metaObjects); diff --git a/src/declarative/qml/qdeclarativenotifier.cpp b/src/declarative/qml/qdeclarativenotifier.cpp new file mode 100644 index 0000000..8e5904c --- /dev/null +++ b/src/declarative/qml/qdeclarativenotifier.cpp @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativenotifier_p.h" + +QT_BEGIN_NAMESPACE + +void QDeclarativeNotifier::emitNotify(QDeclarativeNotifierEndpoint *endpoint) +{ + QDeclarativeNotifierEndpoint::Notifier *n = endpoint->asNotifier(); + + QDeclarativeNotifierEndpoint::Notifier **oldDisconnected = n->disconnected; + n->disconnected = &n; + + if (n->next) + emitNotify(n->next); + + if (n) { + void *args[] = { 0 }; + + QMetaObject::metacall(endpoint->target, QMetaObject::InvokeMetaMethod, + endpoint->targetMethod, args); + + if (n) + n->disconnected = oldDisconnected; + } + + if (oldDisconnected) *oldDisconnected = n; +} + +void QDeclarativeNotifierEndpoint::copyAndClear(QDeclarativeNotifierEndpoint &other) +{ + other.disconnect(); + + other.target = target; + other.targetMethod = targetMethod; + + if (!isConnected()) + return; + + if (SignalType == type) { + Signal *other_s = other.toSignal(); + Signal *s = asSignal(); + + other_s->source = s->source; + other_s->sourceSignal = s->sourceSignal; + s->source = 0; + } else if(NotifierType == type) { + Notifier *other_n = other.toNotifier(); + Notifier *n = asNotifier(); + + other_n->notifier = n->notifier; + other_n->disconnected = n->disconnected; + if (other_n->disconnected) *other_n->disconnected = other_n; + + if (n->next) { + other_n->next = n->next; + n->next->asNotifier()->prev = &other_n->next; + } + other_n->prev = n->prev; + *other_n->prev = &other; + + n->prev = 0; + n->next = 0; + n->disconnected = 0; + n->notifier = 0; + } +} + + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qdeclarativenotifier_p.h b/src/declarative/qml/qdeclarativenotifier_p.h new file mode 100644 index 0000000..a0e6b43 --- /dev/null +++ b/src/declarative/qml/qdeclarativenotifier_p.h @@ -0,0 +1,272 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVENOTIFIER_P_H +#define QDECLARATIVENOTIFIER_P_H + +#include "qdeclarativeguard_p.h" + +QT_BEGIN_NAMESPACE + +class QDeclarativeNotifierEndpoint; +class QDeclarativeNotifier +{ +public: + inline QDeclarativeNotifier(); + inline ~QDeclarativeNotifier(); + inline void notify(); + +private: + friend class QDeclarativeNotifierEndpoint; + + static void emitNotify(QDeclarativeNotifierEndpoint *); + QDeclarativeNotifierEndpoint *endpoints; +}; + +class QDeclarativeNotifierEndpoint +{ +public: + inline QDeclarativeNotifierEndpoint(); + inline QDeclarativeNotifierEndpoint(QObject *t, int m); + inline ~QDeclarativeNotifierEndpoint(); + + QObject *target; + int targetMethod; + + inline bool isConnected(); + inline bool isConnected(QObject *source, int sourceSignal); + inline bool isConnected(QDeclarativeNotifier *); + + inline void connect(QObject *source, int sourceSignal); + inline void connect(QDeclarativeNotifier *); + inline void disconnect(); + + void copyAndClear(QDeclarativeNotifierEndpoint &other); + +private: + friend class QDeclarativeNotifier; + + struct Signal { + QDeclarativeGuard<QObject> source; + int sourceSignal; + }; + + struct Notifier { + QDeclarativeNotifier *notifier; + Notifier **disconnected; + + QDeclarativeNotifierEndpoint *next; + QDeclarativeNotifierEndpoint **prev; + }; + + enum { InvalidType, SignalType, NotifierType } type; + union { + char signalData[sizeof(Signal)]; + char notifierData[sizeof(Notifier)]; + }; + + inline Notifier *toNotifier(); + inline Notifier *asNotifier(); + inline Signal *toSignal(); + inline Signal *asSignal(); +}; + +QDeclarativeNotifier::QDeclarativeNotifier() +: endpoints(0) +{ + QDeclarativeNotifierEndpoint *endpoint = endpoints; + while (endpoint) { + QDeclarativeNotifierEndpoint *next = endpoint->asNotifier()->next; + endpoint->asNotifier()->next = 0; + endpoint->asNotifier()->prev = 0; + endpoint->asNotifier()->notifier = 0; + endpoint = next; + } +} + +QDeclarativeNotifier::~QDeclarativeNotifier() +{ +} + +void QDeclarativeNotifier::notify() +{ + if (endpoints) emitNotify(endpoints); +} + +QDeclarativeNotifierEndpoint::QDeclarativeNotifierEndpoint() +: target(0), targetMethod(0), type(InvalidType) +{ +} + +QDeclarativeNotifierEndpoint::QDeclarativeNotifierEndpoint(QObject *t, int m) +: target(t), targetMethod(m), type(InvalidType) +{ +} + +QDeclarativeNotifierEndpoint::~QDeclarativeNotifierEndpoint() +{ + disconnect(); + if (SignalType == type) { + Signal *s = asSignal(); + s->~Signal(); + } +} + +bool QDeclarativeNotifierEndpoint::isConnected() +{ + if (SignalType == type) { + return asSignal()->source; + } else if (NotifierType == type) { + return asNotifier()->notifier; + } else { + return false; + } +} + +bool QDeclarativeNotifierEndpoint::isConnected(QObject *source, int sourceSignal) +{ + return SignalType == type && asSignal()->source == source && asSignal()->sourceSignal == sourceSignal; +} + +bool QDeclarativeNotifierEndpoint::isConnected(QDeclarativeNotifier *notifier) +{ + return NotifierType == type && asNotifier()->notifier == notifier; +} + +void QDeclarativeNotifierEndpoint::connect(QObject *source, int sourceSignal) +{ + Signal *s = toSignal(); + + if (s->source == source && s->sourceSignal == sourceSignal) + return; + + disconnect(); + + QMetaObject::connect(source, sourceSignal, target, targetMethod); + + s->source = source; + s->sourceSignal = sourceSignal; +} + +void QDeclarativeNotifierEndpoint::connect(QDeclarativeNotifier *notifier) +{ + Notifier *n = toNotifier(); + + if (n->notifier == notifier) + return; + + disconnect(); + + n->next = notifier->endpoints; + if (n->next) { n->next->asNotifier()->prev = &n->next; } + notifier->endpoints = this; + n->prev = ¬ifier->endpoints; + n->notifier = notifier; +} + +void QDeclarativeNotifierEndpoint::disconnect() +{ + if (type == SignalType) { + Signal *s = (Signal *)&signalData; + if (s->source) { + QMetaObject::disconnectOne(s->source, s->sourceSignal, target, targetMethod); + s->source = 0; + } + } else if (type == NotifierType) { + Notifier *n = asNotifier(); + + if (n->next) n->next->asNotifier()->prev = n->prev; + if (n->prev) *n->prev = n->next; + if (n->disconnected) *n->disconnected = 0; + n->next = 0; + n->prev = 0; + n->disconnected = 0; + n->notifier = 0; + } +} + +QDeclarativeNotifierEndpoint::Notifier *QDeclarativeNotifierEndpoint::toNotifier() +{ + if (NotifierType == type) + return asNotifier(); + + if (SignalType == type) { + disconnect(); + Signal *s = asSignal(); + s->~Signal(); + } + + Notifier *n = asNotifier(); + n->next = 0; + n->prev = 0; + n->disconnected = 0; + n->notifier = 0; + type = NotifierType; + return n; +} + +QDeclarativeNotifierEndpoint::Notifier *QDeclarativeNotifierEndpoint::asNotifier() +{ + return (Notifier *)(¬ifierData); +} + +QDeclarativeNotifierEndpoint::Signal *QDeclarativeNotifierEndpoint::toSignal() +{ + if (SignalType == type) + return asSignal(); + + disconnect(); + Signal *s = asSignal(); + new (s) Signal; + type = SignalType; + + return s; +} + +QDeclarativeNotifierEndpoint::Signal *QDeclarativeNotifierEndpoint::asSignal() +{ + return (Signal *)(&signalData); +} + +QT_END_NAMESPACE + +#endif // QDECLARATIVENOTIFIER_P_H + diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp index e6f6e5f..32a28fe 100644 --- a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp +++ b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp @@ -59,6 +59,15 @@ QT_BEGIN_NAMESPACE struct ObjectData : public QScriptDeclarativeClass::Object { ObjectData(QObject *o, int t) : object(o), type(t) {} + + virtual ~ObjectData() { + if (object && !object->parent()) { + QDeclarativeDeclarativeData *ddata = QDeclarativeDeclarativeData::get(object, false); + if (ddata && !ddata->indestructible) + object->deleteLater(); + } + } + QDeclarativeGuard<QObject> object; int type; }; @@ -87,7 +96,7 @@ QDeclarativeObjectScriptClass::~QDeclarativeObjectScriptClass() { } -QScriptValue QDeclarativeObjectScriptClass::newQObject(QObject *object, int type) +QScriptValue QDeclarativeObjectScriptClass::newQObject(QObject *object, int type) { QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); @@ -96,7 +105,11 @@ QScriptValue QDeclarativeObjectScriptClass::newQObject(QObject *object, int type QDeclarativeDeclarativeData *ddata = QDeclarativeDeclarativeData::get(object, true); - if (!ddata->scriptValue.isValid()) { + if (!ddata) { + return scriptEngine->undefinedValue(); + } else if (!ddata->indestructible && !object->parent()) { + return newObject(scriptEngine, this, new ObjectData(object, type)); + } else if (!ddata->scriptValue.isValid()) { ddata->scriptValue = newObject(scriptEngine, this, new ObjectData(object, type)); return ddata->scriptValue; } else if (ddata->scriptValue.engine() == QDeclarativeEnginePrivate::getScriptEngine(engine)) { @@ -338,7 +351,8 @@ void QDeclarativeObjectScriptClass::setProperty(QObject *obj, } } - QDeclarativeAbstractBinding *delBinding = QDeclarativePropertyPrivate::setBinding(obj, *lastData, 0); + QDeclarativeAbstractBinding *delBinding = + QDeclarativePropertyPrivate::setBinding(obj, lastData->coreIndex, -1, 0); if (delBinding) delBinding->destroy(); @@ -392,17 +406,30 @@ QScriptValue QDeclarativeObjectScriptClass::tostring(QScriptContext *context, QS QScriptValue QDeclarativeObjectScriptClass::destroy(QScriptContext *context, QScriptEngine *engine) { - QObject* obj = context->thisObject().toQObject(); - if(obj){ - int delay = 0; - if(context->argumentCount() > 0) - delay = context->argument(0).toInt32(); - if (delay > 0) - QTimer::singleShot(delay, obj, SLOT(deleteLater())); - else - obj->deleteLater(); - } - return engine->nullValue(); + QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine); + QScriptValue that = context->thisObject(); + + if (scriptClass(that) != p->objectClass) + return engine->undefinedValue(); + + ObjectData *data = (ObjectData *)p->objectClass->object(that); + if (!data->object) + return engine->undefinedValue(); + + QDeclarativeDeclarativeData *ddata = QDeclarativeDeclarativeData::get(data->object, false); + if (!ddata || ddata->indestructible) + return engine->currentContext()->throwError(QLatin1String("Invalid attempt to destroy() an indestructible object")); + + QObject *obj = data->object; + int delay = 0; + if (context->argumentCount() > 0) + delay = context->argument(0).toInt32(); + if (delay > 0) + QTimer::singleShot(delay, obj, SLOT(deleteLater())); + else + obj->deleteLater(); + + return engine->undefinedValue(); } QStringList QDeclarativeObjectScriptClass::propertyNames(Object *object) @@ -428,6 +455,14 @@ QStringList QDeclarativeObjectScriptClass::propertyNames(Object *object) return cache->propertyNames(); } +bool QDeclarativeObjectScriptClass::compare(Object *o1, Object *o2) +{ + ObjectData *d1 = (ObjectData *)o1; + ObjectData *d2 = (ObjectData *)o2; + + return d1 == d2 || d1->object == d2->object; +} + #if (QT_VERSION > QT_VERSION_CHECK(4, 6, 2)) || defined(QT_HAVE_QSCRIPTDECLARATIVECLASS_VALUE) struct MethodData : public QScriptDeclarativeClass::Object { @@ -441,6 +476,8 @@ QDeclarativeObjectMethodScriptClass::QDeclarativeObjectMethodScriptClass(QDeclar : QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine) { + qRegisterMetaType<QList<QObject *> >("QList<QObject *>"); + setSupportsCall(true); QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); @@ -551,7 +588,7 @@ private: inline void cleanup(); - char *data[16]; + void *data[4]; int type; }; } @@ -569,11 +606,13 @@ MetaCallArgument::~MetaCallArgument() void MetaCallArgument::cleanup() { if (type == QMetaType::QString) { - ((QString *)data)->~QString(); + ((QString *)&data)->~QString(); } else if (type == -1 || type == qMetaTypeId<QVariant>()) { - ((QVariant *)data)->~QVariant(); + ((QVariant *)&data)->~QVariant(); } else if (type == qMetaTypeId<QScriptValue>()) { - ((QScriptValue *)data)->~QScriptValue(); + ((QScriptValue *)&data)->~QScriptValue(); + } else if (type == qMetaTypeId<QList<QObject *> >()) { + ((QList<QObject *> *)&data)->~QList<QObject *>(); } } @@ -582,7 +621,7 @@ void *MetaCallArgument::dataPtr() if (type == -1) return ((QVariant *)data)->data(); else - return (void *)data; + return (void *)&data; } void MetaCallArgument::initAsType(int callType, QDeclarativeEngine *e) @@ -593,7 +632,7 @@ void MetaCallArgument::initAsType(int callType, QDeclarativeEngine *e) QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(e); if (callType == qMetaTypeId<QScriptValue>()) { - new (data) QScriptValue(engine->undefinedValue()); + new (&data) QScriptValue(engine->undefinedValue()); type = callType; } else if (callType == QMetaType::Int || callType == QMetaType::UInt || @@ -602,17 +641,20 @@ void MetaCallArgument::initAsType(int callType, QDeclarativeEngine *e) callType == QMetaType::Float) { type = callType; } else if (callType == QMetaType::QObjectStar) { - *((QObject **)data) = 0; + *((QObject **)&data) = 0; type = callType; } else if (callType == QMetaType::QString) { - new (data) QString(); + new (&data) QString(); type = callType; } else if (callType == qMetaTypeId<QVariant>()) { - type = qMetaTypeId<QVariant>(); - new (data) QVariant(); + type = callType; + new (&data) QVariant(); + } else if (callType == qMetaTypeId<QList<QObject *> >()) { + type = callType; + new (&data) QList<QObject *>(); } else { type = -1; - new (data) QVariant(callType, (void *)0); + new (&data) QVariant(callType, (void *)0); } } @@ -621,47 +663,50 @@ void MetaCallArgument::fromScriptValue(int callType, QDeclarativeEngine *engine, if (type != 0) { cleanup(); type = 0; } if (callType == qMetaTypeId<QScriptValue>()) { - new (data) QScriptValue(value); + new (&data) QScriptValue(value); type = qMetaTypeId<QScriptValue>(); } else if (callType == QMetaType::Int) { - *((int *)data) = int(value.toInt32()); + *((int *)&data) = int(value.toInt32()); type = callType; } else if (callType == QMetaType::UInt) { - *((uint *)data) = uint(value.toUInt32()); + *((uint *)&data) = uint(value.toUInt32()); type = callType; } else if (callType == QMetaType::Bool) { - *((bool *)data) = value.toBool(); + *((bool *)&data) = value.toBool(); type = callType; } else if (callType == QMetaType::Double) { - *((double *)data) = double(value.toNumber()); + *((double *)&data) = double(value.toNumber()); type = callType; } else if (callType == QMetaType::Float) { - *((float *)data) = float(value.toNumber()); + *((float *)&data) = float(value.toNumber()); type = callType; } else if (callType == QMetaType::QString) { if (value.isNull() || value.isUndefined()) - new (data) QString(); + new (&data) QString(); else - new (data) QString(value.toString()); + new (&data) QString(value.toString()); type = callType; } else if (callType == QMetaType::QObjectStar) { - *((QObject **)data) = value.toQObject(); + *((QObject **)&data) = value.toQObject(); type = callType; } else if (callType == qMetaTypeId<QVariant>()) { - new (data) QVariant(QDeclarativeScriptClass::toVariant(engine, value)); + new (&data) QVariant(QDeclarativeScriptClass::toVariant(engine, value)); + type = callType; + } else if (callType == qMetaTypeId<QList<QObject*> >()) { + new (&data) QList<QObject *>(); // We don't support passing in QList<QObject*> type = callType; } else { - new (data) QVariant(); + new (&data) QVariant(); type = -1; QVariant v = QDeclarativeScriptClass::toVariant(engine, value); if (v.userType() == callType) { - *((QVariant *)data) = v; + *((QVariant *)&data) = v; } else if (v.canConvert((QVariant::Type)callType)) { - *((QVariant *)data) = v; - ((QVariant *)data)->convert((QVariant::Type)callType); + *((QVariant *)&data) = v; + ((QVariant *)&data)->convert((QVariant::Type)callType); } else { - *((QVariant *)data) = QVariant(callType, (void *)0); + *((QVariant *)&data) = QVariant(callType, (void *)0); } } } @@ -671,23 +716,36 @@ QScriptDeclarativeClass::Value MetaCallArgument::toValue(QDeclarativeEngine *e) QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(e); if (type == qMetaTypeId<QScriptValue>()) { - return QScriptDeclarativeClass::Value(engine, *((QScriptValue *)data)); + return QScriptDeclarativeClass::Value(engine, *((QScriptValue *)&data)); } else if (type == QMetaType::Int) { - return QScriptDeclarativeClass::Value(engine, *((int *)data)); + return QScriptDeclarativeClass::Value(engine, *((int *)&data)); } else if (type == QMetaType::UInt) { - return QScriptDeclarativeClass::Value(engine, *((uint *)data)); + return QScriptDeclarativeClass::Value(engine, *((uint *)&data)); } else if (type == QMetaType::Bool) { - return QScriptDeclarativeClass::Value(engine, *((bool *)data)); + return QScriptDeclarativeClass::Value(engine, *((bool *)&data)); } else if (type == QMetaType::Double) { - return QScriptDeclarativeClass::Value(engine, *((double *)data)); + return QScriptDeclarativeClass::Value(engine, *((double *)&data)); } else if (type == QMetaType::Float) { - return QScriptDeclarativeClass::Value(engine, *((float *)data)); + return QScriptDeclarativeClass::Value(engine, *((float *)&data)); } else if (type == QMetaType::QString) { - return QScriptDeclarativeClass::Value(engine, *((QString *)data)); + return QScriptDeclarativeClass::Value(engine, *((QString *)&data)); } else if (type == QMetaType::QObjectStar) { - return QScriptDeclarativeClass::Value(engine, QDeclarativeEnginePrivate::get(e)->objectClass->newQObject(*((QObject **)data))); + QObject *object = *((QObject **)&data); + QDeclarativeDeclarativeData::get(object, true)->setImplicitDestructible(); + QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(e); + return QScriptDeclarativeClass::Value(engine, priv->objectClass->newQObject(object)); + } else if (type == qMetaTypeId<QList<QObject *> >()) { + QList<QObject *> &list = *(QList<QObject *>*)&data; + QScriptValue rv = engine->newArray(list.count()); + QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(e); + for (int ii = 0; ii < list.count(); ++ii) { + QObject *object = list.at(ii); + QDeclarativeDeclarativeData::get(object, true)->setImplicitDestructible(); + rv.setProperty(ii, priv->objectClass->newQObject(object)); + } + return QScriptDeclarativeClass::Value(engine, rv); } else if (type == -1 || type == qMetaTypeId<QVariant>()) { - return QScriptDeclarativeClass::Value(engine, QDeclarativeEnginePrivate::get(e)->scriptValueFromVariant(*((QVariant *)data))); + return QScriptDeclarativeClass::Value(engine, QDeclarativeEnginePrivate::get(e)->scriptValueFromVariant(*((QVariant *)&data))); } else { return QScriptDeclarativeClass::Value(); } diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass_p.h b/src/declarative/qml/qdeclarativeobjectscriptclass_p.h index 04e760f..1f7d1c9 100644 --- a/src/declarative/qml/qdeclarativeobjectscriptclass_p.h +++ b/src/declarative/qml/qdeclarativeobjectscriptclass_p.h @@ -57,6 +57,7 @@ #include "qdeclarativetypenamecache_p.h" #include <private/qdeclarativescriptclass_p.h> +#include <QtScript/qscriptengine.h> QT_BEGIN_NAMESPACE @@ -99,6 +100,7 @@ public: ~QDeclarativeObjectScriptClass(); QScriptValue newQObject(QObject *, int type = QMetaType::QObjectStar); + QObject *toQObject(const QScriptValue &) const; int objectType(const QScriptValue &) const; @@ -118,6 +120,7 @@ public: void setProperty(QObject *, const Identifier &name, const QScriptValue &, QDeclarativeContext *evalContext = 0); virtual QStringList propertyNames(Object *); + virtual bool compare(Object *, Object *); protected: virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, diff --git a/src/declarative/qml/qdeclarativeparser.cpp b/src/declarative/qml/qdeclarativeparser.cpp index b0599ad..51f1660 100644 --- a/src/declarative/qml/qdeclarativeparser.cpp +++ b/src/declarative/qml/qdeclarativeparser.cpp @@ -207,13 +207,14 @@ QDeclarativeParser::Object::DynamicSlot::DynamicSlot(const DynamicSlot &o) } QDeclarativeParser::Property::Property() -: parent(0), type(0), index(-1), value(0), isDefault(true), isDeferred(false) +: parent(0), type(0), index(-1), value(0), isDefault(true), isDeferred(false), + isValueTypeSubProperty(false) { } QDeclarativeParser::Property::Property(const QByteArray &n) : parent(0), type(0), index(-1), value(0), name(n), isDefault(false), - isDeferred(false) + isDeferred(false), isValueTypeSubProperty(false) { } diff --git a/src/declarative/qml/qdeclarativeparser_p.h b/src/declarative/qml/qdeclarativeparser_p.h index 5bf4b68..9dfb86b 100644 --- a/src/declarative/qml/qdeclarativeparser_p.h +++ b/src/declarative/qml/qdeclarativeparser_p.h @@ -351,6 +351,8 @@ namespace QDeclarativeParser // True if the setting of this property will be deferred. Set by the // QDeclarativeCompiler bool isDeferred; + // True if this property is a value-type psuedo-property + bool isValueTypeSubProperty; LocationSpan location; LocationRange listValueRange; diff --git a/src/declarative/qml/qdeclarativeprivate.h b/src/declarative/qml/qdeclarativeprivate.h index 01369d4..bebe82c 100644 --- a/src/declarative/qml/qdeclarativeprivate.h +++ b/src/declarative/qml/qdeclarativeprivate.h @@ -73,6 +73,9 @@ namespace QDeclarativePrivate QObject *create() { return new T; } template<typename T> + void createInto(void *memory) { new (memory) T; } + + template<typename T> QObject *createParent(QObject *p) { return new T(p); } template<class From, class To, int N> @@ -172,7 +175,8 @@ namespace QDeclarativePrivate int typeId; int listId; - QObject *(*create)(); + int objectSize; + void (*create)(void *); const char *uri; int versionMajor; diff --git a/src/declarative/qml/qdeclarativeproperty.cpp b/src/declarative/qml/qdeclarativeproperty.cpp index 945d098..c55c22f 100644 --- a/src/declarative/qml/qdeclarativeproperty.cpp +++ b/src/declarative/qml/qdeclarativeproperty.cpp @@ -494,15 +494,13 @@ QDeclarativeProperty &QDeclarativeProperty::operator=(const QDeclarativeProperty */ bool QDeclarativeProperty::isWritable() const { - QDeclarativeProperty::PropertyTypeCategory category = propertyTypeCategory(); - if (!d->object) return false; - if (category == List) + if (d->core.flags & QDeclarativePropertyCache::Data::IsQList) //list return true; - else if (type() & SignalProperty) + else if (d->core.flags & QDeclarativePropertyCache::Data::IsFunction) //signal handler return false; - else if (d->core.isValid() && d->object) + else if (d->core.isValid()) //normal property return d->core.flags & QDeclarativePropertyCache::Data::IsWritable; else return false; @@ -598,7 +596,6 @@ QMetaMethod QDeclarativeProperty::method() const return QMetaMethod(); } - /*! Returns the binding associated with this property, or 0 if no binding exists. @@ -617,13 +614,18 @@ QDeclarativePropertyPrivate::binding(const QDeclarativeProperty &that) return 0; QDeclarativeAbstractBinding *binding = data->bindings; - while (binding) { - // ### This wont work for value types - if (binding->propertyIndex() == that.d->core.coreIndex) - return binding; + while (binding && binding->propertyIndex() != that.d->core.coreIndex) binding = binding->m_nextBinding; + + if (binding && that.d->valueType.valueTypeCoreIdx != -1) { + if (binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy) { + QDeclarativeValueTypeProxyBinding *proxy = static_cast<QDeclarativeValueTypeProxyBinding *>(binding); + + binding = proxy->binding(bindingIndex(that)); + } } - return 0; + + return binding; } /*! @@ -650,36 +652,36 @@ QDeclarativePropertyPrivate::setBinding(const QDeclarativeProperty &that, return 0; } - return that.d->setBinding(that.d->object, that.d->core, newBinding, flags); + return that.d->setBinding(that.d->object, that.d->core.coreIndex, + that.d->valueType.valueTypeCoreIdx, newBinding, flags); } QDeclarativeAbstractBinding * -QDeclarativePropertyPrivate::setBinding(QObject *object, const QDeclarativePropertyCache::Data &core, - QDeclarativeAbstractBinding *newBinding, WriteFlags flags) +QDeclarativePropertyPrivate::setBinding(QObject *object, int coreIndex, int valueTypeIndex, + QDeclarativeAbstractBinding *newBinding, WriteFlags flags) { QDeclarativeDeclarativeData *data = QDeclarativeDeclarativeData::get(object, 0 != newBinding); + QDeclarativeAbstractBinding *binding = 0; - if (data && data->hasBindingBit(core.coreIndex)) { - QDeclarativeAbstractBinding *binding = data->bindings; - while (binding) { - // ### This wont work for value types - if (binding->propertyIndex() == core.coreIndex) { - binding->setEnabled(false); + if (data && data->hasBindingBit(coreIndex)) { + binding = data->bindings; - if (newBinding) - newBinding->setEnabled(true, flags); + while (binding && binding->propertyIndex() != coreIndex) + binding = binding->m_nextBinding; + } - return binding; // ### QDeclarativeAbstractBinding; - } + if (binding && valueTypeIndex != -1 && binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy) { + int index = coreIndex | (valueTypeIndex << 24); + binding = static_cast<QDeclarativeValueTypeProxyBinding *>(binding)->binding(index); + } - binding = binding->m_nextBinding; - } - } + if (binding) + binding->setEnabled(false); - if (newBinding) + if (newBinding) newBinding->setEnabled(true, flags); - return 0; + return binding; } /*! @@ -1253,6 +1255,18 @@ int QDeclarativePropertyPrivate::valueTypeCoreIndex(const QDeclarativeProperty & return that.d->valueType.valueTypeCoreIdx; } +/*! + Returns the "property index" for use in bindings. The top 8 bits are the value type + offset, and 0 otherwise. The bottom 24-bits are the regular property index. +*/ +int QDeclarativePropertyPrivate::bindingIndex(const QDeclarativeProperty &that) +{ + int rv = that.d->core.coreIndex; + if (rv != -1 && that.d->valueType.valueTypeCoreIdx != -1) + rv = rv | (that.d->valueType.valueTypeCoreIdx << 24); + return rv; +} + struct SerializedData { bool isValueType; QDeclarativePropertyCache::Data core; diff --git a/src/declarative/qml/qdeclarativeproperty_p.h b/src/declarative/qml/qdeclarativeproperty_p.h index c31e2d3..26b85b8 100644 --- a/src/declarative/qml/qdeclarativeproperty_p.h +++ b/src/declarative/qml/qdeclarativeproperty_p.h @@ -110,7 +110,7 @@ public: const QVariant &value, int flags); static bool write(QObject *, const QDeclarativePropertyCache::Data &, const QVariant &, QDeclarativeContext *, WriteFlags flags = 0); - static QDeclarativeAbstractBinding *setBinding(QObject *, const QDeclarativePropertyCache::Data &, + static QDeclarativeAbstractBinding *setBinding(QObject *, int coreIndex, int valueTypeIndex /* -1 */, QDeclarativeAbstractBinding *, WriteFlags flags = DontRemoveBinding); @@ -133,6 +133,7 @@ public: QDeclarativeExpression *) ; static bool write(const QDeclarativeProperty &that, const QVariant &, WriteFlags); static int valueTypeCoreIndex(const QDeclarativeProperty &that); + static int bindingIndex(const QDeclarativeProperty &that); }; Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativePropertyPrivate::WriteFlags) diff --git a/src/declarative/qml/qdeclarativepropertycache_p.h b/src/declarative/qml/qdeclarativepropertycache_p.h index 68e6e6b..bfbeff4 100644 --- a/src/declarative/qml/qdeclarativepropertycache_p.h +++ b/src/declarative/qml/qdeclarativepropertycache_p.h @@ -55,15 +55,16 @@ #include "qdeclarativerefcount_p.h" #include "qdeclarativecleanup_p.h" +#include "qdeclarativenotifier_p.h" #include <QtCore/qvector.h> #include <QtScript/private/qscriptdeclarativeclass_p.h> - QT_BEGIN_NAMESPACE class QDeclarativeEngine; class QMetaProperty; + class QDeclarativePropertyCache : public QDeclarativeRefCount, public QDeclarativeCleanup { public: @@ -83,9 +84,9 @@ public: IsResettable = 0x00000004, // These are mutualy exclusive - IsFunction = 0x00000008, - IsQObjectDerived = 0x00000010, - IsEnumType = 0x00000020, + IsFunction = 0x00000010, + IsQObjectDerived = 0x00000020, + IsEnumType = 0x00000040, IsQList = 0x00000080, IsQmlBinding = 0x00000100, IsQScriptValue = 0x00000200, @@ -96,7 +97,7 @@ public: }; Q_DECLARE_FLAGS(Flags, Flag) - + bool isValid() const { return coreIndex != -1; } Flags flags; @@ -114,9 +115,9 @@ public: struct ValueTypeData { inline ValueTypeData(); inline bool operator==(const ValueTypeData &); - Data::Flags flags; // flags on the value type wrapper - int valueTypeCoreIdx; // The prop index of the access property on the value type wrapper - int valueTypePropType; // The QVariant::Type of access property on the value type wrapper + Data::Flags flags; // flags of the access property on the value type proxy object + int valueTypeCoreIdx; // The prop index of the access property on the value type proxy object + int valueTypePropType; // The QVariant::Type of access property on the value type proxy object }; void update(QDeclarativeEngine *, const QMetaObject *); diff --git a/src/declarative/qml/qdeclarativevaluetype.cpp b/src/declarative/qml/qdeclarativevaluetype.cpp index c070123..00e6704 100644 --- a/src/declarative/qml/qdeclarativevaluetype.cpp +++ b/src/declarative/qml/qdeclarativevaluetype.cpp @@ -61,7 +61,7 @@ int qmlRegisterValueTypeEnums(const char *qmlName) QDeclarativePrivate::RegisterType type = { 0, - qRegisterMetaType<T *>(pointerName.constData()), 0, 0, + qRegisterMetaType<T *>(pointerName.constData()), 0, 0, 0, "Qt", 4, 6, qmlName, &T::staticMetaObject, diff --git a/src/declarative/qml/qdeclarativevaluetypescriptclass.cpp b/src/declarative/qml/qdeclarativevaluetypescriptclass.cpp index 9cb65f8..a567c38 100644 --- a/src/declarative/qml/qdeclarativevaluetypescriptclass.cpp +++ b/src/declarative/qml/qdeclarativevaluetypescriptclass.cpp @@ -41,6 +41,8 @@ #include "qdeclarativevaluetypescriptclass_p.h" +#include "qdeclarativebinding_p.h" +#include "qdeclarativeproperty_p.h" #include "qdeclarativeengine_p.h" #include "qdeclarativeguard_p.h" @@ -115,6 +117,11 @@ void QDeclarativeValueTypeScriptClass::setProperty(Object *obj, const Identifier { QDeclarativeValueTypeReference *ref = static_cast<QDeclarativeValueTypeReference *>(obj); + QDeclarativeAbstractBinding *delBinding = + QDeclarativePropertyPrivate::setBinding(ref->object, ref->property, m_lastIndex, 0); + if (delBinding) + delBinding->destroy(); + QVariant v = QDeclarativeScriptClass::toVariant(engine, value); ref->type->read(ref->object, ref->property); diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp index 6a08674..05553fd 100644 --- a/src/declarative/qml/qdeclarativevme.cpp +++ b/src/declarative/qml/qdeclarativevme.cpp @@ -130,9 +130,9 @@ void QDeclarativeVME::runDeferred(QObject *object) } QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, QDeclarativeContext *ctxt, - QDeclarativeCompiledData *comp, - int start, int count, - const QBitField &bindingSkipList) + QDeclarativeCompiledData *comp, + int start, int count, + const QBitField &bindingSkipList) { Q_ASSERT(comp); Q_ASSERT(ctxt); @@ -197,6 +197,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, QDeclarati QDeclarativeDeclarativeData *ddata = QDeclarativeDeclarativeData::get(o); Q_ASSERT(ddata); + ddata->setImplicitDestructible(); ddata->outerContext = ctxt; ddata->lineNumber = instr.line; ddata->columnNumber = instr.create.column; @@ -236,7 +237,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, QDeclarati case QDeclarativeInstruction::SetDefault: { QObject *target = stack.top(); - ctxt->addDefaultObject(target); + ctxt->setContextObject(target); } break; @@ -247,6 +248,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, QDeclarati QDeclarativeEngine::setContextForObject(qcomp, ctxt); QDeclarativeDeclarativeData *ddata = QDeclarativeDeclarativeData::get(qcomp); Q_ASSERT(ddata); + ddata->setImplicitDestructible(); ddata->outerContext = ctxt; ddata->lineNumber = instr.line; ddata->columnNumber = instr.create.column; @@ -832,11 +834,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, QDeclarati if (parserStatus.count) ep->parserStatus << parserStatus; - if (stack.isEmpty()) - return 0; - else - return stack.top(); - return 0; + Q_ASSERT(stack.count() == 1); + return stack.top(); } bool QDeclarativeVME::isError() const diff --git a/src/declarative/qml/qdeclarativevme_p.h b/src/declarative/qml/qdeclarativevme_p.h index 951f6a7..bcd3ac9 100644 --- a/src/declarative/qml/qdeclarativevme_p.h +++ b/src/declarative/qml/qdeclarativevme_p.h @@ -71,7 +71,7 @@ template<typename T, int N = 128> class QDeclarativeVMEStack { public: QDeclarativeVMEStack() : index(-1), maxSize(N), data(fixedData) {} - ~QDeclarativeVMEStack() { if (data != fixedData) qFree(fixedData); } + ~QDeclarativeVMEStack() { if (data != fixedData) qFree(data); } bool isEmpty() const { return index == -1; } const T &top() const { return data[index]; } diff --git a/src/declarative/qml/qdeclarativeworkerscript.cpp b/src/declarative/qml/qdeclarativeworkerscript.cpp index 784353a..10c0b54 100644 --- a/src/declarative/qml/qdeclarativeworkerscript.cpp +++ b/src/declarative/qml/qdeclarativeworkerscript.cpp @@ -40,7 +40,8 @@ ****************************************************************************/ #include "qdeclarativeworkerscript_p.h" - +#include "qdeclarativelistmodel_p.h" +#include "qdeclarativelistmodelworkeragent_p.h" #include "qdeclarativeengine_p.h" #include <QtCore/qcoreevent.h> @@ -104,6 +105,7 @@ private: class QDeclarativeWorkerScriptEnginePrivate : public QObject { + Q_OBJECT public: QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *eng); @@ -165,87 +167,6 @@ private: void processLoad(int, const QUrl &); }; -// Currently this will leak as no-one releases it in the worker thread -class QDeclarativeWorkerListModelAgent : public QObject -{ - Q_OBJECT - Q_PROPERTY(int count READ count) - -public: - QDeclarativeWorkerListModelAgent(QDeclarativeWorkerListModel *); - ~QDeclarativeWorkerListModelAgent(); - - 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(QDeclarativeWorkerListModelAgent *_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; - } - - QDeclarativeWorkerListModelAgent *a; - }; -protected: - virtual bool event(QEvent *); - -private: - friend class QDeclarativeWorkerScriptEnginePrivate; - friend class QDeclarativeWorkerListModel; - 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; - QDeclarativeWorkerListModel *m_model; -}; - -QT_END_NAMESPACE - -Q_DECLARE_METATYPE(QDeclarativeWorkerListModelAgent::VariantRef); - -QT_BEGIN_NAMESPACE - QDeclarativeWorkerScriptEnginePrivate::QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *engine) : workerEngine(0), qmlengine(engine), m_nextId(0) { @@ -390,10 +311,15 @@ QVariant QDeclarativeWorkerScriptEnginePrivate::scriptValueToVariant(const QScri return QVariant(list); } else if (value.isQObject()) { - QDeclarativeWorkerListModel *lm = qobject_cast<QDeclarativeWorkerListModel *>(value.toQObject()); + QDeclarativeListModel *lm = qobject_cast<QDeclarativeListModel *>(value.toQObject()); if (lm) { - QDeclarativeWorkerListModelAgent::VariantRef v(lm->agent()); - return qVariantFromValue(v); + QDeclarativeListModelWorkerAgent *agent = lm->agent(); + if (agent) { + QDeclarativeListModelWorkerAgent::VariantRef v(agent); + return qVariantFromValue(v); + } else { + return QVariant(); + } } else { // No other QObject's are allowed to be sent return QVariant(); @@ -423,11 +349,11 @@ QScriptValue QDeclarativeWorkerScriptEnginePrivate::variantToScriptValue(const Q return QScriptValue(value.toString()); } else if (value.userType() == QMetaType::QReal) { return QScriptValue(value.toReal()); - } else if (value.userType() == qMetaTypeId<QDeclarativeWorkerListModelAgent::VariantRef>()) { - QDeclarativeWorkerListModelAgent::VariantRef vr = qvariant_cast<QDeclarativeWorkerListModelAgent::VariantRef>(value); - if (vr.a->m_engine == 0) - vr.a->m_engine = engine; - else if (vr.a->m_engine != engine) + } else if (value.userType() == qMetaTypeId<QDeclarativeListModelWorkerAgent::VariantRef>()) { + QDeclarativeListModelWorkerAgent::VariantRef vr = qvariant_cast<QDeclarativeListModelWorkerAgent::VariantRef>(value); + if (vr.a->scriptEngine() == 0) + vr.a->setScriptEngine(engine); + else if (vr.a->scriptEngine() != 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 @@ -619,8 +545,6 @@ void QDeclarativeWorkerScriptEngine::run() called, triggering the \tt WorkerScript.onMessage() handler in \tt source.js. This in turn sends a reply message that is then received by the \tt onMessage() handler of \tt myWorker. - - \sa WorkerListModel */ QDeclarativeWorkerScript::QDeclarativeWorkerScript(QObject *parent) : QObject(parent), m_engine(0), m_scriptId(-1) @@ -714,544 +638,7 @@ bool QDeclarativeWorkerScript::event(QEvent *event) } } -void QDeclarativeWorkerListModelAgent::Data::clearChange() -{ - changes.clear(); -} - -void QDeclarativeWorkerListModelAgent::Data::insertChange(int index, int count) -{ - Change c = { Change::Inserted, index, count, 0 }; - changes << c; -} - -void QDeclarativeWorkerListModelAgent::Data::removeChange(int index, int count) -{ - Change c = { Change::Removed, index, count, 0 }; - changes << c; -} - -void QDeclarativeWorkerListModelAgent::Data::changedChange(int index, int count) -{ - Change c = { Change::Changed, index, count, 0 }; - changes << c; -} - -QDeclarativeWorkerListModelAgent::QDeclarativeWorkerListModelAgent(QDeclarativeWorkerListModel *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; -} - -QDeclarativeWorkerListModelAgent::~QDeclarativeWorkerListModelAgent() -{ -} - -void QDeclarativeWorkerListModelAgent::addref() -{ - m_ref.ref(); -} - -void QDeclarativeWorkerListModelAgent::release() -{ - bool del = !m_ref.deref(); - - if (del) - delete this; -} - -int QDeclarativeWorkerListModelAgent::count() const -{ - return data.values.count(); -} - -void QDeclarativeWorkerListModelAgent::clear() -{ - data.clearChange(); - data.removeChange(0, data.values.count()); - data.values.clear(); -} - -void QDeclarativeWorkerListModelAgent::remove(int index) -{ - if (data.values.count() <= index) - return; - - data.values.removeAt(index); - data.removeChange(index, 1); -} - -void QDeclarativeWorkerListModelAgent::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 QDeclarativeWorkerListModelAgent::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 QDeclarativeWorkerListModelAgent::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 QDeclarativeWorkerListModelAgent::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 QDeclarativeWorkerListModelAgent::sync() -{ - Sync *s = new Sync; - s->data = data; - data.changes.clear(); - QCoreApplication::postEvent(this, s); -} - -bool QDeclarativeWorkerListModelAgent::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); -} - -/*! - \qmlclass WorkerListModel QDeclarativeWorkerListModel - \brief The WorkerListModel element provides a threaded list model. - - Use WorkerListModel together with WorkerScript to define a list model - that is controlled by a separate thread. This is useful if list modification - operations are synchronous and take some time: using WorkerListModel - moves these operations to a different thread and avoids blocking of the - main GUI thread. - - The thread that creates the WorkerListModel can modify the model for any - initial set-up requirements. However, once the model has been modified by - the associated WorkerScript, the model can only be modified by that worker - script and becomes read-only to all other threads. - - Here is an example application that uses WorkerScript to append the - current time to a WorkerListModel: - - \snippet examples/declarative/workerlistmodel/timedisplay.qml 0 - - The included file, \tt dataloader.js, looks like this: - - \snippet examples/declarative/workerlistmodel/dataloader.js 0 - - The application's \tt Timer object periodically sends a message to the - worker script by calling \tt WorkerScript::sendMessage(). When this message - is received, \tt WorkerScript.onMessage() is invoked in - \tt dataloader.js, which appends the current time to the worker list - model. - - Note that unlike ListModel, WorkerListModel does not have \tt move() and - \tt setProperty() methods. - - \sa WorkerScript, ListModel -*/ -QDeclarativeWorkerListModel::QDeclarativeWorkerListModel(QObject *parent) -: QListModelInterface(parent), m_agent(0) -{ -} - -QDeclarativeWorkerListModel::~QDeclarativeWorkerListModel() -{ - if (m_agent) { - m_agent->m_model = 0; - m_agent->release(); - } -} - -/*! - \qmlmethod WorkerListModel::clear() - - Deletes all content from the model. The properties are cleared such that - different properties may be set on subsequent additions. - - \sa append() remove() -*/ -void QDeclarativeWorkerListModel::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(); - } -} - -/*! - \qmlmethod WorkerListModel::remove(int index) - - Deletes the content at \a index from the model. - - \sa clear() -*/ -void QDeclarativeWorkerListModel::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(); -} - -/*! - \qmlmethod WorkerListModel::append(jsobject dict) - - Adds a new item to the end of the list model, with the - values in \a dict. - - \code - FruitModel.append({"cost": 5.95, "name":"Pizza"}) - \endcode - - \sa set() remove() -*/ -void QDeclarativeWorkerListModel::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(); -} - -/*! - \qmlmethod WorkerListModel::insert(int index, jsobject dict) - - Adds a new item to the list model at position \a index, with the - values in \a dict. - - \code - FruitModel.insert(2, {"cost": 5.95, "name":"Pizza"}) - \endcode - - The \a index must be to an existing item in the list, or one past - the end of the list (equivalent to append). - - \sa set() append() -*/ -void QDeclarativeWorkerListModel::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(); -} - -/*! - \qmlmethod object ListModel::get(int index) - - Returns the item at \a index in the list model. - - \code - FruitModel.append({"cost": 5.95, "name":"Jackfruit"}) - FruitModel.get(0).cost - \endcode - - The \a index must be an element in the list. - - Note that properties of the returned object that are themselves objects - will also be models, and this get() method is used to access elements: - - \code - FruitModel.append(..., "attributes": - [{"name":"spikes","value":"7mm"}, - {"name":"color","value":"green"}]); - FruitModel.get(0).attributes.get(1).value; // == "green" - \endcode - - \sa append() -*/ -QScriptValue QDeclarativeWorkerListModel::get(int index) const -{ - QDeclarativeEngine *engine = qmlEngine(this); - if (!engine || m_values.count() <= index) - return QScriptValue(); - - QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::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; -} - -/*! - \qmlmethod WorkerListModel::set(int index, jsobject dict) - - Changes the item at \a index in the list model with the - values in \a dict. Properties not appearing in \a valuemap - are left unchanged. - - \code - FruitModel.set(3, {"cost": 5.95, "name":"Pizza"}) - \endcode - - The \a index must be an element in the list. - - \sa append() -*/ -void QDeclarativeWorkerListModel::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()); - } -} - -/*! - \qmlmethod WorkerListModel::sync() - - Writes any unsaved changes to the list model. This must be called after - changes have been made to the list model in the worker script. - - Note that this method can only be called from the associated worker script. -*/ -void QDeclarativeWorkerListModel::sync() -{ - // This is really a dummy method to make it look like sync() exists in - // WorkerListModel (and not QDeclarativeWorkerListModelAgent) and to let - // us document sync(). - qmlInfo(this) << "sync() can only be called from a WorkerScript"; -} - -QDeclarativeWorkerListModelAgent *QDeclarativeWorkerListModel::agent() -{ - if (!m_agent) - m_agent = new QDeclarativeWorkerListModelAgent(this); - - return m_agent; -} - -QList<int> QDeclarativeWorkerListModel::roles() const -{ - return m_roles.keys(); -} - -QString QDeclarativeWorkerListModel::toString(int role) const -{ - return m_roles.value(role); -} - -/*! - \qmlproperty int ListModel::count - The number of data entries in the model. -*/ -int QDeclarativeWorkerListModel::count() const -{ - return m_values.count(); -} - -QHash<int,QVariant> QDeclarativeWorkerListModel::data(int index, const QList<int> &) const -{ - if (m_values.count() <= index) - return QHash<int, QVariant>(); - else - return m_values.at(index); -} - -QVariant QDeclarativeWorkerListModel::data(int index, int role) const -{ - if (m_values.count() <= index) - return QVariant(); - else - return m_values.at(index).value(role); -} - QT_END_NAMESPACE -#include "qdeclarativeworkerscript.moc" +#include <qdeclarativeworkerscript.moc> diff --git a/src/declarative/qml/qdeclarativeworkerscript_p.h b/src/declarative/qml/qdeclarativeworkerscript_p.h index 912eac9..6cce799 100644 --- a/src/declarative/qml/qdeclarativeworkerscript_p.h +++ b/src/declarative/qml/qdeclarativeworkerscript_p.h @@ -55,7 +55,6 @@ #include "qdeclarative.h" #include "qdeclarativeparserstatus.h" -#include <private/qlistmodelinterface_p.h> #include <QtCore/qthread.h> #include <QtScript/qscriptvalue.h> @@ -118,49 +117,9 @@ private: QUrl m_source; }; -class QDeclarativeWorkerListModelAgent; -class Q_DECLARATIVE_EXPORT QDeclarativeWorkerListModel : public QListModelInterface -{ - Q_OBJECT - Q_PROPERTY(int count READ count NOTIFY countChanged) - -public: - QDeclarativeWorkerListModel(QObject * = 0); - virtual ~QDeclarativeWorkerListModel(); - - 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(); - - QDeclarativeWorkerListModelAgent *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 QDeclarativeWorkerListModelAgent; - - QHash<int, QString> m_roles; - QHash<QString, int> m_strings; - QList<QHash<int, QVariant> > m_values; - - QDeclarativeWorkerListModelAgent *m_agent; -}; - QT_END_NAMESPACE QML_DECLARE_TYPE(QDeclarativeWorkerScript); -QML_DECLARE_TYPE(QDeclarativeWorkerListModel); QT_END_HEADER diff --git a/src/declarative/qml/qdeclarativexmlhttprequest.cpp b/src/declarative/qml/qdeclarativexmlhttprequest.cpp index 87cab85..58e67fa 100644 --- a/src/declarative/qml/qdeclarativexmlhttprequest.cpp +++ b/src/declarative/qml/qdeclarativexmlhttprequest.cpp @@ -1245,7 +1245,7 @@ void QDeclarativeXMLHttpRequest::finished() if (m_redirectCount < XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION) { QVariant redirect = m_network->attribute(QNetworkRequest::RedirectionTargetAttribute); if (redirect.isValid()) { - QUrl url = redirect.toUrl(); + QUrl url = m_network->url().resolved(redirect.toUrl()); destroyNetwork(); requestFromUrl(url); return; diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index aa1a34b..49888c3 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -38,6 +38,7 @@ SOURCES += \ $$PWD/qdeclarativescript.cpp \ $$PWD/qdeclarativecleanup.cpp \ $$PWD/qdeclarativepropertycache.cpp \ + $$PWD/qdeclarativenotifier.cpp \ $$PWD/qdeclarativeintegercache.cpp \ $$PWD/qdeclarativetypenamecache.cpp \ $$PWD/qdeclarativescriptstring.cpp \ @@ -108,6 +109,7 @@ HEADERS += \ $$PWD/qdeclarativewatcher_p.h \ $$PWD/qdeclarativecleanup_p.h \ $$PWD/qdeclarativepropertycache_p.h \ + $$PWD/qdeclarativenotifier_p.h \ $$PWD/qdeclarativeintegercache_p.h \ $$PWD/qdeclarativetypenamecache_p.h \ $$PWD/qdeclarativescriptstring.h \ |